@backstage/frontend-plugin-api 0.12.2-next.2 → 0.13.1
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 +35 -0
- package/dist/frontend-internal/src/routing/OpaqueExternalRouteRef.esm.js +9 -0
- package/dist/frontend-internal/src/routing/OpaqueExternalRouteRef.esm.js.map +1 -0
- package/dist/frontend-internal/src/routing/OpaqueRouteRef.esm.js +9 -0
- package/dist/frontend-internal/src/routing/OpaqueRouteRef.esm.js.map +1 -0
- package/dist/frontend-internal/src/routing/OpaqueSubRouteRef.esm.js +9 -0
- package/dist/frontend-internal/src/routing/OpaqueSubRouteRef.esm.js.map +1 -0
- package/dist/frontend-internal/src/wiring/InternalExtensionDefinition.esm.js.map +1 -1
- package/dist/frontend-internal/src/wiring/InternalExtensionInput.esm.js.map +1 -1
- package/dist/index.d.ts +13 -10
- package/dist/routing/ExternalRouteRef.esm.js +36 -20
- package/dist/routing/ExternalRouteRef.esm.js.map +1 -1
- package/dist/routing/RouteRef.esm.js +34 -56
- package/dist/routing/RouteRef.esm.js.map +1 -1
- package/dist/routing/SubRouteRef.esm.js +21 -32
- package/dist/routing/SubRouteRef.esm.js.map +1 -1
- package/dist/wiring/createExtension.esm.js +2 -2
- package/dist/wiring/createExtension.esm.js.map +1 -1
- package/dist/wiring/createExtensionBlueprint.esm.js.map +1 -1
- package/dist/wiring/createFrontendPlugin.esm.js.map +1 -1
- package/package.json +9 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# @backstage/frontend-plugin-api
|
|
2
2
|
|
|
3
|
+
## 0.13.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- eea6b51: Fixed a versioning conflict that could result in a `.withContext` is not a function error.
|
|
8
|
+
|
|
9
|
+
## 0.13.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 7d87b4f: Renamed `ExtensionDefinition` to `OverridableExtensionDefinition` and introduced a slimmer `ExtensionDefinition` type that does not include override methods. The overridable type is generally used as an output type, while plain `ExtensionDefinition`s are used for input. This reduces type conflicts across different of `@backstage/frontend-plugin-api`, improving long-term compatibility.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 4d03f08: Internal refactor of route reference implementations with minor updates to the `toString` implementations.
|
|
18
|
+
- 7c6a66d: Added support for plugin-relative `attachTo` declarations for extension definitions. This allows for the creation of extension and extension blueprints that attach to other extensions of a particular `kind` in the same plugin, rather than needing to provide the exact extension ID. This is particularly useful when wanting to provide extension blueprints with a built-in hierarchy where the extensions created from one blueprint attach to extensions created from the other blueprint, for example:
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
// kind: 'tabbed-page'
|
|
22
|
+
const parentPage = TabbedPageBlueprint.make({
|
|
23
|
+
params: {....}
|
|
24
|
+
})
|
|
25
|
+
// attachTo: { kind: 'tabbed-page', input: 'tabs' }
|
|
26
|
+
const child1 = TabContentBlueprint.make({
|
|
27
|
+
name: 'tab1',
|
|
28
|
+
params: {....}
|
|
29
|
+
})
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- 878c251: Updated to `ExtensionInput` to make all type parameters optional.
|
|
33
|
+
- 05f60e1: Refactored constructor parameter properties to explicit property declarations for compatibility with TypeScript's `erasableSyntaxOnly` setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.
|
|
34
|
+
- Updated dependencies
|
|
35
|
+
- @backstage/core-components@0.18.3
|
|
36
|
+
- @backstage/core-plugin-api@1.12.0
|
|
37
|
+
|
|
3
38
|
## 0.12.2-next.2
|
|
4
39
|
|
|
5
40
|
### Patch Changes
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { OpaqueType } from '../../../opaque-internal/src/OpaqueType.esm.js';
|
|
2
|
+
|
|
3
|
+
const OpaqueExternalRouteRef = OpaqueType.create({
|
|
4
|
+
type: "@backstage/ExternalRouteRef",
|
|
5
|
+
versions: ["v1"]
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export { OpaqueExternalRouteRef };
|
|
9
|
+
//# sourceMappingURL=OpaqueExternalRouteRef.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpaqueExternalRouteRef.esm.js","sources":["../../../../../frontend-internal/src/routing/OpaqueExternalRouteRef.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 { ExternalRouteRef } from '@backstage/frontend-plugin-api';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueExternalRouteRef = OpaqueType.create<{\n public: ExternalRouteRef;\n versions: {\n readonly version: 'v1';\n\n getParams(): string[];\n getDescription(): string;\n getDefaultTarget(): string | undefined;\n\n setId(id: string): void;\n };\n}>({\n type: '@backstage/ExternalRouteRef',\n versions: ['v1'],\n});\n"],"names":[],"mappings":";;AAmBO,MAAM,sBAAA,GAAyB,WAAW,MAAA,CAW9C;AAAA,EACD,IAAA,EAAM,6BAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAI;AACjB,CAAC;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpaqueRouteRef.esm.js","sources":["../../../../../frontend-internal/src/routing/OpaqueRouteRef.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 { RouteRef } from '@backstage/frontend-plugin-api';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueRouteRef = OpaqueType.create<{\n public: RouteRef;\n versions: {\n readonly version: 'v1';\n\n getParams(): string[];\n getDescription(): string;\n\n alias: string | undefined;\n\n setId(id: string): void;\n };\n}>({\n type: '@backstage/RouteRef',\n versions: ['v1'],\n});\n"],"names":[],"mappings":";;AAmBO,MAAM,cAAA,GAAiB,WAAW,MAAA,CAYtC;AAAA,EACD,IAAA,EAAM,qBAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAI;AACjB,CAAC;;;;"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { OpaqueType } from '../../../opaque-internal/src/OpaqueType.esm.js';
|
|
2
|
+
|
|
3
|
+
const OpaqueSubRouteRef = OpaqueType.create({
|
|
4
|
+
type: "@backstage/SubRouteRef",
|
|
5
|
+
versions: ["v1"]
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export { OpaqueSubRouteRef };
|
|
9
|
+
//# sourceMappingURL=OpaqueSubRouteRef.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpaqueSubRouteRef.esm.js","sources":["../../../../../frontend-internal/src/routing/OpaqueSubRouteRef.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 { RouteRef, SubRouteRef } from '@backstage/frontend-plugin-api';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueSubRouteRef = OpaqueType.create<{\n public: SubRouteRef;\n versions: {\n readonly version: 'v1';\n\n getParams(): string[];\n getParent(): RouteRef;\n getDescription(): string;\n };\n}>({\n type: '@backstage/SubRouteRef',\n versions: ['v1'],\n});\n"],"names":[],"mappings":";;AAmBO,MAAM,iBAAA,GAAoB,WAAW,MAAA,CASzC;AAAA,EACD,IAAA,EAAM,wBAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAI;AACjB,CAAC;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InternalExtensionDefinition.esm.js","sources":["../../../../../frontend-internal/src/wiring/InternalExtensionDefinition.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ApiHolder,\n AppNode,\n ExtensionDefinitionAttachTo,\n ExtensionDataValue,\n ExtensionDataRef,\n
|
|
1
|
+
{"version":3,"file":"InternalExtensionDefinition.esm.js","sources":["../../../../../frontend-internal/src/wiring/InternalExtensionDefinition.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ApiHolder,\n AppNode,\n ExtensionDefinitionAttachTo,\n ExtensionDataValue,\n ExtensionDataRef,\n OverridableExtensionDefinition,\n ExtensionDefinitionParameters,\n ExtensionInput,\n PortableSchema,\n ResolvedExtensionInputs,\n} from '@backstage/frontend-plugin-api';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueExtensionDefinition = OpaqueType.create<{\n public: OverridableExtensionDefinition<ExtensionDefinitionParameters>;\n versions:\n | {\n readonly version: 'v1';\n readonly kind?: string;\n readonly namespace?: string;\n readonly name?: string;\n readonly attachTo: ExtensionDefinitionAttachTo;\n readonly disabled: boolean;\n readonly configSchema?: PortableSchema<any, any>;\n readonly inputs: {\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 readonly output: {\n [name in string]: ExtensionDataRef;\n };\n factory(context: {\n node: AppNode;\n apis: ApiHolder;\n config: object;\n inputs: {\n [inputName in string]: unknown;\n };\n }): {\n [inputName in string]: unknown;\n };\n }\n | {\n readonly version: 'v2';\n readonly kind?: string;\n readonly namespace?: string;\n readonly name?: string;\n readonly attachTo: ExtensionDefinitionAttachTo;\n readonly disabled: boolean;\n readonly configSchema?: PortableSchema<any, any>;\n readonly inputs: { [inputName in string]: ExtensionInput };\n readonly output: Array<ExtensionDataRef>;\n factory(context: {\n node: AppNode;\n apis: ApiHolder;\n config: object;\n inputs: ResolvedExtensionInputs<{\n [inputName in string]: ExtensionInput;\n }>;\n }): Iterable<ExtensionDataValue<any, any>>;\n };\n}>({\n type: '@backstage/ExtensionDefinition',\n versions: ['v1', 'v2'],\n});\n"],"names":[],"mappings":";;AA8BO,MAAM,yBAAA,GAA4B,WAAW,MAAA,CAqDjD;AAAA,EACD,IAAA,EAAM,gCAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAA,EAAM,IAAI;AACvB,CAAC;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InternalExtensionInput.esm.js","sources":["../../../../../frontend-internal/src/wiring/InternalExtensionInput.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ExtensionInput } from '@backstage/frontend-plugin-api';\nimport { OpaqueType } from '@internal/opaque';\n\nexport type ExtensionInputContext = {\n input: string;\n kind?: string;\n name?: string;\n};\n\nexport const OpaqueExtensionInput = OpaqueType.create<{\n public: ExtensionInput;\n versions: {\n readonly version: undefined;\n readonly context?: ExtensionInputContext;\n withContext(context: ExtensionInputContext): ExtensionInput;\n };\n}>({\n type: '@backstage/ExtensionInput',\n versions: [undefined],\n});\n"],"names":[],"mappings":";;AAyBO,MAAM,oBAAA,GAAuB,WAAW,MAAA,CAO5C;AAAA,EACD,IAAA,EAAM,2BAAA;AAAA,EACN,QAAA,EAAU,CAAC,MAAS;AACtB,CAAC;;;;"}
|
|
1
|
+
{"version":3,"file":"InternalExtensionInput.esm.js","sources":["../../../../../frontend-internal/src/wiring/InternalExtensionInput.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ExtensionInput } from '@backstage/frontend-plugin-api';\nimport { OpaqueType } from '@internal/opaque';\n\nexport type ExtensionInputContext = {\n input: string;\n kind?: string;\n name?: string;\n};\n\nexport const OpaqueExtensionInput = OpaqueType.create<{\n public: ExtensionInput;\n versions: {\n readonly version: undefined;\n readonly context?: ExtensionInputContext;\n withContext?(context: ExtensionInputContext): ExtensionInput;\n };\n}>({\n type: '@backstage/ExtensionInput',\n versions: [undefined],\n});\n"],"names":[],"mappings":";;AAyBO,MAAM,oBAAA,GAAuB,WAAW,MAAA,CAO5C;AAAA,EACD,IAAA,EAAM,2BAAA;AAAA,EACN,QAAA,EAAU,CAAC,MAAS;AACtB,CAAC;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -400,7 +400,7 @@ interface ExternalRouteRef<TParams extends AnyRouteRefParams = AnyRouteRefParams
|
|
|
400
400
|
*/
|
|
401
401
|
declare function createExternalRouteRef<TParams extends {
|
|
402
402
|
[param in TParamKeys]: string;
|
|
403
|
-
} | undefined = undefined, TParamKeys extends string = string>(
|
|
403
|
+
} | undefined = undefined, TParamKeys extends string = string>(config?: {
|
|
404
404
|
/**
|
|
405
405
|
* The parameters that will be provided to the external route reference.
|
|
406
406
|
*/
|
|
@@ -513,7 +513,7 @@ interface OverridableFrontendPlugin<TRoutes extends {
|
|
|
513
513
|
} = {
|
|
514
514
|
[id in string]: ExtensionDefinition;
|
|
515
515
|
}> extends FrontendPlugin<TRoutes, TExternalRoutes> {
|
|
516
|
-
getExtension<TId extends keyof TExtensionMap>(id: TId): TExtensionMap[TId]
|
|
516
|
+
getExtension<TId extends keyof TExtensionMap>(id: TId): OverridableExtensionDefinition<TExtensionMap[TId]['T']>;
|
|
517
517
|
withOverrides(options: {
|
|
518
518
|
extensions: Array<ExtensionDefinition>;
|
|
519
519
|
/**
|
|
@@ -757,7 +757,7 @@ interface ExtensionBlueprint<T extends ExtensionBlueprintParameters = ExtensionB
|
|
|
757
757
|
attachTo?: ExtensionDefinitionAttachTo<UParentInputs> & VerifyExtensionAttachTo<NonNullable<T['output']>, UParentInputs>;
|
|
758
758
|
disabled?: boolean;
|
|
759
759
|
params: TParamsInput extends ExtensionBlueprintDefineParams ? TParamsInput : T['params'] extends ExtensionBlueprintDefineParams ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `<blueprint>.make({ params: defineParams => defineParams(<params>) })`' : T['params'];
|
|
760
|
-
}):
|
|
760
|
+
}): OverridableExtensionDefinition<{
|
|
761
761
|
kind: T['kind'];
|
|
762
762
|
name: string | undefined extends TName ? undefined : TName;
|
|
763
763
|
config: T['config'];
|
|
@@ -800,7 +800,7 @@ interface ExtensionBlueprint<T extends ExtensionBlueprintParameters = ExtensionB
|
|
|
800
800
|
};
|
|
801
801
|
inputs: Expand<ResolvedExtensionInputs<T['inputs'] & TExtraInputs>>;
|
|
802
802
|
}): Iterable<UFactoryOutput> & VerifyExtensionFactoryOutput<ExtensionDataRef extends UNewOutput ? NonNullable<T['output']> : UNewOutput, UFactoryOutput>;
|
|
803
|
-
}):
|
|
803
|
+
}): OverridableExtensionDefinition<{
|
|
804
804
|
config: (string extends keyof TExtensionConfigSchema ? {} : {
|
|
805
805
|
[key in keyof TExtensionConfigSchema]: z.infer<ReturnType<TExtensionConfigSchema[key]>>;
|
|
806
806
|
}) & T['config'];
|
|
@@ -1013,9 +1013,12 @@ type ExtensionDefinitionParameters = {
|
|
|
1013
1013
|
*/
|
|
1014
1014
|
type AnyParamsInput<TParams extends object | ExtensionBlueprintDefineParams> = TParams extends ExtensionBlueprintDefineParams<infer IParams> ? IParams | ((define: TParams) => ReturnType<TParams>) : TParams | ((define: ExtensionBlueprintDefineParams<TParams, TParams>) => ReturnType<ExtensionBlueprintDefineParams<TParams, TParams>>);
|
|
1015
1015
|
/** @public */
|
|
1016
|
-
|
|
1016
|
+
interface ExtensionDefinition<TParams extends ExtensionDefinitionParameters = ExtensionDefinitionParameters> {
|
|
1017
1017
|
$$type: '@backstage/ExtensionDefinition';
|
|
1018
|
-
readonly T:
|
|
1018
|
+
readonly T: TParams;
|
|
1019
|
+
}
|
|
1020
|
+
/** @public */
|
|
1021
|
+
interface OverridableExtensionDefinition<T extends ExtensionDefinitionParameters = ExtensionDefinitionParameters> extends ExtensionDefinition<T> {
|
|
1019
1022
|
/**
|
|
1020
1023
|
* References to the inputs of this extension, which can be used to attach child extensions.
|
|
1021
1024
|
*/
|
|
@@ -1053,7 +1056,7 @@ type ExtensionDefinition<T extends ExtensionDefinitionParameters = ExtensionDefi
|
|
|
1053
1056
|
}): Iterable<UFactoryOutput>;
|
|
1054
1057
|
} & ([T['params']] extends [never] ? {} : {
|
|
1055
1058
|
params?: TParamsInput extends ExtensionBlueprintDefineParams ? TParamsInput : T['params'] extends ExtensionBlueprintDefineParams ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(defineParams => defineParams(<params>))`' : Partial<T['params']>;
|
|
1056
|
-
})> & VerifyExtensionFactoryOutput<ExtensionDataRef extends UNewOutput ? NonNullable<T['output']> : UNewOutput, UFactoryOutput>):
|
|
1059
|
+
})> & VerifyExtensionFactoryOutput<ExtensionDataRef extends UNewOutput ? NonNullable<T['output']> : UNewOutput, UFactoryOutput>): OverridableExtensionDefinition<{
|
|
1057
1060
|
kind: T['kind'];
|
|
1058
1061
|
name: T['name'];
|
|
1059
1062
|
output: ExtensionDataRef extends UNewOutput ? T['output'] : UNewOutput;
|
|
@@ -1065,7 +1068,7 @@ type ExtensionDefinition<T extends ExtensionDefinitionParameters = ExtensionDefi
|
|
|
1065
1068
|
[key in keyof TExtensionConfigSchema]: ReturnType<TExtensionConfigSchema[key]>;
|
|
1066
1069
|
}>>;
|
|
1067
1070
|
}>;
|
|
1068
|
-
}
|
|
1071
|
+
}
|
|
1069
1072
|
/**
|
|
1070
1073
|
* Creates a new extension definition for installation in a Backstage app.
|
|
1071
1074
|
*
|
|
@@ -1105,7 +1108,7 @@ declare function createExtension<UOutput extends ExtensionDataRef, TInputs exten
|
|
|
1105
1108
|
[inputName in string]: ExtensionInput;
|
|
1106
1109
|
}, TConfigSchema extends {
|
|
1107
1110
|
[key: string]: (zImpl: typeof z) => z.ZodType;
|
|
1108
|
-
}, UFactoryOutput extends ExtensionDataValue<any, any>, const TKind extends string | undefined = undefined, const TName extends string | undefined = undefined, UParentInputs extends ExtensionDataRef = ExtensionDataRef>(options: CreateExtensionOptions<TKind, TName, UOutput, TInputs, TConfigSchema, UFactoryOutput, UParentInputs>):
|
|
1111
|
+
}, UFactoryOutput extends ExtensionDataValue<any, any>, const TKind extends string | undefined = undefined, const TName extends string | undefined = undefined, UParentInputs extends ExtensionDataRef = ExtensionDataRef>(options: CreateExtensionOptions<TKind, TName, UOutput, TInputs, TConfigSchema, UFactoryOutput, UParentInputs>): OverridableExtensionDefinition<{
|
|
1109
1112
|
config: string extends keyof TConfigSchema ? {} : {
|
|
1110
1113
|
[key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>;
|
|
1111
1114
|
};
|
|
@@ -2016,4 +2019,4 @@ declare const SwappableComponentBlueprint: ExtensionBlueprint<{
|
|
|
2016
2019
|
};
|
|
2017
2020
|
}>;
|
|
2018
2021
|
|
|
2019
|
-
export { type AnalyticsApi, AnalyticsContext, type AnalyticsContextValue, type AnalyticsEvent, type AnalyticsEventAttributes, type AnalyticsImplementation, AnalyticsImplementationBlueprint, type AnalyticsImplementationFactory, type AnalyticsTracker, type AnyExtensionDataRef, type AnyRouteRefParams, ApiBlueprint, type AppNode, type AppNodeEdges, type AppNodeInstance, type AppNodeSpec, AppRootElementBlueprint, AppRootWrapperBlueprint, type AppTree, type AppTreeApi, type ConfigurableExtensionDataRef, type CreateExtensionBlueprintOptions, type CreateExtensionOptions, type CreateFrontendFeatureLoaderOptions, type CreateFrontendModuleOptions, type CreateSwappableComponentOptions, type DialogApi, type DialogApiDialog, ErrorDisplay, type ErrorDisplayProps, type Extension, type ExtensionAttachTo, type ExtensionAttachToSpec, type ExtensionBlueprint, type ExtensionBlueprintDefineParams, type ExtensionBlueprintParameters, type ExtensionBlueprintParams, ExtensionBoundary, type ExtensionBoundaryProps, type ExtensionDataContainer, type ExtensionDataRef, type ExtensionDataRefToValue, type ExtensionDataValue, type ExtensionDefinition, type ExtensionDefinitionAttachTo, type ExtensionDefinitionParameters, type ExtensionFactoryMiddleware, type ExtensionInput, type ExternalRouteRef, type FeatureFlagConfig, type FrontendFeature, type FrontendFeatureLoader, type FrontendModule, type FrontendPlugin, type FrontendPluginInfo, type FrontendPluginInfoOptions, IconBundleBlueprint, type IconComponent, type IconsApi, NavContentBlueprint, type NavContentComponent, type NavContentComponentProps, NavItemBlueprint, NotFoundErrorPage, type NotFoundErrorPageProps, type OverridableFrontendPlugin, PageBlueprint, type PluginOptions, type PortableSchema, Progress, type ProgressProps, type ResolvedExtensionInput, type ResolvedExtensionInputs, type RouteFunc, type RouteRef, type RouteResolutionApi, RouterBlueprint, SignInPageBlueprint, type SubRouteRef, SwappableComponentBlueprint, type SwappableComponentRef, type SwappableComponentsApi, ThemeBlueprint, TranslationBlueprint, analyticsApiRef, appTreeApiRef, coreExtensionData, createExtension, createExtensionBlueprint, createExtensionBlueprintParams, createExtensionDataRef, createExtensionInput, createExternalRouteRef, createFrontendFeatureLoader, createFrontendModule, createFrontendPlugin, createRouteRef, createSubRouteRef, createSwappableComponent, dialogApiRef, iconsApiRef, routeResolutionApiRef, swappableComponentsApiRef, useAnalytics, useAppNode, useRouteRef, useRouteRefParams };
|
|
2022
|
+
export { type AnalyticsApi, AnalyticsContext, type AnalyticsContextValue, type AnalyticsEvent, type AnalyticsEventAttributes, type AnalyticsImplementation, AnalyticsImplementationBlueprint, type AnalyticsImplementationFactory, type AnalyticsTracker, type AnyExtensionDataRef, type AnyRouteRefParams, ApiBlueprint, type AppNode, type AppNodeEdges, type AppNodeInstance, type AppNodeSpec, AppRootElementBlueprint, AppRootWrapperBlueprint, type AppTree, type AppTreeApi, type ConfigurableExtensionDataRef, type CreateExtensionBlueprintOptions, type CreateExtensionOptions, type CreateFrontendFeatureLoaderOptions, type CreateFrontendModuleOptions, type CreateSwappableComponentOptions, type DialogApi, type DialogApiDialog, ErrorDisplay, type ErrorDisplayProps, type Extension, type ExtensionAttachTo, type ExtensionAttachToSpec, type ExtensionBlueprint, type ExtensionBlueprintDefineParams, type ExtensionBlueprintParameters, type ExtensionBlueprintParams, ExtensionBoundary, type ExtensionBoundaryProps, type ExtensionDataContainer, type ExtensionDataRef, type ExtensionDataRefToValue, type ExtensionDataValue, type ExtensionDefinition, type ExtensionDefinitionAttachTo, type ExtensionDefinitionParameters, type ExtensionFactoryMiddleware, type ExtensionInput, type ExternalRouteRef, type FeatureFlagConfig, type FrontendFeature, type FrontendFeatureLoader, type FrontendModule, type FrontendPlugin, type FrontendPluginInfo, type FrontendPluginInfoOptions, IconBundleBlueprint, type IconComponent, type IconsApi, NavContentBlueprint, type NavContentComponent, type NavContentComponentProps, NavItemBlueprint, NotFoundErrorPage, type NotFoundErrorPageProps, type OverridableExtensionDefinition, type OverridableFrontendPlugin, PageBlueprint, type PluginOptions, type PortableSchema, Progress, type ProgressProps, type ResolvedExtensionInput, type ResolvedExtensionInputs, type RouteFunc, type RouteRef, type RouteResolutionApi, RouterBlueprint, SignInPageBlueprint, type SubRouteRef, SwappableComponentBlueprint, type SwappableComponentRef, type SwappableComponentsApi, ThemeBlueprint, TranslationBlueprint, analyticsApiRef, appTreeApiRef, coreExtensionData, createExtension, createExtensionBlueprint, createExtensionBlueprintParams, createExtensionDataRef, createExtensionInput, createExternalRouteRef, createFrontendFeatureLoader, createFrontendModule, createFrontendPlugin, createRouteRef, createSubRouteRef, createSwappableComponent, dialogApiRef, iconsApiRef, routeResolutionApiRef, swappableComponentsApiRef, useAnalytics, useAppNode, useRouteRef, useRouteRefParams };
|
|
@@ -1,25 +1,41 @@
|
|
|
1
|
-
import { RouteRefImpl } from './RouteRef.esm.js';
|
|
2
1
|
import { describeParentCallSite } from './describeParentCallSite.esm.js';
|
|
2
|
+
import { OpaqueExternalRouteRef } from '../frontend-internal/src/routing/OpaqueExternalRouteRef.esm.js';
|
|
3
|
+
import '../frontend-internal/src/routing/OpaqueRouteRef.esm.js';
|
|
4
|
+
import '../frontend-internal/src/routing/OpaqueSubRouteRef.esm.js';
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
6
|
+
function createExternalRouteRef(config) {
|
|
7
|
+
const params = config?.params ?? [];
|
|
8
|
+
const creationSite = describeParentCallSite();
|
|
9
|
+
let id = void 0;
|
|
10
|
+
return OpaqueExternalRouteRef.createInstance("v1", {
|
|
11
|
+
T: void 0,
|
|
12
|
+
getParams() {
|
|
13
|
+
return params;
|
|
14
|
+
},
|
|
15
|
+
getDescription() {
|
|
16
|
+
if (id) {
|
|
17
|
+
return id;
|
|
18
|
+
}
|
|
19
|
+
return `created at '${creationSite}'`;
|
|
20
|
+
},
|
|
21
|
+
getDefaultTarget() {
|
|
22
|
+
return config?.defaultTarget;
|
|
23
|
+
},
|
|
24
|
+
setId(newId) {
|
|
25
|
+
if (!newId) {
|
|
26
|
+
throw new Error(`ExternalRouteRef id must be a non-empty string`);
|
|
27
|
+
}
|
|
28
|
+
if (id && id !== newId) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
`ExternalRouteRef was referenced twice as both '${id}' and '${newId}'`
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
id = newId;
|
|
34
|
+
},
|
|
35
|
+
toString() {
|
|
36
|
+
return `externalRouteRef{id=${id},at='${creationSite}'}`;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
23
39
|
}
|
|
24
40
|
|
|
25
41
|
export { createExternalRouteRef };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExternalRouteRef.esm.js","sources":["../../src/routing/ExternalRouteRef.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {
|
|
1
|
+
{"version":3,"file":"ExternalRouteRef.esm.js","sources":["../../src/routing/ExternalRouteRef.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { OpaqueExternalRouteRef } from '@internal/frontend';\nimport { describeParentCallSite } from './describeParentCallSite';\nimport { AnyRouteRefParams } from './types';\n\n/**\n * Route descriptor, to be later bound to a concrete route by the app. Used to implement cross-plugin route references.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#routing-system}.\n *\n * @public\n */\nexport interface ExternalRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n> {\n readonly $$type: '@backstage/ExternalRouteRef';\n readonly T: TParams;\n}\n\n/** @internal */\nexport interface InternalExternalRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n> extends ExternalRouteRef<TParams> {\n readonly version: 'v1';\n getParams(): string[];\n getDescription(): string;\n getDefaultTarget(): string | undefined;\n\n setId(id: string): void;\n}\n\n/** @internal */\nexport function toInternalExternalRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n>(resource: ExternalRouteRef<TParams>): InternalExternalRouteRef<TParams> {\n const r = resource as InternalExternalRouteRef<TParams>;\n if (r.$$type !== '@backstage/ExternalRouteRef') {\n throw new Error(`Invalid ExternalRouteRef, bad type '${r.$$type}'`);\n }\n\n return r;\n}\n\n/**\n * Creates a route descriptor, to be later bound to a concrete route by the app. Used to implement cross-plugin route references.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#routing-system}.\n *\n * @param options - Description of the route reference to be created.\n * @public\n */\nexport function createExternalRouteRef<\n TParams extends { [param in TParamKeys]: string } | undefined = undefined,\n TParamKeys extends string = string,\n>(config?: {\n /**\n * The parameters that will be provided to the external route reference.\n */\n readonly params?: string extends TParamKeys\n ? (keyof TParams)[]\n : TParamKeys[];\n\n /**\n * The route (typically in another plugin) that this should map to by default.\n *\n * The string is expected to be on the standard `<plugin id>.<route id>` form,\n * for example `techdocs.docRoot`.\n */\n defaultTarget?: string;\n}): ExternalRouteRef<\n keyof TParams extends never\n ? undefined\n : string extends TParamKeys\n ? TParams\n : { [param in TParamKeys]: string }\n> {\n const params = (config?.params ?? []) as string[];\n const creationSite = describeParentCallSite();\n\n let id: string | undefined = undefined;\n\n return OpaqueExternalRouteRef.createInstance('v1', {\n T: undefined as unknown as TParams,\n getParams() {\n return params;\n },\n getDescription() {\n if (id) {\n return id;\n }\n return `created at '${creationSite}'`;\n },\n getDefaultTarget() {\n return config?.defaultTarget;\n },\n setId(newId: string) {\n if (!newId) {\n throw new Error(`ExternalRouteRef id must be a non-empty string`);\n }\n if (id && id !== newId) {\n throw new Error(\n `ExternalRouteRef was referenced twice as both '${id}' and '${newId}'`,\n );\n }\n id = newId;\n },\n toString(): string {\n return `externalRouteRef{id=${id},at='${creationSite}'}`;\n },\n });\n}\n"],"names":[],"mappings":";;;;;AAsEO,SAAS,uBAGd,MAAA,EAqBA;AACA,EAAA,MAAM,MAAA,GAAU,MAAA,EAAQ,MAAA,IAAU,EAAC;AACnC,EAAA,MAAM,eAAe,sBAAA,EAAuB;AAE5C,EAAA,IAAI,EAAA,GAAyB,MAAA;AAE7B,EAAA,OAAO,sBAAA,CAAuB,eAAe,IAAA,EAAM;AAAA,IACjD,CAAA,EAAG,MAAA;AAAA,IACH,SAAA,GAAY;AACV,MAAA,OAAO,MAAA;AAAA,IACT,CAAA;AAAA,IACA,cAAA,GAAiB;AACf,MAAA,IAAI,EAAA,EAAI;AACN,QAAA,OAAO,EAAA;AAAA,MACT;AACA,MAAA,OAAO,eAAe,YAAY,CAAA,CAAA,CAAA;AAAA,IACpC,CAAA;AAAA,IACA,gBAAA,GAAmB;AACjB,MAAA,OAAO,MAAA,EAAQ,aAAA;AAAA,IACjB,CAAA;AAAA,IACA,MAAM,KAAA,EAAe;AACnB,MAAA,IAAI,CAAC,KAAA,EAAO;AACV,QAAA,MAAM,IAAI,MAAM,CAAA,8CAAA,CAAgD,CAAA;AAAA,MAClE;AACA,MAAA,IAAI,EAAA,IAAM,OAAO,KAAA,EAAO;AACtB,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,+CAAA,EAAkD,EAAE,CAAA,OAAA,EAAU,KAAK,CAAA,CAAA;AAAA,SACrE;AAAA,MACF;AACA,MAAA,EAAA,GAAK,KAAA;AAAA,IACP,CAAA;AAAA,IACA,QAAA,GAAmB;AACjB,MAAA,OAAO,CAAA,oBAAA,EAAuB,EAAE,CAAA,KAAA,EAAQ,YAAY,CAAA,EAAA,CAAA;AAAA,IACtD;AAAA,GACD,CAAA;AACH;;;;"}
|
|
@@ -1,62 +1,40 @@
|
|
|
1
1
|
import { describeParentCallSite } from './describeParentCallSite.esm.js';
|
|
2
|
+
import { OpaqueRouteRef } from '../frontend-internal/src/routing/OpaqueRouteRef.esm.js';
|
|
3
|
+
import '../frontend-internal/src/routing/OpaqueSubRouteRef.esm.js';
|
|
4
|
+
import '../frontend-internal/src/routing/OpaqueExternalRouteRef.esm.js';
|
|
2
5
|
|
|
3
|
-
function toInternalRouteRef(resource) {
|
|
4
|
-
const r = resource;
|
|
5
|
-
if (r.$$type !== "@backstage/RouteRef") {
|
|
6
|
-
throw new Error(`Invalid RouteRef, bad type '${r.$$type}'`);
|
|
7
|
-
}
|
|
8
|
-
return r;
|
|
9
|
-
}
|
|
10
|
-
class RouteRefImpl {
|
|
11
|
-
constructor(params = [], creationSite, alias) {
|
|
12
|
-
this.params = params;
|
|
13
|
-
this.#params = params;
|
|
14
|
-
this.#creationSite = creationSite;
|
|
15
|
-
this.#alias = alias;
|
|
16
|
-
}
|
|
17
|
-
$$type = "@backstage/RouteRef";
|
|
18
|
-
version = "v1";
|
|
19
|
-
#id;
|
|
20
|
-
#params;
|
|
21
|
-
#creationSite;
|
|
22
|
-
#alias;
|
|
23
|
-
getParams() {
|
|
24
|
-
return this.#params;
|
|
25
|
-
}
|
|
26
|
-
get alias() {
|
|
27
|
-
return this.#alias;
|
|
28
|
-
}
|
|
29
|
-
getDescription() {
|
|
30
|
-
if (this.#id) {
|
|
31
|
-
return this.#id;
|
|
32
|
-
}
|
|
33
|
-
return `created at '${this.#creationSite}'`;
|
|
34
|
-
}
|
|
35
|
-
get #name() {
|
|
36
|
-
return this.$$type.slice("@backstage/".length);
|
|
37
|
-
}
|
|
38
|
-
setId(id) {
|
|
39
|
-
if (!id) {
|
|
40
|
-
throw new Error(`${this.#name} id must be a non-empty string`);
|
|
41
|
-
}
|
|
42
|
-
if (this.#id && this.#id !== id) {
|
|
43
|
-
throw new Error(
|
|
44
|
-
`${this.#name} was referenced twice as both '${this.#id}' and '${id}'`
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
this.#id = id;
|
|
48
|
-
}
|
|
49
|
-
toString() {
|
|
50
|
-
return `${this.#name}{${this.getDescription()}}`;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
6
|
function createRouteRef(config) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
7
|
+
const params = config?.params ?? [];
|
|
8
|
+
const creationSite = describeParentCallSite();
|
|
9
|
+
let id = void 0;
|
|
10
|
+
return OpaqueRouteRef.createInstance("v1", {
|
|
11
|
+
T: void 0,
|
|
12
|
+
getParams() {
|
|
13
|
+
return params;
|
|
14
|
+
},
|
|
15
|
+
getDescription() {
|
|
16
|
+
if (id) {
|
|
17
|
+
return id;
|
|
18
|
+
}
|
|
19
|
+
return `created at '${creationSite}'`;
|
|
20
|
+
},
|
|
21
|
+
alias: config?.aliasFor,
|
|
22
|
+
setId(newId) {
|
|
23
|
+
if (!newId) {
|
|
24
|
+
throw new Error(`RouteRef id must be a non-empty string`);
|
|
25
|
+
}
|
|
26
|
+
if (id && id !== newId) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
`RouteRef was referenced twice as both '${id}' and '${newId}'`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
id = newId;
|
|
32
|
+
},
|
|
33
|
+
toString() {
|
|
34
|
+
return `routeRef{id=${id},at='${creationSite}'}`;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
59
37
|
}
|
|
60
38
|
|
|
61
|
-
export {
|
|
39
|
+
export { createRouteRef };
|
|
62
40
|
//# sourceMappingURL=RouteRef.esm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RouteRef.esm.js","sources":["../../src/routing/RouteRef.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { describeParentCallSite } from './describeParentCallSite';\nimport { AnyRouteRefParams } from './types';\n\n/**\n * Absolute route reference.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#routing-system}.\n *\n * @public\n */\nexport interface RouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n> {\n readonly $$type: '@backstage/RouteRef';\n readonly T: TParams;\n}\n\n
|
|
1
|
+
{"version":3,"file":"RouteRef.esm.js","sources":["../../src/routing/RouteRef.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { OpaqueRouteRef } from '@internal/frontend';\nimport { describeParentCallSite } from './describeParentCallSite';\nimport { AnyRouteRefParams } from './types';\n\n/**\n * Absolute route reference.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#routing-system}.\n *\n * @public\n */\nexport interface RouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n> {\n readonly $$type: '@backstage/RouteRef';\n readonly T: TParams;\n}\n\n/**\n * Create a {@link RouteRef} from a route descriptor.\n *\n * @param config - Description of the route reference to be created.\n * @public\n */\nexport function createRouteRef<\n // Params is the type that we care about and the one to be embedded in the route ref.\n // For example, given the params ['name', 'kind'], Params will be {name: string, kind: string}\n TParams extends { [param in TParamKeys]: string } | undefined = undefined,\n TParamKeys extends string = string,\n>(config?: {\n /** A list of parameter names that the path that this route ref is bound to must contain */\n readonly params?: string extends TParamKeys\n ? (keyof TParams)[]\n : TParamKeys[];\n\n aliasFor?: string;\n}): RouteRef<\n keyof TParams extends never\n ? undefined\n : string extends TParamKeys\n ? TParams\n : { [param in TParamKeys]: string }\n> {\n const params = (config?.params ?? []) as string[];\n const creationSite = describeParentCallSite();\n\n let id: string | undefined = undefined;\n\n return OpaqueRouteRef.createInstance('v1', {\n T: undefined as unknown as TParams,\n getParams() {\n return params;\n },\n getDescription() {\n if (id) {\n return id;\n }\n return `created at '${creationSite}'`;\n },\n alias: config?.aliasFor,\n setId(newId: string) {\n if (!newId) {\n throw new Error(`RouteRef id must be a non-empty string`);\n }\n if (id && id !== newId) {\n throw new Error(\n `RouteRef was referenced twice as both '${id}' and '${newId}'`,\n );\n }\n id = newId;\n },\n toString(): string {\n return `routeRef{id=${id},at='${creationSite}'}`;\n },\n });\n}\n"],"names":[],"mappings":";;;;;AA0CO,SAAS,eAKd,MAAA,EAaA;AACA,EAAA,MAAM,MAAA,GAAU,MAAA,EAAQ,MAAA,IAAU,EAAC;AACnC,EAAA,MAAM,eAAe,sBAAA,EAAuB;AAE5C,EAAA,IAAI,EAAA,GAAyB,MAAA;AAE7B,EAAA,OAAO,cAAA,CAAe,eAAe,IAAA,EAAM;AAAA,IACzC,CAAA,EAAG,MAAA;AAAA,IACH,SAAA,GAAY;AACV,MAAA,OAAO,MAAA;AAAA,IACT,CAAA;AAAA,IACA,cAAA,GAAiB;AACf,MAAA,IAAI,EAAA,EAAI;AACN,QAAA,OAAO,EAAA;AAAA,MACT;AACA,MAAA,OAAO,eAAe,YAAY,CAAA,CAAA,CAAA;AAAA,IACpC,CAAA;AAAA,IACA,OAAO,MAAA,EAAQ,QAAA;AAAA,IACf,MAAM,KAAA,EAAe;AACnB,MAAA,IAAI,CAAC,KAAA,EAAO;AACV,QAAA,MAAM,IAAI,MAAM,CAAA,sCAAA,CAAwC,CAAA;AAAA,MAC1D;AACA,MAAA,IAAI,EAAA,IAAM,OAAO,KAAA,EAAO;AACtB,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,uCAAA,EAA0C,EAAE,CAAA,OAAA,EAAU,KAAK,CAAA,CAAA;AAAA,SAC7D;AAAA,MACF;AACA,MAAA,EAAA,GAAK,KAAA;AAAA,IACP,CAAA;AAAA,IACA,QAAA,GAAmB;AACjB,MAAA,OAAO,CAAA,YAAA,EAAe,EAAE,CAAA,KAAA,EAAQ,YAAY,CAAA,EAAA,CAAA;AAAA,IAC9C;AAAA,GACD,CAAA;AACH;;;;"}
|
|
@@ -1,34 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { OpaqueSubRouteRef } from '../frontend-internal/src/routing/OpaqueSubRouteRef.esm.js';
|
|
2
|
+
import { OpaqueRouteRef } from '../frontend-internal/src/routing/OpaqueRouteRef.esm.js';
|
|
3
|
+
import '../frontend-internal/src/routing/OpaqueExternalRouteRef.esm.js';
|
|
2
4
|
|
|
3
5
|
const PARAM_PATTERN = /^\w+$/;
|
|
4
|
-
class SubRouteRefImpl {
|
|
5
|
-
constructor(path, params, parent) {
|
|
6
|
-
this.path = path;
|
|
7
|
-
this.#params = params;
|
|
8
|
-
this.#parent = parent;
|
|
9
|
-
}
|
|
10
|
-
$$type = "@backstage/SubRouteRef";
|
|
11
|
-
version = "v1";
|
|
12
|
-
#params;
|
|
13
|
-
#parent;
|
|
14
|
-
getParams() {
|
|
15
|
-
return this.#params;
|
|
16
|
-
}
|
|
17
|
-
getParent() {
|
|
18
|
-
return this.#parent;
|
|
19
|
-
}
|
|
20
|
-
getDescription() {
|
|
21
|
-
const parent = toInternalRouteRef(this.#parent);
|
|
22
|
-
return `at ${this.path} with parent ${parent.getDescription()}`;
|
|
23
|
-
}
|
|
24
|
-
toString() {
|
|
25
|
-
return `SubRouteRef{${this.getDescription()}}`;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
6
|
function createSubRouteRef(config) {
|
|
29
7
|
const { path, parent } = config;
|
|
30
|
-
const internalParent =
|
|
8
|
+
const internalParent = OpaqueRouteRef.toInternal(parent);
|
|
31
9
|
const parentParams = internalParent.getParams();
|
|
10
|
+
const parentDescription = internalParent.getDescription();
|
|
32
11
|
const pathParams = path.split("/").filter((p) => p.startsWith(":")).map((p) => p.substring(1));
|
|
33
12
|
const params = [...parentParams, ...pathParams];
|
|
34
13
|
if (parentParams.some((p) => pathParams.includes(p))) {
|
|
@@ -47,13 +26,23 @@ function createSubRouteRef(config) {
|
|
|
47
26
|
throw new Error(`SubRouteRef path has invalid param, got '${param}'`);
|
|
48
27
|
}
|
|
49
28
|
}
|
|
50
|
-
|
|
29
|
+
return OpaqueSubRouteRef.createInstance("v1", {
|
|
30
|
+
T: void 0,
|
|
51
31
|
path,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
32
|
+
getParams() {
|
|
33
|
+
return params;
|
|
34
|
+
},
|
|
35
|
+
getParent() {
|
|
36
|
+
return parent;
|
|
37
|
+
},
|
|
38
|
+
getDescription() {
|
|
39
|
+
return `at ${path} with parent ${parentDescription}`;
|
|
40
|
+
},
|
|
41
|
+
toString() {
|
|
42
|
+
return `subRouteRef{path='${path}',parent=${parent}}`;
|
|
43
|
+
}
|
|
44
|
+
});
|
|
56
45
|
}
|
|
57
46
|
|
|
58
|
-
export {
|
|
47
|
+
export { createSubRouteRef };
|
|
59
48
|
//# sourceMappingURL=SubRouteRef.esm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubRouteRef.esm.js","sources":["../../src/routing/SubRouteRef.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {
|
|
1
|
+
{"version":3,"file":"SubRouteRef.esm.js","sources":["../../src/routing/SubRouteRef.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { OpaqueRouteRef, OpaqueSubRouteRef } from '@internal/frontend';\nimport { RouteRef } from './RouteRef';\nimport { AnyRouteRefParams } from './types';\n\n// Should match the pattern in react-router\nconst PARAM_PATTERN = /^\\w+$/;\n\n/**\n * Descriptor of a route relative to an absolute {@link RouteRef}.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#routing-system}.\n *\n * @public\n */\nexport interface SubRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n> {\n readonly $$type: '@backstage/SubRouteRef';\n\n readonly T: TParams;\n\n readonly path: string;\n}\n\n/** @internal */\nexport interface InternalSubRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n> extends SubRouteRef<TParams> {\n readonly version: 'v1';\n\n getParams(): string[];\n getParent(): RouteRef;\n getDescription(): string;\n}\n\n/**\n * Used in {@link PathParams} type declaration.\n * @ignore\n */\ntype ParamPart<S extends string> = S extends `:${infer Param}` ? Param : never;\n\n/**\n * Used in {@link PathParams} type declaration.\n * @ignore\n */\ntype ParamNames<S extends string> = S extends `${infer Part}/${infer Rest}`\n ? ParamPart<Part> | ParamNames<Rest>\n : ParamPart<S>;\n/**\n * This utility type helps us infer a Param object type from a string path\n * For example, `/foo/:bar/:baz` inferred to `{ bar: string, baz: string }`\n * @ignore\n */\ntype PathParams<S extends string> = { [name in ParamNames<S>]: string };\n\n/**\n * Merges a param object type with an optional params type into a params object.\n * @ignore\n */\ntype MergeParams<\n P1 extends { [param in string]: string },\n P2 extends AnyRouteRefParams,\n> = (P1[keyof P1] extends never ? {} : P1) & (P2 extends undefined ? {} : P2);\n\n/**\n * Convert empty params to undefined.\n * @ignore\n */\ntype TrimEmptyParams<Params extends { [param in string]: string }> =\n keyof Params extends never ? undefined : Params;\n\n/**\n * Creates a SubRouteRef type given the desired parameters and parent route parameters.\n * The parameters types are merged together while ensuring that there is no overlap between the two.\n *\n * @ignore\n */\ntype MakeSubRouteRef<\n Params extends { [param in string]: string },\n ParentParams extends AnyRouteRefParams,\n> = keyof Params & keyof ParentParams extends never\n ? SubRouteRef<TrimEmptyParams<MergeParams<Params, ParentParams>>>\n : never;\n\n/**\n * Create a {@link SubRouteRef} from a route descriptor.\n *\n * @param config - Description of the route reference to be created.\n * @public\n */\nexport function createSubRouteRef<\n Path extends string,\n ParentParams extends AnyRouteRefParams = never,\n>(config: {\n path: Path;\n parent: RouteRef<ParentParams>;\n}): MakeSubRouteRef<PathParams<Path>, ParentParams> {\n const { path, parent } = config;\n type Params = PathParams<Path>;\n\n const internalParent = OpaqueRouteRef.toInternal(parent);\n const parentParams = internalParent.getParams();\n const parentDescription = internalParent.getDescription();\n\n // Collect runtime parameters from the path, e.g. ['bar', 'baz'] from '/foo/:bar/:baz'\n const pathParams = path\n .split('/')\n .filter(p => p.startsWith(':'))\n .map(p => p.substring(1));\n const params = [...parentParams, ...pathParams];\n\n if (parentParams.some(p => pathParams.includes(p as string))) {\n throw new Error(\n 'SubRouteRef may not have params that overlap with its parent',\n );\n }\n if (!path.startsWith('/')) {\n throw new Error(`SubRouteRef path must start with '/', got '${path}'`);\n }\n if (path.endsWith('/')) {\n throw new Error(`SubRouteRef path must not end with '/', got '${path}'`);\n }\n for (const param of pathParams) {\n if (!PARAM_PATTERN.test(param)) {\n throw new Error(`SubRouteRef path has invalid param, got '${param}'`);\n }\n }\n\n return OpaqueSubRouteRef.createInstance('v1', {\n T: undefined as unknown as TrimEmptyParams<\n MergeParams<Params, ParentParams>\n >,\n path,\n getParams() {\n return params;\n },\n getParent() {\n return parent;\n },\n getDescription() {\n return `at ${path} with parent ${parentDescription}`;\n },\n toString() {\n return `subRouteRef{path='${path}',parent=${parent}}`;\n },\n });\n}\n"],"names":[],"mappings":";;;;AAqBA,MAAM,aAAA,GAAgB,OAAA;AAuFf,SAAS,kBAGd,MAAA,EAGkD;AAClD,EAAA,MAAM,EAAE,IAAA,EAAM,MAAA,EAAO,GAAI,MAAA;AAGzB,EAAA,MAAM,cAAA,GAAiB,cAAA,CAAe,UAAA,CAAW,MAAM,CAAA;AACvD,EAAA,MAAM,YAAA,GAAe,eAAe,SAAA,EAAU;AAC9C,EAAA,MAAM,iBAAA,GAAoB,eAAe,cAAA,EAAe;AAGxD,EAAA,MAAM,aAAa,IAAA,CAChB,KAAA,CAAM,GAAG,CAAA,CACT,OAAO,CAAA,CAAA,KAAK,CAAA,CAAE,UAAA,CAAW,GAAG,CAAC,CAAA,CAC7B,GAAA,CAAI,OAAK,CAAA,CAAE,SAAA,CAAU,CAAC,CAAC,CAAA;AAC1B,EAAA,MAAM,MAAA,GAAS,CAAC,GAAG,YAAA,EAAc,GAAG,UAAU,CAAA;AAE9C,EAAA,IAAI,aAAa,IAAA,CAAK,CAAA,CAAA,KAAK,WAAW,QAAA,CAAS,CAAW,CAAC,CAAA,EAAG;AAC5D,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AACA,EAAA,IAAI,CAAC,IAAA,CAAK,UAAA,CAAW,GAAG,CAAA,EAAG;AACzB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2CAAA,EAA8C,IAAI,CAAA,CAAA,CAAG,CAAA;AAAA,EACvE;AACA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,GAAG,CAAA,EAAG;AACtB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,6CAAA,EAAgD,IAAI,CAAA,CAAA,CAAG,CAAA;AAAA,EACzE;AACA,EAAA,KAAA,MAAW,SAAS,UAAA,EAAY;AAC9B,IAAA,IAAI,CAAC,aAAA,CAAc,IAAA,CAAK,KAAK,CAAA,EAAG;AAC9B,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,yCAAA,EAA4C,KAAK,CAAA,CAAA,CAAG,CAAA;AAAA,IACtE;AAAA,EACF;AAEA,EAAA,OAAO,iBAAA,CAAkB,eAAe,IAAA,EAAM;AAAA,IAC5C,CAAA,EAAG,MAAA;AAAA,IAGH,IAAA;AAAA,IACA,SAAA,GAAY;AACV,MAAA,OAAO,MAAA;AAAA,IACT,CAAA;AAAA,IACA,SAAA,GAAY;AACV,MAAA,OAAO,MAAA;AAAA,IACT,CAAA;AAAA,IACA,cAAA,GAAiB;AACf,MAAA,OAAO,CAAA,GAAA,EAAM,IAAI,CAAA,aAAA,EAAgB,iBAAiB,CAAA,CAAA;AAAA,IACpD,CAAA;AAAA,IACA,QAAA,GAAW;AACT,MAAA,OAAO,CAAA,kBAAA,EAAqB,IAAI,CAAA,SAAA,EAAY,MAAM,CAAA,CAAA,CAAA;AAAA,IACpD;AAAA,GACD,CAAA;AACH;;;;"}
|
|
@@ -14,11 +14,11 @@ function bindInputs(inputs, kind, name) {
|
|
|
14
14
|
return Object.fromEntries(
|
|
15
15
|
Object.entries(inputs).map(([inputName, input]) => [
|
|
16
16
|
inputName,
|
|
17
|
-
OpaqueExtensionInput.toInternal(input).withContext({
|
|
17
|
+
OpaqueExtensionInput.toInternal(input).withContext?.({
|
|
18
18
|
kind,
|
|
19
19
|
name,
|
|
20
20
|
input: inputName
|
|
21
|
-
})
|
|
21
|
+
}) ?? input
|
|
22
22
|
])
|
|
23
23
|
);
|
|
24
24
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createExtension.esm.js","sources":["../../src/wiring/createExtension.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 { ApiHolder, AppNode } from '../apis';\nimport { Expand } from '@backstage/types';\nimport {\n ResolvedInputValueOverrides,\n resolveInputOverrides,\n} from './resolveInputOverrides';\nimport {\n createExtensionDataContainer,\n OpaqueExtensionInput,\n} from '@internal/frontend';\nimport { ExtensionDataRef, ExtensionDataValue } from './createExtensionDataRef';\nimport { ExtensionInput } from './createExtensionInput';\nimport { z } from 'zod';\nimport { createSchemaFromZod } from '../schema/createSchemaFromZod';\nimport { OpaqueExtensionDefinition } from '@internal/frontend';\nimport { ExtensionDataContainer } from './types';\nimport {\n ExtensionBlueprint,\n ExtensionBlueprintDefineParams,\n} from './createExtensionBlueprint';\nimport { FrontendPlugin } from './createFrontendPlugin';\nimport { FrontendModule } from './createFrontendModule';\n\n/**\n * This symbol is used to pass parameter overrides from the extension override to the blueprint factory\n * @internal\n */\nexport const ctxParamsSymbol = Symbol('params');\n\n/**\n * Convert a single extension input into a matching resolved input.\n * @public\n */\nexport type ResolvedExtensionInput<TExtensionInput extends ExtensionInput> =\n TExtensionInput['extensionData'] extends Array<ExtensionDataRef>\n ? {\n node: AppNode;\n } & ExtensionDataContainer<TExtensionInput['extensionData'][number]>\n : never;\n\n/**\n * Converts an extension input map into a matching collection of resolved inputs.\n * @public\n */\nexport type ResolvedExtensionInputs<\n TInputs extends {\n [name in string]: ExtensionInput;\n },\n> = {\n [InputName in keyof TInputs]: false extends TInputs[InputName]['config']['singleton']\n ? Array<Expand<ResolvedExtensionInput<TInputs[InputName]>>>\n : false extends TInputs[InputName]['config']['optional']\n ? Expand<ResolvedExtensionInput<TInputs[InputName]>>\n : Expand<ResolvedExtensionInput<TInputs[InputName]> | undefined>;\n};\n\ntype ToIntersection<U> = (U extends any ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never;\n\ntype PopUnion<U> = ToIntersection<\n U extends any ? () => U : never\n> extends () => infer R\n ? [rest: Exclude<U, R>, next: R]\n : undefined;\n\n/** @ignore */\ntype JoinStringUnion<\n U,\n TDiv extends string = ', ',\n TResult extends string = '',\n> = PopUnion<U> extends [infer IRest extends string, infer INext extends string]\n ? TResult extends ''\n ? JoinStringUnion<IRest, TDiv, INext>\n : JoinStringUnion<IRest, TDiv, `${TResult}${TDiv}${INext}`>\n : TResult;\n\n/** @ignore */\nexport type RequiredExtensionIds<UExtensionData extends ExtensionDataRef> =\n UExtensionData extends any\n ? UExtensionData['config']['optional'] extends true\n ? never\n : UExtensionData['id']\n : never;\n\n/** @ignore */\nexport type VerifyExtensionFactoryOutput<\n UDeclaredOutput extends ExtensionDataRef,\n UFactoryOutput extends ExtensionDataValue<any, any>,\n> = [RequiredExtensionIds<UDeclaredOutput>] extends [UFactoryOutput['id']]\n ? [UFactoryOutput['id']] extends [UDeclaredOutput['id']]\n ? {}\n : `Error: The extension factory has undeclared output(s): ${JoinStringUnion<\n Exclude<UFactoryOutput['id'], UDeclaredOutput['id']>\n >}`\n : `Error: The extension factory is missing the following output(s): ${JoinStringUnion<\n Exclude<RequiredExtensionIds<UDeclaredOutput>, UFactoryOutput['id']>\n >}`;\n\n/** @ignore */\nexport type VerifyExtensionAttachTo<\n UOutput extends ExtensionDataRef,\n UParentInput extends ExtensionDataRef,\n> = ExtensionDataRef extends UParentInput\n ? {}\n : [RequiredExtensionIds<UParentInput>] extends [RequiredExtensionIds<UOutput>]\n ? {}\n : `Error: This parent extension input requires the following extension data, but it is not declared as guaranteed output of this extension: ${JoinStringUnion<\n Exclude<RequiredExtensionIds<UParentInput>, RequiredExtensionIds<UOutput>>\n >}`;\n\n/**\n * Specifies where an extension should attach in the extension tree.\n *\n * @remarks\n *\n * A standard attachment point declaration will specify the ID of the parent extension, as well as the name of the input to attach to.\n *\n * There are three more advanced forms that are available for more complex use-cases:\n *\n * 1. Relative attachment points: using the `relative` property instead of `id`, the attachment point is resolved relative to the current plugin.\n * 2. Extension input references: using a reference in code to another extension's input in the same plugin. These references are always relative.\n * 3. Array of attachment points: an array of attachment points can be used to clone and attach to multiple extensions at once.\n *\n * @example\n * ```ts\n * // Attach to a specific extension by full ID\n * { id: 'app/routes', input: 'routes' }\n *\n * // Attach to an extension in the same plugin by kind\n * { relative: { kind: 'page' }, input: 'actions' }\n *\n * // Attach to a specific input of another extension\n * const page = ParentBlueprint.make({ ... });\n * const child = ChildBlueprint.make({ attachTo: page.inputs.children });\n *\n * // Attach to multiple parents at once\n * [\n * { id: 'page/home', input: 'widgets' },\n * { relative: { kind: 'page' }, input: 'widgets' },\n * ]\n * ```\n *\n * @public\n */\nexport type ExtensionDefinitionAttachTo<\n UParentInputs extends ExtensionDataRef = ExtensionDataRef,\n> =\n | { id: string; input: string; relative?: never }\n | { relative: { kind?: string; name?: string }; input: string; id?: never }\n | ExtensionInput<UParentInputs>\n | Array<\n | { id: string; input: string; relative?: never }\n | {\n relative: { kind?: string; name?: string };\n input: string;\n id?: never;\n }\n | ExtensionInput<UParentInputs>\n >;\n\n/** @public */\nexport type CreateExtensionOptions<\n TKind extends string | undefined,\n TName extends string | undefined,\n UOutput extends ExtensionDataRef,\n TInputs extends { [inputName in string]: ExtensionInput },\n TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodType },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n UParentInputs extends ExtensionDataRef,\n> = {\n kind?: TKind;\n name?: TName;\n attachTo: ExtensionDefinitionAttachTo<UParentInputs> &\n VerifyExtensionAttachTo<UOutput, UParentInputs>;\n disabled?: boolean;\n inputs?: TInputs;\n output: Array<UOutput>;\n config?: {\n schema: TConfigSchema;\n };\n factory(context: {\n node: AppNode;\n apis: ApiHolder;\n config: {\n [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>;\n };\n inputs: Expand<ResolvedExtensionInputs<TInputs>>;\n }): Iterable<UFactoryOutput>;\n} & VerifyExtensionFactoryOutput<UOutput, UFactoryOutput>;\n\n/** @public */\nexport type ExtensionDefinitionParameters = {\n kind?: string;\n name?: string;\n configInput?: { [K in string]: any };\n config?: { [K in string]: any };\n output?: ExtensionDataRef;\n inputs?: { [KName in string]: ExtensionInput };\n params?: object | ExtensionBlueprintDefineParams;\n};\n\n/**\n * Same as the one in `createExtensionBlueprint`, but with `ParamsFactory` inlined.\n * It can't be exported because it breaks API reports.\n * @ignore\n */\ntype AnyParamsInput<TParams extends object | ExtensionBlueprintDefineParams> =\n TParams extends ExtensionBlueprintDefineParams<infer IParams>\n ? IParams | ((define: TParams) => ReturnType<TParams>)\n :\n | TParams\n | ((\n define: ExtensionBlueprintDefineParams<TParams, TParams>,\n ) => ReturnType<ExtensionBlueprintDefineParams<TParams, TParams>>);\n\n/** @public */\nexport type ExtensionDefinition<\n T extends ExtensionDefinitionParameters = ExtensionDefinitionParameters,\n> = {\n $$type: '@backstage/ExtensionDefinition';\n readonly T: T;\n\n /**\n * References to the inputs of this extension, which can be used to attach child extensions.\n */\n readonly inputs: {\n [K in keyof T['inputs']]: ExtensionInput<\n T['inputs'][K] extends ExtensionInput<infer IData> ? IData : never\n >;\n };\n\n override<\n TExtensionConfigSchema extends {\n [key in string]: (zImpl: typeof z) => z.ZodType;\n },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n UNewOutput extends ExtensionDataRef,\n TExtraInputs extends { [inputName in string]: ExtensionInput },\n TParamsInput extends AnyParamsInput<NonNullable<T['params']>>,\n UParentInputs extends ExtensionDataRef,\n >(\n args: Expand<\n {\n attachTo?: ExtensionDefinitionAttachTo<UParentInputs> &\n VerifyExtensionAttachTo<\n ExtensionDataRef extends UNewOutput\n ? NonNullable<T['output']>\n : UNewOutput,\n UParentInputs\n >;\n disabled?: boolean;\n inputs?: TExtraInputs & {\n [KName in keyof T['inputs']]?: `Error: Input '${KName &\n string}' is already defined in parent definition`;\n };\n output?: Array<UNewOutput>;\n config?: {\n schema: TExtensionConfigSchema & {\n [KName in keyof T['config']]?: `Error: Config key '${KName &\n string}' is already defined in parent schema`;\n };\n };\n factory?(\n originalFactory: <\n TFactoryParamsReturn extends AnyParamsInput<\n NonNullable<T['params']>\n >,\n >(\n context?: Expand<\n {\n config?: T['config'];\n inputs?: ResolvedInputValueOverrides<NonNullable<T['inputs']>>;\n } & ([T['params']] extends [never]\n ? {}\n : {\n params?: TFactoryParamsReturn extends ExtensionBlueprintDefineParams\n ? TFactoryParamsReturn\n : T['params'] extends ExtensionBlueprintDefineParams\n ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(defineParams => defineParams(<params>))`'\n : Partial<T['params']>;\n })\n >,\n ) => ExtensionDataContainer<NonNullable<T['output']>>,\n context: {\n node: AppNode;\n apis: ApiHolder;\n config: T['config'] & {\n [key in keyof TExtensionConfigSchema]: z.infer<\n ReturnType<TExtensionConfigSchema[key]>\n >;\n };\n inputs: Expand<ResolvedExtensionInputs<T['inputs'] & TExtraInputs>>;\n },\n ): Iterable<UFactoryOutput>;\n } & ([T['params']] extends [never]\n ? {}\n : {\n params?: TParamsInput extends ExtensionBlueprintDefineParams\n ? TParamsInput\n : T['params'] extends ExtensionBlueprintDefineParams\n ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(defineParams => defineParams(<params>))`'\n : Partial<T['params']>;\n })\n > &\n VerifyExtensionFactoryOutput<\n ExtensionDataRef extends UNewOutput\n ? NonNullable<T['output']>\n : UNewOutput,\n UFactoryOutput\n >,\n ): ExtensionDefinition<{\n kind: T['kind'];\n name: T['name'];\n output: ExtensionDataRef extends UNewOutput ? T['output'] : UNewOutput;\n inputs: T['inputs'] & TExtraInputs;\n config: T['config'] & {\n [key in keyof TExtensionConfigSchema]: z.infer<\n ReturnType<TExtensionConfigSchema[key]>\n >;\n };\n configInput: T['configInput'] &\n z.input<\n z.ZodObject<{\n [key in keyof TExtensionConfigSchema]: ReturnType<\n TExtensionConfigSchema[key]\n >;\n }>\n >;\n }>;\n};\n\n/**\n * @internal\n */\nfunction bindInputs(\n inputs: { [inputName in string]: ExtensionInput } | undefined,\n kind?: string,\n name?: string,\n) {\n if (!inputs) {\n return {};\n }\n\n return Object.fromEntries(\n Object.entries(inputs).map(([inputName, input]) => [\n inputName,\n OpaqueExtensionInput.toInternal(input).withContext({\n kind,\n name,\n input: inputName,\n }),\n ]),\n );\n}\n\n/**\n * Creates a new extension definition for installation in a Backstage app.\n *\n * @remarks\n *\n * This is a low-level function for creation of extensions with arbitrary inputs\n * and outputs and is typically only intended to be used for advanced overrides\n * or framework-level extensions. For most extension creation needs, it is\n * recommended to use existing {@link ExtensionBlueprint}s instead. You can find\n * blueprints both in the `@backstage/frontend-plugin-api` package as well as\n * other plugin libraries. There is also a list of\n * {@link https://backstage.io/docs/frontend-system/building-plugins/common-extension-blueprints | commonly used blueprints}\n * in the frontend system documentation.\n *\n * Extension definitions that are created with this function can be installed in\n * a Backstage app via a {@link FrontendPlugin} or {@link FrontendModule}.\n *\n * For more details on how extensions work, see the\n * {@link https://backstage.io/docs/frontend-system/architecture/extensions | documentation for extensions}.\n *\n * @example\n *\n * ```ts\n * const myExtension = createExtension({\n * name: 'example',\n * attachTo: { id: 'app', input: 'root' },\n * output: [coreExtensionData.reactElement],\n * factory() {\n * return [coreExtensionData.reactElement(<h1>Hello, world!</h1>)];\n * },\n * });\n * ```\n *\n * @public\n */\nexport function createExtension<\n UOutput extends ExtensionDataRef,\n TInputs extends { [inputName in string]: ExtensionInput },\n TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodType },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n const TKind extends string | undefined = undefined,\n const TName extends string | undefined = undefined,\n UParentInputs extends ExtensionDataRef = ExtensionDataRef,\n>(\n options: CreateExtensionOptions<\n TKind,\n TName,\n UOutput,\n TInputs,\n TConfigSchema,\n UFactoryOutput,\n UParentInputs\n >,\n): ExtensionDefinition<{\n config: string extends keyof TConfigSchema\n ? {}\n : {\n [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>;\n };\n configInput: string extends keyof TConfigSchema\n ? {}\n : z.input<\n z.ZodObject<{\n [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;\n }>\n >;\n // This inference and remapping back to ExtensionDataRef eliminates any occurrences ConfigurationExtensionDataRef\n output: UOutput extends ExtensionDataRef<\n infer IData,\n infer IId,\n infer IConfig\n >\n ? ExtensionDataRef<IData, IId, IConfig>\n : never;\n inputs: TInputs;\n params: never;\n kind: string | undefined extends TKind ? undefined : TKind;\n name: string | undefined extends TName ? undefined : TName;\n}> {\n const schemaDeclaration = options.config?.schema;\n const configSchema =\n schemaDeclaration &&\n createSchemaFromZod(innerZ =>\n innerZ.object(\n Object.fromEntries(\n Object.entries(schemaDeclaration).map(([k, v]) => [k, v(innerZ)]),\n ),\n ),\n );\n\n return OpaqueExtensionDefinition.createInstance('v2', {\n T: undefined as unknown as {\n config: string extends keyof TConfigSchema\n ? {}\n : {\n [key in keyof TConfigSchema]: z.infer<\n ReturnType<TConfigSchema[key]>\n >;\n };\n configInput: string extends keyof TConfigSchema\n ? {}\n : z.input<\n z.ZodObject<{\n [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;\n }>\n >;\n output: UOutput;\n inputs: TInputs;\n kind: string | undefined extends TKind ? undefined : TKind;\n name: string | undefined extends TName ? undefined : TName;\n },\n kind: options.kind,\n name: options.name,\n attachTo: options.attachTo,\n disabled: options.disabled ?? false,\n inputs: bindInputs(options.inputs, options.kind, options.name),\n output: options.output,\n configSchema,\n factory: options.factory,\n toString() {\n const parts: string[] = [];\n if (options.kind) {\n parts.push(`kind=${options.kind}`);\n }\n if (options.name) {\n parts.push(`name=${options.name}`);\n }\n const attachTo = [options.attachTo]\n .flat()\n .map(aAny => {\n const a = aAny as ExtensionDefinitionAttachTo;\n if (OpaqueExtensionInput.isType(a)) {\n const { context } = OpaqueExtensionInput.toInternal(a);\n if (!context) {\n return '<detached-input>';\n }\n let id = '<plugin>';\n if (context?.kind) {\n id = `${context?.kind}:${id}`;\n }\n if (context?.name) {\n id = `${id}/${context?.name}`;\n }\n return `${id}@${context.input}`;\n }\n if ('relative' in a && a.relative) {\n let id = '<plugin>';\n if (a.relative.kind) {\n id = `${a.relative.kind}:${id}`;\n }\n if (a.relative.name) {\n id = `${id}/${a.relative.name}`;\n }\n return `${id}@${a.input}`;\n }\n if ('id' in a) {\n return `${a.id}@${a.input}`;\n }\n throw new Error('Invalid attachment point specification');\n })\n .join('+');\n parts.push(`attachTo=${attachTo}`);\n return `ExtensionDefinition{${parts.join(',')}}`;\n },\n override(overrideOptions) {\n if (!Array.isArray(options.output)) {\n throw new Error(\n 'Cannot override an extension that is not declared using the new format with outputs as an array',\n );\n }\n\n // TODO(Rugvip): Making this a type check would be optimal, but it seems\n // like it's tricky to add that and still have the type\n // inference work correctly for the factory output.\n if (overrideOptions.output && !overrideOptions.factory) {\n throw new Error(\n 'Refused to override output without also overriding factory',\n );\n }\n // TODO(Rugvip): Similar to above, would be nice to error during type checking, but don't want to complicate the types too much\n if (overrideOptions.params && overrideOptions.factory) {\n throw new Error(\n 'Refused to override params and factory at the same time',\n );\n }\n\n return createExtension({\n kind: options.kind,\n name: options.name,\n attachTo: (overrideOptions.attachTo ??\n options.attachTo) as ExtensionDefinitionAttachTo,\n disabled: overrideOptions.disabled ?? options.disabled,\n inputs: bindInputs(\n {\n ...(options.inputs ?? {}),\n ...(overrideOptions.inputs ?? {}),\n },\n options.kind,\n options.name,\n ),\n output: (overrideOptions.output ??\n options.output) as ExtensionDataRef[],\n config:\n options.config || overrideOptions.config\n ? {\n schema: {\n ...options.config?.schema,\n ...overrideOptions.config?.schema,\n },\n }\n : undefined,\n factory: ({ node, apis, config, inputs }) => {\n if (!overrideOptions.factory) {\n return options.factory({\n node,\n apis,\n config: config as any,\n inputs: inputs as any,\n [ctxParamsSymbol as any]: overrideOptions.params,\n });\n }\n const parentResult = overrideOptions.factory(\n (innerContext): ExtensionDataContainer<UOutput> => {\n return createExtensionDataContainer<UOutput>(\n options.factory({\n node,\n apis,\n config: (innerContext?.config ?? config) as any,\n inputs: resolveInputOverrides(\n options.inputs,\n inputs,\n innerContext?.inputs,\n ) as any,\n [ctxParamsSymbol as any]: innerContext?.params,\n }) as Iterable<any>,\n 'original extension factory',\n options.output,\n );\n },\n {\n node,\n apis,\n config: config as any,\n inputs: inputs as any,\n },\n );\n\n if (\n typeof parentResult !== 'object' ||\n !parentResult?.[Symbol.iterator]\n ) {\n throw new Error(\n 'extension factory override did not provide an iterable object',\n );\n }\n\n const deduplicatedResult = new Map<\n string,\n ExtensionDataValue<any, any>\n >();\n for (const item of parentResult) {\n deduplicatedResult.set(item.id, item);\n }\n\n return deduplicatedResult.values();\n },\n }) as ExtensionDefinition<any>;\n },\n });\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createExtension.esm.js","sources":["../../src/wiring/createExtension.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 { ApiHolder, AppNode } from '../apis';\nimport { Expand } from '@backstage/types';\nimport {\n ResolvedInputValueOverrides,\n resolveInputOverrides,\n} from './resolveInputOverrides';\nimport {\n createExtensionDataContainer,\n OpaqueExtensionInput,\n} from '@internal/frontend';\nimport { ExtensionDataRef, ExtensionDataValue } from './createExtensionDataRef';\nimport { ExtensionInput } from './createExtensionInput';\nimport { z } from 'zod';\nimport { createSchemaFromZod } from '../schema/createSchemaFromZod';\nimport { OpaqueExtensionDefinition } from '@internal/frontend';\nimport { ExtensionDataContainer } from './types';\nimport {\n ExtensionBlueprint,\n ExtensionBlueprintDefineParams,\n} from './createExtensionBlueprint';\nimport { FrontendPlugin } from './createFrontendPlugin';\nimport { FrontendModule } from './createFrontendModule';\n\n/**\n * This symbol is used to pass parameter overrides from the extension override to the blueprint factory\n * @internal\n */\nexport const ctxParamsSymbol = Symbol('params');\n\n/**\n * Convert a single extension input into a matching resolved input.\n * @public\n */\nexport type ResolvedExtensionInput<TExtensionInput extends ExtensionInput> =\n TExtensionInput['extensionData'] extends Array<ExtensionDataRef>\n ? {\n node: AppNode;\n } & ExtensionDataContainer<TExtensionInput['extensionData'][number]>\n : never;\n\n/**\n * Converts an extension input map into a matching collection of resolved inputs.\n * @public\n */\nexport type ResolvedExtensionInputs<\n TInputs extends {\n [name in string]: ExtensionInput;\n },\n> = {\n [InputName in keyof TInputs]: false extends TInputs[InputName]['config']['singleton']\n ? Array<Expand<ResolvedExtensionInput<TInputs[InputName]>>>\n : false extends TInputs[InputName]['config']['optional']\n ? Expand<ResolvedExtensionInput<TInputs[InputName]>>\n : Expand<ResolvedExtensionInput<TInputs[InputName]> | undefined>;\n};\n\ntype ToIntersection<U> = (U extends any ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never;\n\ntype PopUnion<U> = ToIntersection<\n U extends any ? () => U : never\n> extends () => infer R\n ? [rest: Exclude<U, R>, next: R]\n : undefined;\n\n/** @ignore */\ntype JoinStringUnion<\n U,\n TDiv extends string = ', ',\n TResult extends string = '',\n> = PopUnion<U> extends [infer IRest extends string, infer INext extends string]\n ? TResult extends ''\n ? JoinStringUnion<IRest, TDiv, INext>\n : JoinStringUnion<IRest, TDiv, `${TResult}${TDiv}${INext}`>\n : TResult;\n\n/** @ignore */\nexport type RequiredExtensionIds<UExtensionData extends ExtensionDataRef> =\n UExtensionData extends any\n ? UExtensionData['config']['optional'] extends true\n ? never\n : UExtensionData['id']\n : never;\n\n/** @ignore */\nexport type VerifyExtensionFactoryOutput<\n UDeclaredOutput extends ExtensionDataRef,\n UFactoryOutput extends ExtensionDataValue<any, any>,\n> = [RequiredExtensionIds<UDeclaredOutput>] extends [UFactoryOutput['id']]\n ? [UFactoryOutput['id']] extends [UDeclaredOutput['id']]\n ? {}\n : `Error: The extension factory has undeclared output(s): ${JoinStringUnion<\n Exclude<UFactoryOutput['id'], UDeclaredOutput['id']>\n >}`\n : `Error: The extension factory is missing the following output(s): ${JoinStringUnion<\n Exclude<RequiredExtensionIds<UDeclaredOutput>, UFactoryOutput['id']>\n >}`;\n\n/** @ignore */\nexport type VerifyExtensionAttachTo<\n UOutput extends ExtensionDataRef,\n UParentInput extends ExtensionDataRef,\n> = ExtensionDataRef extends UParentInput\n ? {}\n : [RequiredExtensionIds<UParentInput>] extends [RequiredExtensionIds<UOutput>]\n ? {}\n : `Error: This parent extension input requires the following extension data, but it is not declared as guaranteed output of this extension: ${JoinStringUnion<\n Exclude<RequiredExtensionIds<UParentInput>, RequiredExtensionIds<UOutput>>\n >}`;\n\n/**\n * Specifies where an extension should attach in the extension tree.\n *\n * @remarks\n *\n * A standard attachment point declaration will specify the ID of the parent extension, as well as the name of the input to attach to.\n *\n * There are three more advanced forms that are available for more complex use-cases:\n *\n * 1. Relative attachment points: using the `relative` property instead of `id`, the attachment point is resolved relative to the current plugin.\n * 2. Extension input references: using a reference in code to another extension's input in the same plugin. These references are always relative.\n * 3. Array of attachment points: an array of attachment points can be used to clone and attach to multiple extensions at once.\n *\n * @example\n * ```ts\n * // Attach to a specific extension by full ID\n * { id: 'app/routes', input: 'routes' }\n *\n * // Attach to an extension in the same plugin by kind\n * { relative: { kind: 'page' }, input: 'actions' }\n *\n * // Attach to a specific input of another extension\n * const page = ParentBlueprint.make({ ... });\n * const child = ChildBlueprint.make({ attachTo: page.inputs.children });\n *\n * // Attach to multiple parents at once\n * [\n * { id: 'page/home', input: 'widgets' },\n * { relative: { kind: 'page' }, input: 'widgets' },\n * ]\n * ```\n *\n * @public\n */\nexport type ExtensionDefinitionAttachTo<\n UParentInputs extends ExtensionDataRef = ExtensionDataRef,\n> =\n | { id: string; input: string; relative?: never }\n | { relative: { kind?: string; name?: string }; input: string; id?: never }\n | ExtensionInput<UParentInputs>\n | Array<\n | { id: string; input: string; relative?: never }\n | {\n relative: { kind?: string; name?: string };\n input: string;\n id?: never;\n }\n | ExtensionInput<UParentInputs>\n >;\n\n/** @public */\nexport type CreateExtensionOptions<\n TKind extends string | undefined,\n TName extends string | undefined,\n UOutput extends ExtensionDataRef,\n TInputs extends { [inputName in string]: ExtensionInput },\n TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodType },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n UParentInputs extends ExtensionDataRef,\n> = {\n kind?: TKind;\n name?: TName;\n attachTo: ExtensionDefinitionAttachTo<UParentInputs> &\n VerifyExtensionAttachTo<UOutput, UParentInputs>;\n disabled?: boolean;\n inputs?: TInputs;\n output: Array<UOutput>;\n config?: {\n schema: TConfigSchema;\n };\n factory(context: {\n node: AppNode;\n apis: ApiHolder;\n config: {\n [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>;\n };\n inputs: Expand<ResolvedExtensionInputs<TInputs>>;\n }): Iterable<UFactoryOutput>;\n} & VerifyExtensionFactoryOutput<UOutput, UFactoryOutput>;\n\n/** @public */\nexport type ExtensionDefinitionParameters = {\n kind?: string;\n name?: string;\n configInput?: { [K in string]: any };\n config?: { [K in string]: any };\n output?: ExtensionDataRef;\n inputs?: { [KName in string]: ExtensionInput };\n params?: object | ExtensionBlueprintDefineParams;\n};\n\n/**\n * Same as the one in `createExtensionBlueprint`, but with `ParamsFactory` inlined.\n * It can't be exported because it breaks API reports.\n * @ignore\n */\ntype AnyParamsInput<TParams extends object | ExtensionBlueprintDefineParams> =\n TParams extends ExtensionBlueprintDefineParams<infer IParams>\n ? IParams | ((define: TParams) => ReturnType<TParams>)\n :\n | TParams\n | ((\n define: ExtensionBlueprintDefineParams<TParams, TParams>,\n ) => ReturnType<ExtensionBlueprintDefineParams<TParams, TParams>>);\n\n/** @public */\nexport interface ExtensionDefinition<\n TParams extends ExtensionDefinitionParameters = ExtensionDefinitionParameters,\n> {\n $$type: '@backstage/ExtensionDefinition';\n readonly T: TParams;\n}\n\n/** @public */\nexport interface OverridableExtensionDefinition<\n T extends ExtensionDefinitionParameters = ExtensionDefinitionParameters,\n> extends ExtensionDefinition<T> {\n /**\n * References to the inputs of this extension, which can be used to attach child extensions.\n */\n readonly inputs: {\n [K in keyof T['inputs']]: ExtensionInput<\n T['inputs'][K] extends ExtensionInput<infer IData> ? IData : never\n >;\n };\n\n override<\n TExtensionConfigSchema extends {\n [key in string]: (zImpl: typeof z) => z.ZodType;\n },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n UNewOutput extends ExtensionDataRef,\n TExtraInputs extends { [inputName in string]: ExtensionInput },\n TParamsInput extends AnyParamsInput<NonNullable<T['params']>>,\n UParentInputs extends ExtensionDataRef,\n >(\n args: Expand<\n {\n attachTo?: ExtensionDefinitionAttachTo<UParentInputs> &\n VerifyExtensionAttachTo<\n ExtensionDataRef extends UNewOutput\n ? NonNullable<T['output']>\n : UNewOutput,\n UParentInputs\n >;\n disabled?: boolean;\n inputs?: TExtraInputs & {\n [KName in keyof T['inputs']]?: `Error: Input '${KName &\n string}' is already defined in parent definition`;\n };\n output?: Array<UNewOutput>;\n config?: {\n schema: TExtensionConfigSchema & {\n [KName in keyof T['config']]?: `Error: Config key '${KName &\n string}' is already defined in parent schema`;\n };\n };\n factory?(\n originalFactory: <\n TFactoryParamsReturn extends AnyParamsInput<\n NonNullable<T['params']>\n >,\n >(\n context?: Expand<\n {\n config?: T['config'];\n inputs?: ResolvedInputValueOverrides<NonNullable<T['inputs']>>;\n } & ([T['params']] extends [never]\n ? {}\n : {\n params?: TFactoryParamsReturn extends ExtensionBlueprintDefineParams\n ? TFactoryParamsReturn\n : T['params'] extends ExtensionBlueprintDefineParams\n ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(defineParams => defineParams(<params>))`'\n : Partial<T['params']>;\n })\n >,\n ) => ExtensionDataContainer<NonNullable<T['output']>>,\n context: {\n node: AppNode;\n apis: ApiHolder;\n config: T['config'] & {\n [key in keyof TExtensionConfigSchema]: z.infer<\n ReturnType<TExtensionConfigSchema[key]>\n >;\n };\n inputs: Expand<ResolvedExtensionInputs<T['inputs'] & TExtraInputs>>;\n },\n ): Iterable<UFactoryOutput>;\n } & ([T['params']] extends [never]\n ? {}\n : {\n params?: TParamsInput extends ExtensionBlueprintDefineParams\n ? TParamsInput\n : T['params'] extends ExtensionBlueprintDefineParams\n ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(defineParams => defineParams(<params>))`'\n : Partial<T['params']>;\n })\n > &\n VerifyExtensionFactoryOutput<\n ExtensionDataRef extends UNewOutput\n ? NonNullable<T['output']>\n : UNewOutput,\n UFactoryOutput\n >,\n ): OverridableExtensionDefinition<{\n kind: T['kind'];\n name: T['name'];\n output: ExtensionDataRef extends UNewOutput ? T['output'] : UNewOutput;\n inputs: T['inputs'] & TExtraInputs;\n config: T['config'] & {\n [key in keyof TExtensionConfigSchema]: z.infer<\n ReturnType<TExtensionConfigSchema[key]>\n >;\n };\n configInput: T['configInput'] &\n z.input<\n z.ZodObject<{\n [key in keyof TExtensionConfigSchema]: ReturnType<\n TExtensionConfigSchema[key]\n >;\n }>\n >;\n }>;\n}\n\n/**\n * @internal\n */\nfunction bindInputs(\n inputs: { [inputName in string]: ExtensionInput } | undefined,\n kind?: string,\n name?: string,\n) {\n if (!inputs) {\n return {};\n }\n\n return Object.fromEntries(\n Object.entries(inputs).map(([inputName, input]) => [\n inputName,\n OpaqueExtensionInput.toInternal(input).withContext?.({\n kind,\n name,\n input: inputName,\n }) ?? input,\n ]),\n );\n}\n\n/**\n * Creates a new extension definition for installation in a Backstage app.\n *\n * @remarks\n *\n * This is a low-level function for creation of extensions with arbitrary inputs\n * and outputs and is typically only intended to be used for advanced overrides\n * or framework-level extensions. For most extension creation needs, it is\n * recommended to use existing {@link ExtensionBlueprint}s instead. You can find\n * blueprints both in the `@backstage/frontend-plugin-api` package as well as\n * other plugin libraries. There is also a list of\n * {@link https://backstage.io/docs/frontend-system/building-plugins/common-extension-blueprints | commonly used blueprints}\n * in the frontend system documentation.\n *\n * Extension definitions that are created with this function can be installed in\n * a Backstage app via a {@link FrontendPlugin} or {@link FrontendModule}.\n *\n * For more details on how extensions work, see the\n * {@link https://backstage.io/docs/frontend-system/architecture/extensions | documentation for extensions}.\n *\n * @example\n *\n * ```ts\n * const myExtension = createExtension({\n * name: 'example',\n * attachTo: { id: 'app', input: 'root' },\n * output: [coreExtensionData.reactElement],\n * factory() {\n * return [coreExtensionData.reactElement(<h1>Hello, world!</h1>)];\n * },\n * });\n * ```\n *\n * @public\n */\nexport function createExtension<\n UOutput extends ExtensionDataRef,\n TInputs extends { [inputName in string]: ExtensionInput },\n TConfigSchema extends { [key: string]: (zImpl: typeof z) => z.ZodType },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n const TKind extends string | undefined = undefined,\n const TName extends string | undefined = undefined,\n UParentInputs extends ExtensionDataRef = ExtensionDataRef,\n>(\n options: CreateExtensionOptions<\n TKind,\n TName,\n UOutput,\n TInputs,\n TConfigSchema,\n UFactoryOutput,\n UParentInputs\n >,\n): OverridableExtensionDefinition<{\n config: string extends keyof TConfigSchema\n ? {}\n : {\n [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>;\n };\n configInput: string extends keyof TConfigSchema\n ? {}\n : z.input<\n z.ZodObject<{\n [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;\n }>\n >;\n // This inference and remapping back to ExtensionDataRef eliminates any occurrences ConfigurationExtensionDataRef\n output: UOutput extends ExtensionDataRef<\n infer IData,\n infer IId,\n infer IConfig\n >\n ? ExtensionDataRef<IData, IId, IConfig>\n : never;\n inputs: TInputs;\n params: never;\n kind: string | undefined extends TKind ? undefined : TKind;\n name: string | undefined extends TName ? undefined : TName;\n}> {\n const schemaDeclaration = options.config?.schema;\n const configSchema =\n schemaDeclaration &&\n createSchemaFromZod(innerZ =>\n innerZ.object(\n Object.fromEntries(\n Object.entries(schemaDeclaration).map(([k, v]) => [k, v(innerZ)]),\n ),\n ),\n );\n\n return OpaqueExtensionDefinition.createInstance('v2', {\n T: undefined as unknown as {\n config: string extends keyof TConfigSchema\n ? {}\n : {\n [key in keyof TConfigSchema]: z.infer<\n ReturnType<TConfigSchema[key]>\n >;\n };\n configInput: string extends keyof TConfigSchema\n ? {}\n : z.input<\n z.ZodObject<{\n [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;\n }>\n >;\n output: UOutput;\n inputs: TInputs;\n kind: string | undefined extends TKind ? undefined : TKind;\n name: string | undefined extends TName ? undefined : TName;\n },\n kind: options.kind,\n name: options.name,\n attachTo: options.attachTo,\n disabled: options.disabled ?? false,\n inputs: bindInputs(options.inputs, options.kind, options.name),\n output: options.output,\n configSchema,\n factory: options.factory,\n toString() {\n const parts: string[] = [];\n if (options.kind) {\n parts.push(`kind=${options.kind}`);\n }\n if (options.name) {\n parts.push(`name=${options.name}`);\n }\n const attachTo = [options.attachTo]\n .flat()\n .map(aAny => {\n const a = aAny as ExtensionDefinitionAttachTo;\n if (OpaqueExtensionInput.isType(a)) {\n const { context } = OpaqueExtensionInput.toInternal(a);\n if (!context) {\n return '<detached-input>';\n }\n let id = '<plugin>';\n if (context?.kind) {\n id = `${context?.kind}:${id}`;\n }\n if (context?.name) {\n id = `${id}/${context?.name}`;\n }\n return `${id}@${context.input}`;\n }\n if ('relative' in a && a.relative) {\n let id = '<plugin>';\n if (a.relative.kind) {\n id = `${a.relative.kind}:${id}`;\n }\n if (a.relative.name) {\n id = `${id}/${a.relative.name}`;\n }\n return `${id}@${a.input}`;\n }\n if ('id' in a) {\n return `${a.id}@${a.input}`;\n }\n throw new Error('Invalid attachment point specification');\n })\n .join('+');\n parts.push(`attachTo=${attachTo}`);\n return `ExtensionDefinition{${parts.join(',')}}`;\n },\n override(overrideOptions) {\n if (!Array.isArray(options.output)) {\n throw new Error(\n 'Cannot override an extension that is not declared using the new format with outputs as an array',\n );\n }\n\n // TODO(Rugvip): Making this a type check would be optimal, but it seems\n // like it's tricky to add that and still have the type\n // inference work correctly for the factory output.\n if (overrideOptions.output && !overrideOptions.factory) {\n throw new Error(\n 'Refused to override output without also overriding factory',\n );\n }\n // TODO(Rugvip): Similar to above, would be nice to error during type checking, but don't want to complicate the types too much\n if (overrideOptions.params && overrideOptions.factory) {\n throw new Error(\n 'Refused to override params and factory at the same time',\n );\n }\n\n return createExtension({\n kind: options.kind,\n name: options.name,\n attachTo: (overrideOptions.attachTo ??\n options.attachTo) as ExtensionDefinitionAttachTo,\n disabled: overrideOptions.disabled ?? options.disabled,\n inputs: bindInputs(\n {\n ...(options.inputs ?? {}),\n ...(overrideOptions.inputs ?? {}),\n },\n options.kind,\n options.name,\n ),\n output: (overrideOptions.output ??\n options.output) as ExtensionDataRef[],\n config:\n options.config || overrideOptions.config\n ? {\n schema: {\n ...options.config?.schema,\n ...overrideOptions.config?.schema,\n },\n }\n : undefined,\n factory: ({ node, apis, config, inputs }) => {\n if (!overrideOptions.factory) {\n return options.factory({\n node,\n apis,\n config: config as any,\n inputs: inputs as any,\n [ctxParamsSymbol as any]: overrideOptions.params,\n });\n }\n const parentResult = overrideOptions.factory(\n (innerContext): ExtensionDataContainer<UOutput> => {\n return createExtensionDataContainer<UOutput>(\n options.factory({\n node,\n apis,\n config: (innerContext?.config ?? config) as any,\n inputs: resolveInputOverrides(\n options.inputs,\n inputs,\n innerContext?.inputs,\n ) as any,\n [ctxParamsSymbol as any]: innerContext?.params,\n }) as Iterable<any>,\n 'original extension factory',\n options.output,\n );\n },\n {\n node,\n apis,\n config: config as any,\n inputs: inputs as any,\n },\n );\n\n if (\n typeof parentResult !== 'object' ||\n !parentResult?.[Symbol.iterator]\n ) {\n throw new Error(\n 'extension factory override did not provide an iterable object',\n );\n }\n\n const deduplicatedResult = new Map<\n string,\n ExtensionDataValue<any, any>\n >();\n for (const item of parentResult) {\n deduplicatedResult.set(item.id, item);\n }\n\n return deduplicatedResult.values();\n },\n }) as OverridableExtensionDefinition<any>;\n },\n });\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createExtensionBlueprint.esm.js","sources":["../../src/wiring/createExtensionBlueprint.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ApiHolder, AppNode } from '../apis';\nimport { Expand } from '@backstage/types';\nimport { OpaqueType } from '@internal/opaque';\nimport {\n ExtensionDefinitionAttachTo,\n ExtensionDefinition,\n ResolvedExtensionInputs,\n VerifyExtensionFactoryOutput,\n createExtension,\n ctxParamsSymbol,\n VerifyExtensionAttachTo,\n} from './createExtension';\nimport { z } from 'zod';\nimport { ExtensionInput } from './createExtensionInput';\nimport { ExtensionDataRef, ExtensionDataValue } from './createExtensionDataRef';\nimport { createExtensionDataContainer } from '@internal/frontend';\nimport {\n ResolvedInputValueOverrides,\n resolveInputOverrides,\n} from './resolveInputOverrides';\nimport { ExtensionDataContainer } from './types';\nimport { PageBlueprint } from '../blueprints/PageBlueprint';\n\n/**\n * A function used to define a parameter mapping function in order to facilitate\n * advanced parameter typing for extension blueprints.\n *\n * @remarks\n *\n * This function is primarily intended to enable the use of inferred type\n * parameters for blueprint params, but it can also be used to transoform the\n * params before they are handed ot the blueprint.\n *\n * The function must return an object created with\n * {@link createExtensionBlueprintParams}.\n *\n * @public\n */\nexport type ExtensionBlueprintDefineParams<\n TParams extends object = object,\n TInput = any,\n> = (params: TInput) => ExtensionBlueprintParams<TParams>;\n\n/**\n * An opaque type that represents a set of parameters to be passed to a blueprint.\n *\n * @remarks\n *\n * Created with {@link createExtensionBlueprintParams}.\n *\n * @public\n */\nexport type ExtensionBlueprintParams<T extends object = object> = {\n $$type: '@backstage/BlueprintParams';\n T: T;\n};\n\nconst OpaqueBlueprintParams = OpaqueType.create<{\n public: ExtensionBlueprintParams;\n versions: {\n version: 'v1';\n params: object;\n };\n}>({\n type: '@backstage/BlueprintParams',\n versions: ['v1'],\n});\n\n/**\n * Wraps a plain blueprint parameter object in an opaque {@link ExtensionBlueprintParams} object.\n *\n * This is used in the definition of the `defineParams` option of {@link ExtensionBlueprint}.\n *\n * @public\n * @param params - The plain blueprint parameter object to wrap.\n * @returns The wrapped blueprint parameter object.\n */\nexport function createExtensionBlueprintParams<T extends object = object>(\n params: T,\n): ExtensionBlueprintParams<T> {\n return OpaqueBlueprintParams.createInstance('v1', { T: null as any, params });\n}\n\n/**\n * @public\n */\nexport type CreateExtensionBlueprintOptions<\n TKind extends string,\n TParams extends object | ExtensionBlueprintDefineParams,\n UOutput extends ExtensionDataRef,\n TInputs extends { [inputName in string]: ExtensionInput },\n TConfigSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n TDataRefs extends { [name in string]: ExtensionDataRef },\n UParentInputs extends ExtensionDataRef,\n> = {\n kind: TKind;\n attachTo: ExtensionDefinitionAttachTo<UParentInputs> &\n VerifyExtensionAttachTo<UOutput, UParentInputs>;\n disabled?: boolean;\n inputs?: TInputs;\n output: Array<UOutput>;\n config?: {\n schema: TConfigSchema;\n };\n /**\n * This option is used to further refine the blueprint params. When this\n * option is used, the blueprint will require params to be passed in callback\n * form. This function can both transform the params before they are handed to\n * the blueprint factory, but importantly it also allows you to define\n * inferred type parameters for your blueprint params.\n *\n * @example\n * Blueprint definition with inferred type parameters:\n * ```ts\n * const ExampleBlueprint = createExtensionBlueprint({\n * kind: 'example',\n * attachTo: { id: 'example', input: 'example' },\n * output: [exampleComponentDataRef, exampleFetcherDataRef],\n * defineParams<T>(params: {\n * component(props: ExampleProps<T>): JSX.Element | null\n * fetcher(options: FetchOptions): Promise<FetchResult<T>>\n * }) {\n * return createExtensionBlueprintParams(params);\n * },\n * *factory(params) {\n * yield exampleComponentDataRef(params.component)\n * yield exampleFetcherDataRef(params.fetcher)\n * },\n * });\n * ```\n *\n * @example\n * Usage of the above example blueprint:\n * ```ts\n * const example = ExampleBlueprint.make({\n * params: defineParams => defineParams({\n * component: ...,\n * fetcher: ...,\n * }),\n * });\n * ```\n */\n defineParams?: TParams extends ExtensionBlueprintDefineParams\n ? TParams\n : 'The defineParams option must be a function if provided, see the docs for details';\n factory(\n params: TParams extends ExtensionBlueprintDefineParams\n ? ReturnType<TParams>['T']\n : TParams,\n context: {\n node: AppNode;\n apis: ApiHolder;\n config: {\n [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>;\n };\n inputs: Expand<ResolvedExtensionInputs<TInputs>>;\n },\n ): Iterable<UFactoryOutput>;\n\n dataRefs?: TDataRefs;\n} & VerifyExtensionFactoryOutput<UOutput, UFactoryOutput>;\n\n/** @public */\nexport type ExtensionBlueprintParameters = {\n kind: string;\n params?: object | ExtensionBlueprintDefineParams;\n configInput?: { [K in string]: any };\n config?: { [K in string]: any };\n output?: ExtensionDataRef;\n inputs?: { [KName in string]: ExtensionInput };\n dataRefs?: { [name in string]: ExtensionDataRef };\n};\n\n/** @ignore */\ntype ParamsFactory<TDefiner extends ExtensionBlueprintDefineParams> = (\n defineParams: TDefiner,\n) => ReturnType<TDefiner>;\n\n/**\n * Represents any form of params input that can be passed to a blueprint.\n * This also includes the invalid form of passing a plain params object to a blueprint that uses a definition callback.\n *\n * @ignore\n */\ntype AnyParamsInput<TParams extends object | ExtensionBlueprintDefineParams> =\n TParams extends ExtensionBlueprintDefineParams<infer IParams>\n ? IParams | ParamsFactory<TParams>\n : TParams | ParamsFactory<ExtensionBlueprintDefineParams<TParams, TParams>>;\n\n/**\n * @public\n */\nexport interface ExtensionBlueprint<\n T extends ExtensionBlueprintParameters = ExtensionBlueprintParameters,\n> {\n dataRefs: T['dataRefs'];\n\n make<\n TName extends string | undefined,\n TParamsInput extends AnyParamsInput<NonNullable<T['params']>>,\n UParentInputs extends ExtensionDataRef,\n >(args: {\n name?: TName;\n attachTo?: ExtensionDefinitionAttachTo<UParentInputs> &\n VerifyExtensionAttachTo<NonNullable<T['output']>, UParentInputs>;\n disabled?: boolean;\n params: TParamsInput extends ExtensionBlueprintDefineParams\n ? TParamsInput\n : T['params'] extends ExtensionBlueprintDefineParams\n ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `<blueprint>.make({ params: defineParams => defineParams(<params>) })`'\n : T['params'];\n }): ExtensionDefinition<{\n kind: T['kind'];\n name: string | undefined extends TName ? undefined : TName;\n config: T['config'];\n configInput: T['configInput'];\n output: T['output'];\n inputs: T['inputs'];\n params: T['params'];\n }>;\n\n /**\n * Creates a new extension from the blueprint.\n *\n * You must either pass `params` directly, or define a `factory` that can\n * optionally call the original factory with the same params.\n */\n makeWithOverrides<\n TName extends string | undefined,\n TExtensionConfigSchema extends {\n [key in string]: (zImpl: typeof z) => z.ZodType;\n },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n UNewOutput extends ExtensionDataRef,\n TExtraInputs extends { [inputName in string]: ExtensionInput },\n UParentInputs extends ExtensionDataRef,\n >(args: {\n name?: TName;\n attachTo?: ExtensionDefinitionAttachTo<UParentInputs> &\n VerifyExtensionAttachTo<\n ExtensionDataRef extends UNewOutput\n ? NonNullable<T['output']>\n : UNewOutput,\n UParentInputs\n >;\n disabled?: boolean;\n inputs?: TExtraInputs & {\n [KName in keyof T['inputs']]?: `Error: Input '${KName &\n string}' is already defined in parent definition`;\n };\n output?: Array<UNewOutput>;\n config?: {\n schema: TExtensionConfigSchema & {\n [KName in keyof T['config']]?: `Error: Config key '${KName &\n string}' is already defined in parent schema`;\n };\n };\n factory(\n originalFactory: <\n TParamsInput extends AnyParamsInput<NonNullable<T['params']>>,\n >(\n params: TParamsInput extends ExtensionBlueprintDefineParams\n ? TParamsInput\n : T['params'] extends ExtensionBlueprintDefineParams\n ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(defineParams => defineParams(<params>))`'\n : T['params'],\n context?: {\n config?: T['config'];\n inputs?: ResolvedInputValueOverrides<NonNullable<T['inputs']>>;\n },\n ) => ExtensionDataContainer<NonNullable<T['output']>>,\n context: {\n node: AppNode;\n apis: ApiHolder;\n config: T['config'] & {\n [key in keyof TExtensionConfigSchema]: z.infer<\n ReturnType<TExtensionConfigSchema[key]>\n >;\n };\n inputs: Expand<ResolvedExtensionInputs<T['inputs'] & TExtraInputs>>;\n },\n ): Iterable<UFactoryOutput> &\n VerifyExtensionFactoryOutput<\n ExtensionDataRef extends UNewOutput\n ? NonNullable<T['output']>\n : UNewOutput,\n UFactoryOutput\n >;\n }): ExtensionDefinition<{\n config: (string extends keyof TExtensionConfigSchema\n ? {}\n : {\n [key in keyof TExtensionConfigSchema]: z.infer<\n ReturnType<TExtensionConfigSchema[key]>\n >;\n }) &\n T['config'];\n configInput: (string extends keyof TExtensionConfigSchema\n ? {}\n : z.input<\n z.ZodObject<{\n [key in keyof TExtensionConfigSchema]: ReturnType<\n TExtensionConfigSchema[key]\n >;\n }>\n >) &\n T['configInput'];\n output: ExtensionDataRef extends UNewOutput ? T['output'] : UNewOutput;\n inputs: T['inputs'] & TExtraInputs;\n kind: T['kind'];\n name: string | undefined extends TName ? undefined : TName;\n params: T['params'];\n }>;\n}\n\nfunction unwrapParamsFactory<TParams extends object>(\n // Allow `Function` because `typeof <object> === 'function'` allows it, but in practice this should always be a param factory\n params: ParamsFactory<ExtensionBlueprintDefineParams> | Function,\n defineParams: ExtensionBlueprintDefineParams,\n kind: string,\n): TParams {\n const paramDefinition = (\n params as ParamsFactory<ExtensionBlueprintDefineParams>\n )(defineParams);\n try {\n return OpaqueBlueprintParams.toInternal(paramDefinition).params as TParams;\n } catch (e) {\n throw new TypeError(\n `Invalid invocation of blueprint with kind '${kind}', the parameter definition callback function did not return a valid parameter definition object; Caused by: ${e.message}`,\n );\n }\n}\n\nfunction unwrapParams<TParams extends object>(\n params: object | ParamsFactory<ExtensionBlueprintDefineParams> | string,\n ctx: { node: AppNode; [ctxParamsSymbol]?: any },\n defineParams: ExtensionBlueprintDefineParams | undefined,\n kind: string,\n): TParams {\n const overrideParams = ctx[ctxParamsSymbol] as\n | object\n | ParamsFactory<ExtensionBlueprintDefineParams>\n | undefined;\n\n if (defineParams) {\n if (overrideParams) {\n if (typeof overrideParams !== 'function') {\n throw new TypeError(\n `Invalid extension override of blueprint with kind '${kind}', the override params were passed as a plain object, but this blueprint requires them to be passed in callback form`,\n );\n }\n return unwrapParamsFactory(overrideParams, defineParams, kind);\n }\n\n if (typeof params !== 'function') {\n throw new TypeError(\n `Invalid invocation of blueprint with kind '${kind}', the parameters where passed as a plain object, but this blueprint requires them to be passed in callback form`,\n );\n }\n return unwrapParamsFactory(params, defineParams, kind);\n }\n\n const base =\n typeof params === 'function'\n ? unwrapParamsFactory<TParams>(\n params,\n createExtensionBlueprintParams,\n kind,\n )\n : (params as TParams);\n const overrides =\n typeof overrideParams === 'function'\n ? unwrapParamsFactory<TParams>(\n overrideParams,\n createExtensionBlueprintParams,\n kind,\n )\n : (overrideParams as Partial<TParams>);\n\n return {\n ...base,\n ...overrides,\n };\n}\n\n/**\n * Creates a new extension blueprint that encapsulates the creation of\n * extensions of particular kinds.\n *\n * @remarks\n *\n * For details on how blueprints work, see the\n * {@link https://backstage.io/docs/frontend-system/architecture/extension-blueprints | documentation for extension blueprints}\n * in the frontend system documentation.\n *\n * Extension blueprints make it much easier for users to create new extensions\n * for your plugin. Rather than letting them use {@link createExtension}\n * directly, you can define a set of parameters and default factory for your\n * blueprint, removing a lot of the boilerplate and complexity that is otherwise\n * needed to create an extension.\n *\n * Each blueprint has its own `kind` that helps identify and group the\n * extensions that have been created with it. For example the\n * {@link PageBlueprint} has the kind `'page'`, and extensions created with it\n * will be given the ID `'page:<plugin-id>[/<name>]'`. Blueprints should always\n * be exported as `<PascalCaseKind>Blueprint`.\n *\n * When creating a blueprint the type of the parameters are inferred from the\n * `factory` function that you provide. The exception to that is when you need\n * your blueprint to include inferred type parameters, in which case you need to\n * use the `defineParams` option. See the documentation for the `defineParams`\n * option for more details on how that works.\n *\n * @example\n * ```tsx\n * // In your plugin library\n * export const GreetingBlueprint = createExtensionBlueprint({\n * kind: 'greeting',\n * attachTo: { id: 'example', input: 'greetings' },\n * output: [coreExtensionData.reactElement],\n * factory(params: { greeting: string }) {\n * return [coreExtensionData.reactElement(<h1>{params.greeting}</h1>)];\n * },\n * });\n *\n * // Someone using your blueprint in their plugin\n * const exampleGreeting = GreetingBlueprint.make({\n * params: {\n * greeting: 'Hello, world!',\n * },\n * });\n * ```\n * @public\n */\nexport function createExtensionBlueprint<\n TParams extends object | ExtensionBlueprintDefineParams,\n UOutput extends ExtensionDataRef,\n TInputs extends { [inputName in string]: ExtensionInput },\n TConfigSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n TKind extends string,\n UParentInputs extends ExtensionDataRef,\n TDataRefs extends { [name in string]: ExtensionDataRef } = never,\n>(\n options: CreateExtensionBlueprintOptions<\n TKind,\n TParams,\n UOutput,\n TInputs,\n TConfigSchema,\n UFactoryOutput,\n TDataRefs,\n UParentInputs\n >,\n): ExtensionBlueprint<{\n kind: TKind;\n params: TParams;\n // This inference and remapping back to ExtensionDataRef eliminates any occurrences ConfigurationExtensionDataRef\n output: UOutput extends ExtensionDataRef<\n infer IData,\n infer IId,\n infer IConfig\n >\n ? ExtensionDataRef<IData, IId, IConfig>\n : never;\n inputs: string extends keyof TInputs ? {} : TInputs;\n config: string extends keyof TConfigSchema\n ? {}\n : { [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>> };\n configInput: string extends keyof TConfigSchema\n ? {}\n : z.input<\n z.ZodObject<{\n [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;\n }>\n >;\n dataRefs: TDataRefs;\n}> {\n const defineParams = options.defineParams as\n | ExtensionBlueprintDefineParams\n | undefined;\n\n return {\n dataRefs: options.dataRefs,\n make(args) {\n return createExtension({\n kind: options.kind,\n name: args.name,\n attachTo: (args.attachTo ??\n options.attachTo) as ExtensionDefinitionAttachTo,\n disabled: args.disabled ?? options.disabled,\n inputs: options.inputs,\n output: options.output as ExtensionDataRef[],\n config: options.config,\n factory: ctx =>\n options.factory(\n unwrapParams(args.params, ctx, defineParams, options.kind),\n ctx,\n ) as Iterable<ExtensionDataValue<any, any>>,\n }) as ExtensionDefinition;\n },\n makeWithOverrides(args) {\n return createExtension({\n kind: options.kind,\n name: args.name,\n attachTo: (args.attachTo ??\n options.attachTo) as ExtensionDefinitionAttachTo,\n disabled: args.disabled ?? options.disabled,\n inputs: { ...args.inputs, ...options.inputs },\n output: (args.output ?? options.output) as ExtensionDataRef[],\n config:\n options.config || args.config\n ? {\n schema: {\n ...options.config?.schema,\n ...args.config?.schema,\n },\n }\n : undefined,\n factory: ctx => {\n const { node, config, inputs, apis } = ctx;\n return args.factory(\n (innerParams, innerContext) => {\n return createExtensionDataContainer<\n UOutput extends ExtensionDataRef<\n infer IData,\n infer IId,\n infer IConfig\n >\n ? ExtensionDataRef<IData, IId, IConfig>\n : never\n >(\n options.factory(\n unwrapParams(innerParams, ctx, defineParams, options.kind),\n {\n apis,\n node,\n config: (innerContext?.config ?? config) as any,\n inputs: resolveInputOverrides(\n options.inputs,\n inputs,\n innerContext?.inputs,\n ) as any,\n },\n ) as Iterable<any>,\n 'original blueprint factory',\n options.output,\n );\n },\n {\n apis,\n node,\n config: config as any,\n inputs: inputs as any,\n },\n ) as Iterable<ExtensionDataValue<any, any>>;\n },\n }) as ExtensionDefinition;\n },\n } as ExtensionBlueprint<{\n kind: TKind;\n params: TParams;\n output: any;\n inputs: string extends keyof TInputs ? {} : TInputs;\n config: string extends keyof TConfigSchema\n ? {}\n : {\n [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>;\n };\n configInput: string extends keyof TConfigSchema\n ? {}\n : z.input<\n z.ZodObject<{\n [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;\n }>\n >;\n dataRefs: TDataRefs;\n }>;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createExtensionBlueprint.esm.js","sources":["../../src/wiring/createExtensionBlueprint.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ApiHolder, AppNode } from '../apis';\nimport { Expand } from '@backstage/types';\nimport { OpaqueType } from '@internal/opaque';\nimport {\n ExtensionDefinitionAttachTo,\n OverridableExtensionDefinition,\n ResolvedExtensionInputs,\n VerifyExtensionFactoryOutput,\n createExtension,\n ctxParamsSymbol,\n VerifyExtensionAttachTo,\n} from './createExtension';\nimport { z } from 'zod';\nimport { ExtensionInput } from './createExtensionInput';\nimport { ExtensionDataRef, ExtensionDataValue } from './createExtensionDataRef';\nimport { createExtensionDataContainer } from '@internal/frontend';\nimport {\n ResolvedInputValueOverrides,\n resolveInputOverrides,\n} from './resolveInputOverrides';\nimport { ExtensionDataContainer } from './types';\nimport { PageBlueprint } from '../blueprints/PageBlueprint';\n\n/**\n * A function used to define a parameter mapping function in order to facilitate\n * advanced parameter typing for extension blueprints.\n *\n * @remarks\n *\n * This function is primarily intended to enable the use of inferred type\n * parameters for blueprint params, but it can also be used to transoform the\n * params before they are handed ot the blueprint.\n *\n * The function must return an object created with\n * {@link createExtensionBlueprintParams}.\n *\n * @public\n */\nexport type ExtensionBlueprintDefineParams<\n TParams extends object = object,\n TInput = any,\n> = (params: TInput) => ExtensionBlueprintParams<TParams>;\n\n/**\n * An opaque type that represents a set of parameters to be passed to a blueprint.\n *\n * @remarks\n *\n * Created with {@link createExtensionBlueprintParams}.\n *\n * @public\n */\nexport type ExtensionBlueprintParams<T extends object = object> = {\n $$type: '@backstage/BlueprintParams';\n T: T;\n};\n\nconst OpaqueBlueprintParams = OpaqueType.create<{\n public: ExtensionBlueprintParams;\n versions: {\n version: 'v1';\n params: object;\n };\n}>({\n type: '@backstage/BlueprintParams',\n versions: ['v1'],\n});\n\n/**\n * Wraps a plain blueprint parameter object in an opaque {@link ExtensionBlueprintParams} object.\n *\n * This is used in the definition of the `defineParams` option of {@link ExtensionBlueprint}.\n *\n * @public\n * @param params - The plain blueprint parameter object to wrap.\n * @returns The wrapped blueprint parameter object.\n */\nexport function createExtensionBlueprintParams<T extends object = object>(\n params: T,\n): ExtensionBlueprintParams<T> {\n return OpaqueBlueprintParams.createInstance('v1', { T: null as any, params });\n}\n\n/**\n * @public\n */\nexport type CreateExtensionBlueprintOptions<\n TKind extends string,\n TParams extends object | ExtensionBlueprintDefineParams,\n UOutput extends ExtensionDataRef,\n TInputs extends { [inputName in string]: ExtensionInput },\n TConfigSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n TDataRefs extends { [name in string]: ExtensionDataRef },\n UParentInputs extends ExtensionDataRef,\n> = {\n kind: TKind;\n attachTo: ExtensionDefinitionAttachTo<UParentInputs> &\n VerifyExtensionAttachTo<UOutput, UParentInputs>;\n disabled?: boolean;\n inputs?: TInputs;\n output: Array<UOutput>;\n config?: {\n schema: TConfigSchema;\n };\n /**\n * This option is used to further refine the blueprint params. When this\n * option is used, the blueprint will require params to be passed in callback\n * form. This function can both transform the params before they are handed to\n * the blueprint factory, but importantly it also allows you to define\n * inferred type parameters for your blueprint params.\n *\n * @example\n * Blueprint definition with inferred type parameters:\n * ```ts\n * const ExampleBlueprint = createExtensionBlueprint({\n * kind: 'example',\n * attachTo: { id: 'example', input: 'example' },\n * output: [exampleComponentDataRef, exampleFetcherDataRef],\n * defineParams<T>(params: {\n * component(props: ExampleProps<T>): JSX.Element | null\n * fetcher(options: FetchOptions): Promise<FetchResult<T>>\n * }) {\n * return createExtensionBlueprintParams(params);\n * },\n * *factory(params) {\n * yield exampleComponentDataRef(params.component)\n * yield exampleFetcherDataRef(params.fetcher)\n * },\n * });\n * ```\n *\n * @example\n * Usage of the above example blueprint:\n * ```ts\n * const example = ExampleBlueprint.make({\n * params: defineParams => defineParams({\n * component: ...,\n * fetcher: ...,\n * }),\n * });\n * ```\n */\n defineParams?: TParams extends ExtensionBlueprintDefineParams\n ? TParams\n : 'The defineParams option must be a function if provided, see the docs for details';\n factory(\n params: TParams extends ExtensionBlueprintDefineParams\n ? ReturnType<TParams>['T']\n : TParams,\n context: {\n node: AppNode;\n apis: ApiHolder;\n config: {\n [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>;\n };\n inputs: Expand<ResolvedExtensionInputs<TInputs>>;\n },\n ): Iterable<UFactoryOutput>;\n\n dataRefs?: TDataRefs;\n} & VerifyExtensionFactoryOutput<UOutput, UFactoryOutput>;\n\n/** @public */\nexport type ExtensionBlueprintParameters = {\n kind: string;\n params?: object | ExtensionBlueprintDefineParams;\n configInput?: { [K in string]: any };\n config?: { [K in string]: any };\n output?: ExtensionDataRef;\n inputs?: { [KName in string]: ExtensionInput };\n dataRefs?: { [name in string]: ExtensionDataRef };\n};\n\n/** @ignore */\ntype ParamsFactory<TDefiner extends ExtensionBlueprintDefineParams> = (\n defineParams: TDefiner,\n) => ReturnType<TDefiner>;\n\n/**\n * Represents any form of params input that can be passed to a blueprint.\n * This also includes the invalid form of passing a plain params object to a blueprint that uses a definition callback.\n *\n * @ignore\n */\ntype AnyParamsInput<TParams extends object | ExtensionBlueprintDefineParams> =\n TParams extends ExtensionBlueprintDefineParams<infer IParams>\n ? IParams | ParamsFactory<TParams>\n : TParams | ParamsFactory<ExtensionBlueprintDefineParams<TParams, TParams>>;\n\n/**\n * @public\n */\nexport interface ExtensionBlueprint<\n T extends ExtensionBlueprintParameters = ExtensionBlueprintParameters,\n> {\n dataRefs: T['dataRefs'];\n\n make<\n TName extends string | undefined,\n TParamsInput extends AnyParamsInput<NonNullable<T['params']>>,\n UParentInputs extends ExtensionDataRef,\n >(args: {\n name?: TName;\n attachTo?: ExtensionDefinitionAttachTo<UParentInputs> &\n VerifyExtensionAttachTo<NonNullable<T['output']>, UParentInputs>;\n disabled?: boolean;\n params: TParamsInput extends ExtensionBlueprintDefineParams\n ? TParamsInput\n : T['params'] extends ExtensionBlueprintDefineParams\n ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `<blueprint>.make({ params: defineParams => defineParams(<params>) })`'\n : T['params'];\n }): OverridableExtensionDefinition<{\n kind: T['kind'];\n name: string | undefined extends TName ? undefined : TName;\n config: T['config'];\n configInput: T['configInput'];\n output: T['output'];\n inputs: T['inputs'];\n params: T['params'];\n }>;\n\n /**\n * Creates a new extension from the blueprint.\n *\n * You must either pass `params` directly, or define a `factory` that can\n * optionally call the original factory with the same params.\n */\n makeWithOverrides<\n TName extends string | undefined,\n TExtensionConfigSchema extends {\n [key in string]: (zImpl: typeof z) => z.ZodType;\n },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n UNewOutput extends ExtensionDataRef,\n TExtraInputs extends { [inputName in string]: ExtensionInput },\n UParentInputs extends ExtensionDataRef,\n >(args: {\n name?: TName;\n attachTo?: ExtensionDefinitionAttachTo<UParentInputs> &\n VerifyExtensionAttachTo<\n ExtensionDataRef extends UNewOutput\n ? NonNullable<T['output']>\n : UNewOutput,\n UParentInputs\n >;\n disabled?: boolean;\n inputs?: TExtraInputs & {\n [KName in keyof T['inputs']]?: `Error: Input '${KName &\n string}' is already defined in parent definition`;\n };\n output?: Array<UNewOutput>;\n config?: {\n schema: TExtensionConfigSchema & {\n [KName in keyof T['config']]?: `Error: Config key '${KName &\n string}' is already defined in parent schema`;\n };\n };\n factory(\n originalFactory: <\n TParamsInput extends AnyParamsInput<NonNullable<T['params']>>,\n >(\n params: TParamsInput extends ExtensionBlueprintDefineParams\n ? TParamsInput\n : T['params'] extends ExtensionBlueprintDefineParams\n ? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(defineParams => defineParams(<params>))`'\n : T['params'],\n context?: {\n config?: T['config'];\n inputs?: ResolvedInputValueOverrides<NonNullable<T['inputs']>>;\n },\n ) => ExtensionDataContainer<NonNullable<T['output']>>,\n context: {\n node: AppNode;\n apis: ApiHolder;\n config: T['config'] & {\n [key in keyof TExtensionConfigSchema]: z.infer<\n ReturnType<TExtensionConfigSchema[key]>\n >;\n };\n inputs: Expand<ResolvedExtensionInputs<T['inputs'] & TExtraInputs>>;\n },\n ): Iterable<UFactoryOutput> &\n VerifyExtensionFactoryOutput<\n ExtensionDataRef extends UNewOutput\n ? NonNullable<T['output']>\n : UNewOutput,\n UFactoryOutput\n >;\n }): OverridableExtensionDefinition<{\n config: (string extends keyof TExtensionConfigSchema\n ? {}\n : {\n [key in keyof TExtensionConfigSchema]: z.infer<\n ReturnType<TExtensionConfigSchema[key]>\n >;\n }) &\n T['config'];\n configInput: (string extends keyof TExtensionConfigSchema\n ? {}\n : z.input<\n z.ZodObject<{\n [key in keyof TExtensionConfigSchema]: ReturnType<\n TExtensionConfigSchema[key]\n >;\n }>\n >) &\n T['configInput'];\n output: ExtensionDataRef extends UNewOutput ? T['output'] : UNewOutput;\n inputs: T['inputs'] & TExtraInputs;\n kind: T['kind'];\n name: string | undefined extends TName ? undefined : TName;\n params: T['params'];\n }>;\n}\n\nfunction unwrapParamsFactory<TParams extends object>(\n // Allow `Function` because `typeof <object> === 'function'` allows it, but in practice this should always be a param factory\n params: ParamsFactory<ExtensionBlueprintDefineParams> | Function,\n defineParams: ExtensionBlueprintDefineParams,\n kind: string,\n): TParams {\n const paramDefinition = (\n params as ParamsFactory<ExtensionBlueprintDefineParams>\n )(defineParams);\n try {\n return OpaqueBlueprintParams.toInternal(paramDefinition).params as TParams;\n } catch (e) {\n throw new TypeError(\n `Invalid invocation of blueprint with kind '${kind}', the parameter definition callback function did not return a valid parameter definition object; Caused by: ${e.message}`,\n );\n }\n}\n\nfunction unwrapParams<TParams extends object>(\n params: object | ParamsFactory<ExtensionBlueprintDefineParams> | string,\n ctx: { node: AppNode; [ctxParamsSymbol]?: any },\n defineParams: ExtensionBlueprintDefineParams | undefined,\n kind: string,\n): TParams {\n const overrideParams = ctx[ctxParamsSymbol] as\n | object\n | ParamsFactory<ExtensionBlueprintDefineParams>\n | undefined;\n\n if (defineParams) {\n if (overrideParams) {\n if (typeof overrideParams !== 'function') {\n throw new TypeError(\n `Invalid extension override of blueprint with kind '${kind}', the override params were passed as a plain object, but this blueprint requires them to be passed in callback form`,\n );\n }\n return unwrapParamsFactory(overrideParams, defineParams, kind);\n }\n\n if (typeof params !== 'function') {\n throw new TypeError(\n `Invalid invocation of blueprint with kind '${kind}', the parameters where passed as a plain object, but this blueprint requires them to be passed in callback form`,\n );\n }\n return unwrapParamsFactory(params, defineParams, kind);\n }\n\n const base =\n typeof params === 'function'\n ? unwrapParamsFactory<TParams>(\n params,\n createExtensionBlueprintParams,\n kind,\n )\n : (params as TParams);\n const overrides =\n typeof overrideParams === 'function'\n ? unwrapParamsFactory<TParams>(\n overrideParams,\n createExtensionBlueprintParams,\n kind,\n )\n : (overrideParams as Partial<TParams>);\n\n return {\n ...base,\n ...overrides,\n };\n}\n\n/**\n * Creates a new extension blueprint that encapsulates the creation of\n * extensions of particular kinds.\n *\n * @remarks\n *\n * For details on how blueprints work, see the\n * {@link https://backstage.io/docs/frontend-system/architecture/extension-blueprints | documentation for extension blueprints}\n * in the frontend system documentation.\n *\n * Extension blueprints make it much easier for users to create new extensions\n * for your plugin. Rather than letting them use {@link createExtension}\n * directly, you can define a set of parameters and default factory for your\n * blueprint, removing a lot of the boilerplate and complexity that is otherwise\n * needed to create an extension.\n *\n * Each blueprint has its own `kind` that helps identify and group the\n * extensions that have been created with it. For example the\n * {@link PageBlueprint} has the kind `'page'`, and extensions created with it\n * will be given the ID `'page:<plugin-id>[/<name>]'`. Blueprints should always\n * be exported as `<PascalCaseKind>Blueprint`.\n *\n * When creating a blueprint the type of the parameters are inferred from the\n * `factory` function that you provide. The exception to that is when you need\n * your blueprint to include inferred type parameters, in which case you need to\n * use the `defineParams` option. See the documentation for the `defineParams`\n * option for more details on how that works.\n *\n * @example\n * ```tsx\n * // In your plugin library\n * export const GreetingBlueprint = createExtensionBlueprint({\n * kind: 'greeting',\n * attachTo: { id: 'example', input: 'greetings' },\n * output: [coreExtensionData.reactElement],\n * factory(params: { greeting: string }) {\n * return [coreExtensionData.reactElement(<h1>{params.greeting}</h1>)];\n * },\n * });\n *\n * // Someone using your blueprint in their plugin\n * const exampleGreeting = GreetingBlueprint.make({\n * params: {\n * greeting: 'Hello, world!',\n * },\n * });\n * ```\n * @public\n */\nexport function createExtensionBlueprint<\n TParams extends object | ExtensionBlueprintDefineParams,\n UOutput extends ExtensionDataRef,\n TInputs extends { [inputName in string]: ExtensionInput },\n TConfigSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType },\n UFactoryOutput extends ExtensionDataValue<any, any>,\n TKind extends string,\n UParentInputs extends ExtensionDataRef,\n TDataRefs extends { [name in string]: ExtensionDataRef } = never,\n>(\n options: CreateExtensionBlueprintOptions<\n TKind,\n TParams,\n UOutput,\n TInputs,\n TConfigSchema,\n UFactoryOutput,\n TDataRefs,\n UParentInputs\n >,\n): ExtensionBlueprint<{\n kind: TKind;\n params: TParams;\n // This inference and remapping back to ExtensionDataRef eliminates any occurrences ConfigurationExtensionDataRef\n output: UOutput extends ExtensionDataRef<\n infer IData,\n infer IId,\n infer IConfig\n >\n ? ExtensionDataRef<IData, IId, IConfig>\n : never;\n inputs: string extends keyof TInputs ? {} : TInputs;\n config: string extends keyof TConfigSchema\n ? {}\n : { [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>> };\n configInput: string extends keyof TConfigSchema\n ? {}\n : z.input<\n z.ZodObject<{\n [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;\n }>\n >;\n dataRefs: TDataRefs;\n}> {\n const defineParams = options.defineParams as\n | ExtensionBlueprintDefineParams\n | undefined;\n\n return {\n dataRefs: options.dataRefs,\n make(args) {\n return createExtension({\n kind: options.kind,\n name: args.name,\n attachTo: (args.attachTo ??\n options.attachTo) as ExtensionDefinitionAttachTo,\n disabled: args.disabled ?? options.disabled,\n inputs: options.inputs,\n output: options.output as ExtensionDataRef[],\n config: options.config,\n factory: ctx =>\n options.factory(\n unwrapParams(args.params, ctx, defineParams, options.kind),\n ctx,\n ) as Iterable<ExtensionDataValue<any, any>>,\n }) as OverridableExtensionDefinition;\n },\n makeWithOverrides(args) {\n return createExtension({\n kind: options.kind,\n name: args.name,\n attachTo: (args.attachTo ??\n options.attachTo) as ExtensionDefinitionAttachTo,\n disabled: args.disabled ?? options.disabled,\n inputs: { ...args.inputs, ...options.inputs },\n output: (args.output ?? options.output) as ExtensionDataRef[],\n config:\n options.config || args.config\n ? {\n schema: {\n ...options.config?.schema,\n ...args.config?.schema,\n },\n }\n : undefined,\n factory: ctx => {\n const { node, config, inputs, apis } = ctx;\n return args.factory(\n (innerParams, innerContext) => {\n return createExtensionDataContainer<\n UOutput extends ExtensionDataRef<\n infer IData,\n infer IId,\n infer IConfig\n >\n ? ExtensionDataRef<IData, IId, IConfig>\n : never\n >(\n options.factory(\n unwrapParams(innerParams, ctx, defineParams, options.kind),\n {\n apis,\n node,\n config: (innerContext?.config ?? config) as any,\n inputs: resolveInputOverrides(\n options.inputs,\n inputs,\n innerContext?.inputs,\n ) as any,\n },\n ) as Iterable<any>,\n 'original blueprint factory',\n options.output,\n );\n },\n {\n apis,\n node,\n config: config as any,\n inputs: inputs as any,\n },\n ) as Iterable<ExtensionDataValue<any, any>>;\n },\n }) as OverridableExtensionDefinition;\n },\n } as ExtensionBlueprint<{\n kind: TKind;\n params: TParams;\n output: any;\n inputs: string extends keyof TInputs ? {} : TInputs;\n config: string extends keyof TConfigSchema\n ? {}\n : {\n [key in keyof TConfigSchema]: z.infer<ReturnType<TConfigSchema[key]>>;\n };\n configInput: string extends keyof TConfigSchema\n ? {}\n : z.input<\n z.ZodObject<{\n [key in keyof TConfigSchema]: ReturnType<TConfigSchema[key]>;\n }>\n >;\n dataRefs: TDataRefs;\n }>;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createFrontendPlugin.esm.js","sources":["../../src/wiring/createFrontendPlugin.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 OpaqueExtensionDefinition,\n OpaqueFrontendPlugin,\n} from '@internal/frontend';\nimport { ExtensionDefinition } from './createExtension';\nimport {\n Extension,\n resolveExtensionDefinition,\n} from './resolveExtensionDefinition';\nimport { FeatureFlagConfig } from './types';\nimport { MakeSortedExtensionsMap } from './MakeSortedExtensionsMap';\nimport { JsonObject } from '@backstage/types';\nimport { RouteRef, SubRouteRef, ExternalRouteRef } from '../routing';\n\n/**\n * Information about the plugin.\n *\n * @public\n * @remarks\n *\n * This interface is intended to be extended via [module\n * augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation)\n * in order to add fields that are specific to each project.\n *\n * For example, one might add a `slackChannel` field that is read from the\n * opaque manifest file.\n *\n * See the options for `createApp` for more information about how to\n * customize the parsing of manifest files.\n */\nexport interface FrontendPluginInfo {\n /**\n * The name of the package that implements the plugin.\n */\n packageName?: string;\n\n /**\n * The version of the plugin, typically the version of the package.json file.\n */\n version?: string;\n\n /**\n * As short description of the plugin, typically the description field in\n * package.json.\n */\n description?: string;\n\n /**\n * The owner entity references of the plugin.\n */\n ownerEntityRefs?: string[];\n\n /**\n * Links related to the plugin.\n */\n links?: Array<{ title: string; url: string }>;\n}\n\n/**\n * Options for providing information for a plugin.\n *\n * @public\n */\nexport type FrontendPluginInfoOptions = {\n /**\n * A loader function for the package.json file for the plugin.\n */\n packageJson?: () => Promise<{ name: string } & JsonObject>;\n /**\n * A loader function for an opaque manifest file for the plugin.\n */\n manifest?: () => Promise<JsonObject>;\n};\n\n/**\n * A variant of the {@link FrontendPlugin} interface that can also be used to install overrides for the plugin.\n *\n * @public\n */\nexport interface OverridableFrontendPlugin<\n TRoutes extends { [name in string]: RouteRef | SubRouteRef } = {\n [name in string]: RouteRef | SubRouteRef;\n },\n TExternalRoutes extends { [name in string]: ExternalRouteRef } = {\n [name in string]: ExternalRouteRef;\n },\n TExtensionMap extends { [id in string]: ExtensionDefinition } = {\n [id in string]: ExtensionDefinition;\n },\n> extends FrontendPlugin<TRoutes, TExternalRoutes> {\n getExtension<TId extends keyof TExtensionMap>(id: TId): TExtensionMap[TId];\n withOverrides(options: {\n extensions: Array<ExtensionDefinition>;\n\n /**\n * Overrides the original info loaders of the plugin one by one.\n */\n info?: FrontendPluginInfoOptions;\n }): OverridableFrontendPlugin<TRoutes, TExternalRoutes, TExtensionMap>;\n}\n\n/** @public */\nexport interface FrontendPlugin<\n TRoutes extends { [name in string]: RouteRef | SubRouteRef } = {\n [name in string]: RouteRef | SubRouteRef;\n },\n TExternalRoutes extends { [name in string]: ExternalRouteRef } = {\n [name in string]: ExternalRouteRef;\n },\n> {\n readonly $$type: '@backstage/FrontendPlugin';\n readonly id: string;\n readonly routes: TRoutes;\n readonly externalRoutes: TExternalRoutes;\n\n /**\n * Loads the plugin info.\n */\n info(): Promise<FrontendPluginInfo>;\n}\n\n/** @public */\nexport interface PluginOptions<\n TId extends string,\n TRoutes extends { [name in string]: RouteRef | SubRouteRef },\n TExternalRoutes extends { [name in string]: ExternalRouteRef },\n TExtensions extends readonly ExtensionDefinition[],\n> {\n pluginId: TId;\n routes?: TRoutes;\n externalRoutes?: TExternalRoutes;\n extensions?: TExtensions;\n featureFlags?: FeatureFlagConfig[];\n info?: FrontendPluginInfoOptions;\n}\n\n/**\n * Creates a new plugin that can be installed in a Backstage app.\n *\n * @remarks\n *\n * Every plugin is created with a unique ID and a set of extensions\n * that are installed as part of the plugin.\n *\n * For more information on how plugins work, see the\n * {@link https://backstage.io/docs/frontend-system/building-plugins/index | documentation for plugins}\n * in the frontend system documentation.\n *\n * @example\n *\n * ```tsx\n * import { createFrontendPlugin } from '@backstage/frontend-plugin-api';\n *\n * export const examplePlugin = createFrontendPlugin({\n * pluginId: 'example',\n * extensions: [\n * PageBlueprint.make({\n * path: '/example',\n * loader: () => import('./ExamplePage').then(m => <m.ExamplePage />),\n * }),\n * ],\n * });\n * ```\n *\n * @public\n */\nexport function createFrontendPlugin<\n TId extends string,\n TExtensions extends readonly ExtensionDefinition[],\n TRoutes extends { [name in string]: RouteRef | SubRouteRef } = {},\n TExternalRoutes extends { [name in string]: ExternalRouteRef } = {},\n>(\n options: PluginOptions<TId, TRoutes, TExternalRoutes, TExtensions>,\n): OverridableFrontendPlugin<\n TRoutes,\n TExternalRoutes,\n MakeSortedExtensionsMap<TExtensions[number], TId>\n> {\n const pluginId = options.pluginId;\n\n const extensions = new Array<Extension<any>>();\n const extensionDefinitionsById = new Map<\n string,\n typeof OpaqueExtensionDefinition.TInternal\n >();\n\n for (const def of options.extensions ?? []) {\n const internal = OpaqueExtensionDefinition.toInternal(def);\n const ext = resolveExtensionDefinition(def, { namespace: pluginId });\n extensions.push(ext);\n extensionDefinitionsById.set(ext.id, {\n ...internal,\n namespace: pluginId,\n });\n }\n\n if (extensions.length !== extensionDefinitionsById.size) {\n const extensionIds = extensions.map(e => e.id);\n const duplicates = Array.from(\n new Set(\n extensionIds.filter((id, index) => extensionIds.indexOf(id) !== index),\n ),\n );\n // TODO(Rugvip): This could provide some more information about the kind + name of the extensions\n throw new Error(\n `Plugin '${pluginId}' provided duplicate extensions: ${duplicates.join(\n ', ',\n )}`,\n );\n }\n\n return OpaqueFrontendPlugin.createInstance('v1', {\n id: pluginId,\n routes: options.routes ?? ({} as TRoutes),\n externalRoutes: options.externalRoutes ?? ({} as TExternalRoutes),\n featureFlags: options.featureFlags ?? [],\n extensions: extensions,\n infoOptions: options.info,\n\n // This method is overridden when the plugin instance is installed in an app\n async info() {\n throw new Error(\n `Attempted to load plugin info for plugin '${pluginId}', but the plugin instance is not installed in an app`,\n );\n },\n getExtension(id) {\n const ext = extensionDefinitionsById.get(id);\n if (!ext) {\n throw new Error(\n `Attempted to get non-existent extension '${id}' from plugin '${pluginId}'`,\n );\n }\n return ext;\n },\n toString() {\n return `Plugin{id=${pluginId}}`;\n },\n withOverrides(overrides) {\n const overriddenExtensionIds = new Set(\n overrides.extensions.map(\n e => resolveExtensionDefinition(e, { namespace: pluginId }).id,\n ),\n );\n const nonOverriddenExtensions = (options.extensions ?? []).filter(\n e =>\n !overriddenExtensionIds.has(\n resolveExtensionDefinition(e, { namespace: pluginId }).id,\n ),\n );\n return createFrontendPlugin({\n ...options,\n pluginId,\n extensions: [...nonOverriddenExtensions, ...overrides.extensions],\n info: {\n ...options.info,\n ...overrides.info,\n },\n });\n },\n });\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createFrontendPlugin.esm.js","sources":["../../src/wiring/createFrontendPlugin.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 OpaqueExtensionDefinition,\n OpaqueFrontendPlugin,\n} from '@internal/frontend';\nimport {\n ExtensionDefinition,\n OverridableExtensionDefinition,\n} from './createExtension';\nimport {\n Extension,\n resolveExtensionDefinition,\n} from './resolveExtensionDefinition';\nimport { FeatureFlagConfig } from './types';\nimport { MakeSortedExtensionsMap } from './MakeSortedExtensionsMap';\nimport { JsonObject } from '@backstage/types';\nimport { RouteRef, SubRouteRef, ExternalRouteRef } from '../routing';\n\n/**\n * Information about the plugin.\n *\n * @public\n * @remarks\n *\n * This interface is intended to be extended via [module\n * augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation)\n * in order to add fields that are specific to each project.\n *\n * For example, one might add a `slackChannel` field that is read from the\n * opaque manifest file.\n *\n * See the options for `createApp` for more information about how to\n * customize the parsing of manifest files.\n */\nexport interface FrontendPluginInfo {\n /**\n * The name of the package that implements the plugin.\n */\n packageName?: string;\n\n /**\n * The version of the plugin, typically the version of the package.json file.\n */\n version?: string;\n\n /**\n * As short description of the plugin, typically the description field in\n * package.json.\n */\n description?: string;\n\n /**\n * The owner entity references of the plugin.\n */\n ownerEntityRefs?: string[];\n\n /**\n * Links related to the plugin.\n */\n links?: Array<{ title: string; url: string }>;\n}\n\n/**\n * Options for providing information for a plugin.\n *\n * @public\n */\nexport type FrontendPluginInfoOptions = {\n /**\n * A loader function for the package.json file for the plugin.\n */\n packageJson?: () => Promise<{ name: string } & JsonObject>;\n /**\n * A loader function for an opaque manifest file for the plugin.\n */\n manifest?: () => Promise<JsonObject>;\n};\n\n/**\n * A variant of the {@link FrontendPlugin} interface that can also be used to install overrides for the plugin.\n *\n * @public\n */\nexport interface OverridableFrontendPlugin<\n TRoutes extends { [name in string]: RouteRef | SubRouteRef } = {\n [name in string]: RouteRef | SubRouteRef;\n },\n TExternalRoutes extends { [name in string]: ExternalRouteRef } = {\n [name in string]: ExternalRouteRef;\n },\n TExtensionMap extends { [id in string]: ExtensionDefinition } = {\n [id in string]: ExtensionDefinition;\n },\n> extends FrontendPlugin<TRoutes, TExternalRoutes> {\n getExtension<TId extends keyof TExtensionMap>(\n id: TId,\n ): OverridableExtensionDefinition<TExtensionMap[TId]['T']>;\n withOverrides(options: {\n extensions: Array<ExtensionDefinition>;\n\n /**\n * Overrides the original info loaders of the plugin one by one.\n */\n info?: FrontendPluginInfoOptions;\n }): OverridableFrontendPlugin<TRoutes, TExternalRoutes, TExtensionMap>;\n}\n\n/** @public */\nexport interface FrontendPlugin<\n TRoutes extends { [name in string]: RouteRef | SubRouteRef } = {\n [name in string]: RouteRef | SubRouteRef;\n },\n TExternalRoutes extends { [name in string]: ExternalRouteRef } = {\n [name in string]: ExternalRouteRef;\n },\n> {\n readonly $$type: '@backstage/FrontendPlugin';\n readonly id: string;\n readonly routes: TRoutes;\n readonly externalRoutes: TExternalRoutes;\n\n /**\n * Loads the plugin info.\n */\n info(): Promise<FrontendPluginInfo>;\n}\n\n/** @public */\nexport interface PluginOptions<\n TId extends string,\n TRoutes extends { [name in string]: RouteRef | SubRouteRef },\n TExternalRoutes extends { [name in string]: ExternalRouteRef },\n TExtensions extends readonly ExtensionDefinition[],\n> {\n pluginId: TId;\n routes?: TRoutes;\n externalRoutes?: TExternalRoutes;\n extensions?: TExtensions;\n featureFlags?: FeatureFlagConfig[];\n info?: FrontendPluginInfoOptions;\n}\n\n/**\n * Creates a new plugin that can be installed in a Backstage app.\n *\n * @remarks\n *\n * Every plugin is created with a unique ID and a set of extensions\n * that are installed as part of the plugin.\n *\n * For more information on how plugins work, see the\n * {@link https://backstage.io/docs/frontend-system/building-plugins/index | documentation for plugins}\n * in the frontend system documentation.\n *\n * @example\n *\n * ```tsx\n * import { createFrontendPlugin } from '@backstage/frontend-plugin-api';\n *\n * export const examplePlugin = createFrontendPlugin({\n * pluginId: 'example',\n * extensions: [\n * PageBlueprint.make({\n * path: '/example',\n * loader: () => import('./ExamplePage').then(m => <m.ExamplePage />),\n * }),\n * ],\n * });\n * ```\n *\n * @public\n */\nexport function createFrontendPlugin<\n TId extends string,\n TExtensions extends readonly ExtensionDefinition[],\n TRoutes extends { [name in string]: RouteRef | SubRouteRef } = {},\n TExternalRoutes extends { [name in string]: ExternalRouteRef } = {},\n>(\n options: PluginOptions<TId, TRoutes, TExternalRoutes, TExtensions>,\n): OverridableFrontendPlugin<\n TRoutes,\n TExternalRoutes,\n MakeSortedExtensionsMap<TExtensions[number], TId>\n> {\n const pluginId = options.pluginId;\n\n const extensions = new Array<Extension<any>>();\n const extensionDefinitionsById = new Map<\n string,\n typeof OpaqueExtensionDefinition.TInternal\n >();\n\n for (const def of options.extensions ?? []) {\n const internal = OpaqueExtensionDefinition.toInternal(def);\n const ext = resolveExtensionDefinition(def, { namespace: pluginId });\n extensions.push(ext);\n extensionDefinitionsById.set(ext.id, {\n ...internal,\n namespace: pluginId,\n });\n }\n\n if (extensions.length !== extensionDefinitionsById.size) {\n const extensionIds = extensions.map(e => e.id);\n const duplicates = Array.from(\n new Set(\n extensionIds.filter((id, index) => extensionIds.indexOf(id) !== index),\n ),\n );\n // TODO(Rugvip): This could provide some more information about the kind + name of the extensions\n throw new Error(\n `Plugin '${pluginId}' provided duplicate extensions: ${duplicates.join(\n ', ',\n )}`,\n );\n }\n\n return OpaqueFrontendPlugin.createInstance('v1', {\n id: pluginId,\n routes: options.routes ?? ({} as TRoutes),\n externalRoutes: options.externalRoutes ?? ({} as TExternalRoutes),\n featureFlags: options.featureFlags ?? [],\n extensions: extensions,\n infoOptions: options.info,\n\n // This method is overridden when the plugin instance is installed in an app\n async info() {\n throw new Error(\n `Attempted to load plugin info for plugin '${pluginId}', but the plugin instance is not installed in an app`,\n );\n },\n getExtension(id) {\n const ext = extensionDefinitionsById.get(id);\n if (!ext) {\n throw new Error(\n `Attempted to get non-existent extension '${id}' from plugin '${pluginId}'`,\n );\n }\n return ext;\n },\n toString() {\n return `Plugin{id=${pluginId}}`;\n },\n withOverrides(overrides) {\n const overriddenExtensionIds = new Set(\n overrides.extensions.map(\n e => resolveExtensionDefinition(e, { namespace: pluginId }).id,\n ),\n );\n const nonOverriddenExtensions = (options.extensions ?? []).filter(\n e =>\n !overriddenExtensionIds.has(\n resolveExtensionDefinition(e, { namespace: pluginId }).id,\n ),\n );\n return createFrontendPlugin({\n ...options,\n pluginId,\n extensions: [...nonOverriddenExtensions, ...overrides.extensions],\n info: {\n ...options.info,\n ...overrides.info,\n },\n });\n },\n });\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/frontend-plugin-api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"backstage": {
|
|
5
5
|
"role": "web-library"
|
|
6
6
|
},
|
|
@@ -31,20 +31,20 @@
|
|
|
31
31
|
"test": "backstage-cli package test"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@backstage/core-components": "0.18.3
|
|
35
|
-
"@backstage/core-plugin-api": "1.
|
|
36
|
-
"@backstage/types": "1.2.2",
|
|
37
|
-
"@backstage/version-bridge": "1.0.11",
|
|
34
|
+
"@backstage/core-components": "^0.18.3",
|
|
35
|
+
"@backstage/core-plugin-api": "^1.12.0",
|
|
36
|
+
"@backstage/types": "^1.2.2",
|
|
37
|
+
"@backstage/version-bridge": "^1.0.11",
|
|
38
38
|
"@material-ui/core": "^4.12.4",
|
|
39
39
|
"lodash": "^4.17.21",
|
|
40
40
|
"zod": "^3.22.4",
|
|
41
41
|
"zod-to-json-schema": "^3.21.4"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@backstage/cli": "0.34.5
|
|
45
|
-
"@backstage/frontend-app-api": "0.13.2
|
|
46
|
-
"@backstage/frontend-test-utils": "0.4.1
|
|
47
|
-
"@backstage/test-utils": "1.7.13
|
|
44
|
+
"@backstage/cli": "^0.34.5",
|
|
45
|
+
"@backstage/frontend-app-api": "^0.13.2",
|
|
46
|
+
"@backstage/frontend-test-utils": "^0.4.1",
|
|
47
|
+
"@backstage/test-utils": "^1.7.13",
|
|
48
48
|
"@testing-library/jest-dom": "^6.0.0",
|
|
49
49
|
"@testing-library/react": "^16.0.0",
|
|
50
50
|
"@types/react": "^18.0.0",
|