@backstage/frontend-app-api 0.16.8-next.2 → 0.16.9-next.0
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 +26 -0
- package/dist/catalog-model/src/entity/constants.esm.js.map +1 -1
- package/dist/catalog-model/src/entity/ref.esm.js +1 -3
- package/dist/catalog-model/src/entity/ref.esm.js.map +1 -1
- package/dist/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.esm.js.map +1 -1
- package/dist/core-app-api/src/apis/implementations/IdentityApi/startCookieAuthRefresh.esm.js.map +1 -1
- package/dist/extensions/Root.esm.js.map +1 -1
- package/dist/frontend-internal/src/apis/OpaqueApiRef.esm.js.map +1 -1
- package/dist/frontend-internal/src/routing/OpaqueExternalRouteRef.esm.js.map +1 -1
- package/dist/frontend-internal/src/routing/OpaqueRouteRef.esm.js.map +1 -1
- package/dist/frontend-internal/src/routing/OpaqueSubRouteRef.esm.js.map +1 -1
- package/dist/frontend-internal/src/wiring/InternalExtensionDefinition.esm.js.map +1 -1
- package/dist/frontend-internal/src/wiring/InternalExtensionInput.esm.js.map +1 -1
- package/dist/frontend-internal/src/wiring/InternalFrontendPlugin.esm.js.map +1 -1
- package/dist/frontend-internal/src/wiring/createExtensionDataContainer.esm.js.map +1 -1
- package/dist/frontend-plugin-api/src/wiring/createFrontendModule.esm.js.map +1 -1
- package/dist/frontend-plugin-api/src/wiring/resolveExtensionDefinition.esm.js.map +1 -1
- package/dist/opaque-internal/src/OpaqueType.esm.js.map +1 -1
- package/dist/routing/RouteAliasResolver.esm.js.map +1 -1
- package/dist/routing/RouteResolver.esm.js.map +1 -1
- package/dist/routing/collectRouteIds.esm.js.map +1 -1
- package/dist/routing/extractRouteInfoFromAppNode.esm.js.map +1 -1
- package/dist/routing/getBasePath.esm.js.map +1 -1
- package/dist/routing/joinPaths.esm.js.map +1 -1
- package/dist/routing/resolveRouteBindings.esm.js.map +1 -1
- package/dist/tree/instantiateAppNodeTree.esm.js.map +1 -1
- package/dist/tree/readAppExtensionsConfig.esm.js.map +1 -1
- package/dist/tree/resolveAppNodeSpecs.esm.js.map +1 -1
- package/dist/tree/resolveAppTree.esm.js.map +1 -1
- package/dist/wiring/FrontendApiRegistry.esm.js.map +1 -1
- package/dist/wiring/apiFactories.esm.js.map +1 -1
- package/dist/wiring/createErrorCollector.esm.js.map +1 -1
- package/dist/wiring/createPluginInfoAttacher.esm.js.map +1 -1
- package/dist/wiring/createSpecializedApp.esm.js.map +1 -1
- package/dist/wiring/phaseApis.esm.js.map +1 -1
- package/dist/wiring/predicates.esm.js.map +1 -1
- package/dist/wiring/prepareSpecializedApp.esm.js.map +1 -1
- package/dist/wiring/treeLifecycle.esm.js.map +1 -1
- package/package.json +13 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractRouteInfoFromAppNode.esm.js","sources":["../../src/routing/extractRouteInfoFromAppNode.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 { RouteRef, coreExtensionData } from '@backstage/frontend-plugin-api';\nimport { BackstageRouteObject } from './types';\nimport { AppNode } from '@backstage/frontend-plugin-api';\nimport {\n createExactRouteAliasResolver,\n RouteAliasResolver,\n} from './RouteAliasResolver';\nimport { joinPaths } from './joinPaths';\n\n/** @internal */\nexport type RouteInfo = {\n routePaths: Map<RouteRef, string>;\n routeParents: Map<RouteRef, RouteRef | undefined>;\n routeObjects: BackstageRouteObject[];\n routeAliasResolver: RouteAliasResolver;\n};\n\n// We always add a child that matches all subroutes but without any route refs. This makes\n// sure that we're always able to match each route no matter how deep the navigation goes.\n// The route resolver then takes care of selecting the most specific match in order to find\n// mount points that are as deep in the routing tree as possible.\nexport const MATCH_ALL_ROUTE: BackstageRouteObject = {\n caseSensitive: false,\n path: '*',\n element: 'match-all', // These elements aren't used, so we add in a bit of debug information\n routeRefs: new Set(),\n};\n\nexport function extractRouteInfoFromAppNode(\n node: AppNode,\n routeAliasResolver: RouteAliasResolver,\n): RouteInfo {\n // This tracks the route path for each route ref, the value is the route path relative to the parent ref\n const routePaths = new Map<RouteRef, string>();\n // This tracks the parents of each route ref. To find the full path of any route ref you traverse\n // upwards in this tree and substitute each route ref for its route path along then way.\n const routeParents = new Map<RouteRef, RouteRef | undefined>();\n // This route object tree is passed to react-router in order to be able to look up the current route\n // ref or extension/source based on our current location.\n const routeObjects = new Array<BackstageRouteObject>();\n // This tracks all resolved route aliases. By storing and re-using the resolutions here we make sure that it's not\n // possible to pass an aliased route ref directly to the resolver, e.g. `useRouteRef(createRouteRef({ aliasFor: 'example.root' }))`\n const routeAliases = new Map<RouteRef, RouteRef | undefined>();\n\n function visit(\n current: AppNode,\n collectedPath?: string,\n foundRefForCollectedPath: boolean = false,\n parentRef?: RouteRef,\n candidateParentRef?: RouteRef,\n parentObj?: BackstageRouteObject,\n ) {\n const routePath = current.instance\n ?.getData(coreExtensionData.routePath)\n ?.replace(/^\\//, '');\n\n const foundRouteRef = current.instance?.getData(coreExtensionData.routeRef);\n const routeRef = routeAliasResolver(foundRouteRef, current.spec.plugin?.id);\n if (foundRouteRef && routeRef !== foundRouteRef) {\n routeAliases.set(foundRouteRef, routeRef);\n }\n\n const parentChildren = parentObj?.children ?? routeObjects;\n let currentObj = parentObj;\n\n let newCollectedPath = collectedPath;\n let newFoundRefForCollectedPath = foundRefForCollectedPath;\n\n let newParentRef = parentRef;\n let newCandidateParentRef = candidateParentRef;\n\n // Whenever a route path is encountered, a new node is created in the routing tree.\n if (routePath !== undefined) {\n currentObj = {\n path: routePath,\n element: 'mounted',\n routeRefs: new Set<RouteRef>(),\n caseSensitive: false,\n children: [MATCH_ALL_ROUTE],\n appNode: current,\n };\n parentChildren.push(currentObj);\n\n // Each route path that we discover creates a new node in the routing tree, at that point\n // we also switch out our candidate parent ref to be the active one.\n newParentRef = candidateParentRef;\n newCandidateParentRef = undefined;\n\n // We need to collect and concatenate route paths until the path has been assigned a route ref:\n // Once we find a route ref the collection starts over from an empty path, that way each route\n // path assignment only contains the diff from the parent ref.\n if (newFoundRefForCollectedPath) {\n newCollectedPath = routePath;\n newFoundRefForCollectedPath = false;\n } else {\n newCollectedPath = collectedPath\n ? joinPaths(collectedPath, routePath)\n : routePath;\n }\n }\n\n // Whenever a route ref is encountered, we need to give it a route path and position in the ref tree.\n if (routeRef) {\n // The first route ref we find after encountering a route path is selected to be used as the\n // parent ref further down the tree. We don't start using this candidate ref until we encounter\n // another route path though, at which point we repeat the process and select another candidate.\n if (!newCandidateParentRef) {\n newCandidateParentRef = routeRef;\n }\n\n // Check if we've encountered any route paths since the closest route ref, in that case we assign\n // that path to this and following route refs until we encounter another route path.\n if (newCollectedPath !== undefined) {\n routePaths.set(routeRef, newCollectedPath);\n newFoundRefForCollectedPath = true;\n }\n\n routeParents.set(routeRef, newParentRef);\n currentObj?.routeRefs.add(routeRef);\n }\n\n for (const children of current.edges.attachments.values()) {\n for (const child of children) {\n visit(\n child,\n newCollectedPath,\n newFoundRefForCollectedPath,\n newParentRef,\n newCandidateParentRef,\n currentObj,\n );\n }\n }\n }\n\n visit(node);\n\n return {\n routePaths,\n routeParents,\n routeObjects,\n routeAliasResolver: createExactRouteAliasResolver(routeAliases),\n };\n}\n"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"extractRouteInfoFromAppNode.esm.js","sources":["../../src/routing/extractRouteInfoFromAppNode.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 { RouteRef, coreExtensionData } from '@backstage/frontend-plugin-api';\nimport { BackstageRouteObject } from './types';\nimport { AppNode } from '@backstage/frontend-plugin-api';\nimport {\n createExactRouteAliasResolver,\n RouteAliasResolver,\n} from './RouteAliasResolver';\nimport { joinPaths } from './joinPaths';\n\n/** @internal */\nexport type RouteInfo = {\n routePaths: Map<RouteRef, string>;\n routeParents: Map<RouteRef, RouteRef | undefined>;\n routeObjects: BackstageRouteObject[];\n routeAliasResolver: RouteAliasResolver;\n};\n\n// We always add a child that matches all subroutes but without any route refs. This makes\n// sure that we're always able to match each route no matter how deep the navigation goes.\n// The route resolver then takes care of selecting the most specific match in order to find\n// mount points that are as deep in the routing tree as possible.\nexport const MATCH_ALL_ROUTE: BackstageRouteObject = {\n caseSensitive: false,\n path: '*',\n element: 'match-all', // These elements aren't used, so we add in a bit of debug information\n routeRefs: new Set(),\n};\n\nexport function extractRouteInfoFromAppNode(\n node: AppNode,\n routeAliasResolver: RouteAliasResolver,\n): RouteInfo {\n // This tracks the route path for each route ref, the value is the route path relative to the parent ref\n const routePaths = new Map<RouteRef, string>();\n // This tracks the parents of each route ref. To find the full path of any route ref you traverse\n // upwards in this tree and substitute each route ref for its route path along then way.\n const routeParents = new Map<RouteRef, RouteRef | undefined>();\n // This route object tree is passed to react-router in order to be able to look up the current route\n // ref or extension/source based on our current location.\n const routeObjects = new Array<BackstageRouteObject>();\n // This tracks all resolved route aliases. By storing and re-using the resolutions here we make sure that it's not\n // possible to pass an aliased route ref directly to the resolver, e.g. `useRouteRef(createRouteRef({ aliasFor: 'example.root' }))`\n const routeAliases = new Map<RouteRef, RouteRef | undefined>();\n\n function visit(\n current: AppNode,\n collectedPath?: string,\n foundRefForCollectedPath: boolean = false,\n parentRef?: RouteRef,\n candidateParentRef?: RouteRef,\n parentObj?: BackstageRouteObject,\n ) {\n const routePath = current.instance\n ?.getData(coreExtensionData.routePath)\n ?.replace(/^\\//, '');\n\n const foundRouteRef = current.instance?.getData(coreExtensionData.routeRef);\n const routeRef = routeAliasResolver(foundRouteRef, current.spec.plugin?.id);\n if (foundRouteRef && routeRef !== foundRouteRef) {\n routeAliases.set(foundRouteRef, routeRef);\n }\n\n const parentChildren = parentObj?.children ?? routeObjects;\n let currentObj = parentObj;\n\n let newCollectedPath = collectedPath;\n let newFoundRefForCollectedPath = foundRefForCollectedPath;\n\n let newParentRef = parentRef;\n let newCandidateParentRef = candidateParentRef;\n\n // Whenever a route path is encountered, a new node is created in the routing tree.\n if (routePath !== undefined) {\n currentObj = {\n path: routePath,\n element: 'mounted',\n routeRefs: new Set<RouteRef>(),\n caseSensitive: false,\n children: [MATCH_ALL_ROUTE],\n appNode: current,\n };\n parentChildren.push(currentObj);\n\n // Each route path that we discover creates a new node in the routing tree, at that point\n // we also switch out our candidate parent ref to be the active one.\n newParentRef = candidateParentRef;\n newCandidateParentRef = undefined;\n\n // We need to collect and concatenate route paths until the path has been assigned a route ref:\n // Once we find a route ref the collection starts over from an empty path, that way each route\n // path assignment only contains the diff from the parent ref.\n if (newFoundRefForCollectedPath) {\n newCollectedPath = routePath;\n newFoundRefForCollectedPath = false;\n } else {\n newCollectedPath = collectedPath\n ? joinPaths(collectedPath, routePath)\n : routePath;\n }\n }\n\n // Whenever a route ref is encountered, we need to give it a route path and position in the ref tree.\n if (routeRef) {\n // The first route ref we find after encountering a route path is selected to be used as the\n // parent ref further down the tree. We don't start using this candidate ref until we encounter\n // another route path though, at which point we repeat the process and select another candidate.\n if (!newCandidateParentRef) {\n newCandidateParentRef = routeRef;\n }\n\n // Check if we've encountered any route paths since the closest route ref, in that case we assign\n // that path to this and following route refs until we encounter another route path.\n if (newCollectedPath !== undefined) {\n routePaths.set(routeRef, newCollectedPath);\n newFoundRefForCollectedPath = true;\n }\n\n routeParents.set(routeRef, newParentRef);\n currentObj?.routeRefs.add(routeRef);\n }\n\n for (const children of current.edges.attachments.values()) {\n for (const child of children) {\n visit(\n child,\n newCollectedPath,\n newFoundRefForCollectedPath,\n newParentRef,\n newCandidateParentRef,\n currentObj,\n );\n }\n }\n }\n\n visit(node);\n\n return {\n routePaths,\n routeParents,\n routeObjects,\n routeAliasResolver: createExactRouteAliasResolver(routeAliases),\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getBasePath.esm.js","sources":["../../src/routing/getBasePath.ts"],"sourcesContent":["/*\n * Copyright 2024 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 { ConfigApi } from '@backstage/frontend-plugin-api';\n\n/** @internal */\nexport function getBasePath(configApi: ConfigApi) {\n let { pathname } = new URL(\n configApi.getOptionalString('app.baseUrl') ?? '/',\n 'http://sample.dev', // baseUrl can be specified as just a path\n );\n pathname = pathname.replace(/\\/*$/, '');\n return pathname;\n}\n"],"names":[],"mappings":"AAmBO,SAAS,YAAY,SAAA,EAAsB;AAChD,EAAA,IAAI,EAAE,QAAA,EAAS,GAAI,IAAI,GAAA;AAAA,IACrB,SAAA,CAAU,iBAAA,CAAkB,aAAa,CAAA,IAAK,GAAA;AAAA,IAC9C;AAAA;AAAA,GACF;AACA,EAAA,QAAA,GAAW,QAAA,CAAS,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA;AACtC,EAAA,OAAO,QAAA;AACT
|
|
1
|
+
{"version":3,"file":"getBasePath.esm.js","sources":["../../src/routing/getBasePath.ts"],"sourcesContent":["/*\n * Copyright 2024 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 { ConfigApi } from '@backstage/frontend-plugin-api';\n\n/** @internal */\nexport function getBasePath(configApi: ConfigApi) {\n let { pathname } = new URL(\n configApi.getOptionalString('app.baseUrl') ?? '/',\n 'http://sample.dev', // baseUrl can be specified as just a path\n );\n pathname = pathname.replace(/\\/*$/, '');\n return pathname;\n}\n"],"names":[],"mappings":"AAmBO,SAAS,YAAY,SAAA,EAAsB;AAChD,EAAA,IAAI,EAAE,QAAA,EAAS,GAAI,IAAI,GAAA;AAAA,IACrB,SAAA,CAAU,iBAAA,CAAkB,aAAa,CAAA,IAAK,GAAA;AAAA,IAC9C;AAAA;AAAA,GACF;AACA,EAAA,QAAA,GAAW,QAAA,CAAS,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA;AACtC,EAAA,OAAO,QAAA;AACT;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"joinPaths.esm.js","sources":["../../src/routing/joinPaths.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\n// Joins a list of paths together, avoiding trailing and duplicate slashes\nexport function joinPaths(...paths: string[]): string {\n const normalized = paths.join('/').replace(/\\/\\/+/g, '/');\n if (normalized !== '/' && normalized.endsWith('/')) {\n return normalized.slice(0, -1);\n }\n return normalized;\n}\n"],"names":[],"mappings":"AAiBO,SAAS,aAAa,KAAA,EAAyB;AACpD,EAAA,MAAM,aAAa,KAAA,CAAM,IAAA,CAAK,GAAG,CAAA,CAAE,OAAA,CAAQ,UAAU,GAAG,CAAA;AACxD,EAAA,IAAI,UAAA,KAAe,GAAA,IAAO,UAAA,CAAW,QAAA,CAAS,GAAG,CAAA,EAAG;AAClD,IAAA,OAAO,UAAA,CAAW,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EAC/B;AACA,EAAA,OAAO,UAAA;AACT
|
|
1
|
+
{"version":3,"file":"joinPaths.esm.js","sources":["../../src/routing/joinPaths.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\n// Joins a list of paths together, avoiding trailing and duplicate slashes\nexport function joinPaths(...paths: string[]): string {\n const normalized = paths.join('/').replace(/\\/\\/+/g, '/');\n if (normalized !== '/' && normalized.endsWith('/')) {\n return normalized.slice(0, -1);\n }\n return normalized;\n}\n"],"names":[],"mappings":"AAiBO,SAAS,aAAa,KAAA,EAAyB;AACpD,EAAA,MAAM,aAAa,KAAA,CAAM,IAAA,CAAK,GAAG,CAAA,CAAE,OAAA,CAAQ,UAAU,GAAG,CAAA;AACxD,EAAA,IAAI,UAAA,KAAe,GAAA,IAAO,UAAA,CAAW,QAAA,CAAS,GAAG,CAAA,EAAG;AAClD,IAAA,OAAO,UAAA,CAAW,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EAC/B;AACA,EAAA,OAAO,UAAA;AACT;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveRouteBindings.esm.js","sources":["../../src/routing/resolveRouteBindings.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 {\n RouteRef,\n SubRouteRef,\n ExternalRouteRef,\n} from '@backstage/frontend-plugin-api';\nimport { RouteRefsById } from './collectRouteIds';\nimport { ErrorCollector } from '../wiring/createErrorCollector';\nimport { Config } from '@backstage/config';\nimport { JsonObject } from '@backstage/types';\nimport { OpaqueExternalRouteRef } from '@internal/frontend';\n\n/**\n * Extracts a union of the keys in a map whose value extends the given type\n *\n * @ignore\n */\ntype KeysWithType<Obj extends { [key in string]: any }, Type> = {\n [key in keyof Obj]: Obj[key] extends Type ? key : never;\n}[keyof Obj];\n\n/**\n * Takes a map Map required values and makes all keys matching Keys optional\n *\n * @ignore\n */\ntype PartialKeys<\n Map extends { [name in string]: any },\n Keys extends keyof Map,\n> = Partial<Pick<Map, Keys>> & Required<Omit<Map, Keys>>;\n\n/**\n * Creates a map of target routes with matching parameters based on a map of external routes.\n *\n * @ignore\n */\ntype TargetRouteMap<\n ExternalRoutes extends { [name: string]: ExternalRouteRef },\n> = {\n [name in keyof ExternalRoutes]: ExternalRoutes[name] extends ExternalRouteRef<\n infer Params\n >\n ? RouteRef<Params> | SubRouteRef<Params> | false\n : never;\n};\n\n/**\n * A function that can bind from external routes of a given plugin, to concrete\n * routes of other plugins. See {@link @backstage/frontend-defaults#createApp}.\n *\n * @public\n */\nexport type CreateAppRouteBinder = <\n TExternalRoutes extends { [name: string]: ExternalRouteRef },\n>(\n externalRoutes: TExternalRoutes,\n targetRoutes: PartialKeys<\n TargetRouteMap<TExternalRoutes>,\n KeysWithType<TExternalRoutes, ExternalRouteRef<any>>\n >,\n) => void;\n\n/** @internal */\nexport function resolveRouteBindings(\n bindRoutes: ((context: { bind: CreateAppRouteBinder }) => void) | undefined,\n config: Config,\n routesById: RouteRefsById,\n collector: ErrorCollector,\n): Map<ExternalRouteRef, RouteRef | SubRouteRef> {\n const result = new Map<ExternalRouteRef, RouteRef | SubRouteRef>();\n const disabledExternalRefs = new Set<ExternalRouteRef>();\n\n // Perform callback bindings first with highest priority\n if (bindRoutes) {\n const bind: CreateAppRouteBinder = (\n externalRoutes,\n targetRoutes: { [name: string]: RouteRef | SubRouteRef },\n ) => {\n for (const [key, value] of Object.entries(targetRoutes)) {\n const externalRoute = externalRoutes[key];\n if (!externalRoute) {\n collector.report({\n code: 'ROUTE_NOT_FOUND',\n message: `Key ${key} is not an existing external route`,\n context: { routeId: String(key) },\n });\n continue;\n }\n if (value) {\n result.set(externalRoute, value);\n } else if (value === false) {\n disabledExternalRefs.add(externalRoute);\n }\n }\n };\n bindRoutes({ bind });\n }\n\n // Then perform config based bindings with lower priority\n const bindings = config\n .getOptionalConfig('app.routes.bindings')\n ?.get<JsonObject>();\n if (bindings) {\n for (const [externalRefId, targetRefId] of Object.entries(bindings)) {\n if (!isValidTargetRefId(targetRefId)) {\n collector.report({\n code: 'ROUTE_BINDING_INVALID_VALUE',\n message: `Invalid config at app.routes.bindings['${externalRefId}'], value must be a non-empty string or false`,\n context: { routeId: externalRefId },\n });\n continue;\n }\n\n const externalRef = routesById.externalRoutes.get(externalRefId);\n if (!externalRef) {\n collector.report({\n code: 'ROUTE_NOT_FOUND',\n message: `Invalid config at app.routes.bindings, '${externalRefId}' is not a valid external route`,\n context: { routeId: externalRefId },\n });\n continue;\n }\n\n // Skip if binding was already defined in code\n if (result.has(externalRef) || disabledExternalRefs.has(externalRef)) {\n continue;\n }\n\n if (targetRefId === false) {\n disabledExternalRefs.add(externalRef);\n } else {\n const targetRef = routesById.routes.get(targetRefId);\n if (!targetRef) {\n collector.report({\n code: 'ROUTE_NOT_FOUND',\n message: `Invalid config at app.routes.bindings['${externalRefId}'], '${String(\n targetRefId,\n )}' is not a valid route`,\n context: { routeId: String(targetRefId) },\n });\n continue;\n }\n\n result.set(externalRef, targetRef);\n }\n }\n }\n\n // Finally fall back to attempting to map defaults, at lowest priority\n for (const externalRef of routesById.externalRoutes.values()) {\n if (!result.has(externalRef) && !disabledExternalRefs.has(externalRef)) {\n const defaultRefId =\n OpaqueExternalRouteRef.toInternal(externalRef).getDefaultTarget();\n if (defaultRefId) {\n const defaultRef = routesById.routes.get(defaultRefId);\n if (defaultRef) {\n result.set(externalRef, defaultRef);\n }\n }\n }\n }\n\n return result;\n}\n\nfunction isValidTargetRefId(value: unknown): value is string | false {\n if (value === false) {\n return true;\n }\n\n if (typeof value === 'string' && value) {\n return true;\n }\n\n return false;\n}\n"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"resolveRouteBindings.esm.js","sources":["../../src/routing/resolveRouteBindings.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 {\n RouteRef,\n SubRouteRef,\n ExternalRouteRef,\n} from '@backstage/frontend-plugin-api';\nimport { RouteRefsById } from './collectRouteIds';\nimport { ErrorCollector } from '../wiring/createErrorCollector';\nimport { Config } from '@backstage/config';\nimport { JsonObject } from '@backstage/types';\nimport { OpaqueExternalRouteRef } from '@internal/frontend';\n\n/**\n * Extracts a union of the keys in a map whose value extends the given type\n *\n * @ignore\n */\ntype KeysWithType<Obj extends { [key in string]: any }, Type> = {\n [key in keyof Obj]: Obj[key] extends Type ? key : never;\n}[keyof Obj];\n\n/**\n * Takes a map Map required values and makes all keys matching Keys optional\n *\n * @ignore\n */\ntype PartialKeys<\n Map extends { [name in string]: any },\n Keys extends keyof Map,\n> = Partial<Pick<Map, Keys>> & Required<Omit<Map, Keys>>;\n\n/**\n * Creates a map of target routes with matching parameters based on a map of external routes.\n *\n * @ignore\n */\ntype TargetRouteMap<\n ExternalRoutes extends { [name: string]: ExternalRouteRef },\n> = {\n [name in keyof ExternalRoutes]: ExternalRoutes[name] extends ExternalRouteRef<\n infer Params\n >\n ? RouteRef<Params> | SubRouteRef<Params> | false\n : never;\n};\n\n/**\n * A function that can bind from external routes of a given plugin, to concrete\n * routes of other plugins. See {@link @backstage/frontend-defaults#createApp}.\n *\n * @public\n */\nexport type CreateAppRouteBinder = <\n TExternalRoutes extends { [name: string]: ExternalRouteRef },\n>(\n externalRoutes: TExternalRoutes,\n targetRoutes: PartialKeys<\n TargetRouteMap<TExternalRoutes>,\n KeysWithType<TExternalRoutes, ExternalRouteRef<any>>\n >,\n) => void;\n\n/** @internal */\nexport function resolveRouteBindings(\n bindRoutes: ((context: { bind: CreateAppRouteBinder }) => void) | undefined,\n config: Config,\n routesById: RouteRefsById,\n collector: ErrorCollector,\n): Map<ExternalRouteRef, RouteRef | SubRouteRef> {\n const result = new Map<ExternalRouteRef, RouteRef | SubRouteRef>();\n const disabledExternalRefs = new Set<ExternalRouteRef>();\n\n // Perform callback bindings first with highest priority\n if (bindRoutes) {\n const bind: CreateAppRouteBinder = (\n externalRoutes,\n targetRoutes: { [name: string]: RouteRef | SubRouteRef },\n ) => {\n for (const [key, value] of Object.entries(targetRoutes)) {\n const externalRoute = externalRoutes[key];\n if (!externalRoute) {\n collector.report({\n code: 'ROUTE_NOT_FOUND',\n message: `Key ${key} is not an existing external route`,\n context: { routeId: String(key) },\n });\n continue;\n }\n if (value) {\n result.set(externalRoute, value);\n } else if (value === false) {\n disabledExternalRefs.add(externalRoute);\n }\n }\n };\n bindRoutes({ bind });\n }\n\n // Then perform config based bindings with lower priority\n const bindings = config\n .getOptionalConfig('app.routes.bindings')\n ?.get<JsonObject>();\n if (bindings) {\n for (const [externalRefId, targetRefId] of Object.entries(bindings)) {\n if (!isValidTargetRefId(targetRefId)) {\n collector.report({\n code: 'ROUTE_BINDING_INVALID_VALUE',\n message: `Invalid config at app.routes.bindings['${externalRefId}'], value must be a non-empty string or false`,\n context: { routeId: externalRefId },\n });\n continue;\n }\n\n const externalRef = routesById.externalRoutes.get(externalRefId);\n if (!externalRef) {\n collector.report({\n code: 'ROUTE_NOT_FOUND',\n message: `Invalid config at app.routes.bindings, '${externalRefId}' is not a valid external route`,\n context: { routeId: externalRefId },\n });\n continue;\n }\n\n // Skip if binding was already defined in code\n if (result.has(externalRef) || disabledExternalRefs.has(externalRef)) {\n continue;\n }\n\n if (targetRefId === false) {\n disabledExternalRefs.add(externalRef);\n } else {\n const targetRef = routesById.routes.get(targetRefId);\n if (!targetRef) {\n collector.report({\n code: 'ROUTE_NOT_FOUND',\n message: `Invalid config at app.routes.bindings['${externalRefId}'], '${String(\n targetRefId,\n )}' is not a valid route`,\n context: { routeId: String(targetRefId) },\n });\n continue;\n }\n\n result.set(externalRef, targetRef);\n }\n }\n }\n\n // Finally fall back to attempting to map defaults, at lowest priority\n for (const externalRef of routesById.externalRoutes.values()) {\n if (!result.has(externalRef) && !disabledExternalRefs.has(externalRef)) {\n const defaultRefId =\n OpaqueExternalRouteRef.toInternal(externalRef).getDefaultTarget();\n if (defaultRefId) {\n const defaultRef = routesById.routes.get(defaultRefId);\n if (defaultRef) {\n result.set(externalRef, defaultRef);\n }\n }\n }\n }\n\n return result;\n}\n\nfunction isValidTargetRefId(value: unknown): value is string | false {\n if (value === false) {\n return true;\n }\n\n if (typeof value === 'string' && value) {\n return true;\n }\n\n return false;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instantiateAppNodeTree.esm.js","sources":["../../src/tree/instantiateAppNodeTree.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 ApiHolder,\n ExtensionDataContainer,\n ExtensionDataRef,\n ExtensionInput,\n} from '@backstage/frontend-plugin-api';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { ResolvedExtensionInputs } from '../../../frontend-plugin-api/src/wiring/createExtension';\nimport { ExtensionFactoryMiddleware } from '../wiring/types';\nimport mapValues from 'lodash/mapValues';\nimport { AppNode, AppNodeInstance } from '@backstage/frontend-plugin-api';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalExtension } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';\nimport { createExtensionDataContainer } from '@internal/frontend';\nimport { ErrorCollector } from '../wiring/createErrorCollector';\nimport { evaluateFilterPredicate } from '@backstage/filter-predicates';\n\nconst INSTANTIATION_FAILED = new Error('Instantiation failed');\n\n/**\n * Like `array.map`, but if `INSTANTIATION_FAILED` is thrown, the iteration will continue but afterwards re-throw `INSTANTIATION_FAILED`\n * @returns\n */\nfunction mapWithFailures<T, U>(\n iterable: Iterable<T>,\n callback: (item: T) => U,\n options?: { ignoreFailures?: boolean },\n): U[] {\n let failed = false;\n const results = [];\n for (const item of iterable) {\n try {\n results.push(callback(item));\n } catch (error) {\n if (error === INSTANTIATION_FAILED) {\n failed = true;\n } else {\n throw error;\n }\n }\n }\n if (failed && !options?.ignoreFailures) {\n throw INSTANTIATION_FAILED;\n }\n return results;\n}\n\ntype Mutable<T> = {\n -readonly [P in keyof T]: T[P];\n};\n\ntype InstantiateAppNodeSubtreeOptions = {\n rootNode: AppNode;\n apis: ApiHolder;\n collector: ErrorCollector;\n extensionFactoryMiddleware?: ExtensionFactoryMiddleware;\n stopAtAttachment?(ctx: { node: AppNode; input: string }): boolean;\n skipChild?(ctx: { node: AppNode; input: string; child: AppNode }): boolean;\n onMissingApi?(ctx: { node: AppNode; apiRefId: string }): void;\n predicateContext?: Record<string, unknown>;\n reuseExistingInstances?: boolean;\n writeNodeInstances?: boolean;\n};\n\nfunction resolveV1InputDataMap(\n dataMap: {\n [name in string]: ExtensionDataRef;\n },\n attachment: AppNode,\n inputName: string,\n) {\n return Object.fromEntries(\n mapWithFailures(Object.entries(dataMap), ([key, ref]) => {\n const value = attachment.instance?.getData(ref);\n if (value === undefined && !ref.config.optional) {\n const expected = Object.values(dataMap)\n .filter(r => !r.config.optional)\n .map(r => `'${r.id}'`)\n .join(', ');\n\n const provided = [...(attachment.instance?.getDataRefs() ?? [])]\n .map(r => `'${r.id}'`)\n .join(', ');\n\n throw new Error(\n `extension '${attachment.spec.id}' could not be attached because its output data (${provided}) does not match what the input '${inputName}' requires (${expected})`,\n );\n }\n return [key, value];\n }),\n );\n}\n\nfunction resolveInputDataContainer(\n extensionData: Array<ExtensionDataRef>,\n attachment: AppNode,\n inputName: string,\n collector: ErrorCollector<{ node: AppNode; inputName: string }>,\n): { node: AppNode } & ExtensionDataContainer<ExtensionDataRef> {\n const dataMap = new Map<string, unknown>();\n\n mapWithFailures(extensionData, ref => {\n if (dataMap.has(ref.id)) {\n collector.report({\n code: 'EXTENSION_INPUT_DATA_IGNORED',\n message: `Unexpected duplicate input data '${ref.id}'`,\n });\n return;\n }\n\n const value = attachment.instance?.getData(ref);\n if (value === undefined && !ref.config.optional) {\n const expected = extensionData\n .filter(r => !r.config.optional)\n .map(r => `'${r.id}'`)\n .join(', ');\n\n const provided = [...(attachment.instance?.getDataRefs() ?? [])]\n .map(r => `'${r.id}'`)\n .join(', ');\n\n collector.child({ node: attachment }).report({\n code: 'EXTENSION_INPUT_DATA_MISSING',\n message: `extension '${attachment.spec.id}' could not be attached because its output data (${provided}) does not match what the input '${inputName}' requires (${expected})`,\n });\n throw INSTANTIATION_FAILED;\n }\n\n dataMap.set(ref.id, value);\n });\n\n return {\n node: attachment,\n get(ref) {\n return dataMap.get(ref.id);\n },\n *[Symbol.iterator]() {\n for (const [id, value] of dataMap) {\n // TODO: Would be better to be able to create a new instance using the ref here instead\n yield {\n $$type: '@backstage/ExtensionDataValue',\n id,\n value,\n };\n }\n },\n } as { node: AppNode } & ExtensionDataContainer<ExtensionDataRef>;\n}\n\nfunction reportUndeclaredAttachments(\n id: string,\n inputMap: { [name in string]: unknown },\n attachments: ReadonlyMap<string, AppNode[]>,\n) {\n const undeclaredAttachments = Array.from(attachments.entries()).filter(\n ([inputName]) => inputMap[inputName] === undefined,\n );\n\n const inputNames = Object.keys(inputMap);\n\n for (const [name, nodes] of undeclaredAttachments) {\n const pl = nodes.length > 1;\n // eslint-disable-next-line no-console\n console.warn(\n [\n `The extension${pl ? 's' : ''} '${nodes\n .map(n => n.spec.id)\n .join(\"', '\")}' ${pl ? 'are' : 'is'}`,\n `attached to the input '${name}' of the extension '${id}', but it`,\n inputNames.length === 0\n ? 'has no inputs'\n : `has no such input (candidates are '${inputNames.join(\"', '\")}')`,\n ].join(' '),\n );\n }\n}\n\nfunction resolveV1Inputs(\n inputMap: {\n [inputName in string]: {\n $$type: '@backstage/ExtensionInput';\n extensionData: {\n [name in string]: ExtensionDataRef;\n };\n config: { optional: boolean; singleton: boolean };\n };\n },\n attachments: ReadonlyMap<string, AppNode[]>,\n) {\n return Object.fromEntries(\n mapWithFailures(Object.entries(inputMap), ([inputName, input]) => {\n const attachedNodes = attachments.get(inputName) ?? [];\n\n if (input.config.singleton) {\n if (attachedNodes.length > 1) {\n const attachedNodeIds = attachedNodes.map(e => e.spec.id);\n throw Error(\n `expected ${\n input.config.optional ? 'at most' : 'exactly'\n } one '${inputName}' input but received multiple: '${attachedNodeIds.join(\n \"', '\",\n )}'`,\n );\n } else if (attachedNodes.length === 0) {\n if (input.config.optional) {\n return [inputName, undefined];\n }\n throw Error(`input '${inputName}' is required but was not received`);\n }\n return [\n inputName,\n {\n node: attachedNodes[0],\n output: resolveV1InputDataMap(\n input.extensionData,\n attachedNodes[0],\n inputName,\n ),\n },\n ];\n }\n\n return [\n inputName,\n attachedNodes.map(attachment => ({\n node: attachment,\n output: resolveV1InputDataMap(\n input.extensionData,\n attachment,\n inputName,\n ),\n })),\n ];\n }),\n ) as {\n [inputName in string]: {\n node: AppNode;\n output: {\n [name in string]: unknown;\n };\n };\n };\n}\n\nfunction resolveV2Inputs(\n inputMap: { [inputName in string]: ExtensionInput },\n attachments: ReadonlyMap<string, AppNode[]>,\n parentCollector: ErrorCollector<{ node: AppNode }>,\n node: AppNode,\n): ResolvedExtensionInputs<{ [inputName in string]: ExtensionInput }> {\n return mapValues(inputMap, (input, inputName) => {\n const allAttachedNodes = attachments.get(inputName) ?? [];\n const collector = parentCollector.child({ inputName });\n const inputPluginId = node.spec.plugin.pluginId;\n\n const attachedNodes = input.config.internal\n ? allAttachedNodes.filter(attachment => {\n const attachmentPluginId = attachment.spec.plugin.pluginId;\n if (attachmentPluginId !== inputPluginId) {\n collector.report({\n code: 'EXTENSION_INPUT_INTERNAL_IGNORED',\n message:\n `extension '${attachment.spec.id}' from plugin '${attachmentPluginId}' attached to input '${inputName}' on '${node.spec.id}' was ignored, ` +\n `the input is marked as internal and attached extensions must therefore be provided via an override or a module for the '${inputPluginId}' plugin, not the '${attachmentPluginId}' plugin`,\n context: {\n extensionId: attachment.spec.id,\n plugin: attachment.spec.plugin,\n },\n });\n return false;\n }\n return true;\n })\n : allAttachedNodes;\n\n if (input.config.singleton) {\n if (attachedNodes.length > 1) {\n const attachedNodeIds = attachedNodes.map(e => e.spec.id).join(\"', '\");\n collector.report({\n code: 'EXTENSION_ATTACHMENT_CONFLICT',\n message: `expected ${\n input.config.optional ? 'at most' : 'exactly'\n } one '${inputName}' input but received multiple: '${attachedNodeIds}'`,\n });\n throw INSTANTIATION_FAILED;\n } else if (attachedNodes.length === 0) {\n if (!input.config.optional) {\n collector.report({\n code: 'EXTENSION_ATTACHMENT_MISSING',\n message: `input '${inputName}' is required but was not received`,\n });\n throw INSTANTIATION_FAILED;\n }\n return undefined;\n }\n try {\n return resolveInputDataContainer(\n input.extensionData,\n attachedNodes[0],\n inputName,\n collector,\n );\n } catch (error) {\n if (error === INSTANTIATION_FAILED) {\n if (input.config.optional) {\n return undefined;\n }\n collector.report({\n code: 'EXTENSION_ATTACHMENT_MISSING',\n message: `input '${inputName}' is required but it failed to be instantiated`,\n });\n }\n throw error;\n }\n }\n\n return mapWithFailures(\n attachedNodes,\n attachment =>\n resolveInputDataContainer(\n input.extensionData,\n attachment,\n inputName,\n collector,\n ),\n { ignoreFailures: true },\n );\n }) as ResolvedExtensionInputs<{ [inputName in string]: ExtensionInput }>;\n}\n\n/** @internal */\nexport function createAppNodeInstance(options: {\n extensionFactoryMiddleware?: ExtensionFactoryMiddleware;\n node: AppNode;\n apis: ApiHolder;\n attachments: ReadonlyMap<string, AppNode[]>;\n collector: ErrorCollector;\n onMissingApi?(ctx: { node: AppNode; apiRefId: string }): void;\n}): AppNodeInstance | undefined {\n const { node, apis, attachments } = options;\n const collector = options.collector.child({ node });\n const { id, extension, config } = node.spec;\n const extensionData = new Map<string, unknown>();\n const extensionDataRefs = new Set<ExtensionDataRef<unknown>>();\n const scopedApis: ApiHolder =\n options.onMissingApi === undefined\n ? apis\n : {\n get(apiRef) {\n const api = apis.get(apiRef);\n if (api === undefined) {\n options.onMissingApi?.({\n node,\n apiRefId: apiRef.id,\n });\n }\n return api;\n },\n };\n\n let parsedConfig: { [x: string]: any };\n try {\n parsedConfig = extension.configSchema?.parse(config ?? {}) as {\n [x: string]: any;\n };\n } catch (e) {\n collector.report({\n code: 'EXTENSION_CONFIGURATION_INVALID',\n message: `Invalid configuration for extension '${id}'; caused by ${e}`,\n });\n return undefined;\n }\n\n try {\n const internalExtension = toInternalExtension(extension);\n\n if (process.env.NODE_ENV !== 'production') {\n reportUndeclaredAttachments(id, internalExtension.inputs, attachments);\n }\n\n if (internalExtension.version === 'v1') {\n const namedOutputs = internalExtension.factory({\n node,\n apis: scopedApis,\n config: parsedConfig,\n inputs: resolveV1Inputs(internalExtension.inputs, attachments),\n });\n\n for (const [name, output] of Object.entries(namedOutputs)) {\n const ref = internalExtension.output[name];\n if (!ref) {\n throw new Error(`unknown output provided via '${name}'`);\n }\n if (extensionData.has(ref.id)) {\n throw new Error(\n `duplicate extension data '${ref.id}' received via output '${name}'`,\n );\n }\n extensionData.set(ref.id, output);\n extensionDataRefs.add(ref);\n }\n } else if (internalExtension.version === 'v2') {\n const context = {\n node,\n apis: scopedApis,\n config: parsedConfig,\n inputs: resolveV2Inputs(\n internalExtension.inputs,\n attachments,\n collector,\n node,\n ),\n };\n const outputDataValues = options.extensionFactoryMiddleware\n ? createExtensionDataContainer(\n options.extensionFactoryMiddleware(overrideContext => {\n return createExtensionDataContainer(\n internalExtension.factory({\n node: context.node,\n apis: context.apis,\n inputs: context.inputs,\n config: overrideContext?.config ?? context.config,\n }),\n 'extension factory',\n );\n }, context),\n 'extension factory middleware',\n )\n : internalExtension.factory(context);\n\n if (\n typeof outputDataValues !== 'object' ||\n !outputDataValues?.[Symbol.iterator]\n ) {\n throw new Error('extension factory did not provide an iterable object');\n }\n\n const outputDataMap = new Map<string, unknown>();\n mapWithFailures(outputDataValues, value => {\n if (outputDataMap.has(value.id)) {\n collector.report({\n code: 'EXTENSION_OUTPUT_CONFLICT',\n message: `extension factory output duplicate data '${value.id}'`,\n context: {\n dataRefId: value.id,\n },\n });\n throw INSTANTIATION_FAILED;\n } else {\n outputDataMap.set(value.id, value.value);\n }\n });\n\n for (const ref of internalExtension.output) {\n const value = outputDataMap.get(ref.id);\n outputDataMap.delete(ref.id);\n if (value === undefined) {\n if (!ref.config.optional) {\n collector.report({\n code: 'EXTENSION_OUTPUT_MISSING',\n message: `missing required extension data output '${ref.id}'`,\n context: {\n dataRefId: ref.id,\n },\n });\n throw INSTANTIATION_FAILED;\n }\n } else {\n extensionData.set(ref.id, value);\n extensionDataRefs.add(ref);\n }\n }\n\n if (outputDataMap.size > 0) {\n for (const dataRefId of outputDataMap.keys()) {\n // TODO: Make this a warning\n collector.report({\n code: 'EXTENSION_OUTPUT_IGNORED',\n message: `unexpected output '${dataRefId}'`,\n context: {\n dataRefId: dataRefId,\n },\n });\n }\n }\n } else {\n collector.report({\n code: 'EXTENSION_INVALID',\n message: `unexpected extension version '${\n (internalExtension as any).version\n }'`,\n });\n throw INSTANTIATION_FAILED;\n }\n } catch (e) {\n if (e !== INSTANTIATION_FAILED) {\n collector.report({\n code: 'EXTENSION_FACTORY_ERROR',\n message: `Failed to instantiate extension '${id}'${\n e.name === 'Error' ? `, ${e.message}` : `; caused by ${e}`\n }`,\n });\n }\n return undefined;\n }\n\n return {\n getDataRefs() {\n return extensionDataRefs.values();\n },\n getData<T>(ref: ExtensionDataRef<T>): T | undefined {\n return extensionData.get(ref.id) as T | undefined;\n },\n };\n}\n\n/**\n * Starting at the provided node, instantiate a subtree without necessarily\n * mutating the original app tree.\n *\n * @internal\n */\nexport function instantiateAppNodeSubtree(\n options: InstantiateAppNodeSubtreeOptions,\n): AppNode | undefined {\n const instantiatedNodes = new WeakMap<AppNode, AppNode | null>();\n\n function createInstance(node: AppNode): AppNode | undefined {\n if (instantiatedNodes.has(node)) {\n return instantiatedNodes.get(node) ?? undefined;\n }\n if (options.reuseExistingInstances !== false && node.instance) {\n instantiatedNodes.set(node, node);\n return node;\n }\n if (node.spec.disabled) {\n instantiatedNodes.set(node, null);\n return undefined;\n }\n if (\n options.predicateContext !== undefined &&\n node.spec.if !== undefined &&\n !evaluateFilterPredicate(node.spec.if, options.predicateContext)\n ) {\n instantiatedNodes.set(node, null);\n return undefined;\n }\n\n const instantiatedAttachments = new Map<string, AppNode[]>();\n\n for (const [input, children] of node.edges.attachments) {\n if (options.stopAtAttachment?.({ node, input })) {\n continue;\n }\n const instantiatedChildren = children.flatMap(child => {\n if (options.skipChild?.({ node, input, child })) {\n return [];\n }\n const childNode = createInstance(child);\n return childNode ? [childNode] : [];\n });\n if (instantiatedChildren.length > 0) {\n instantiatedAttachments.set(input, instantiatedChildren);\n }\n }\n\n const instance = createAppNodeInstance({\n extensionFactoryMiddleware: options.extensionFactoryMiddleware,\n node,\n apis: options.apis,\n attachments: instantiatedAttachments,\n collector: options.collector,\n onMissingApi: options.onMissingApi,\n });\n if (!instance) {\n instantiatedNodes.set(node, null);\n return undefined;\n }\n\n if (options.writeNodeInstances === false) {\n const detachedNode: AppNode = {\n spec: node.spec,\n edges: node.edges,\n instance,\n };\n instantiatedNodes.set(node, detachedNode);\n return detachedNode;\n }\n\n (node as Mutable<AppNode>).instance = instance;\n instantiatedNodes.set(node, node);\n return node;\n }\n\n return createInstance(options.rootNode);\n}\n\n/**\n * Starting at the provided node, instantiate all reachable nodes in the tree that have not been disabled.\n * @internal\n */\nexport function instantiateAppNodeTree(\n rootNode: AppNode,\n apis: ApiHolder,\n collector: ErrorCollector,\n extensionFactoryMiddleware?: ExtensionFactoryMiddleware,\n optionsOrPredicateContext?:\n | {\n stopAtAttachment?(ctx: { node: AppNode; input: string }): boolean;\n skipChild?(ctx: {\n node: AppNode;\n input: string;\n child: AppNode;\n }): boolean;\n onMissingApi?(ctx: { node: AppNode; apiRefId: string }): void;\n predicateContext?: Record<string, unknown>;\n }\n | Record<string, unknown>,\n): boolean {\n const options: {\n stopAtAttachment?(ctx: { node: AppNode; input: string }): boolean;\n skipChild?(ctx: { node: AppNode; input: string; child: AppNode }): boolean;\n onMissingApi?(ctx: { node: AppNode; apiRefId: string }): void;\n predicateContext?: Record<string, unknown>;\n } =\n optionsOrPredicateContext &&\n ('stopAtAttachment' in optionsOrPredicateContext ||\n 'skipChild' in optionsOrPredicateContext ||\n 'onMissingApi' in optionsOrPredicateContext ||\n 'predicateContext' in optionsOrPredicateContext)\n ? optionsOrPredicateContext\n : {\n predicateContext: optionsOrPredicateContext,\n };\n\n return (\n instantiateAppNodeSubtree({\n rootNode,\n apis,\n collector,\n extensionFactoryMiddleware,\n stopAtAttachment: options.stopAtAttachment,\n skipChild: options.skipChild,\n onMissingApi: options.onMissingApi,\n predicateContext: options.predicateContext,\n }) !== undefined\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"instantiateAppNodeTree.esm.js","sources":["../../src/tree/instantiateAppNodeTree.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 ApiHolder,\n ExtensionDataContainer,\n ExtensionDataRef,\n ExtensionInput,\n} from '@backstage/frontend-plugin-api';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { ResolvedExtensionInputs } from '../../../frontend-plugin-api/src/wiring/createExtension';\nimport { ExtensionFactoryMiddleware } from '../wiring/types';\nimport mapValues from 'lodash/mapValues';\nimport { AppNode, AppNodeInstance } from '@backstage/frontend-plugin-api';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalExtension } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';\nimport { createExtensionDataContainer } from '@internal/frontend';\nimport { ErrorCollector } from '../wiring/createErrorCollector';\nimport { evaluateFilterPredicate } from '@backstage/filter-predicates';\n\nconst INSTANTIATION_FAILED = new Error('Instantiation failed');\n\n/**\n * Like `array.map`, but if `INSTANTIATION_FAILED` is thrown, the iteration will continue but afterwards re-throw `INSTANTIATION_FAILED`\n * @returns\n */\nfunction mapWithFailures<T, U>(\n iterable: Iterable<T>,\n callback: (item: T) => U,\n options?: { ignoreFailures?: boolean },\n): U[] {\n let failed = false;\n const results = [];\n for (const item of iterable) {\n try {\n results.push(callback(item));\n } catch (error) {\n if (error === INSTANTIATION_FAILED) {\n failed = true;\n } else {\n throw error;\n }\n }\n }\n if (failed && !options?.ignoreFailures) {\n throw INSTANTIATION_FAILED;\n }\n return results;\n}\n\ntype Mutable<T> = {\n -readonly [P in keyof T]: T[P];\n};\n\ntype InstantiateAppNodeSubtreeOptions = {\n rootNode: AppNode;\n apis: ApiHolder;\n collector: ErrorCollector;\n extensionFactoryMiddleware?: ExtensionFactoryMiddleware;\n stopAtAttachment?(ctx: { node: AppNode; input: string }): boolean;\n skipChild?(ctx: { node: AppNode; input: string; child: AppNode }): boolean;\n onMissingApi?(ctx: { node: AppNode; apiRefId: string }): void;\n predicateContext?: Record<string, unknown>;\n reuseExistingInstances?: boolean;\n writeNodeInstances?: boolean;\n};\n\nfunction resolveV1InputDataMap(\n dataMap: {\n [name in string]: ExtensionDataRef;\n },\n attachment: AppNode,\n inputName: string,\n) {\n return Object.fromEntries(\n mapWithFailures(Object.entries(dataMap), ([key, ref]) => {\n const value = attachment.instance?.getData(ref);\n if (value === undefined && !ref.config.optional) {\n const expected = Object.values(dataMap)\n .filter(r => !r.config.optional)\n .map(r => `'${r.id}'`)\n .join(', ');\n\n const provided = [...(attachment.instance?.getDataRefs() ?? [])]\n .map(r => `'${r.id}'`)\n .join(', ');\n\n throw new Error(\n `extension '${attachment.spec.id}' could not be attached because its output data (${provided}) does not match what the input '${inputName}' requires (${expected})`,\n );\n }\n return [key, value];\n }),\n );\n}\n\nfunction resolveInputDataContainer(\n extensionData: Array<ExtensionDataRef>,\n attachment: AppNode,\n inputName: string,\n collector: ErrorCollector<{ node: AppNode; inputName: string }>,\n): { node: AppNode } & ExtensionDataContainer<ExtensionDataRef> {\n const dataMap = new Map<string, unknown>();\n\n mapWithFailures(extensionData, ref => {\n if (dataMap.has(ref.id)) {\n collector.report({\n code: 'EXTENSION_INPUT_DATA_IGNORED',\n message: `Unexpected duplicate input data '${ref.id}'`,\n });\n return;\n }\n\n const value = attachment.instance?.getData(ref);\n if (value === undefined && !ref.config.optional) {\n const expected = extensionData\n .filter(r => !r.config.optional)\n .map(r => `'${r.id}'`)\n .join(', ');\n\n const provided = [...(attachment.instance?.getDataRefs() ?? [])]\n .map(r => `'${r.id}'`)\n .join(', ');\n\n collector.child({ node: attachment }).report({\n code: 'EXTENSION_INPUT_DATA_MISSING',\n message: `extension '${attachment.spec.id}' could not be attached because its output data (${provided}) does not match what the input '${inputName}' requires (${expected})`,\n });\n throw INSTANTIATION_FAILED;\n }\n\n dataMap.set(ref.id, value);\n });\n\n return {\n node: attachment,\n get(ref) {\n return dataMap.get(ref.id);\n },\n *[Symbol.iterator]() {\n for (const [id, value] of dataMap) {\n // TODO: Would be better to be able to create a new instance using the ref here instead\n yield {\n $$type: '@backstage/ExtensionDataValue',\n id,\n value,\n };\n }\n },\n } as { node: AppNode } & ExtensionDataContainer<ExtensionDataRef>;\n}\n\nfunction reportUndeclaredAttachments(\n id: string,\n inputMap: { [name in string]: unknown },\n attachments: ReadonlyMap<string, AppNode[]>,\n) {\n const undeclaredAttachments = Array.from(attachments.entries()).filter(\n ([inputName]) => inputMap[inputName] === undefined,\n );\n\n const inputNames = Object.keys(inputMap);\n\n for (const [name, nodes] of undeclaredAttachments) {\n const pl = nodes.length > 1;\n // eslint-disable-next-line no-console\n console.warn(\n [\n `The extension${pl ? 's' : ''} '${nodes\n .map(n => n.spec.id)\n .join(\"', '\")}' ${pl ? 'are' : 'is'}`,\n `attached to the input '${name}' of the extension '${id}', but it`,\n inputNames.length === 0\n ? 'has no inputs'\n : `has no such input (candidates are '${inputNames.join(\"', '\")}')`,\n ].join(' '),\n );\n }\n}\n\nfunction resolveV1Inputs(\n inputMap: {\n [inputName in string]: {\n $$type: '@backstage/ExtensionInput';\n extensionData: {\n [name in string]: ExtensionDataRef;\n };\n config: { optional: boolean; singleton: boolean };\n };\n },\n attachments: ReadonlyMap<string, AppNode[]>,\n) {\n return Object.fromEntries(\n mapWithFailures(Object.entries(inputMap), ([inputName, input]) => {\n const attachedNodes = attachments.get(inputName) ?? [];\n\n if (input.config.singleton) {\n if (attachedNodes.length > 1) {\n const attachedNodeIds = attachedNodes.map(e => e.spec.id);\n throw Error(\n `expected ${\n input.config.optional ? 'at most' : 'exactly'\n } one '${inputName}' input but received multiple: '${attachedNodeIds.join(\n \"', '\",\n )}'`,\n );\n } else if (attachedNodes.length === 0) {\n if (input.config.optional) {\n return [inputName, undefined];\n }\n throw Error(`input '${inputName}' is required but was not received`);\n }\n return [\n inputName,\n {\n node: attachedNodes[0],\n output: resolveV1InputDataMap(\n input.extensionData,\n attachedNodes[0],\n inputName,\n ),\n },\n ];\n }\n\n return [\n inputName,\n attachedNodes.map(attachment => ({\n node: attachment,\n output: resolveV1InputDataMap(\n input.extensionData,\n attachment,\n inputName,\n ),\n })),\n ];\n }),\n ) as {\n [inputName in string]: {\n node: AppNode;\n output: {\n [name in string]: unknown;\n };\n };\n };\n}\n\nfunction resolveV2Inputs(\n inputMap: { [inputName in string]: ExtensionInput },\n attachments: ReadonlyMap<string, AppNode[]>,\n parentCollector: ErrorCollector<{ node: AppNode }>,\n node: AppNode,\n): ResolvedExtensionInputs<{ [inputName in string]: ExtensionInput }> {\n return mapValues(inputMap, (input, inputName) => {\n const allAttachedNodes = attachments.get(inputName) ?? [];\n const collector = parentCollector.child({ inputName });\n const inputPluginId = node.spec.plugin.pluginId;\n\n const attachedNodes = input.config.internal\n ? allAttachedNodes.filter(attachment => {\n const attachmentPluginId = attachment.spec.plugin.pluginId;\n if (attachmentPluginId !== inputPluginId) {\n collector.report({\n code: 'EXTENSION_INPUT_INTERNAL_IGNORED',\n message:\n `extension '${attachment.spec.id}' from plugin '${attachmentPluginId}' attached to input '${inputName}' on '${node.spec.id}' was ignored, ` +\n `the input is marked as internal and attached extensions must therefore be provided via an override or a module for the '${inputPluginId}' plugin, not the '${attachmentPluginId}' plugin`,\n context: {\n extensionId: attachment.spec.id,\n plugin: attachment.spec.plugin,\n },\n });\n return false;\n }\n return true;\n })\n : allAttachedNodes;\n\n if (input.config.singleton) {\n if (attachedNodes.length > 1) {\n const attachedNodeIds = attachedNodes.map(e => e.spec.id).join(\"', '\");\n collector.report({\n code: 'EXTENSION_ATTACHMENT_CONFLICT',\n message: `expected ${\n input.config.optional ? 'at most' : 'exactly'\n } one '${inputName}' input but received multiple: '${attachedNodeIds}'`,\n });\n throw INSTANTIATION_FAILED;\n } else if (attachedNodes.length === 0) {\n if (!input.config.optional) {\n collector.report({\n code: 'EXTENSION_ATTACHMENT_MISSING',\n message: `input '${inputName}' is required but was not received`,\n });\n throw INSTANTIATION_FAILED;\n }\n return undefined;\n }\n try {\n return resolveInputDataContainer(\n input.extensionData,\n attachedNodes[0],\n inputName,\n collector,\n );\n } catch (error) {\n if (error === INSTANTIATION_FAILED) {\n if (input.config.optional) {\n return undefined;\n }\n collector.report({\n code: 'EXTENSION_ATTACHMENT_MISSING',\n message: `input '${inputName}' is required but it failed to be instantiated`,\n });\n }\n throw error;\n }\n }\n\n return mapWithFailures(\n attachedNodes,\n attachment =>\n resolveInputDataContainer(\n input.extensionData,\n attachment,\n inputName,\n collector,\n ),\n { ignoreFailures: true },\n );\n }) as ResolvedExtensionInputs<{ [inputName in string]: ExtensionInput }>;\n}\n\n/** @internal */\nexport function createAppNodeInstance(options: {\n extensionFactoryMiddleware?: ExtensionFactoryMiddleware;\n node: AppNode;\n apis: ApiHolder;\n attachments: ReadonlyMap<string, AppNode[]>;\n collector: ErrorCollector;\n onMissingApi?(ctx: { node: AppNode; apiRefId: string }): void;\n}): AppNodeInstance | undefined {\n const { node, apis, attachments } = options;\n const collector = options.collector.child({ node });\n const { id, extension, config } = node.spec;\n const extensionData = new Map<string, unknown>();\n const extensionDataRefs = new Set<ExtensionDataRef<unknown>>();\n const scopedApis: ApiHolder =\n options.onMissingApi === undefined\n ? apis\n : {\n get(apiRef) {\n const api = apis.get(apiRef);\n if (api === undefined) {\n options.onMissingApi?.({\n node,\n apiRefId: apiRef.id,\n });\n }\n return api;\n },\n };\n\n let parsedConfig: { [x: string]: any };\n try {\n parsedConfig = extension.configSchema?.parse(config ?? {}) as {\n [x: string]: any;\n };\n } catch (e) {\n collector.report({\n code: 'EXTENSION_CONFIGURATION_INVALID',\n message: `Invalid configuration for extension '${id}'; caused by ${e}`,\n });\n return undefined;\n }\n\n try {\n const internalExtension = toInternalExtension(extension);\n\n if (process.env.NODE_ENV !== 'production') {\n reportUndeclaredAttachments(id, internalExtension.inputs, attachments);\n }\n\n if (internalExtension.version === 'v1') {\n const namedOutputs = internalExtension.factory({\n node,\n apis: scopedApis,\n config: parsedConfig,\n inputs: resolveV1Inputs(internalExtension.inputs, attachments),\n });\n\n for (const [name, output] of Object.entries(namedOutputs)) {\n const ref = internalExtension.output[name];\n if (!ref) {\n throw new Error(`unknown output provided via '${name}'`);\n }\n if (extensionData.has(ref.id)) {\n throw new Error(\n `duplicate extension data '${ref.id}' received via output '${name}'`,\n );\n }\n extensionData.set(ref.id, output);\n extensionDataRefs.add(ref);\n }\n } else if (internalExtension.version === 'v2') {\n const context = {\n node,\n apis: scopedApis,\n config: parsedConfig,\n inputs: resolveV2Inputs(\n internalExtension.inputs,\n attachments,\n collector,\n node,\n ),\n };\n const outputDataValues = options.extensionFactoryMiddleware\n ? createExtensionDataContainer(\n options.extensionFactoryMiddleware(overrideContext => {\n return createExtensionDataContainer(\n internalExtension.factory({\n node: context.node,\n apis: context.apis,\n inputs: context.inputs,\n config: overrideContext?.config ?? context.config,\n }),\n 'extension factory',\n );\n }, context),\n 'extension factory middleware',\n )\n : internalExtension.factory(context);\n\n if (\n typeof outputDataValues !== 'object' ||\n !outputDataValues?.[Symbol.iterator]\n ) {\n throw new Error('extension factory did not provide an iterable object');\n }\n\n const outputDataMap = new Map<string, unknown>();\n mapWithFailures(outputDataValues, value => {\n if (outputDataMap.has(value.id)) {\n collector.report({\n code: 'EXTENSION_OUTPUT_CONFLICT',\n message: `extension factory output duplicate data '${value.id}'`,\n context: {\n dataRefId: value.id,\n },\n });\n throw INSTANTIATION_FAILED;\n } else {\n outputDataMap.set(value.id, value.value);\n }\n });\n\n for (const ref of internalExtension.output) {\n const value = outputDataMap.get(ref.id);\n outputDataMap.delete(ref.id);\n if (value === undefined) {\n if (!ref.config.optional) {\n collector.report({\n code: 'EXTENSION_OUTPUT_MISSING',\n message: `missing required extension data output '${ref.id}'`,\n context: {\n dataRefId: ref.id,\n },\n });\n throw INSTANTIATION_FAILED;\n }\n } else {\n extensionData.set(ref.id, value);\n extensionDataRefs.add(ref);\n }\n }\n\n if (outputDataMap.size > 0) {\n for (const dataRefId of outputDataMap.keys()) {\n // TODO: Make this a warning\n collector.report({\n code: 'EXTENSION_OUTPUT_IGNORED',\n message: `unexpected output '${dataRefId}'`,\n context: {\n dataRefId: dataRefId,\n },\n });\n }\n }\n } else {\n collector.report({\n code: 'EXTENSION_INVALID',\n message: `unexpected extension version '${\n (internalExtension as any).version\n }'`,\n });\n throw INSTANTIATION_FAILED;\n }\n } catch (e) {\n if (e !== INSTANTIATION_FAILED) {\n collector.report({\n code: 'EXTENSION_FACTORY_ERROR',\n message: `Failed to instantiate extension '${id}'${\n e.name === 'Error' ? `, ${e.message}` : `; caused by ${e}`\n }`,\n });\n }\n return undefined;\n }\n\n return {\n getDataRefs() {\n return extensionDataRefs.values();\n },\n getData<T>(ref: ExtensionDataRef<T>): T | undefined {\n return extensionData.get(ref.id) as T | undefined;\n },\n };\n}\n\n/**\n * Starting at the provided node, instantiate a subtree without necessarily\n * mutating the original app tree.\n *\n * @internal\n */\nexport function instantiateAppNodeSubtree(\n options: InstantiateAppNodeSubtreeOptions,\n): AppNode | undefined {\n const instantiatedNodes = new WeakMap<AppNode, AppNode | null>();\n\n function createInstance(node: AppNode): AppNode | undefined {\n if (instantiatedNodes.has(node)) {\n return instantiatedNodes.get(node) ?? undefined;\n }\n if (options.reuseExistingInstances !== false && node.instance) {\n instantiatedNodes.set(node, node);\n return node;\n }\n if (node.spec.disabled) {\n instantiatedNodes.set(node, null);\n return undefined;\n }\n if (\n options.predicateContext !== undefined &&\n node.spec.if !== undefined &&\n !evaluateFilterPredicate(node.spec.if, options.predicateContext)\n ) {\n instantiatedNodes.set(node, null);\n return undefined;\n }\n\n const instantiatedAttachments = new Map<string, AppNode[]>();\n\n for (const [input, children] of node.edges.attachments) {\n if (options.stopAtAttachment?.({ node, input })) {\n continue;\n }\n const instantiatedChildren = children.flatMap(child => {\n if (options.skipChild?.({ node, input, child })) {\n return [];\n }\n const childNode = createInstance(child);\n return childNode ? [childNode] : [];\n });\n if (instantiatedChildren.length > 0) {\n instantiatedAttachments.set(input, instantiatedChildren);\n }\n }\n\n const instance = createAppNodeInstance({\n extensionFactoryMiddleware: options.extensionFactoryMiddleware,\n node,\n apis: options.apis,\n attachments: instantiatedAttachments,\n collector: options.collector,\n onMissingApi: options.onMissingApi,\n });\n if (!instance) {\n instantiatedNodes.set(node, null);\n return undefined;\n }\n\n if (options.writeNodeInstances === false) {\n const detachedNode: AppNode = {\n spec: node.spec,\n edges: node.edges,\n instance,\n };\n instantiatedNodes.set(node, detachedNode);\n return detachedNode;\n }\n\n (node as Mutable<AppNode>).instance = instance;\n instantiatedNodes.set(node, node);\n return node;\n }\n\n return createInstance(options.rootNode);\n}\n\n/**\n * Starting at the provided node, instantiate all reachable nodes in the tree that have not been disabled.\n * @internal\n */\nexport function instantiateAppNodeTree(\n rootNode: AppNode,\n apis: ApiHolder,\n collector: ErrorCollector,\n extensionFactoryMiddleware?: ExtensionFactoryMiddleware,\n optionsOrPredicateContext?:\n | {\n stopAtAttachment?(ctx: { node: AppNode; input: string }): boolean;\n skipChild?(ctx: {\n node: AppNode;\n input: string;\n child: AppNode;\n }): boolean;\n onMissingApi?(ctx: { node: AppNode; apiRefId: string }): void;\n predicateContext?: Record<string, unknown>;\n }\n | Record<string, unknown>,\n): boolean {\n const options: {\n stopAtAttachment?(ctx: { node: AppNode; input: string }): boolean;\n skipChild?(ctx: { node: AppNode; input: string; child: AppNode }): boolean;\n onMissingApi?(ctx: { node: AppNode; apiRefId: string }): void;\n predicateContext?: Record<string, unknown>;\n } =\n optionsOrPredicateContext &&\n ('stopAtAttachment' in optionsOrPredicateContext ||\n 'skipChild' in optionsOrPredicateContext ||\n 'onMissingApi' in optionsOrPredicateContext ||\n 'predicateContext' in optionsOrPredicateContext)\n ? optionsOrPredicateContext\n : {\n predicateContext: optionsOrPredicateContext,\n };\n\n return (\n instantiateAppNodeSubtree({\n rootNode,\n apis,\n collector,\n extensionFactoryMiddleware,\n stopAtAttachment: options.stopAtAttachment,\n skipChild: options.skipChild,\n onMissingApi: options.onMissingApi,\n predicateContext: options.predicateContext,\n }) !== undefined\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readAppExtensionsConfig.esm.js","sources":["../../src/tree/readAppExtensionsConfig.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 { Config } from '@backstage/config';\nimport { JsonValue } from '@backstage/types';\n\nexport interface ExtensionParameters {\n id: string;\n attachTo?: { id: string; input: string };\n disabled?: boolean;\n config?: unknown;\n}\n\nconst knownExtensionParameters = ['attachTo', 'disabled', 'config'];\n\n// Since we'll never merge arrays in config the config reader context\n// isn't too much of a help. Fall back to manual config reading logic\n// as the Config interface makes it quite hard for us otherwise.\n/** @internal */\nexport function readAppExtensionsConfig(\n rootConfig: Config,\n): ExtensionParameters[] {\n const arr = rootConfig.getOptional('app.extensions');\n if (!Array.isArray(arr)) {\n if (arr === undefined) {\n return [];\n }\n // This will throw, and show which part of config had the wrong type\n rootConfig.getConfigArray('app.extensions');\n return [];\n }\n\n return arr.map((arrayEntry, arrayIndex) =>\n expandShorthandExtensionParameters(arrayEntry, arrayIndex),\n );\n}\n\n/** @internal */\nexport function expandShorthandExtensionParameters(\n arrayEntry: JsonValue,\n arrayIndex: number,\n): ExtensionParameters {\n function errorMsg(msg: string, key?: string, prop?: string) {\n return `Invalid extension configuration at app.extensions[${arrayIndex}]${\n key ? `[${key}]` : ''\n }${prop ? `.${prop}` : ''}, ${msg}`;\n }\n\n // NOTE(freben): This check is intentionally not complete and doesn't check\n // whether letters and digits are used, etc. It's not up to the config reading\n // logic to decide what constitutes a valid extension ID; that should be\n // decided by the logic that loads and instantiates the extensions. This check\n // is just here to catch real mistakes or truly conceptually wrong input.\n function assertValidId(id: string) {\n if (!id || id !== id.trim()) {\n throw new Error(\n errorMsg('extension ID must not be empty or contain whitespace'),\n );\n }\n }\n\n // Example YAML:\n // - entity.card.about\n if (typeof arrayEntry === 'string') {\n assertValidId(arrayEntry);\n return {\n id: arrayEntry,\n disabled: false,\n };\n }\n\n // All remaining cases are single-key objects\n if (\n typeof arrayEntry !== 'object' ||\n arrayEntry === null ||\n Array.isArray(arrayEntry)\n ) {\n throw new Error(errorMsg('must be a string or an object'));\n }\n const keys = Object.keys(arrayEntry);\n if (keys.length !== 1) {\n const joinedKeys = keys.length ? `'${keys.join(\"', '\")}'` : 'none';\n throw new Error(errorMsg(`must have exactly one key, got ${joinedKeys}`));\n }\n\n const id = String(keys[0]);\n const value = arrayEntry[id];\n assertValidId(id);\n\n // This example covers a potentially common mistake in the syntax\n // Example YAML:\n // - entity.card.about:\n if (value === null) {\n return {\n id,\n disabled: false,\n };\n }\n\n // Example YAML:\n // - catalog.page.cicd: false\n if (typeof value === 'boolean') {\n return {\n id,\n disabled: !value,\n };\n }\n\n // Environment variable substitution always produces a string, so boolean-ish\n // strings need to be coerced too. Example YAML:\n // - catalog.page.cicd: ${CATALOG_PAGE_CICD_ENABLED}\n if (value === 'true' || value === 'false') {\n return {\n id,\n disabled: value === 'false',\n };\n }\n\n // The remaining case is the generic object. Example YAML:\n // - tech-radar.page:\n // at: core.router/routes\n // disabled: false\n // config:\n // path: /tech-radar\n // width: 1500\n // height: 800\n if (typeof value !== 'object' || Array.isArray(value)) {\n // We don't mention null here - we don't want people to explicitly enter\n // - entity.card.about: null\n throw new Error(\n errorMsg(\"value must be a boolean, 'true', 'false', or object\", id),\n );\n }\n\n const attachTo = value.attachTo as { id: string; input: string } | undefined;\n let disabled = value.disabled;\n const config = value.config;\n\n if (attachTo !== undefined) {\n if (\n attachTo === null ||\n typeof attachTo !== 'object' ||\n Array.isArray(attachTo)\n ) {\n throw new Error(errorMsg('must be an object', id, 'attachTo'));\n }\n if (typeof attachTo.id !== 'string' || attachTo.id === '') {\n throw new Error(\n errorMsg('must be a non-empty string', id, 'attachTo.id'),\n );\n }\n if (typeof attachTo.input !== 'string' || attachTo.input === '') {\n throw new Error(\n errorMsg('must be a non-empty string', id, 'attachTo.input'),\n );\n }\n }\n if (disabled !== undefined && typeof disabled !== 'boolean') {\n // Environment variable substitution always produces a string, e.g.\n // disabled: ${CATALOG_OVERVIEW_DISABLED}\n if (disabled === 'true' || disabled === 'false') {\n disabled = disabled === 'true';\n } else {\n throw new Error(\n errorMsg(\"must be a boolean, 'true', or 'false'\", id, 'disabled'),\n );\n }\n }\n if (\n config !== undefined &&\n (typeof config !== 'object' || config === null || Array.isArray(config))\n ) {\n throw new Error(errorMsg('must be an object', id, 'config'));\n }\n\n const unknownKeys = Object.keys(value).filter(\n k => !knownExtensionParameters.includes(k),\n );\n if (unknownKeys.length > 0) {\n throw new Error(\n errorMsg(\n `unknown parameter; expected one of '${knownExtensionParameters.join(\n \"', '\",\n )}'`,\n id,\n unknownKeys.join(', '),\n ),\n );\n }\n\n return {\n id,\n attachTo,\n disabled,\n config,\n };\n}\n"],"names":["id"],"mappings":"AA0BA,MAAM,wBAAA,GAA2B,CAAC,UAAA,EAAY,UAAA,EAAY,QAAQ,CAAA;AAM3D,SAAS,wBACd,UAAA,EACuB;AACvB,EAAA,MAAM,GAAA,GAAM,UAAA,CAAW,WAAA,CAAY,gBAAgB,CAAA;AACnD,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AACvB,IAAA,IAAI,QAAQ,MAAA,EAAW;AACrB,MAAA,OAAO,EAAC;AAAA,IACV;AAEA,IAAA,UAAA,CAAW,eAAe,gBAAgB,CAAA;AAC1C,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,OAAO,GAAA,CAAI,GAAA;AAAA,IAAI,CAAC,UAAA,EAAY,UAAA,KAC1B,kCAAA,CAAmC,YAAY,UAAU;AAAA,GAC3D;AACF;AAGO,SAAS,kCAAA,CACd,YACA,UAAA,EACqB;AACrB,EAAA,SAAS,QAAA,CAAS,GAAA,EAAa,GAAA,EAAc,IAAA,EAAe;AAC1D,IAAA,OAAO,CAAA,kDAAA,EAAqD,UAAU,CAAA,CAAA,EACpE,GAAA,GAAM,IAAI,GAAG,CAAA,CAAA,CAAA,GAAM,EACrB,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,GAAK,EAAE,KAAK,GAAG,CAAA,CAAA;AAAA,EACnC;AAOA,EAAA,SAAS,cAAcA,GAAAA,EAAY;AACjC,IAAA,IAAI,CAACA,GAAAA,IAAMA,GAAAA,KAAOA,GAAAA,CAAG,MAAK,EAAG;AAC3B,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,SAAS,sDAAsD;AAAA,OACjE;AAAA,IACF;AAAA,EACF;AAIA,EAAA,IAAI,OAAO,eAAe,QAAA,EAAU;AAClC,IAAA,aAAA,CAAc,UAAU,CAAA;AACxB,IAAA,OAAO;AAAA,MACL,EAAA,EAAI,UAAA;AAAA,MACJ,QAAA,EAAU;AAAA,KACZ;AAAA,EACF;AAGA,EAAA,IACE,OAAO,eAAe,QAAA,IACtB,UAAA,KAAe,QACf,KAAA,CAAM,OAAA,CAAQ,UAAU,CAAA,EACxB;AACA,IAAA,MAAM,IAAI,KAAA,CAAM,QAAA,CAAS,+BAA+B,CAAC,CAAA;AAAA,EAC3D;AACA,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,UAAU,CAAA;AACnC,EAAA,IAAI,IAAA,CAAK,WAAW,CAAA,EAAG;AACrB,IAAA,MAAM,UAAA,GAAa,KAAK,MAAA,GAAS,CAAA,CAAA,EAAI,KAAK,IAAA,CAAK,MAAM,CAAC,CAAA,CAAA,CAAA,GAAM,MAAA;AAC5D,IAAA,MAAM,IAAI,KAAA,CAAM,QAAA,CAAS,CAAA,+BAAA,EAAkC,UAAU,EAAE,CAAC,CAAA;AAAA,EAC1E;AAEA,EAAA,MAAM,EAAA,GAAK,MAAA,CAAO,IAAA,CAAK,CAAC,CAAC,CAAA;AACzB,EAAA,MAAM,KAAA,GAAQ,WAAW,EAAE,CAAA;AAC3B,EAAA,aAAA,CAAc,EAAE,CAAA;AAKhB,EAAA,IAAI,UAAU,IAAA,EAAM;AAClB,IAAA,OAAO;AAAA,MACL,EAAA;AAAA,MACA,QAAA,EAAU;AAAA,KACZ;AAAA,EACF;AAIA,EAAA,IAAI,OAAO,UAAU,SAAA,EAAW;AAC9B,IAAA,OAAO;AAAA,MACL,EAAA;AAAA,MACA,UAAU,CAAC;AAAA,KACb;AAAA,EACF;AAKA,EAAA,IAAI,KAAA,KAAU,MAAA,IAAU,KAAA,KAAU,OAAA,EAAS;AACzC,IAAA,OAAO;AAAA,MACL,EAAA;AAAA,MACA,UAAU,KAAA,KAAU;AAAA,KACtB;AAAA,EACF;AAUA,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AAGrD,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,QAAA,CAAS,uDAAuD,EAAE;AAAA,KACpE;AAAA,EACF;AAEA,EAAA,MAAM,WAAW,KAAA,CAAM,QAAA;AACvB,EAAA,IAAI,WAAW,KAAA,CAAM,QAAA;AACrB,EAAA,MAAM,SAAS,KAAA,CAAM,MAAA;AAErB,EAAA,IAAI,aAAa,MAAA,EAAW;AAC1B,IAAA,IACE,QAAA,KAAa,QACb,OAAO,QAAA,KAAa,YACpB,KAAA,CAAM,OAAA,CAAQ,QAAQ,CAAA,EACtB;AACA,MAAA,MAAM,IAAI,KAAA,CAAM,QAAA,CAAS,mBAAA,EAAqB,EAAA,EAAI,UAAU,CAAC,CAAA;AAAA,IAC/D;AACA,IAAA,IAAI,OAAO,QAAA,CAAS,EAAA,KAAO,QAAA,IAAY,QAAA,CAAS,OAAO,EAAA,EAAI;AACzD,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,QAAA,CAAS,4BAAA,EAA8B,EAAA,EAAI,aAAa;AAAA,OAC1D;AAAA,IACF;AACA,IAAA,IAAI,OAAO,QAAA,CAAS,KAAA,KAAU,QAAA,IAAY,QAAA,CAAS,UAAU,EAAA,EAAI;AAC/D,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,QAAA,CAAS,4BAAA,EAA8B,EAAA,EAAI,gBAAgB;AAAA,OAC7D;AAAA,IACF;AAAA,EACF;AACA,EAAA,IAAI,QAAA,KAAa,MAAA,IAAa,OAAO,QAAA,KAAa,SAAA,EAAW;AAG3D,IAAA,IAAI,QAAA,KAAa,MAAA,IAAU,QAAA,KAAa,OAAA,EAAS;AAC/C,MAAA,QAAA,GAAW,QAAA,KAAa,MAAA;AAAA,IAC1B,CAAA,MAAO;AACL,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,QAAA,CAAS,uCAAA,EAAyC,EAAA,EAAI,UAAU;AAAA,OAClE;AAAA,IACF;AAAA,EACF;AACA,EAAA,IACE,MAAA,KAAW,MAAA,KACV,OAAO,MAAA,KAAW,QAAA,IAAY,WAAW,IAAA,IAAQ,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,CAAA,EACtE;AACA,IAAA,MAAM,IAAI,KAAA,CAAM,QAAA,CAAS,mBAAA,EAAqB,EAAA,EAAI,QAAQ,CAAC,CAAA;AAAA,EAC7D;AAEA,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA,CAAE,MAAA;AAAA,IACrC,CAAA,CAAA,KAAK,CAAC,wBAAA,CAAyB,QAAA,CAAS,CAAC;AAAA,GAC3C;AACA,EAAA,IAAI,WAAA,CAAY,SAAS,CAAA,EAAG;AAC1B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,QAAA;AAAA,QACE,uCAAuC,wBAAA,CAAyB,IAAA;AAAA,UAC9D;AAAA,SACD,CAAA,CAAA,CAAA;AAAA,QACD,EAAA;AAAA,QACA,WAAA,CAAY,KAAK,IAAI;AAAA;AACvB,KACF;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,EAAA;AAAA,IACA,QAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"readAppExtensionsConfig.esm.js","sources":["../../src/tree/readAppExtensionsConfig.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 { Config } from '@backstage/config';\nimport { JsonValue } from '@backstage/types';\n\nexport interface ExtensionParameters {\n id: string;\n attachTo?: { id: string; input: string };\n disabled?: boolean;\n config?: unknown;\n}\n\nconst knownExtensionParameters = ['attachTo', 'disabled', 'config'];\n\n// Since we'll never merge arrays in config the config reader context\n// isn't too much of a help. Fall back to manual config reading logic\n// as the Config interface makes it quite hard for us otherwise.\n/** @internal */\nexport function readAppExtensionsConfig(\n rootConfig: Config,\n): ExtensionParameters[] {\n const arr = rootConfig.getOptional('app.extensions');\n if (!Array.isArray(arr)) {\n if (arr === undefined) {\n return [];\n }\n // This will throw, and show which part of config had the wrong type\n rootConfig.getConfigArray('app.extensions');\n return [];\n }\n\n return arr.map((arrayEntry, arrayIndex) =>\n expandShorthandExtensionParameters(arrayEntry, arrayIndex),\n );\n}\n\n/** @internal */\nexport function expandShorthandExtensionParameters(\n arrayEntry: JsonValue,\n arrayIndex: number,\n): ExtensionParameters {\n function errorMsg(msg: string, key?: string, prop?: string) {\n return `Invalid extension configuration at app.extensions[${arrayIndex}]${\n key ? `[${key}]` : ''\n }${prop ? `.${prop}` : ''}, ${msg}`;\n }\n\n // NOTE(freben): This check is intentionally not complete and doesn't check\n // whether letters and digits are used, etc. It's not up to the config reading\n // logic to decide what constitutes a valid extension ID; that should be\n // decided by the logic that loads and instantiates the extensions. This check\n // is just here to catch real mistakes or truly conceptually wrong input.\n function assertValidId(id: string) {\n if (!id || id !== id.trim()) {\n throw new Error(\n errorMsg('extension ID must not be empty or contain whitespace'),\n );\n }\n }\n\n // Example YAML:\n // - entity.card.about\n if (typeof arrayEntry === 'string') {\n assertValidId(arrayEntry);\n return {\n id: arrayEntry,\n disabled: false,\n };\n }\n\n // All remaining cases are single-key objects\n if (\n typeof arrayEntry !== 'object' ||\n arrayEntry === null ||\n Array.isArray(arrayEntry)\n ) {\n throw new Error(errorMsg('must be a string or an object'));\n }\n const keys = Object.keys(arrayEntry);\n if (keys.length !== 1) {\n const joinedKeys = keys.length ? `'${keys.join(\"', '\")}'` : 'none';\n throw new Error(errorMsg(`must have exactly one key, got ${joinedKeys}`));\n }\n\n const id = String(keys[0]);\n const value = arrayEntry[id];\n assertValidId(id);\n\n // This example covers a potentially common mistake in the syntax\n // Example YAML:\n // - entity.card.about:\n if (value === null) {\n return {\n id,\n disabled: false,\n };\n }\n\n // Example YAML:\n // - catalog.page.cicd: false\n if (typeof value === 'boolean') {\n return {\n id,\n disabled: !value,\n };\n }\n\n // Environment variable substitution always produces a string, so boolean-ish\n // strings need to be coerced too. Example YAML:\n // - catalog.page.cicd: ${CATALOG_PAGE_CICD_ENABLED}\n if (value === 'true' || value === 'false') {\n return {\n id,\n disabled: value === 'false',\n };\n }\n\n // The remaining case is the generic object. Example YAML:\n // - tech-radar.page:\n // at: core.router/routes\n // disabled: false\n // config:\n // path: /tech-radar\n // width: 1500\n // height: 800\n if (typeof value !== 'object' || Array.isArray(value)) {\n // We don't mention null here - we don't want people to explicitly enter\n // - entity.card.about: null\n throw new Error(\n errorMsg(\"value must be a boolean, 'true', 'false', or object\", id),\n );\n }\n\n const attachTo = value.attachTo as { id: string; input: string } | undefined;\n let disabled = value.disabled;\n const config = value.config;\n\n if (attachTo !== undefined) {\n if (\n attachTo === null ||\n typeof attachTo !== 'object' ||\n Array.isArray(attachTo)\n ) {\n throw new Error(errorMsg('must be an object', id, 'attachTo'));\n }\n if (typeof attachTo.id !== 'string' || attachTo.id === '') {\n throw new Error(\n errorMsg('must be a non-empty string', id, 'attachTo.id'),\n );\n }\n if (typeof attachTo.input !== 'string' || attachTo.input === '') {\n throw new Error(\n errorMsg('must be a non-empty string', id, 'attachTo.input'),\n );\n }\n }\n if (disabled !== undefined && typeof disabled !== 'boolean') {\n // Environment variable substitution always produces a string, e.g.\n // disabled: ${CATALOG_OVERVIEW_DISABLED}\n if (disabled === 'true' || disabled === 'false') {\n disabled = disabled === 'true';\n } else {\n throw new Error(\n errorMsg(\"must be a boolean, 'true', or 'false'\", id, 'disabled'),\n );\n }\n }\n if (\n config !== undefined &&\n (typeof config !== 'object' || config === null || Array.isArray(config))\n ) {\n throw new Error(errorMsg('must be an object', id, 'config'));\n }\n\n const unknownKeys = Object.keys(value).filter(\n k => !knownExtensionParameters.includes(k),\n );\n if (unknownKeys.length > 0) {\n throw new Error(\n errorMsg(\n `unknown parameter; expected one of '${knownExtensionParameters.join(\n \"', '\",\n )}'`,\n id,\n unknownKeys.join(', '),\n ),\n );\n }\n\n return {\n id,\n attachTo,\n disabled,\n config,\n };\n}\n"],"names":["id"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveAppNodeSpecs.esm.js","sources":["../../src/tree/resolveAppNodeSpecs.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 createFrontendPlugin,\n Extension,\n FrontendFeature,\n FrontendPlugin,\n} from '@backstage/frontend-plugin-api';\nimport { FilterPredicate } from '@backstage/filter-predicates';\nimport { ExtensionParameters } from './readAppExtensionsConfig';\nimport { AppNodeSpec } from '@backstage/frontend-plugin-api';\nimport { OpaqueFrontendPlugin } from '@internal/frontend';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport {\n isInternalFrontendModule,\n toInternalFrontendModule,\n} from '../../../frontend-plugin-api/src/wiring/createFrontendModule';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalExtension } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';\nimport { ErrorCollector } from '../wiring/createErrorCollector';\n\nfunction normalizePlugin(plugin: FrontendPlugin): FrontendPlugin {\n // Ensure pluginId is always set for plugins in the app\n if (!plugin.pluginId && 'id' in plugin && typeof plugin.id === 'string') {\n (plugin as any).pluginId = plugin.id;\n }\n return plugin;\n}\n\nfunction combinePredicates(\n left: FilterPredicate | undefined,\n right: FilterPredicate | undefined,\n) {\n if (!left) {\n return right;\n }\n if (!right) {\n return left;\n }\n\n return { $all: [left, right] };\n}\n\nfunction getExtensionPredicate(options: {\n internalExtension: ReturnType<typeof toInternalExtension>;\n}) {\n if (options.internalExtension.version === 'v2') {\n return options.internalExtension.if;\n }\n return undefined;\n}\n\n/** @internal */\nexport function resolveAppNodeSpecs(options: {\n features?: FrontendFeature[];\n builtinExtensions?: Extension<any, any>[];\n parameters?: Array<ExtensionParameters>;\n forbidden?: Set<string>;\n collector: ErrorCollector;\n}): AppNodeSpec[] {\n const {\n builtinExtensions = [],\n parameters = [],\n forbidden = new Set(),\n features = [],\n collector,\n } = options;\n\n const plugins = features\n .filter(OpaqueFrontendPlugin.isType)\n .map(normalizePlugin);\n const modules = features.filter(isInternalFrontendModule);\n\n const filterForbidden = (\n extension: Extension<any, any> & { plugin: FrontendPlugin },\n ) => {\n if (forbidden.has(extension.id)) {\n collector.report({\n code: 'EXTENSION_IGNORED',\n message: `It is forbidden to override the '${extension.id}' extension, attempted by the '${extension.plugin.pluginId}' plugin`,\n context: {\n plugin: extension.plugin,\n extensionId: extension.id,\n },\n });\n return false;\n }\n return true;\n };\n\n const pluginExtensions = plugins.flatMap(plugin => {\n const internalPlugin = OpaqueFrontendPlugin.toInternal(plugin);\n return internalPlugin.extensions\n .map(extension => {\n const internalExtension = toInternalExtension(extension);\n return {\n ...internalExtension,\n plugin,\n if: combinePredicates(\n internalPlugin.if,\n internalExtension.version === 'v2'\n ? internalExtension.if\n : undefined,\n ),\n };\n })\n .filter(filterForbidden);\n });\n const moduleExtensions = modules.flatMap(mod => {\n const internalModule = toInternalFrontendModule(mod);\n return internalModule.extensions\n .flatMap(extension => {\n const internalExtension = toInternalExtension(extension);\n\n // Modules for plugins that are not installed are ignored\n const plugin = plugins.find(p => p.pluginId === mod.pluginId);\n if (!plugin) {\n return [];\n }\n\n return [\n {\n ...internalExtension,\n plugin,\n if: combinePredicates(\n internalModule.if,\n internalExtension.version === 'v2'\n ? internalExtension.if\n : undefined,\n ),\n },\n ];\n })\n .filter(filterForbidden);\n });\n\n const appPlugin =\n plugins.find(plugin => plugin.pluginId === 'app') ??\n createFrontendPlugin({\n pluginId: 'app',\n });\n\n const configuredExtensions = [\n ...pluginExtensions.map(({ plugin, ...extension }) => {\n const internalExtension = toInternalExtension(extension);\n return {\n extension: internalExtension,\n params: {\n plugin,\n source: plugin,\n attachTo: internalExtension.attachTo,\n disabled: internalExtension.disabled,\n if: getExtensionPredicate({ internalExtension }),\n config: undefined as unknown,\n },\n };\n }),\n ...builtinExtensions.map(extension => {\n const internalExtension = toInternalExtension(extension);\n return {\n extension: internalExtension,\n params: {\n source: appPlugin,\n plugin: appPlugin,\n attachTo: internalExtension.attachTo,\n disabled: internalExtension.disabled,\n if: getExtensionPredicate({ internalExtension }),\n config: undefined as unknown,\n },\n };\n }),\n ];\n\n // Install all module overrides\n for (const extension of moduleExtensions) {\n const internalExtension = toInternalExtension(extension);\n\n // Check if our override is overriding an extension that already exists\n const index = configuredExtensions.findIndex(\n e => e.extension.id === extension.id,\n );\n if (index !== -1) {\n // Only implementation, attachment point and default disabled status are overridden, the source is kept\n configuredExtensions[index].extension = internalExtension;\n configuredExtensions[index].params.attachTo = internalExtension.attachTo;\n configuredExtensions[index].params.disabled = internalExtension.disabled;\n configuredExtensions[index].params.if = getExtensionPredicate({\n internalExtension,\n });\n } else {\n // Add the extension as a new one when not overriding an existing one\n configuredExtensions.push({\n extension: internalExtension,\n params: {\n plugin: extension.plugin,\n source: extension.plugin,\n attachTo: internalExtension.attachTo,\n disabled: internalExtension.disabled,\n if: getExtensionPredicate({ internalExtension }),\n config: undefined,\n },\n });\n }\n }\n\n const seenExtensionIds = new Set<string>();\n const deduplicatedExtensions = configuredExtensions.filter(\n ({ extension, params }) => {\n if (seenExtensionIds.has(extension.id)) {\n collector.report({\n code: 'EXTENSION_IGNORED',\n message: `The '${extension.id}' extension from the '${params.plugin.pluginId}' plugin is a duplicate and will be ignored`,\n context: {\n plugin: params.plugin,\n extensionId: extension.id,\n },\n });\n return false;\n }\n seenExtensionIds.add(extension.id);\n return true;\n },\n );\n\n const order = new Map<string, (typeof deduplicatedExtensions)[number]>();\n for (const overrideParam of parameters) {\n const extensionId = overrideParam.id;\n\n if (forbidden.has(extensionId)) {\n collector.report({\n code: 'INVALID_EXTENSION_CONFIG_KEY',\n message: `Configuration of the '${extensionId}' extension is forbidden`,\n context: {\n extensionId,\n },\n });\n continue;\n }\n\n const existing = deduplicatedExtensions.find(\n e => e.extension.id === extensionId,\n );\n if (existing) {\n if (overrideParam.attachTo) {\n existing.params.attachTo = overrideParam.attachTo;\n }\n if (overrideParam.config) {\n // TODO: merge config?\n existing.params.config = overrideParam.config;\n }\n if (\n Boolean(existing.params.disabled) !== Boolean(overrideParam.disabled)\n ) {\n existing.params.disabled = Boolean(overrideParam.disabled);\n }\n order.set(extensionId, existing);\n } else {\n collector.report({\n code: 'INVALID_EXTENSION_CONFIG_KEY',\n message: `Extension ${extensionId} does not exist`,\n context: {\n extensionId,\n },\n });\n }\n }\n\n const orderedExtensions = [\n ...order.values(),\n ...deduplicatedExtensions.filter(e => !order.has(e.extension.id)),\n ];\n\n return orderedExtensions.map(param => ({\n id: param.extension.id,\n attachTo: param.params.attachTo,\n extension: param.extension,\n disabled: param.params.disabled,\n if: param.params.if,\n plugin: param.params.plugin,\n source: param.params.source,\n config: param.params.config,\n }));\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"resolveAppNodeSpecs.esm.js","sources":["../../src/tree/resolveAppNodeSpecs.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 createFrontendPlugin,\n Extension,\n FrontendFeature,\n FrontendPlugin,\n} from '@backstage/frontend-plugin-api';\nimport { FilterPredicate } from '@backstage/filter-predicates';\nimport { ExtensionParameters } from './readAppExtensionsConfig';\nimport { AppNodeSpec } from '@backstage/frontend-plugin-api';\nimport { OpaqueFrontendPlugin } from '@internal/frontend';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport {\n isInternalFrontendModule,\n toInternalFrontendModule,\n} from '../../../frontend-plugin-api/src/wiring/createFrontendModule';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalExtension } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';\nimport { ErrorCollector } from '../wiring/createErrorCollector';\n\nfunction normalizePlugin(plugin: FrontendPlugin): FrontendPlugin {\n // Ensure pluginId is always set for plugins in the app\n if (!plugin.pluginId && 'id' in plugin && typeof plugin.id === 'string') {\n (plugin as any).pluginId = plugin.id;\n }\n return plugin;\n}\n\nfunction combinePredicates(\n left: FilterPredicate | undefined,\n right: FilterPredicate | undefined,\n) {\n if (!left) {\n return right;\n }\n if (!right) {\n return left;\n }\n\n return { $all: [left, right] };\n}\n\nfunction getExtensionPredicate(options: {\n internalExtension: ReturnType<typeof toInternalExtension>;\n}) {\n if (options.internalExtension.version === 'v2') {\n return options.internalExtension.if;\n }\n return undefined;\n}\n\n/** @internal */\nexport function resolveAppNodeSpecs(options: {\n features?: FrontendFeature[];\n builtinExtensions?: Extension<any, any>[];\n parameters?: Array<ExtensionParameters>;\n forbidden?: Set<string>;\n collector: ErrorCollector;\n}): AppNodeSpec[] {\n const {\n builtinExtensions = [],\n parameters = [],\n forbidden = new Set(),\n features = [],\n collector,\n } = options;\n\n const plugins = features\n .filter(OpaqueFrontendPlugin.isType)\n .map(normalizePlugin);\n const modules = features.filter(isInternalFrontendModule);\n\n const filterForbidden = (\n extension: Extension<any, any> & { plugin: FrontendPlugin },\n ) => {\n if (forbidden.has(extension.id)) {\n collector.report({\n code: 'EXTENSION_IGNORED',\n message: `It is forbidden to override the '${extension.id}' extension, attempted by the '${extension.plugin.pluginId}' plugin`,\n context: {\n plugin: extension.plugin,\n extensionId: extension.id,\n },\n });\n return false;\n }\n return true;\n };\n\n const pluginExtensions = plugins.flatMap(plugin => {\n const internalPlugin = OpaqueFrontendPlugin.toInternal(plugin);\n return internalPlugin.extensions\n .map(extension => {\n const internalExtension = toInternalExtension(extension);\n return {\n ...internalExtension,\n plugin,\n if: combinePredicates(\n internalPlugin.if,\n internalExtension.version === 'v2'\n ? internalExtension.if\n : undefined,\n ),\n };\n })\n .filter(filterForbidden);\n });\n const moduleExtensions = modules.flatMap(mod => {\n const internalModule = toInternalFrontendModule(mod);\n return internalModule.extensions\n .flatMap(extension => {\n const internalExtension = toInternalExtension(extension);\n\n // Modules for plugins that are not installed are ignored\n const plugin = plugins.find(p => p.pluginId === mod.pluginId);\n if (!plugin) {\n return [];\n }\n\n return [\n {\n ...internalExtension,\n plugin,\n if: combinePredicates(\n internalModule.if,\n internalExtension.version === 'v2'\n ? internalExtension.if\n : undefined,\n ),\n },\n ];\n })\n .filter(filterForbidden);\n });\n\n const appPlugin =\n plugins.find(plugin => plugin.pluginId === 'app') ??\n createFrontendPlugin({\n pluginId: 'app',\n });\n\n const configuredExtensions = [\n ...pluginExtensions.map(({ plugin, ...extension }) => {\n const internalExtension = toInternalExtension(extension);\n return {\n extension: internalExtension,\n params: {\n plugin,\n source: plugin,\n attachTo: internalExtension.attachTo,\n disabled: internalExtension.disabled,\n if: getExtensionPredicate({ internalExtension }),\n config: undefined as unknown,\n },\n };\n }),\n ...builtinExtensions.map(extension => {\n const internalExtension = toInternalExtension(extension);\n return {\n extension: internalExtension,\n params: {\n source: appPlugin,\n plugin: appPlugin,\n attachTo: internalExtension.attachTo,\n disabled: internalExtension.disabled,\n if: getExtensionPredicate({ internalExtension }),\n config: undefined as unknown,\n },\n };\n }),\n ];\n\n // Install all module overrides\n for (const extension of moduleExtensions) {\n const internalExtension = toInternalExtension(extension);\n\n // Check if our override is overriding an extension that already exists\n const index = configuredExtensions.findIndex(\n e => e.extension.id === extension.id,\n );\n if (index !== -1) {\n // Only implementation, attachment point and default disabled status are overridden, the source is kept\n configuredExtensions[index].extension = internalExtension;\n configuredExtensions[index].params.attachTo = internalExtension.attachTo;\n configuredExtensions[index].params.disabled = internalExtension.disabled;\n configuredExtensions[index].params.if = getExtensionPredicate({\n internalExtension,\n });\n } else {\n // Add the extension as a new one when not overriding an existing one\n configuredExtensions.push({\n extension: internalExtension,\n params: {\n plugin: extension.plugin,\n source: extension.plugin,\n attachTo: internalExtension.attachTo,\n disabled: internalExtension.disabled,\n if: getExtensionPredicate({ internalExtension }),\n config: undefined,\n },\n });\n }\n }\n\n const seenExtensionIds = new Set<string>();\n const deduplicatedExtensions = configuredExtensions.filter(\n ({ extension, params }) => {\n if (seenExtensionIds.has(extension.id)) {\n collector.report({\n code: 'EXTENSION_IGNORED',\n message: `The '${extension.id}' extension from the '${params.plugin.pluginId}' plugin is a duplicate and will be ignored`,\n context: {\n plugin: params.plugin,\n extensionId: extension.id,\n },\n });\n return false;\n }\n seenExtensionIds.add(extension.id);\n return true;\n },\n );\n\n const order = new Map<string, (typeof deduplicatedExtensions)[number]>();\n for (const overrideParam of parameters) {\n const extensionId = overrideParam.id;\n\n if (forbidden.has(extensionId)) {\n collector.report({\n code: 'INVALID_EXTENSION_CONFIG_KEY',\n message: `Configuration of the '${extensionId}' extension is forbidden`,\n context: {\n extensionId,\n },\n });\n continue;\n }\n\n const existing = deduplicatedExtensions.find(\n e => e.extension.id === extensionId,\n );\n if (existing) {\n if (overrideParam.attachTo) {\n existing.params.attachTo = overrideParam.attachTo;\n }\n if (overrideParam.config) {\n // TODO: merge config?\n existing.params.config = overrideParam.config;\n }\n if (\n Boolean(existing.params.disabled) !== Boolean(overrideParam.disabled)\n ) {\n existing.params.disabled = Boolean(overrideParam.disabled);\n }\n order.set(extensionId, existing);\n } else {\n collector.report({\n code: 'INVALID_EXTENSION_CONFIG_KEY',\n message: `Extension ${extensionId} does not exist`,\n context: {\n extensionId,\n },\n });\n }\n }\n\n const orderedExtensions = [\n ...order.values(),\n ...deduplicatedExtensions.filter(e => !order.has(e.extension.id)),\n ];\n\n return orderedExtensions.map(param => ({\n id: param.extension.id,\n attachTo: param.params.attachTo,\n extension: param.extension,\n disabled: param.params.disabled,\n if: param.params.if,\n plugin: param.params.plugin,\n source: param.params.source,\n config: param.params.config,\n }));\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveAppTree.esm.js","sources":["../../src/tree/resolveAppTree.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 AppTree,\n AppNode,\n AppNodeInstance,\n AppNodeSpec,\n} from '@backstage/frontend-plugin-api';\n\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalExtension } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';\nimport { ErrorCollector } from '../wiring/createErrorCollector';\n\nfunction indent(str: string) {\n return str.replace(/^/gm, ' ');\n}\n\n/** @internal */\nclass SerializableAppNode implements AppNode {\n public readonly spec: AppNodeSpec;\n public readonly edges = {\n attachedTo: undefined as { node: AppNode; input: string } | undefined,\n attachments: new Map<string, SerializableAppNode[]>(),\n };\n public readonly instance?: AppNodeInstance;\n\n constructor(spec: AppNodeSpec) {\n this.spec = spec;\n }\n\n setParent(parent: SerializableAppNode, input: string) {\n this.edges.attachedTo = { node: parent, input };\n\n const parentInputEdges = parent.edges.attachments.get(input);\n if (parentInputEdges) {\n parentInputEdges.push(this);\n } else {\n parent.edges.attachments.set(input, [this]);\n }\n }\n\n toJSON() {\n const dataRefs = this.instance && [...this.instance.getDataRefs()];\n return {\n id: this.spec.id,\n output:\n dataRefs && dataRefs.length > 0\n ? dataRefs.map(ref => ref.id)\n : undefined,\n attachments:\n this.edges.attachments.size > 0\n ? Object.fromEntries(this.edges.attachments)\n : undefined,\n };\n }\n\n toString(): string {\n const dataRefs = this.instance && [...this.instance.getDataRefs()];\n const out =\n dataRefs && dataRefs.length > 0\n ? ` out=[${[...dataRefs].map(r => r.id).join(', ')}]`\n : '';\n\n if (this.edges.attachments.size === 0) {\n return `<${this.spec.id}${out} />`;\n }\n\n return [\n `<${this.spec.id}${out}>`,\n ...[...this.edges.attachments.entries()].map(([k, v]) =>\n indent([`${k} [`, ...v.map(e => indent(e.toString())), `]`].join('\\n')),\n ),\n `</${this.spec.id}>`,\n ].join('\\n');\n }\n}\n\nfunction makeRedirectKey(attachTo: { id: string; input: string }) {\n return `${attachTo.id}%${attachTo.input}`;\n}\n\nconst isValidAttachmentPoint = (\n attachTo: { id: string; input: string },\n nodes: Map<string, SerializableAppNode>,\n) => {\n if (!nodes.has(attachTo.id)) {\n return false;\n }\n\n return (\n attachTo.input in\n toInternalExtension(nodes.get(attachTo.id)!.spec.extension).inputs\n );\n};\n\n/**\n * Build the app tree by iterating through all node specs and constructing the app\n * tree with all attachments in the same order as they appear in the input specs array.\n * @internal\n */\nexport function resolveAppTree(\n rootNodeId: string,\n specs: AppNodeSpec[],\n errorCollector: ErrorCollector,\n): AppTree {\n const nodes = new Map<string, SerializableAppNode>();\n\n const redirectTargetsByKey = new Map<string, { id: string; input: string }>();\n\n for (const spec of specs) {\n // The main check with a helpful error message happens in resolveAppNodeSpecs\n if (nodes.has(spec.id)) {\n continue;\n }\n\n const node = new SerializableAppNode(spec);\n nodes.set(spec.id, node);\n\n const internal = toInternalExtension(spec.extension);\n for (const [inputName, input] of Object.entries(internal.inputs)) {\n if (input.replaces) {\n for (const replace of input.replaces) {\n const key = makeRedirectKey(replace);\n if (redirectTargetsByKey.has(key)) {\n errorCollector.report({\n code: 'EXTENSION_INPUT_REDIRECT_CONFLICT',\n message: `Duplicate redirect target for input '${inputName}' in extension '${spec.id}'`,\n context: {\n node,\n inputName,\n },\n });\n continue;\n }\n redirectTargetsByKey.set(key, { id: spec.id, input: inputName });\n }\n }\n }\n }\n\n const orphans = new Array<SerializableAppNode>();\n const clones = new Map<string, Array<SerializableAppNode>>();\n\n // A node with the provided rootNodeId must be found in the tree, and it must not be attached to anything\n let rootNode: AppNode | undefined = undefined;\n\n for (const node of nodes.values()) {\n const spec = node.spec;\n\n // TODO: For now we simply ignore the attachTo spec of the root node, but it'd be cleaner if we could avoid defining it\n if (spec.id === rootNodeId) {\n rootNode = node;\n } else if (Array.isArray(spec.attachTo)) {\n // eslint-disable-next-line no-console\n console.warn(\n `Extension '${spec.id}' is using multiple attachment points which is deprecated and will be removed in a future release. ` +\n `Use a Utility API instead to share functionality across multiple locations. ` +\n `See https://backstage.io/docs/frontend-system/architecture/27-sharing-extensions for migration guidance.`,\n );\n let foundFirstParent = false;\n for (const origAttachTo of spec.attachTo) {\n let attachTo = origAttachTo;\n\n if (!isValidAttachmentPoint(attachTo, nodes)) {\n attachTo =\n redirectTargetsByKey.get(makeRedirectKey(attachTo)) ?? attachTo;\n }\n\n const parent = nodes.get(attachTo.id);\n if (parent) {\n const cloneParents = clones.get(attachTo.id) ?? [];\n\n if (!foundFirstParent) {\n foundFirstParent = true;\n node.setParent(parent, attachTo.input);\n } else {\n cloneParents.unshift(parent);\n }\n\n for (const extraParent of cloneParents) {\n const clonedNode = new SerializableAppNode(spec);\n clonedNode.setParent(extraParent, attachTo.input);\n clones.set(\n spec.id,\n clones.get(spec.id)?.concat(clonedNode) ?? [clonedNode],\n );\n }\n }\n }\n if (!foundFirstParent) {\n orphans.push(node);\n }\n } else {\n let attachTo = spec.attachTo;\n if (!isValidAttachmentPoint(attachTo, nodes)) {\n attachTo =\n redirectTargetsByKey.get(makeRedirectKey(attachTo)) ?? attachTo;\n }\n\n const parent = nodes.get(attachTo.id);\n if (parent) {\n node.setParent(parent, attachTo.input);\n } else {\n orphans.push(node);\n }\n }\n }\n\n if (!rootNode) {\n throw new Error(`No root node with id '${rootNodeId}' found in app tree`);\n }\n\n return {\n root: rootNode,\n nodes,\n orphans,\n };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"resolveAppTree.esm.js","sources":["../../src/tree/resolveAppTree.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 AppTree,\n AppNode,\n AppNodeInstance,\n AppNodeSpec,\n} from '@backstage/frontend-plugin-api';\n\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalExtension } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';\nimport { ErrorCollector } from '../wiring/createErrorCollector';\n\nfunction indent(str: string) {\n return str.replace(/^/gm, ' ');\n}\n\n/** @internal */\nclass SerializableAppNode implements AppNode {\n public readonly spec: AppNodeSpec;\n public readonly edges = {\n attachedTo: undefined as { node: AppNode; input: string } | undefined,\n attachments: new Map<string, SerializableAppNode[]>(),\n };\n public readonly instance?: AppNodeInstance;\n\n constructor(spec: AppNodeSpec) {\n this.spec = spec;\n }\n\n setParent(parent: SerializableAppNode, input: string) {\n this.edges.attachedTo = { node: parent, input };\n\n const parentInputEdges = parent.edges.attachments.get(input);\n if (parentInputEdges) {\n parentInputEdges.push(this);\n } else {\n parent.edges.attachments.set(input, [this]);\n }\n }\n\n toJSON() {\n const dataRefs = this.instance && [...this.instance.getDataRefs()];\n return {\n id: this.spec.id,\n output:\n dataRefs && dataRefs.length > 0\n ? dataRefs.map(ref => ref.id)\n : undefined,\n attachments:\n this.edges.attachments.size > 0\n ? Object.fromEntries(this.edges.attachments)\n : undefined,\n };\n }\n\n toString(): string {\n const dataRefs = this.instance && [...this.instance.getDataRefs()];\n const out =\n dataRefs && dataRefs.length > 0\n ? ` out=[${[...dataRefs].map(r => r.id).join(', ')}]`\n : '';\n\n if (this.edges.attachments.size === 0) {\n return `<${this.spec.id}${out} />`;\n }\n\n return [\n `<${this.spec.id}${out}>`,\n ...[...this.edges.attachments.entries()].map(([k, v]) =>\n indent([`${k} [`, ...v.map(e => indent(e.toString())), `]`].join('\\n')),\n ),\n `</${this.spec.id}>`,\n ].join('\\n');\n }\n}\n\nfunction makeRedirectKey(attachTo: { id: string; input: string }) {\n return `${attachTo.id}%${attachTo.input}`;\n}\n\nconst isValidAttachmentPoint = (\n attachTo: { id: string; input: string },\n nodes: Map<string, SerializableAppNode>,\n) => {\n if (!nodes.has(attachTo.id)) {\n return false;\n }\n\n return (\n attachTo.input in\n toInternalExtension(nodes.get(attachTo.id)!.spec.extension).inputs\n );\n};\n\n/**\n * Build the app tree by iterating through all node specs and constructing the app\n * tree with all attachments in the same order as they appear in the input specs array.\n * @internal\n */\nexport function resolveAppTree(\n rootNodeId: string,\n specs: AppNodeSpec[],\n errorCollector: ErrorCollector,\n): AppTree {\n const nodes = new Map<string, SerializableAppNode>();\n\n const redirectTargetsByKey = new Map<string, { id: string; input: string }>();\n\n for (const spec of specs) {\n // The main check with a helpful error message happens in resolveAppNodeSpecs\n if (nodes.has(spec.id)) {\n continue;\n }\n\n const node = new SerializableAppNode(spec);\n nodes.set(spec.id, node);\n\n const internal = toInternalExtension(spec.extension);\n for (const [inputName, input] of Object.entries(internal.inputs)) {\n if (input.replaces) {\n for (const replace of input.replaces) {\n const key = makeRedirectKey(replace);\n if (redirectTargetsByKey.has(key)) {\n errorCollector.report({\n code: 'EXTENSION_INPUT_REDIRECT_CONFLICT',\n message: `Duplicate redirect target for input '${inputName}' in extension '${spec.id}'`,\n context: {\n node,\n inputName,\n },\n });\n continue;\n }\n redirectTargetsByKey.set(key, { id: spec.id, input: inputName });\n }\n }\n }\n }\n\n const orphans = new Array<SerializableAppNode>();\n const clones = new Map<string, Array<SerializableAppNode>>();\n\n // A node with the provided rootNodeId must be found in the tree, and it must not be attached to anything\n let rootNode: AppNode | undefined = undefined;\n\n for (const node of nodes.values()) {\n const spec = node.spec;\n\n // TODO: For now we simply ignore the attachTo spec of the root node, but it'd be cleaner if we could avoid defining it\n if (spec.id === rootNodeId) {\n rootNode = node;\n } else if (Array.isArray(spec.attachTo)) {\n // eslint-disable-next-line no-console\n console.warn(\n `Extension '${spec.id}' is using multiple attachment points which is deprecated and will be removed in a future release. ` +\n `Use a Utility API instead to share functionality across multiple locations. ` +\n `See https://backstage.io/docs/frontend-system/architecture/27-sharing-extensions for migration guidance.`,\n );\n let foundFirstParent = false;\n for (const origAttachTo of spec.attachTo) {\n let attachTo = origAttachTo;\n\n if (!isValidAttachmentPoint(attachTo, nodes)) {\n attachTo =\n redirectTargetsByKey.get(makeRedirectKey(attachTo)) ?? attachTo;\n }\n\n const parent = nodes.get(attachTo.id);\n if (parent) {\n const cloneParents = clones.get(attachTo.id) ?? [];\n\n if (!foundFirstParent) {\n foundFirstParent = true;\n node.setParent(parent, attachTo.input);\n } else {\n cloneParents.unshift(parent);\n }\n\n for (const extraParent of cloneParents) {\n const clonedNode = new SerializableAppNode(spec);\n clonedNode.setParent(extraParent, attachTo.input);\n clones.set(\n spec.id,\n clones.get(spec.id)?.concat(clonedNode) ?? [clonedNode],\n );\n }\n }\n }\n if (!foundFirstParent) {\n orphans.push(node);\n }\n } else {\n let attachTo = spec.attachTo;\n if (!isValidAttachmentPoint(attachTo, nodes)) {\n attachTo =\n redirectTargetsByKey.get(makeRedirectKey(attachTo)) ?? attachTo;\n }\n\n const parent = nodes.get(attachTo.id);\n if (parent) {\n node.setParent(parent, attachTo.input);\n } else {\n orphans.push(node);\n }\n }\n }\n\n if (!rootNode) {\n throw new Error(`No root node with id '${rootNodeId}' found in app tree`);\n }\n\n return {\n root: rootNode,\n nodes,\n orphans,\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FrontendApiRegistry.esm.js","sources":["../../src/wiring/FrontendApiRegistry.ts"],"sourcesContent":["/*\n * Copyright 2026 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 AnyApiFactory,\n AnyApiRef,\n ApiFactory,\n ApiHolder,\n ApiRef,\n} from '@backstage/frontend-plugin-api';\n\nexport class FrontendApiRegistry {\n private readonly factories = new Map<string, AnyApiFactory>();\n\n register(factory: AnyApiFactory) {\n if (this.factories.has(factory.api.id)) {\n return false;\n }\n\n this.factories.set(factory.api.id, factory);\n return true;\n }\n\n registerAll(factories: AnyApiFactory[]) {\n for (const factory of factories) {\n this.register(factory);\n }\n }\n\n set(factory: AnyApiFactory) {\n this.factories.set(factory.api.id, factory);\n }\n\n setAll(factories: Iterable<AnyApiFactory>) {\n for (const factory of factories) {\n this.set(factory);\n }\n }\n\n get<T>(\n api: ApiRef<T>,\n ): ApiFactory<T, T, { [name: string]: unknown }> | undefined {\n const factory = this.factories.get(api.id);\n if (!factory) {\n return undefined;\n }\n\n return factory as ApiFactory<T, T, { [name: string]: unknown }>;\n }\n\n getAllApis() {\n const refs = new Set<AnyApiRef>();\n for (const factory of this.factories.values()) {\n refs.add(factory.api);\n }\n return refs;\n }\n}\n\nexport class FrontendApiResolver implements ApiHolder {\n private readonly apis = new Map<string, unknown>();\n private readonly primaryRegistry?: FrontendApiRegistry;\n private readonly secondaryRegistry?: FrontendApiRegistry;\n private readonly fallbackApis?: ApiHolder;\n\n constructor(options: {\n primaryRegistry?: FrontendApiRegistry;\n secondaryRegistry?: FrontendApiRegistry;\n fallbackApis?: ApiHolder;\n }) {\n this.primaryRegistry = options.primaryRegistry;\n this.secondaryRegistry = options.secondaryRegistry;\n this.fallbackApis = options.fallbackApis;\n }\n\n get<T>(ref: ApiRef<T>): T | undefined {\n return this.load(ref);\n }\n\n isMaterialized(apiRefId: string) {\n return this.apis.has(apiRefId);\n }\n\n invalidate(apiRefIds?: Iterable<string>) {\n if (apiRefIds === undefined) {\n this.apis.clear();\n return;\n }\n\n for (const apiRefId of apiRefIds) {\n this.apis.delete(apiRefId);\n }\n }\n\n private load<T>(ref: ApiRef<T>, loading: AnyApiRef[] = []): T | undefined {\n const existing = this.apis.get(ref.id);\n if (this.apis.has(ref.id)) {\n return existing as T;\n }\n\n const factory =\n this.primaryRegistry?.get(ref) ?? this.secondaryRegistry?.get(ref);\n if (!factory) {\n return this.fallbackApis?.get(ref);\n }\n\n if (loading.includes(factory.api)) {\n throw new Error(`Circular dependency of api factory for ${factory.api}`);\n }\n\n const deps = {} as { [name: string]: unknown };\n for (const [key, depRef] of Object.entries(factory.deps)) {\n const dep = this.load(depRef, [...loading, factory.api]);\n if (dep === undefined) {\n throw new Error(\n `No API factory available for dependency ${depRef} of dependent ${factory.api}`,\n );\n }\n deps[key] = dep;\n }\n\n const api = factory.factory(deps);\n this.apis.set(ref.id, api);\n return api as T;\n }\n}\n"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"FrontendApiRegistry.esm.js","sources":["../../src/wiring/FrontendApiRegistry.ts"],"sourcesContent":["/*\n * Copyright 2026 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 AnyApiFactory,\n AnyApiRef,\n ApiFactory,\n ApiHolder,\n ApiRef,\n} from '@backstage/frontend-plugin-api';\n\nexport class FrontendApiRegistry {\n private readonly factories = new Map<string, AnyApiFactory>();\n\n register(factory: AnyApiFactory) {\n if (this.factories.has(factory.api.id)) {\n return false;\n }\n\n this.factories.set(factory.api.id, factory);\n return true;\n }\n\n registerAll(factories: AnyApiFactory[]) {\n for (const factory of factories) {\n this.register(factory);\n }\n }\n\n set(factory: AnyApiFactory) {\n this.factories.set(factory.api.id, factory);\n }\n\n setAll(factories: Iterable<AnyApiFactory>) {\n for (const factory of factories) {\n this.set(factory);\n }\n }\n\n get<T>(\n api: ApiRef<T>,\n ): ApiFactory<T, T, { [name: string]: unknown }> | undefined {\n const factory = this.factories.get(api.id);\n if (!factory) {\n return undefined;\n }\n\n return factory as ApiFactory<T, T, { [name: string]: unknown }>;\n }\n\n getAllApis() {\n const refs = new Set<AnyApiRef>();\n for (const factory of this.factories.values()) {\n refs.add(factory.api);\n }\n return refs;\n }\n}\n\nexport class FrontendApiResolver implements ApiHolder {\n private readonly apis = new Map<string, unknown>();\n private readonly primaryRegistry?: FrontendApiRegistry;\n private readonly secondaryRegistry?: FrontendApiRegistry;\n private readonly fallbackApis?: ApiHolder;\n\n constructor(options: {\n primaryRegistry?: FrontendApiRegistry;\n secondaryRegistry?: FrontendApiRegistry;\n fallbackApis?: ApiHolder;\n }) {\n this.primaryRegistry = options.primaryRegistry;\n this.secondaryRegistry = options.secondaryRegistry;\n this.fallbackApis = options.fallbackApis;\n }\n\n get<T>(ref: ApiRef<T>): T | undefined {\n return this.load(ref);\n }\n\n isMaterialized(apiRefId: string) {\n return this.apis.has(apiRefId);\n }\n\n invalidate(apiRefIds?: Iterable<string>) {\n if (apiRefIds === undefined) {\n this.apis.clear();\n return;\n }\n\n for (const apiRefId of apiRefIds) {\n this.apis.delete(apiRefId);\n }\n }\n\n private load<T>(ref: ApiRef<T>, loading: AnyApiRef[] = []): T | undefined {\n const existing = this.apis.get(ref.id);\n if (this.apis.has(ref.id)) {\n return existing as T;\n }\n\n const factory =\n this.primaryRegistry?.get(ref) ?? this.secondaryRegistry?.get(ref);\n if (!factory) {\n return this.fallbackApis?.get(ref);\n }\n\n if (loading.includes(factory.api)) {\n throw new Error(`Circular dependency of api factory for ${factory.api}`);\n }\n\n const deps = {} as { [name: string]: unknown };\n for (const [key, depRef] of Object.entries(factory.deps)) {\n const dep = this.load(depRef, [...loading, factory.api]);\n if (dep === undefined) {\n throw new Error(\n `No API factory available for dependency ${depRef} of dependent ${factory.api}`,\n );\n }\n deps[key] = dep;\n }\n\n const api = factory.factory(deps);\n this.apis.set(ref.id, api);\n return api as T;\n }\n}\n"],"names":[],"mappings":"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"}
|