@backstage/frontend-test-utils 0.4.3 → 0.4.5-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 +16 -0
- package/dist/app/renderInTestApp.esm.js +12 -6
- package/dist/app/renderInTestApp.esm.js.map +1 -1
- package/dist/app/renderTestApp.esm.js +13 -9
- package/dist/app/renderTestApp.esm.js.map +1 -1
- package/dist/frontend-app-api/src/tree/instantiateAppNodeTree.esm.js +48 -17
- package/dist/frontend-app-api/src/tree/instantiateAppNodeTree.esm.js.map +1 -1
- package/dist/frontend-app-api/src/tree/resolveAppNodeSpecs.esm.js +11 -5
- package/dist/frontend-app-api/src/tree/resolveAppNodeSpecs.esm.js.map +1 -1
- package/dist/frontend-app-api/src/tree/resolveAppTree.esm.js +3 -0
- package/dist/frontend-app-api/src/tree/resolveAppTree.esm.js.map +1 -1
- package/dist/frontend-app-api/src/wiring/createErrorCollector.esm.js.map +1 -1
- package/package.json +11 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @backstage/frontend-test-utils
|
|
2
2
|
|
|
3
|
+
## 0.4.5-next.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- d7dd5bd: Fixed Router deprecation warning and switched to using new `RouterBlueprint` from `@backstage/plugin-app-api`.
|
|
8
|
+
- 69d880e: Bump to latest zod to ensure it has the latest features
|
|
9
|
+
- Updated dependencies
|
|
10
|
+
- @backstage/frontend-app-api@0.14.1-next.0
|
|
11
|
+
- @backstage/frontend-plugin-api@0.14.0-next.0
|
|
12
|
+
- @backstage/plugin-app@0.4.0-next.0
|
|
13
|
+
- @backstage/plugin-app-react@0.1.1-next.0
|
|
14
|
+
- @backstage/config@1.3.6
|
|
15
|
+
- @backstage/test-utils@1.7.15-next.0
|
|
16
|
+
- @backstage/types@1.2.2
|
|
17
|
+
- @backstage/version-bridge@1.0.11
|
|
18
|
+
|
|
3
19
|
## 0.4.3
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
|
@@ -4,7 +4,8 @@ import { Link, MemoryRouter } from 'react-router-dom';
|
|
|
4
4
|
import { createSpecializedApp } from '@backstage/frontend-app-api';
|
|
5
5
|
import { render } from '@testing-library/react';
|
|
6
6
|
import { ConfigReader } from '@backstage/config';
|
|
7
|
-
import { coreExtensionData, NavItemBlueprint, useRouteRef, createExtension,
|
|
7
|
+
import { coreExtensionData, NavItemBlueprint, useRouteRef, createExtension, createFrontendModule, createFrontendPlugin } from '@backstage/frontend-plugin-api';
|
|
8
|
+
import { RouterBlueprint } from '@backstage/plugin-app-react';
|
|
8
9
|
import appPlugin from '@backstage/plugin-app';
|
|
9
10
|
|
|
10
11
|
const DEFAULT_MOCK_CONFIG = {
|
|
@@ -67,11 +68,6 @@ function renderInTestApp(element, options) {
|
|
|
67
68
|
factory: () => {
|
|
68
69
|
return [coreExtensionData.reactElement(element)];
|
|
69
70
|
}
|
|
70
|
-
}),
|
|
71
|
-
RouterBlueprint.make({
|
|
72
|
-
params: {
|
|
73
|
-
component: ({ children }) => /* @__PURE__ */ jsx(MemoryRouter, { initialEntries: options?.initialRouteEntries, children })
|
|
74
|
-
}
|
|
75
71
|
})
|
|
76
72
|
];
|
|
77
73
|
if (options?.mountedRoutes) {
|
|
@@ -96,6 +92,16 @@ function renderInTestApp(element, options) {
|
|
|
96
92
|
}
|
|
97
93
|
}
|
|
98
94
|
const features = [
|
|
95
|
+
createFrontendModule({
|
|
96
|
+
pluginId: "app",
|
|
97
|
+
extensions: [
|
|
98
|
+
RouterBlueprint.make({
|
|
99
|
+
params: {
|
|
100
|
+
component: ({ children }) => /* @__PURE__ */ jsx(MemoryRouter, { initialEntries: options?.initialRouteEntries, children })
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
]
|
|
104
|
+
}),
|
|
99
105
|
createFrontendPlugin({
|
|
100
106
|
pluginId: "test",
|
|
101
107
|
extensions
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderInTestApp.esm.js","sources":["../../src/app/renderInTestApp.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Fragment } from 'react';\nimport { Link, MemoryRouter } from 'react-router-dom';\nimport { createSpecializedApp } from '@backstage/frontend-app-api';\nimport { RenderResult, render } from '@testing-library/react';\nimport { ConfigReader } from '@backstage/config';\nimport { JsonObject } from '@backstage/types';\nimport {\n createExtension,\n ExtensionDefinition,\n coreExtensionData,\n RouteRef,\n useRouteRef,\n IconComponent,\n
|
|
1
|
+
{"version":3,"file":"renderInTestApp.esm.js","sources":["../../src/app/renderInTestApp.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Fragment } from 'react';\nimport { Link, MemoryRouter } from 'react-router-dom';\nimport { createSpecializedApp } from '@backstage/frontend-app-api';\nimport { RenderResult, render } from '@testing-library/react';\nimport { ConfigReader } from '@backstage/config';\nimport { JsonObject } from '@backstage/types';\nimport {\n createExtension,\n ExtensionDefinition,\n coreExtensionData,\n RouteRef,\n useRouteRef,\n IconComponent,\n NavItemBlueprint,\n createFrontendPlugin,\n FrontendFeature,\n createFrontendModule,\n} from '@backstage/frontend-plugin-api';\nimport { RouterBlueprint } from '@backstage/plugin-app-react';\nimport appPlugin from '@backstage/plugin-app';\n\nconst DEFAULT_MOCK_CONFIG = {\n app: { baseUrl: 'http://localhost:3000' },\n backend: { baseUrl: 'http://localhost:7007' },\n};\n\n/**\n * Options to customize the behavior of the test app.\n * @public\n */\nexport type TestAppOptions = {\n /**\n * An object of paths to mount route ref on, with the key being the path and the value\n * being the RouteRef that the path will be bound to. This allows the route refs to be\n * used by `useRouteRef` in the rendered elements.\n *\n * @example\n * ```ts\n * renderInTestApp(<MyComponent />, {\n * mountedRoutes: {\n * '/my-path': myRouteRef,\n * }\n * })\n * // ...\n * const link = useRouteRef(myRouteRef)\n * ```\n */\n mountedRoutes?: { [path: string]: RouteRef };\n\n /**\n * Additional configuration passed to the app when rendering elements inside it.\n */\n config?: JsonObject;\n\n /**\n * Additional features to add to the test app.\n */\n features?: FrontendFeature[];\n\n /**\n * Initial route entries to use for the router.\n */\n initialRouteEntries?: string[];\n};\n\nconst NavItem = (props: {\n routeRef: RouteRef<undefined>;\n title: string;\n icon: IconComponent;\n}) => {\n const { routeRef, title, icon: Icon } = props;\n const link = useRouteRef(routeRef);\n if (!link) {\n return null;\n }\n return (\n <li>\n <Link to={link()}>\n <Icon /> {title}\n </Link>\n </li>\n );\n};\n\nconst appPluginOverride = appPlugin.withOverrides({\n extensions: [\n appPlugin.getExtension('sign-in-page:app').override({\n disabled: true,\n }),\n appPlugin.getExtension('app/layout').override({\n disabled: true,\n }),\n appPlugin.getExtension('app/routes').override({\n disabled: true,\n }),\n appPlugin.getExtension('app/nav').override({\n output: [coreExtensionData.reactElement],\n factory(_originalFactory, { inputs }) {\n return [\n coreExtensionData.reactElement(\n <nav>\n <ul>\n {inputs.items.map((item, index) => {\n const { icon, title, routeRef } = item.get(\n NavItemBlueprint.dataRefs.target,\n );\n\n return (\n <NavItem\n key={index}\n icon={icon}\n title={title}\n routeRef={routeRef}\n />\n );\n })}\n </ul>\n </nav>,\n ),\n ];\n },\n }),\n ],\n});\n\n/**\n * @public\n * Renders the given element in a test app, for use in unit tests.\n */\nexport function renderInTestApp(\n element: JSX.Element,\n options?: TestAppOptions,\n): RenderResult {\n const extensions: Array<ExtensionDefinition> = [\n createExtension({\n attachTo: { id: 'app/root', input: 'children' },\n output: [coreExtensionData.reactElement],\n factory: () => {\n return [coreExtensionData.reactElement(element)];\n },\n }),\n ];\n\n if (options?.mountedRoutes) {\n for (const [path, routeRef] of Object.entries(options.mountedRoutes)) {\n // TODO(Rugvip): add support for external route refs\n extensions.push(\n createExtension({\n kind: 'test-route',\n name: path,\n attachTo: { id: 'app/root', input: 'elements' },\n output: [\n coreExtensionData.reactElement,\n coreExtensionData.routePath,\n coreExtensionData.routeRef,\n ],\n factory: () => [\n coreExtensionData.reactElement(<Fragment />),\n coreExtensionData.routePath(path),\n coreExtensionData.routeRef(routeRef),\n ],\n }),\n );\n }\n }\n\n const features: FrontendFeature[] = [\n createFrontendModule({\n pluginId: 'app',\n extensions: [\n RouterBlueprint.make({\n params: {\n component: ({ children }) => (\n <MemoryRouter initialEntries={options?.initialRouteEntries}>\n {children}\n </MemoryRouter>\n ),\n },\n }),\n ],\n }),\n createFrontendPlugin({\n pluginId: 'test',\n extensions,\n }),\n appPluginOverride,\n ];\n\n if (options?.features) {\n features.push(...options.features);\n }\n\n const app = createSpecializedApp({\n features,\n config: ConfigReader.fromConfigs([\n {\n context: 'render-config',\n data: options?.config ?? DEFAULT_MOCK_CONFIG,\n },\n ]),\n });\n\n return render(\n app.tree.root.instance!.getData(coreExtensionData.reactElement),\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { createSpecializedApp } from '@backstage/frontend-app-api';
|
|
3
|
-
import {
|
|
3
|
+
import { createFrontendModule, createFrontendPlugin, coreExtensionData } from '@backstage/frontend-plugin-api';
|
|
4
4
|
import { render } from '@testing-library/react';
|
|
5
5
|
import appPlugin from '@backstage/plugin-app';
|
|
6
6
|
import { ConfigReader } from '@backstage/config';
|
|
7
7
|
import { MemoryRouter } from 'react-router-dom';
|
|
8
|
+
import { RouterBlueprint } from '@backstage/plugin-app-react';
|
|
8
9
|
|
|
9
10
|
const DEFAULT_MOCK_CONFIG = {
|
|
10
11
|
app: { baseUrl: "http://localhost:3000" },
|
|
@@ -18,15 +19,18 @@ const appPluginOverride = appPlugin.withOverrides({
|
|
|
18
19
|
]
|
|
19
20
|
});
|
|
20
21
|
function renderTestApp(options) {
|
|
21
|
-
const extensions = [
|
|
22
|
-
RouterBlueprint.make({
|
|
23
|
-
params: {
|
|
24
|
-
component: ({ children }) => /* @__PURE__ */ jsx(MemoryRouter, { initialEntries: options.initialRouteEntries, children })
|
|
25
|
-
}
|
|
26
|
-
}),
|
|
27
|
-
...options.extensions ?? []
|
|
28
|
-
];
|
|
22
|
+
const extensions = [...options.extensions ?? []];
|
|
29
23
|
const features = [
|
|
24
|
+
createFrontendModule({
|
|
25
|
+
pluginId: "app",
|
|
26
|
+
extensions: [
|
|
27
|
+
RouterBlueprint.make({
|
|
28
|
+
params: {
|
|
29
|
+
component: ({ children }) => /* @__PURE__ */ jsx(MemoryRouter, { initialEntries: options.initialRouteEntries, children })
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
]
|
|
33
|
+
}),
|
|
30
34
|
createFrontendPlugin({
|
|
31
35
|
pluginId: "test",
|
|
32
36
|
extensions
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderTestApp.esm.js","sources":["../../src/app/renderTestApp.tsx"],"sourcesContent":["/*\n * Copyright 2025 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 { createSpecializedApp } from '@backstage/frontend-app-api';\nimport {\n coreExtensionData,\n createFrontendPlugin,\n ExtensionDefinition,\n FrontendFeature,\n
|
|
1
|
+
{"version":3,"file":"renderTestApp.esm.js","sources":["../../src/app/renderTestApp.tsx"],"sourcesContent":["/*\n * Copyright 2025 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 { createSpecializedApp } from '@backstage/frontend-app-api';\nimport {\n coreExtensionData,\n createFrontendModule,\n createFrontendPlugin,\n ExtensionDefinition,\n FrontendFeature,\n} from '@backstage/frontend-plugin-api';\nimport { render } from '@testing-library/react';\nimport appPlugin from '@backstage/plugin-app';\nimport { JsonObject } from '@backstage/types';\nimport { ConfigReader } from '@backstage/config';\nimport { MemoryRouter } from 'react-router-dom';\nimport { RouterBlueprint } from '@backstage/plugin-app-react';\n\nconst DEFAULT_MOCK_CONFIG = {\n app: { baseUrl: 'http://localhost:3000' },\n backend: { baseUrl: 'http://localhost:7007' },\n};\n\n/**\n * Options for `renderTestApp`.\n *\n * @public\n */\nexport type RenderTestAppOptions = {\n /**\n * Additional configuration passed to the app when rendering elements inside it.\n */\n config?: JsonObject;\n /**\n * Additional extensions to add to the test app.\n */\n extensions?: ExtensionDefinition<any>[];\n\n /**\n * Additional features to add to the test app.\n */\n features?: FrontendFeature[];\n\n /**\n * Initial route entries to use for the router.\n */\n initialRouteEntries?: string[];\n};\n\nconst appPluginOverride = appPlugin.withOverrides({\n extensions: [\n appPlugin.getExtension('sign-in-page:app').override({\n disabled: true,\n }),\n ],\n});\n\n/**\n * Renders the provided extensions inside a Backstage app, returning the same\n * utilities as `@testing-library/react` `render` function.\n *\n * @public\n */\nexport function renderTestApp(options: RenderTestAppOptions) {\n const extensions = [...(options.extensions ?? [])];\n\n const features: FrontendFeature[] = [\n createFrontendModule({\n pluginId: 'app',\n extensions: [\n RouterBlueprint.make({\n params: {\n component: ({ children }) => (\n <MemoryRouter initialEntries={options.initialRouteEntries}>\n {children}\n </MemoryRouter>\n ),\n },\n }),\n ],\n }),\n createFrontendPlugin({\n pluginId: 'test',\n extensions,\n }),\n appPluginOverride,\n ];\n\n if (options.features) {\n features.push(...options.features);\n }\n\n const app = createSpecializedApp({\n features,\n config: ConfigReader.fromConfigs([\n {\n context: 'render-config',\n data: options?.config ?? DEFAULT_MOCK_CONFIG,\n },\n ]),\n });\n\n return render(\n app.tree.root.instance!.getData(coreExtensionData.reactElement),\n );\n}\n"],"names":[],"mappings":";;;;;;;;;AA+BA,MAAM,mBAAA,GAAsB;AAAA,EAC1B,GAAA,EAAK,EAAE,OAAA,EAAS,uBAAA,EAAwB;AAAA,EACxC,OAAA,EAAS,EAAE,OAAA,EAAS,uBAAA;AACtB,CAAA;AA4BA,MAAM,iBAAA,GAAoB,UAAU,aAAA,CAAc;AAAA,EAChD,UAAA,EAAY;AAAA,IACV,SAAA,CAAU,YAAA,CAAa,kBAAkB,CAAA,CAAE,QAAA,CAAS;AAAA,MAClD,QAAA,EAAU;AAAA,KACX;AAAA;AAEL,CAAC,CAAA;AAQM,SAAS,cAAc,OAAA,EAA+B;AAC3D,EAAA,MAAM,aAAa,CAAC,GAAI,OAAA,CAAQ,UAAA,IAAc,EAAG,CAAA;AAEjD,EAAA,MAAM,QAAA,GAA8B;AAAA,IAClC,oBAAA,CAAqB;AAAA,MACnB,QAAA,EAAU,KAAA;AAAA,MACV,UAAA,EAAY;AAAA,QACV,gBAAgB,IAAA,CAAK;AAAA,UACnB,MAAA,EAAQ;AAAA,YACN,SAAA,EAAW,CAAC,EAAE,QAAA,EAAS,yBACpB,YAAA,EAAA,EAAa,cAAA,EAAgB,OAAA,CAAQ,mBAAA,EACnC,QAAA,EACH;AAAA;AAEJ,SACD;AAAA;AACH,KACD,CAAA;AAAA,IACD,oBAAA,CAAqB;AAAA,MACnB,QAAA,EAAU,MAAA;AAAA,MACV;AAAA,KACD,CAAA;AAAA,IACD;AAAA,GACF;AAEA,EAAA,IAAI,QAAQ,QAAA,EAAU;AACpB,IAAA,QAAA,CAAS,IAAA,CAAK,GAAG,OAAA,CAAQ,QAAQ,CAAA;AAAA,EACnC;AAEA,EAAA,MAAM,MAAM,oBAAA,CAAqB;AAAA,IAC/B,QAAA;AAAA,IACA,MAAA,EAAQ,aAAa,WAAA,CAAY;AAAA,MAC/B;AAAA,QACE,OAAA,EAAS,eAAA;AAAA,QACT,IAAA,EAAM,SAAS,MAAA,IAAU;AAAA;AAC3B,KACD;AAAA,GACF,CAAA;AAED,EAAA,OAAO,MAAA;AAAA,IACL,IAAI,IAAA,CAAK,IAAA,CAAK,QAAA,CAAU,OAAA,CAAQ,kBAAkB,YAAY;AAAA,GAChE;AACF;;;;"}
|
|
@@ -7,21 +7,21 @@ import '../../../frontend-internal/src/wiring/InternalFrontendPlugin.esm.js';
|
|
|
7
7
|
import '../../../frontend-internal/src/wiring/InternalSwappableComponentRef.esm.js';
|
|
8
8
|
|
|
9
9
|
const INSTANTIATION_FAILED = new Error("Instantiation failed");
|
|
10
|
-
function mapWithFailures(iterable, callback) {
|
|
10
|
+
function mapWithFailures(iterable, callback, options) {
|
|
11
11
|
let failed = false;
|
|
12
|
-
const results =
|
|
12
|
+
const results = [];
|
|
13
|
+
for (const item of iterable) {
|
|
13
14
|
try {
|
|
14
|
-
|
|
15
|
+
results.push(callback(item));
|
|
15
16
|
} catch (error) {
|
|
16
17
|
if (error === INSTANTIATION_FAILED) {
|
|
17
18
|
failed = true;
|
|
18
19
|
} else {
|
|
19
20
|
throw error;
|
|
20
21
|
}
|
|
21
|
-
return null;
|
|
22
22
|
}
|
|
23
|
-
}
|
|
24
|
-
if (failed) {
|
|
23
|
+
}
|
|
24
|
+
if (failed && !options?.ignoreFailures) {
|
|
25
25
|
throw INSTANTIATION_FAILED;
|
|
26
26
|
}
|
|
27
27
|
return results;
|
|
@@ -55,7 +55,7 @@ function resolveInputDataContainer(extensionData, attachment, inputName, collect
|
|
|
55
55
|
if (value === void 0 && !ref.config.optional) {
|
|
56
56
|
const expected = extensionData.filter((r) => !r.config.optional).map((r) => `'${r.id}'`).join(", ");
|
|
57
57
|
const provided = [...attachment.instance?.getDataRefs() ?? []].map((r) => `'${r.id}'`).join(", ");
|
|
58
|
-
collector.report({
|
|
58
|
+
collector.child({ node: attachment }).report({
|
|
59
59
|
code: "EXTENSION_INPUT_DATA_MISSING",
|
|
60
60
|
message: `extension '${attachment.spec.id}' could not be attached because its output data (${provided}) does not match what the input '${inputName}' requires (${expected})`
|
|
61
61
|
});
|
|
@@ -139,10 +139,26 @@ function resolveV1Inputs(inputMap, attachments) {
|
|
|
139
139
|
})
|
|
140
140
|
);
|
|
141
141
|
}
|
|
142
|
-
function resolveV2Inputs(inputMap, attachments, parentCollector) {
|
|
142
|
+
function resolveV2Inputs(inputMap, attachments, parentCollector, node) {
|
|
143
143
|
return mapValues(inputMap, (input, inputName) => {
|
|
144
|
-
const
|
|
144
|
+
const allAttachedNodes = attachments.get(inputName) ?? [];
|
|
145
145
|
const collector = parentCollector.child({ inputName });
|
|
146
|
+
const inputPluginId = node.spec.plugin.pluginId;
|
|
147
|
+
const attachedNodes = input.config.internal ? allAttachedNodes.filter((attachment) => {
|
|
148
|
+
const attachmentPluginId = attachment.spec.plugin.pluginId;
|
|
149
|
+
if (attachmentPluginId !== inputPluginId) {
|
|
150
|
+
collector.report({
|
|
151
|
+
code: "EXTENSION_INPUT_INTERNAL_IGNORED",
|
|
152
|
+
message: `extension '${attachment.spec.id}' from plugin '${attachmentPluginId}' attached to input '${inputName}' on '${node.spec.id}' was ignored, 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`,
|
|
153
|
+
context: {
|
|
154
|
+
extensionId: attachment.spec.id,
|
|
155
|
+
plugin: attachment.spec.plugin
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
return true;
|
|
161
|
+
}) : allAttachedNodes;
|
|
146
162
|
if (input.config.singleton) {
|
|
147
163
|
if (attachedNodes.length > 1) {
|
|
148
164
|
const attachedNodeIds = attachedNodes.map((e) => e.spec.id).join("', '");
|
|
@@ -161,12 +177,25 @@ function resolveV2Inputs(inputMap, attachments, parentCollector) {
|
|
|
161
177
|
}
|
|
162
178
|
return void 0;
|
|
163
179
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
180
|
+
try {
|
|
181
|
+
return resolveInputDataContainer(
|
|
182
|
+
input.extensionData,
|
|
183
|
+
attachedNodes[0],
|
|
184
|
+
inputName,
|
|
185
|
+
collector
|
|
186
|
+
);
|
|
187
|
+
} catch (error) {
|
|
188
|
+
if (error === INSTANTIATION_FAILED) {
|
|
189
|
+
if (input.config.optional) {
|
|
190
|
+
return void 0;
|
|
191
|
+
}
|
|
192
|
+
collector.report({
|
|
193
|
+
code: "EXTENSION_ATTACHMENT_MISSING",
|
|
194
|
+
message: `input '${inputName}' is required but it failed to be instantiated`
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
throw error;
|
|
198
|
+
}
|
|
170
199
|
}
|
|
171
200
|
return mapWithFailures(
|
|
172
201
|
attachedNodes,
|
|
@@ -175,7 +204,8 @@ function resolveV2Inputs(inputMap, attachments, parentCollector) {
|
|
|
175
204
|
attachment,
|
|
176
205
|
inputName,
|
|
177
206
|
collector
|
|
178
|
-
)
|
|
207
|
+
),
|
|
208
|
+
{ ignoreFailures: true }
|
|
179
209
|
);
|
|
180
210
|
});
|
|
181
211
|
}
|
|
@@ -228,7 +258,8 @@ function createAppNodeInstance(options) {
|
|
|
228
258
|
inputs: resolveV2Inputs(
|
|
229
259
|
internalExtension.inputs,
|
|
230
260
|
attachments,
|
|
231
|
-
collector
|
|
261
|
+
collector,
|
|
262
|
+
node
|
|
232
263
|
)
|
|
233
264
|
};
|
|
234
265
|
const outputDataValues = options.extensionFactoryMiddleware ? createExtensionDataContainer(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instantiateAppNodeTree.esm.js","sources":["../../../../../frontend-app-api/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 ExtensionFactoryMiddleware,\n ExtensionInput,\n ResolvedExtensionInputs,\n} from '@backstage/frontend-plugin-api';\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';\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): U[] {\n let failed = false;\n const results = Array.from(iterable).map(item => {\n try {\n return callback(item);\n } catch (error) {\n if (error === INSTANTIATION_FAILED) {\n failed = true;\n } else {\n throw error;\n }\n return null as any;\n }\n });\n if (failed) {\n throw INSTANTIATION_FAILED;\n }\n return results;\n}\n\ntype Mutable<T> = {\n -readonly [P in keyof T]: T[P];\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.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): ResolvedExtensionInputs<{ [inputName in string]: ExtensionInput }> {\n return mapValues(inputMap, (input, inputName) => {\n const attachedNodes = attachments.get(inputName) ?? [];\n const collector = parentCollector.child({ inputName });\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 return resolveInputDataContainer(\n input.extensionData,\n attachedNodes[0],\n inputName,\n collector,\n );\n }\n\n return mapWithFailures(attachedNodes, attachment =>\n resolveInputDataContainer(\n input.extensionData,\n attachment,\n inputName,\n collector,\n ),\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}): 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\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,\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,\n config: parsedConfig,\n inputs: resolveV2Inputs(\n internalExtension.inputs,\n attachments,\n collector,\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 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): boolean {\n function createInstance(node: AppNode): AppNodeInstance | undefined {\n if (node.instance) {\n return node.instance;\n }\n if (node.spec.disabled) {\n return undefined;\n }\n\n const instantiatedAttachments = new Map<string, AppNode[]>();\n\n for (const [input, children] of node.edges.attachments) {\n const instantiatedChildren = children.flatMap(child => {\n const childInstance = createInstance(child);\n if (!childInstance) {\n return [];\n }\n return [child];\n });\n if (instantiatedChildren.length > 0) {\n instantiatedAttachments.set(input, instantiatedChildren);\n }\n }\n\n (node as Mutable<AppNode>).instance = createAppNodeInstance({\n extensionFactoryMiddleware,\n node,\n apis,\n attachments: instantiatedAttachments,\n collector,\n });\n\n return node.instance;\n }\n\n return createInstance(rootNode) !== undefined;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"instantiateAppNodeTree.esm.js","sources":["../../../../../frontend-app-api/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 ExtensionFactoryMiddleware,\n ExtensionInput,\n ResolvedExtensionInputs,\n} from '@backstage/frontend-plugin-api';\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';\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\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}): 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\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,\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,\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 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): boolean {\n function createInstance(node: AppNode): AppNodeInstance | undefined {\n if (node.instance) {\n return node.instance;\n }\n if (node.spec.disabled) {\n return undefined;\n }\n\n const instantiatedAttachments = new Map<string, AppNode[]>();\n\n for (const [input, children] of node.edges.attachments) {\n const instantiatedChildren = children.flatMap(child => {\n const childInstance = createInstance(child);\n if (!childInstance) {\n return [];\n }\n return [child];\n });\n if (instantiatedChildren.length > 0) {\n instantiatedAttachments.set(input, instantiatedChildren);\n }\n }\n\n (node as Mutable<AppNode>).instance = createAppNodeInstance({\n extensionFactoryMiddleware,\n node,\n apis,\n attachments: instantiatedAttachments,\n collector,\n });\n\n return node.instance;\n }\n\n return createInstance(rootNode) !== undefined;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -6,6 +6,12 @@ import '../../../frontend-internal/src/wiring/InternalExtensionDefinition.esm.js
|
|
|
6
6
|
import '../../../frontend-internal/src/wiring/InternalExtensionInput.esm.js';
|
|
7
7
|
import '../../../frontend-internal/src/wiring/InternalSwappableComponentRef.esm.js';
|
|
8
8
|
|
|
9
|
+
function normalizePlugin(plugin) {
|
|
10
|
+
if (!plugin.pluginId && "id" in plugin && typeof plugin.id === "string") {
|
|
11
|
+
plugin.pluginId = plugin.id;
|
|
12
|
+
}
|
|
13
|
+
return plugin;
|
|
14
|
+
}
|
|
9
15
|
function resolveAppNodeSpecs(options) {
|
|
10
16
|
const {
|
|
11
17
|
builtinExtensions = [],
|
|
@@ -14,13 +20,13 @@ function resolveAppNodeSpecs(options) {
|
|
|
14
20
|
features = [],
|
|
15
21
|
collector
|
|
16
22
|
} = options;
|
|
17
|
-
const plugins = features.filter(OpaqueFrontendPlugin.isType);
|
|
23
|
+
const plugins = features.filter(OpaqueFrontendPlugin.isType).map(normalizePlugin);
|
|
18
24
|
const modules = features.filter(isInternalFrontendModule);
|
|
19
25
|
const filterForbidden = (extension) => {
|
|
20
26
|
if (forbidden.has(extension.id)) {
|
|
21
27
|
collector.report({
|
|
22
28
|
code: "EXTENSION_IGNORED",
|
|
23
|
-
message: `It is forbidden to override the '${extension.id}' extension, attempted by the '${extension.plugin.
|
|
29
|
+
message: `It is forbidden to override the '${extension.id}' extension, attempted by the '${extension.plugin.pluginId}' plugin`,
|
|
24
30
|
context: {
|
|
25
31
|
plugin: extension.plugin,
|
|
26
32
|
extensionId: extension.id
|
|
@@ -38,14 +44,14 @@ function resolveAppNodeSpecs(options) {
|
|
|
38
44
|
});
|
|
39
45
|
const moduleExtensions = modules.flatMap(
|
|
40
46
|
(mod) => toInternalFrontendModule(mod).extensions.flatMap((extension) => {
|
|
41
|
-
const plugin = plugins.find((p) => p.
|
|
47
|
+
const plugin = plugins.find((p) => p.pluginId === mod.pluginId);
|
|
42
48
|
if (!plugin) {
|
|
43
49
|
return [];
|
|
44
50
|
}
|
|
45
51
|
return [{ ...extension, plugin }];
|
|
46
52
|
}).filter(filterForbidden)
|
|
47
53
|
);
|
|
48
|
-
const appPlugin = plugins.find((plugin) => plugin.
|
|
54
|
+
const appPlugin = plugins.find((plugin) => plugin.pluginId === "app") ?? createFrontendPlugin({
|
|
49
55
|
pluginId: "app"
|
|
50
56
|
});
|
|
51
57
|
const configuredExtensions = [
|
|
@@ -104,7 +110,7 @@ function resolveAppNodeSpecs(options) {
|
|
|
104
110
|
if (seenExtensionIds.has(extension.id)) {
|
|
105
111
|
collector.report({
|
|
106
112
|
code: "EXTENSION_IGNORED",
|
|
107
|
-
message: `The '${extension.id}' extension from the '${params.plugin.
|
|
113
|
+
message: `The '${extension.id}' extension from the '${params.plugin.pluginId}' plugin is a duplicate and will be ignored`,
|
|
108
114
|
context: {
|
|
109
115
|
plugin: params.plugin,
|
|
110
116
|
extensionId: extension.id
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveAppNodeSpecs.esm.js","sources":["../../../../../frontend-app-api/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 { 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\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.filter(OpaqueFrontendPlugin.isType);\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.id}' 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 return OpaqueFrontendPlugin.toInternal(plugin)\n .extensions.map(extension => ({\n ...extension,\n plugin,\n }))\n .filter(filterForbidden);\n });\n const moduleExtensions = modules.flatMap(mod =>\n toInternalFrontendModule(mod)\n .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 .filter(filterForbidden),\n );\n\n const appPlugin =\n plugins.find(plugin => plugin.id === '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 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 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 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.id}' 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 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":["../../../../../frontend-app-api/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 { 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\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 return OpaqueFrontendPlugin.toInternal(plugin)\n .extensions.map(extension => ({\n ...extension,\n plugin,\n }))\n .filter(filterForbidden);\n });\n const moduleExtensions = modules.flatMap(mod =>\n toInternalFrontendModule(mod)\n .extensions.flatMap(extension => {\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 [{ ...extension, plugin }];\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 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 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 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 plugin: param.params.plugin,\n source: param.params.source,\n config: param.params.config,\n }));\n}\n"],"names":[],"mappings":";;;;;;;;AAkCA,SAAS,gBAAgB,MAAA,EAAwC;AAE/D,EAAA,IAAI,CAAC,OAAO,QAAA,IAAY,IAAA,IAAQ,UAAU,OAAO,MAAA,CAAO,OAAO,QAAA,EAAU;AACvE,IAAC,MAAA,CAAe,WAAW,MAAA,CAAO,EAAA;AAAA,EACpC;AACA,EAAA,OAAO,MAAA;AACT;AAGO,SAAS,oBAAoB,OAAA,EAMlB;AAChB,EAAA,MAAM;AAAA,IACJ,oBAAoB,EAAC;AAAA,IACrB,aAAa,EAAC;AAAA,IACd,SAAA,uBAAgB,GAAA,EAAI;AAAA,IACpB,WAAW,EAAC;AAAA,IACZ;AAAA,GACF,GAAI,OAAA;AAEJ,EAAA,MAAM,UAAU,QAAA,CACb,MAAA,CAAO,qBAAqB,MAAM,CAAA,CAClC,IAAI,eAAe,CAAA;AACtB,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,MAAA,CAAO,wBAAwB,CAAA;AAExD,EAAA,MAAM,eAAA,GAAkB,CACtB,SAAA,KACG;AACH,IAAA,IAAI,SAAA,CAAU,GAAA,CAAI,SAAA,CAAU,EAAE,CAAA,EAAG;AAC/B,MAAA,SAAA,CAAU,MAAA,CAAO;AAAA,QACf,IAAA,EAAM,mBAAA;AAAA,QACN,SAAS,CAAA,iCAAA,EAAoC,SAAA,CAAU,EAAE,CAAA,+BAAA,EAAkC,SAAA,CAAU,OAAO,QAAQ,CAAA,QAAA,CAAA;AAAA,QACpH,OAAA,EAAS;AAAA,UACP,QAAQ,SAAA,CAAU,MAAA;AAAA,UAClB,aAAa,SAAA,CAAU;AAAA;AACzB,OACD,CAAA;AACD,MAAA,OAAO,KAAA;AAAA,IACT;AACA,IAAA,OAAO,IAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,gBAAA,GAAmB,OAAA,CAAQ,OAAA,CAAQ,CAAA,MAAA,KAAU;AACjD,IAAA,OAAO,qBAAqB,UAAA,CAAW,MAAM,CAAA,CAC1C,UAAA,CAAW,IAAI,CAAA,SAAA,MAAc;AAAA,MAC5B,GAAG,SAAA;AAAA,MACH;AAAA,KACF,CAAE,CAAA,CACD,MAAA,CAAO,eAAe,CAAA;AAAA,EAC3B,CAAC,CAAA;AACD,EAAA,MAAM,mBAAmB,OAAA,CAAQ,OAAA;AAAA,IAAQ,SACvC,wBAAA,CAAyB,GAAG,CAAA,CACzB,UAAA,CAAW,QAAQ,CAAA,SAAA,KAAa;AAE/B,MAAA,MAAM,SAAS,OAAA,CAAQ,IAAA,CAAK,OAAK,CAAA,CAAE,QAAA,KAAa,IAAI,QAAQ,CAAA;AAC5D,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,OAAO,EAAC;AAAA,MACV;AAEA,MAAA,OAAO,CAAC,EAAE,GAAG,SAAA,EAAW,QAAQ,CAAA;AAAA,IAClC,CAAC,CAAA,CACA,MAAA,CAAO,eAAe;AAAA,GAC3B;AAEA,EAAA,MAAM,SAAA,GACJ,QAAQ,IAAA,CAAK,CAAA,MAAA,KAAU,OAAO,QAAA,KAAa,KAAK,KAChD,oBAAA,CAAqB;AAAA,IACnB,QAAA,EAAU;AAAA,GACX,CAAA;AAEH,EAAA,MAAM,oBAAA,GAAuB;AAAA,IAC3B,GAAG,iBAAiB,GAAA,CAAI,CAAC,EAAE,MAAA,EAAQ,GAAG,WAAU,KAAM;AACpD,MAAA,MAAM,iBAAA,GAAoB,oBAAoB,SAAS,CAAA;AACvD,MAAA,OAAO;AAAA,QACL,SAAA,EAAW,iBAAA;AAAA,QACX,MAAA,EAAQ;AAAA,UACN,MAAA;AAAA,UACA,MAAA,EAAQ,MAAA;AAAA,UACR,UAAU,iBAAA,CAAkB,QAAA;AAAA,UAC5B,UAAU,iBAAA,CAAkB,QAAA;AAAA,UAC5B,MAAA,EAAQ;AAAA;AACV,OACF;AAAA,IACF,CAAC,CAAA;AAAA,IACD,GAAG,iBAAA,CAAkB,GAAA,CAAI,CAAA,SAAA,KAAa;AACpC,MAAA,MAAM,iBAAA,GAAoB,oBAAoB,SAAS,CAAA;AACvD,MAAA,OAAO;AAAA,QACL,SAAA,EAAW,iBAAA;AAAA,QACX,MAAA,EAAQ;AAAA,UACN,MAAA,EAAQ,SAAA;AAAA,UACR,MAAA,EAAQ,SAAA;AAAA,UACR,UAAU,iBAAA,CAAkB,QAAA;AAAA,UAC5B,UAAU,iBAAA,CAAkB,QAAA;AAAA,UAC5B,MAAA,EAAQ;AAAA;AACV,OACF;AAAA,IACF,CAAC;AAAA,GACH;AAGA,EAAA,KAAA,MAAW,aAAa,gBAAA,EAAkB;AACxC,IAAA,MAAM,iBAAA,GAAoB,oBAAoB,SAAS,CAAA;AAGvD,IAAA,MAAM,QAAQ,oBAAA,CAAqB,SAAA;AAAA,MACjC,CAAA,CAAA,KAAK,CAAA,CAAE,SAAA,CAAU,EAAA,KAAO,SAAA,CAAU;AAAA,KACpC;AACA,IAAA,IAAI,UAAU,EAAA,EAAI;AAEhB,MAAA,oBAAA,CAAqB,KAAK,EAAE,SAAA,GAAY,iBAAA;AACxC,MAAA,oBAAA,CAAqB,KAAK,CAAA,CAAE,MAAA,CAAO,QAAA,GAAW,iBAAA,CAAkB,QAAA;AAChE,MAAA,oBAAA,CAAqB,KAAK,CAAA,CAAE,MAAA,CAAO,QAAA,GAAW,iBAAA,CAAkB,QAAA;AAAA,IAClE,CAAA,MAAO;AAEL,MAAA,oBAAA,CAAqB,IAAA,CAAK;AAAA,QACxB,SAAA,EAAW,iBAAA;AAAA,QACX,MAAA,EAAQ;AAAA,UACN,QAAQ,SAAA,CAAU,MAAA;AAAA,UAClB,QAAQ,SAAA,CAAU,MAAA;AAAA,UAClB,UAAU,iBAAA,CAAkB,QAAA;AAAA,UAC5B,UAAU,iBAAA,CAAkB,QAAA;AAAA,UAC5B,MAAA,EAAQ;AAAA;AACV,OACD,CAAA;AAAA,IACH;AAAA,EACF;AAEA,EAAA,MAAM,gBAAA,uBAAuB,GAAA,EAAY;AACzC,EAAA,MAAM,yBAAyB,oBAAA,CAAqB,MAAA;AAAA,IAClD,CAAC,EAAE,SAAA,EAAW,MAAA,EAAO,KAAM;AACzB,MAAA,IAAI,gBAAA,CAAiB,GAAA,CAAI,SAAA,CAAU,EAAE,CAAA,EAAG;AACtC,QAAA,SAAA,CAAU,MAAA,CAAO;AAAA,UACf,IAAA,EAAM,mBAAA;AAAA,UACN,SAAS,CAAA,KAAA,EAAQ,SAAA,CAAU,EAAE,CAAA,sBAAA,EAAyB,MAAA,CAAO,OAAO,QAAQ,CAAA,2CAAA,CAAA;AAAA,UAC5E,OAAA,EAAS;AAAA,YACP,QAAQ,MAAA,CAAO,MAAA;AAAA,YACf,aAAa,SAAA,CAAU;AAAA;AACzB,SACD,CAAA;AACD,QAAA,OAAO,KAAA;AAAA,MACT;AACA,MAAA,gBAAA,CAAiB,GAAA,CAAI,UAAU,EAAE,CAAA;AACjC,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,GACF;AAEA,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAqD;AACvE,EAAA,KAAA,MAAW,iBAAiB,UAAA,EAAY;AACtC,IAAA,MAAM,cAAc,aAAA,CAAc,EAAA;AAElC,IAAA,IAAI,SAAA,CAAU,GAAA,CAAI,WAAW,CAAA,EAAG;AAC9B,MAAA,SAAA,CAAU,MAAA,CAAO;AAAA,QACf,IAAA,EAAM,8BAAA;AAAA,QACN,OAAA,EAAS,yBAAyB,WAAW,CAAA,wBAAA,CAAA;AAAA,QAC7C,OAAA,EAAS;AAAA,UACP;AAAA;AACF,OACD,CAAA;AACD,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,WAAW,sBAAA,CAAuB,IAAA;AAAA,MACtC,CAAA,CAAA,KAAK,CAAA,CAAE,SAAA,CAAU,EAAA,KAAO;AAAA,KAC1B;AACA,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,IAAI,cAAc,QAAA,EAAU;AAC1B,QAAA,QAAA,CAAS,MAAA,CAAO,WAAW,aAAA,CAAc,QAAA;AAAA,MAC3C;AACA,MAAA,IAAI,cAAc,MAAA,EAAQ;AAExB,QAAA,QAAA,CAAS,MAAA,CAAO,SAAS,aAAA,CAAc,MAAA;AAAA,MACzC;AACA,MAAA,IACE,OAAA,CAAQ,SAAS,MAAA,CAAO,QAAQ,MAAM,OAAA,CAAQ,aAAA,CAAc,QAAQ,CAAA,EACpE;AACA,QAAA,QAAA,CAAS,MAAA,CAAO,QAAA,GAAW,OAAA,CAAQ,aAAA,CAAc,QAAQ,CAAA;AAAA,MAC3D;AACA,MAAA,KAAA,CAAM,GAAA,CAAI,aAAa,QAAQ,CAAA;AAAA,IACjC,CAAA,MAAO;AACL,MAAA,SAAA,CAAU,MAAA,CAAO;AAAA,QACf,IAAA,EAAM,8BAAA;AAAA,QACN,OAAA,EAAS,aAAa,WAAW,CAAA,eAAA,CAAA;AAAA,QACjC,OAAA,EAAS;AAAA,UACP;AAAA;AACF,OACD,CAAA;AAAA,IACH;AAAA,EACF;AAEA,EAAA,MAAM,iBAAA,GAAoB;AAAA,IACxB,GAAG,MAAM,MAAA,EAAO;AAAA,IAChB,GAAG,sBAAA,CAAuB,MAAA,CAAO,CAAA,CAAA,KAAK,CAAC,MAAM,GAAA,CAAI,CAAA,CAAE,SAAA,CAAU,EAAE,CAAC;AAAA,GAClE;AAEA,EAAA,OAAO,iBAAA,CAAkB,IAAI,CAAA,KAAA,MAAU;AAAA,IACrC,EAAA,EAAI,MAAM,SAAA,CAAU,EAAA;AAAA,IACpB,QAAA,EAAU,MAAM,MAAA,CAAO,QAAA;AAAA,IACvB,WAAW,KAAA,CAAM,SAAA;AAAA,IACjB,QAAA,EAAU,MAAM,MAAA,CAAO,QAAA;AAAA,IACvB,MAAA,EAAQ,MAAM,MAAA,CAAO,MAAA;AAAA,IACrB,MAAA,EAAQ,MAAM,MAAA,CAAO,MAAA;AAAA,IACrB,MAAA,EAAQ,MAAM,MAAA,CAAO;AAAA,GACvB,CAAE,CAAA;AACJ;;;;"}
|
|
@@ -92,6 +92,9 @@ function resolveAppTree(rootNodeId, specs, errorCollector) {
|
|
|
92
92
|
if (spec.id === rootNodeId) {
|
|
93
93
|
rootNode = node;
|
|
94
94
|
} else if (Array.isArray(spec.attachTo)) {
|
|
95
|
+
console.warn(
|
|
96
|
+
`Extension '${spec.id}' is using multiple attachment points which is deprecated and will be removed in a future release. Use a Utility API instead to share functionality across multiple locations. See https://backstage.io/docs/frontend-system/architecture/27-sharing-extensions for migration guidance.`
|
|
97
|
+
);
|
|
95
98
|
let foundFirstParent = false;
|
|
96
99
|
for (const origAttachTo of spec.attachTo) {
|
|
97
100
|
let attachTo = origAttachTo;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveAppTree.esm.js","sources":["../../../../../frontend-app-api/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 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":["../../../../../frontend-app-api/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":"createErrorCollector.esm.js","sources":["../../../../../frontend-app-api/src/wiring/createErrorCollector.ts"],"sourcesContent":["/*\n * Copyright 2025 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 { AppNode, FrontendPlugin } from '@backstage/frontend-plugin-api';\n\n/**\n * @public\n */\nexport type AppErrorTypes = {\n // resolveAppNodeSpecs\n EXTENSION_IGNORED: {\n context: { plugin: FrontendPlugin; extensionId: string };\n };\n INVALID_EXTENSION_CONFIG_KEY: {\n context: { extensionId: string };\n };\n // resolveAppTree\n EXTENSION_INPUT_REDIRECT_CONFLICT: {\n context: { node: AppNode; inputName: string };\n };\n // instantiateAppNodeTree\n EXTENSION_INPUT_DATA_IGNORED: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_INPUT_DATA_MISSING: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_ATTACHMENT_CONFLICT: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_ATTACHMENT_MISSING: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_CONFIGURATION_INVALID: {\n context: { node: AppNode };\n };\n EXTENSION_INVALID: {\n context: { node: AppNode };\n };\n EXTENSION_OUTPUT_CONFLICT: {\n context: { node: AppNode; dataRefId: string };\n };\n EXTENSION_OUTPUT_MISSING: {\n context: { node: AppNode; dataRefId: string };\n };\n EXTENSION_OUTPUT_IGNORED: {\n context: { node: AppNode; dataRefId: string };\n };\n EXTENSION_FACTORY_ERROR: {\n context: { node: AppNode };\n };\n // createSpecializedApp\n API_EXTENSION_INVALID: {\n context: { node: AppNode };\n };\n API_FACTORY_CONFLICT: {\n context: {\n node: AppNode;\n apiRefId: string;\n pluginId: string;\n existingPluginId: string;\n };\n };\n // routing\n ROUTE_DUPLICATE: {\n context: { routeId: string };\n };\n ROUTE_BINDING_INVALID_VALUE: {\n context: { routeId: string };\n };\n ROUTE_NOT_FOUND: {\n context: { routeId: string };\n };\n};\n\n/**\n * @public\n */\nexport type AppError =\n keyof AppErrorTypes extends infer ICode extends keyof AppErrorTypes\n ? ICode extends any\n ? {\n code: ICode;\n message: string;\n context: AppErrorTypes[ICode]['context'];\n }\n : never\n : never;\n\n/** @internal */\nexport interface ErrorCollector<TContext extends {} = {}> {\n report<TCode extends keyof AppErrorTypes>(\n report: Omit<\n AppErrorTypes[TCode]['context'],\n keyof TContext\n > extends infer IContext extends {}\n ? {} extends IContext\n ? {\n code: TCode;\n message: string;\n }\n : {\n code: TCode;\n message: string;\n context: IContext;\n }\n : never,\n ): void;\n child<TAdditionalContext extends {}>(\n context: TAdditionalContext,\n ): ErrorCollector<TContext & TAdditionalContext>;\n collectErrors(): AppError[] | undefined;\n}\n\n/** @internal */\nexport function createErrorCollector(\n context?: Partial<AppError['context']>,\n): ErrorCollector {\n const errors: AppError[] = [];\n const children: ErrorCollector[] = [];\n return {\n report(report: { code: string; message: string; context?: {} }) {\n errors.push({\n ...report,\n context: { ...context, ...report.context },\n } as AppError);\n },\n collectErrors() {\n const allErrors = [\n ...errors,\n ...children.flatMap(child => child.collectErrors() ?? []),\n ];\n errors.length = 0;\n if (allErrors.length === 0) {\n return undefined;\n }\n return allErrors;\n },\n child(childContext) {\n const child = createErrorCollector({ ...context, ...childContext });\n children.push(child);\n return child as ErrorCollector<any>;\n },\n };\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"createErrorCollector.esm.js","sources":["../../../../../frontend-app-api/src/wiring/createErrorCollector.ts"],"sourcesContent":["/*\n * Copyright 2025 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 { AppNode, FrontendPlugin } from '@backstage/frontend-plugin-api';\n\n/**\n * @public\n */\nexport type AppErrorTypes = {\n // resolveAppNodeSpecs\n EXTENSION_IGNORED: {\n context: { plugin: FrontendPlugin; extensionId: string };\n };\n INVALID_EXTENSION_CONFIG_KEY: {\n context: { extensionId: string };\n };\n // resolveAppTree\n EXTENSION_INPUT_REDIRECT_CONFLICT: {\n context: { node: AppNode; inputName: string };\n };\n // instantiateAppNodeTree\n EXTENSION_INPUT_DATA_IGNORED: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_INPUT_DATA_MISSING: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_INPUT_INTERNAL_IGNORED: {\n context: {\n node: AppNode;\n inputName: string;\n extensionId: string;\n plugin: FrontendPlugin;\n };\n };\n EXTENSION_ATTACHMENT_CONFLICT: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_ATTACHMENT_MISSING: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_CONFIGURATION_INVALID: {\n context: { node: AppNode };\n };\n EXTENSION_INVALID: {\n context: { node: AppNode };\n };\n EXTENSION_OUTPUT_CONFLICT: {\n context: { node: AppNode; dataRefId: string };\n };\n EXTENSION_OUTPUT_MISSING: {\n context: { node: AppNode; dataRefId: string };\n };\n EXTENSION_OUTPUT_IGNORED: {\n context: { node: AppNode; dataRefId: string };\n };\n EXTENSION_FACTORY_ERROR: {\n context: { node: AppNode };\n };\n // createSpecializedApp\n API_EXTENSION_INVALID: {\n context: { node: AppNode };\n };\n API_FACTORY_CONFLICT: {\n context: {\n node: AppNode;\n apiRefId: string;\n pluginId: string;\n existingPluginId: string;\n };\n };\n // routing\n ROUTE_DUPLICATE: {\n context: { routeId: string };\n };\n ROUTE_BINDING_INVALID_VALUE: {\n context: { routeId: string };\n };\n ROUTE_NOT_FOUND: {\n context: { routeId: string };\n };\n};\n\n/**\n * @public\n */\nexport type AppError =\n keyof AppErrorTypes extends infer ICode extends keyof AppErrorTypes\n ? ICode extends any\n ? {\n code: ICode;\n message: string;\n context: AppErrorTypes[ICode]['context'];\n }\n : never\n : never;\n\n/** @internal */\nexport interface ErrorCollector<TContext extends {} = {}> {\n report<TCode extends keyof AppErrorTypes>(\n report: Omit<\n AppErrorTypes[TCode]['context'],\n keyof TContext\n > extends infer IContext extends {}\n ? {} extends IContext\n ? {\n code: TCode;\n message: string;\n }\n : {\n code: TCode;\n message: string;\n context: IContext;\n }\n : never,\n ): void;\n child<TAdditionalContext extends {}>(\n context: TAdditionalContext,\n ): ErrorCollector<TContext & TAdditionalContext>;\n collectErrors(): AppError[] | undefined;\n}\n\n/** @internal */\nexport function createErrorCollector(\n context?: Partial<AppError['context']>,\n): ErrorCollector {\n const errors: AppError[] = [];\n const children: ErrorCollector[] = [];\n return {\n report(report: { code: string; message: string; context?: {} }) {\n errors.push({\n ...report,\n context: { ...context, ...report.context },\n } as AppError);\n },\n collectErrors() {\n const allErrors = [\n ...errors,\n ...children.flatMap(child => child.collectErrors() ?? []),\n ];\n errors.length = 0;\n if (allErrors.length === 0) {\n return undefined;\n }\n return allErrors;\n },\n child(childContext) {\n const child = createErrorCollector({ ...context, ...childContext });\n children.push(child);\n return child as ErrorCollector<any>;\n },\n };\n}\n"],"names":[],"mappings":"AAwIO,SAAS,qBACd,OAAA,EACgB;AAChB,EAAA,MAAM,SAAqB,EAAC;AAC5B,EAAA,MAAM,WAA6B,EAAC;AACpC,EAAA,OAAO;AAAA,IACL,OAAO,MAAA,EAAyD;AAC9D,MAAA,MAAA,CAAO,IAAA,CAAK;AAAA,QACV,GAAG,MAAA;AAAA,QACH,SAAS,EAAE,GAAG,OAAA,EAAS,GAAG,OAAO,OAAA;AAAQ,OAC9B,CAAA;AAAA,IACf,CAAA;AAAA,IACA,aAAA,GAAgB;AACd,MAAA,MAAM,SAAA,GAAY;AAAA,QAChB,GAAG,MAAA;AAAA,QACH,GAAG,SAAS,OAAA,CAAQ,CAAA,KAAA,KAAS,MAAM,aAAA,EAAc,IAAK,EAAE;AAAA,OAC1D;AACA,MAAA,MAAA,CAAO,MAAA,GAAS,CAAA;AAChB,MAAA,IAAI,SAAA,CAAU,WAAW,CAAA,EAAG;AAC1B,QAAA,OAAO,MAAA;AAAA,MACT;AACA,MAAA,OAAO,SAAA;AAAA,IACT,CAAA;AAAA,IACA,MAAM,YAAA,EAAc;AAClB,MAAA,MAAM,QAAQ,oBAAA,CAAqB,EAAE,GAAG,OAAA,EAAS,GAAG,cAAc,CAAA;AAClE,MAAA,QAAA,CAAS,KAAK,KAAK,CAAA;AACnB,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,GACF;AACF;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/frontend-test-utils",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5-next.0",
|
|
4
4
|
"backstage": {
|
|
5
5
|
"role": "web-library"
|
|
6
6
|
},
|
|
@@ -31,17 +31,18 @@
|
|
|
31
31
|
"test": "backstage-cli package test"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@backstage/config": "
|
|
35
|
-
"@backstage/frontend-app-api": "
|
|
36
|
-
"@backstage/frontend-plugin-api": "
|
|
37
|
-
"@backstage/plugin-app": "
|
|
38
|
-
"@backstage/
|
|
39
|
-
"@backstage/
|
|
40
|
-
"@backstage/
|
|
41
|
-
"
|
|
34
|
+
"@backstage/config": "1.3.6",
|
|
35
|
+
"@backstage/frontend-app-api": "0.14.1-next.0",
|
|
36
|
+
"@backstage/frontend-plugin-api": "0.14.0-next.0",
|
|
37
|
+
"@backstage/plugin-app": "0.4.0-next.0",
|
|
38
|
+
"@backstage/plugin-app-react": "0.1.1-next.0",
|
|
39
|
+
"@backstage/test-utils": "1.7.15-next.0",
|
|
40
|
+
"@backstage/types": "1.2.2",
|
|
41
|
+
"@backstage/version-bridge": "1.0.11",
|
|
42
|
+
"zod": "^3.25.76"
|
|
42
43
|
},
|
|
43
44
|
"devDependencies": {
|
|
44
|
-
"@backstage/cli": "
|
|
45
|
+
"@backstage/cli": "0.35.3-next.0",
|
|
45
46
|
"@testing-library/jest-dom": "^6.0.0",
|
|
46
47
|
"@types/react": "^18.0.0",
|
|
47
48
|
"react": "^18.0.2",
|