@backstage/frontend-app-api 0.11.2-next.3 → 0.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @backstage/frontend-app-api
|
|
2
2
|
|
|
3
|
+
## 0.11.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 173db8f: Updates to use the new `plugin` property of `AppNodeSpec`.
|
|
8
|
+
- 1f04491: Added the ability to ignore unknown extension config by passing `{ flags: { allowUnknownExtensionConfig: true } }` to `createSpecializedApp`.
|
|
9
|
+
- 72d019d: Removed various typos
|
|
10
|
+
- Updated dependencies
|
|
11
|
+
- @backstage/frontend-plugin-api@0.10.2
|
|
12
|
+
- @backstage/core-app-api@1.17.0
|
|
13
|
+
- @backstage/core-plugin-api@1.10.7
|
|
14
|
+
- @backstage/frontend-defaults@0.2.2
|
|
15
|
+
- @backstage/config@1.3.2
|
|
16
|
+
- @backstage/errors@1.2.7
|
|
17
|
+
- @backstage/types@1.2.1
|
|
18
|
+
- @backstage/version-bridge@1.0.11
|
|
19
|
+
|
|
3
20
|
## 0.11.2-next.3
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
|
@@ -59,8 +59,8 @@ function extractRouteInfoFromAppNode(node) {
|
|
|
59
59
|
}
|
|
60
60
|
routeParents.set(routeRef, newParentRef);
|
|
61
61
|
currentObj?.routeRefs.add(routeRef);
|
|
62
|
-
if (current.spec.
|
|
63
|
-
currentObj?.plugins.add(toLegacyPlugin(current.spec.
|
|
62
|
+
if (current.spec.plugin) {
|
|
63
|
+
currentObj?.plugins.add(toLegacyPlugin(current.spec.plugin));
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
for (const children of current.edges.attachments.values()) {
|
|
@@ -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 { toLegacyPlugin } from './toLegacyPlugin';\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 plugins: new Set(),\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\nexport function extractRouteInfoFromAppNode(node: AppNode): {\n routePaths: Map<RouteRef, string>;\n routeParents: Map<RouteRef, RouteRef | undefined>;\n routeObjects: BackstageRouteObject[];\n} {\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\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 const routeRef = current.instance?.getData(coreExtensionData.routeRef);\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 plugins: new Set(),\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 if (current.spec.
|
|
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 { toLegacyPlugin } from './toLegacyPlugin';\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 plugins: new Set(),\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\nexport function extractRouteInfoFromAppNode(node: AppNode): {\n routePaths: Map<RouteRef, string>;\n routeParents: Map<RouteRef, RouteRef | undefined>;\n routeObjects: BackstageRouteObject[];\n} {\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\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 const routeRef = current.instance?.getData(coreExtensionData.routeRef);\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 plugins: new Set(),\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 if (current.spec.plugin) {\n currentObj?.plugins.add(toLegacyPlugin(current.spec.plugin));\n }\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 { routePaths, routeParents, routeObjects };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -12,44 +12,45 @@ function resolveAppNodeSpecs(options) {
|
|
|
12
12
|
} = options;
|
|
13
13
|
const plugins = features.filter(OpaqueFrontendPlugin.isType);
|
|
14
14
|
const modules = features.filter(isInternalFrontendModule);
|
|
15
|
-
const pluginExtensions = plugins.flatMap((
|
|
16
|
-
return OpaqueFrontendPlugin.toInternal(
|
|
15
|
+
const pluginExtensions = plugins.flatMap((plugin) => {
|
|
16
|
+
return OpaqueFrontendPlugin.toInternal(plugin).extensions.map(
|
|
17
17
|
(extension) => ({
|
|
18
18
|
...extension,
|
|
19
|
-
|
|
19
|
+
plugin
|
|
20
20
|
})
|
|
21
21
|
);
|
|
22
22
|
});
|
|
23
23
|
const moduleExtensions = modules.flatMap(
|
|
24
24
|
(mod) => toInternalFrontendModule(mod).extensions.flatMap((extension) => {
|
|
25
|
-
const
|
|
26
|
-
if (!
|
|
25
|
+
const plugin = plugins.find((p) => p.id === mod.pluginId);
|
|
26
|
+
if (!plugin) {
|
|
27
27
|
return [];
|
|
28
28
|
}
|
|
29
|
-
return [{ ...extension,
|
|
29
|
+
return [{ ...extension, plugin }];
|
|
30
30
|
})
|
|
31
31
|
);
|
|
32
32
|
if (pluginExtensions.some(({ id }) => forbidden.has(id))) {
|
|
33
|
-
const pluginsStr = pluginExtensions.filter(({ id }) => forbidden.has(id)).map(({
|
|
33
|
+
const pluginsStr = pluginExtensions.filter(({ id }) => forbidden.has(id)).map(({ plugin }) => `'${plugin.id}'`).join(", ");
|
|
34
34
|
const forbiddenStr = [...forbidden].map((id) => `'${id}'`).join(", ");
|
|
35
35
|
throw new Error(
|
|
36
36
|
`It is forbidden to override the following extension(s): ${forbiddenStr}, which is done by the following plugin(s): ${pluginsStr}`
|
|
37
37
|
);
|
|
38
38
|
}
|
|
39
39
|
if (moduleExtensions.some(({ id }) => forbidden.has(id))) {
|
|
40
|
-
const pluginsStr = moduleExtensions.filter(({ id }) => forbidden.has(id)).map(({
|
|
40
|
+
const pluginsStr = moduleExtensions.filter(({ id }) => forbidden.has(id)).map(({ plugin }) => `'${plugin.id}'`).join(", ");
|
|
41
41
|
const forbiddenStr = [...forbidden].map((id) => `'${id}'`).join(", ");
|
|
42
42
|
throw new Error(
|
|
43
43
|
`It is forbidden to override the following extension(s): ${forbiddenStr}, which is done by a module for the following plugin(s): ${pluginsStr}`
|
|
44
44
|
);
|
|
45
45
|
}
|
|
46
46
|
const configuredExtensions = [
|
|
47
|
-
...pluginExtensions.map(({
|
|
47
|
+
...pluginExtensions.map(({ plugin, ...extension }) => {
|
|
48
48
|
const internalExtension = toInternalExtension(extension);
|
|
49
49
|
return {
|
|
50
50
|
extension: internalExtension,
|
|
51
51
|
params: {
|
|
52
|
-
|
|
52
|
+
plugin,
|
|
53
|
+
source: plugin,
|
|
53
54
|
attachTo: internalExtension.attachTo,
|
|
54
55
|
disabled: internalExtension.disabled,
|
|
55
56
|
config: void 0
|
|
@@ -62,6 +63,7 @@ function resolveAppNodeSpecs(options) {
|
|
|
62
63
|
extension: internalExtension,
|
|
63
64
|
params: {
|
|
64
65
|
source: void 0,
|
|
66
|
+
plugin: void 0,
|
|
65
67
|
attachTo: internalExtension.attachTo,
|
|
66
68
|
disabled: internalExtension.disabled,
|
|
67
69
|
config: void 0
|
|
@@ -82,7 +84,8 @@ function resolveAppNodeSpecs(options) {
|
|
|
82
84
|
configuredExtensions.push({
|
|
83
85
|
extension: internalExtension,
|
|
84
86
|
params: {
|
|
85
|
-
|
|
87
|
+
plugin: extension.plugin,
|
|
88
|
+
source: extension.plugin,
|
|
86
89
|
attachTo: internalExtension.attachTo,
|
|
87
90
|
disabled: internalExtension.disabled,
|
|
88
91
|
config: void 0
|
|
@@ -150,6 +153,7 @@ function resolveAppNodeSpecs(options) {
|
|
|
150
153
|
attachTo: param.params.attachTo,
|
|
151
154
|
extension: param.extension,
|
|
152
155
|
disabled: param.params.disabled,
|
|
156
|
+
plugin: param.params.plugin,
|
|
153
157
|
source: param.params.source,
|
|
154
158
|
config: param.params.config
|
|
155
159
|
}));
|
|
@@ -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 { Extension } from '@backstage/frontend-plugin-api';\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 { FrontendFeature } from '../wiring';\n\n/** @internal */\nexport function resolveAppNodeSpecs(options: {\n features?: FrontendFeature[];\n builtinExtensions?: Extension<any, any>[];\n parameters?: Array<ExtensionParameters>;\n forbidden?: Set<string>;\n allowUnknownExtensionConfig?: boolean;\n}): AppNodeSpec[] {\n const {\n builtinExtensions = [],\n parameters = [],\n forbidden = new Set(),\n features = [],\n allowUnknownExtensionConfig = false,\n } = options;\n\n const plugins = features.filter(OpaqueFrontendPlugin.isType);\n const modules = features.filter(isInternalFrontendModule);\n\n const pluginExtensions = plugins.flatMap(source => {\n return OpaqueFrontendPlugin.toInternal(source).extensions.map(\n extension => ({\n ...extension,\n source,\n }),\n );\n });\n const moduleExtensions = modules.flatMap(mod =>\n toInternalFrontendModule(mod).extensions.flatMap(extension => {\n // Modules for plugins that are not installed are ignored\n const source = plugins.find(p => p.id === mod.pluginId);\n if (!source) {\n return [];\n }\n\n return [{ ...extension, source }];\n }),\n );\n\n // Prevent core override\n if (pluginExtensions.some(({ id }) => forbidden.has(id))) {\n const pluginsStr = pluginExtensions\n .filter(({ id }) => forbidden.has(id))\n .map(({ source }) => `'${source.id}'`)\n .join(', ');\n const forbiddenStr = [...forbidden].map(id => `'${id}'`).join(', ');\n throw new Error(\n `It is forbidden to override the following extension(s): ${forbiddenStr}, which is done by the following plugin(s): ${pluginsStr}`,\n );\n }\n if (moduleExtensions.some(({ id }) => forbidden.has(id))) {\n const pluginsStr = moduleExtensions\n .filter(({ id }) => forbidden.has(id))\n .map(({ source }) => `'${source.id}'`)\n .join(', ');\n const forbiddenStr = [...forbidden].map(id => `'${id}'`).join(', ');\n throw new Error(\n `It is forbidden to override the following extension(s): ${forbiddenStr}, which is done by a module for the following plugin(s): ${pluginsStr}`,\n );\n }\n\n const configuredExtensions = [\n ...pluginExtensions.map(({ source, ...extension }) => {\n const internalExtension = toInternalExtension(extension);\n return {\n extension: internalExtension,\n params: {\n source,\n attachTo: internalExtension.attachTo,\n disabled: internalExtension.disabled,\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: undefined,\n attachTo: internalExtension.attachTo,\n disabled: internalExtension.disabled,\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 } else {\n // Add the extension as a new one when not overriding an existing one\n configuredExtensions.push({\n extension: internalExtension,\n params: {\n source: extension.source,\n attachTo: internalExtension.attachTo,\n disabled: internalExtension.disabled,\n config: undefined,\n },\n });\n }\n }\n\n const duplicatedExtensionIds = new Set<string>();\n const duplicatedExtensionData = configuredExtensions.reduce<\n Record<string, Record<string, number>>\n >((data, { extension, params }) => {\n const extensionId = extension.id;\n const extensionData = data?.[extensionId];\n if (extensionData) duplicatedExtensionIds.add(extensionId);\n const pluginId = params.source?.id ?? 'internal';\n const pluginCount = extensionData?.[pluginId] ?? 0;\n return {\n ...data,\n [extensionId]: { ...extensionData, [pluginId]: pluginCount + 1 },\n };\n }, {});\n\n if (duplicatedExtensionIds.size > 0) {\n throw new Error(\n `The following extensions are duplicated: ${Array.from(\n duplicatedExtensionIds,\n )\n .map(\n extensionId =>\n `The extension '${extensionId}' was provided ${Object.keys(\n duplicatedExtensionData[extensionId],\n )\n .map(\n pluginId =>\n `${duplicatedExtensionData[extensionId][pluginId]} time(s) by the plugin '${pluginId}'`,\n )\n .join(' and ')}`,\n )\n .join(', ')}`,\n );\n }\n\n const order = new Map<string, (typeof configuredExtensions)[number]>();\n for (const overrideParam of parameters) {\n const extensionId = overrideParam.id;\n\n if (forbidden.has(extensionId)) {\n throw new Error(\n `Configuration of the '${extensionId}' extension is forbidden`,\n );\n }\n\n const existing = configuredExtensions.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 if (!allowUnknownExtensionConfig) {\n throw new Error(`Extension ${extensionId} does not exist`);\n }\n }\n\n const orderedExtensions = [\n ...order.values(),\n ...configuredExtensions.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 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 { Extension } from '@backstage/frontend-plugin-api';\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 { FrontendFeature } from '../wiring';\n\n/** @internal */\nexport function resolveAppNodeSpecs(options: {\n features?: FrontendFeature[];\n builtinExtensions?: Extension<any, any>[];\n parameters?: Array<ExtensionParameters>;\n forbidden?: Set<string>;\n allowUnknownExtensionConfig?: boolean;\n}): AppNodeSpec[] {\n const {\n builtinExtensions = [],\n parameters = [],\n forbidden = new Set(),\n features = [],\n allowUnknownExtensionConfig = false,\n } = options;\n\n const plugins = features.filter(OpaqueFrontendPlugin.isType);\n const modules = features.filter(isInternalFrontendModule);\n\n const pluginExtensions = plugins.flatMap(plugin => {\n return OpaqueFrontendPlugin.toInternal(plugin).extensions.map(\n extension => ({\n ...extension,\n plugin,\n }),\n );\n });\n const moduleExtensions = modules.flatMap(mod =>\n toInternalFrontendModule(mod).extensions.flatMap(extension => {\n // Modules for plugins that are not installed are ignored\n const plugin = plugins.find(p => p.id === mod.pluginId);\n if (!plugin) {\n return [];\n }\n\n return [{ ...extension, plugin }];\n }),\n );\n\n // Prevent core override\n if (pluginExtensions.some(({ id }) => forbidden.has(id))) {\n const pluginsStr = pluginExtensions\n .filter(({ id }) => forbidden.has(id))\n .map(({ plugin }) => `'${plugin.id}'`)\n .join(', ');\n const forbiddenStr = [...forbidden].map(id => `'${id}'`).join(', ');\n throw new Error(\n `It is forbidden to override the following extension(s): ${forbiddenStr}, which is done by the following plugin(s): ${pluginsStr}`,\n );\n }\n if (moduleExtensions.some(({ id }) => forbidden.has(id))) {\n const pluginsStr = moduleExtensions\n .filter(({ id }) => forbidden.has(id))\n .map(({ plugin }) => `'${plugin.id}'`)\n .join(', ');\n const forbiddenStr = [...forbidden].map(id => `'${id}'`).join(', ');\n throw new Error(\n `It is forbidden to override the following extension(s): ${forbiddenStr}, which is done by a module for the following plugin(s): ${pluginsStr}`,\n );\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 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: undefined,\n plugin: undefined,\n attachTo: internalExtension.attachTo,\n disabled: internalExtension.disabled,\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 } 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 config: undefined,\n },\n });\n }\n }\n\n const duplicatedExtensionIds = new Set<string>();\n const duplicatedExtensionData = configuredExtensions.reduce<\n Record<string, Record<string, number>>\n >((data, { extension, params }) => {\n const extensionId = extension.id;\n const extensionData = data?.[extensionId];\n if (extensionData) duplicatedExtensionIds.add(extensionId);\n const pluginId = params.source?.id ?? 'internal';\n const pluginCount = extensionData?.[pluginId] ?? 0;\n return {\n ...data,\n [extensionId]: { ...extensionData, [pluginId]: pluginCount + 1 },\n };\n }, {});\n\n if (duplicatedExtensionIds.size > 0) {\n throw new Error(\n `The following extensions are duplicated: ${Array.from(\n duplicatedExtensionIds,\n )\n .map(\n extensionId =>\n `The extension '${extensionId}' was provided ${Object.keys(\n duplicatedExtensionData[extensionId],\n )\n .map(\n pluginId =>\n `${duplicatedExtensionData[extensionId][pluginId]} time(s) by the plugin '${pluginId}'`,\n )\n .join(' and ')}`,\n )\n .join(', ')}`,\n );\n }\n\n const order = new Map<string, (typeof configuredExtensions)[number]>();\n for (const overrideParam of parameters) {\n const extensionId = overrideParam.id;\n\n if (forbidden.has(extensionId)) {\n throw new Error(\n `Configuration of the '${extensionId}' extension is forbidden`,\n );\n }\n\n const existing = configuredExtensions.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 if (!allowUnknownExtensionConfig) {\n throw new Error(`Extension ${extensionId} does not exist`);\n }\n }\n\n const orderedExtensions = [\n ...order.values(),\n ...configuredExtensions.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 plugin: param.params.plugin,\n source: param.params.source,\n config: param.params.config,\n }));\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/frontend-app-api",
|
|
3
|
-
"version": "0.11.2
|
|
3
|
+
"version": "0.11.2",
|
|
4
4
|
"backstage": {
|
|
5
5
|
"role": "web-library"
|
|
6
6
|
},
|
|
@@ -32,21 +32,21 @@
|
|
|
32
32
|
"test": "backstage-cli package test"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@backstage/config": "1.3.2",
|
|
36
|
-
"@backstage/core-app-api": "1.17.0
|
|
37
|
-
"@backstage/core-plugin-api": "1.10.7
|
|
38
|
-
"@backstage/errors": "1.2.7",
|
|
39
|
-
"@backstage/frontend-defaults": "0.2.2
|
|
40
|
-
"@backstage/frontend-plugin-api": "0.10.2
|
|
41
|
-
"@backstage/types": "1.2.1",
|
|
42
|
-
"@backstage/version-bridge": "1.0.11",
|
|
35
|
+
"@backstage/config": "^1.3.2",
|
|
36
|
+
"@backstage/core-app-api": "^1.17.0",
|
|
37
|
+
"@backstage/core-plugin-api": "^1.10.7",
|
|
38
|
+
"@backstage/errors": "^1.2.7",
|
|
39
|
+
"@backstage/frontend-defaults": "^0.2.2",
|
|
40
|
+
"@backstage/frontend-plugin-api": "^0.10.2",
|
|
41
|
+
"@backstage/types": "^1.2.1",
|
|
42
|
+
"@backstage/version-bridge": "^1.0.11",
|
|
43
43
|
"lodash": "^4.17.21",
|
|
44
44
|
"zod": "^3.22.4"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@backstage/cli": "0.32.1
|
|
48
|
-
"@backstage/plugin-app": "0.1.9
|
|
49
|
-
"@backstage/test-utils": "1.7.8
|
|
47
|
+
"@backstage/cli": "^0.32.1",
|
|
48
|
+
"@backstage/plugin-app": "^0.1.9",
|
|
49
|
+
"@backstage/test-utils": "^1.7.8",
|
|
50
50
|
"@testing-library/jest-dom": "^6.0.0",
|
|
51
51
|
"@testing-library/react": "^16.0.0",
|
|
52
52
|
"@types/react": "^18.0.0",
|