@backstage/frontend-test-utils 0.6.4 → 0.6.5-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/apis/AlertApi/MockAlertApi.esm.js.map +1 -1
- package/dist/apis/AnalyticsApi/MockAnalyticsApi.esm.js.map +1 -1
- package/dist/apis/ConfigApi/MockConfigApi.esm.js.map +1 -1
- package/dist/apis/ErrorApi/MockErrorApi.esm.js +1 -0
- package/dist/apis/ErrorApi/MockErrorApi.esm.js.map +1 -1
- package/dist/apis/FeatureFlagsApi/MockFeatureFlagsApi.esm.js.map +1 -1
- package/dist/apis/FetchApi/MockFetchApi.esm.js.map +1 -1
- package/dist/apis/MockWithApiFactory.esm.js.map +1 -1
- package/dist/apis/PermissionApi/MockPermissionApi.esm.js +1 -0
- package/dist/apis/PermissionApi/MockPermissionApi.esm.js.map +1 -1
- package/dist/apis/StorageApi/MockStorageApi.esm.js.map +1 -1
- package/dist/apis/TestApiProvider.esm.js.map +1 -1
- package/dist/apis/TranslationApi/MockTranslationApi.esm.js.map +1 -1
- package/dist/apis/createApiMock.esm.js.map +1 -1
- package/dist/apis/mockApis.esm.js.map +1 -1
- package/dist/app/createExtensionTester.esm.js.map +1 -1
- package/dist/app/renderInTestApp.esm.js.map +1 -1
- package/dist/app/renderTestApp.esm.js.map +1 -1
- package/dist/core-app-api/src/apis/implementations/TranslationApi/I18nextTranslationApi.esm.js.map +1 -1
- package/dist/core-app-api/src/apis/system/ApiAggregator.esm.js.map +1 -1
- package/dist/core-app-api/src/apis/system/ApiProvider.esm.js.map +1 -1
- package/dist/frontend-app-api/src/routing/getBasePath.esm.js.map +1 -1
- package/dist/frontend-app-api/src/tree/instantiateAppNodeTree.esm.js.map +1 -1
- package/dist/frontend-app-api/src/tree/readAppExtensionsConfig.esm.js.map +1 -1
- package/dist/frontend-app-api/src/tree/resolveAppNodeSpecs.esm.js.map +1 -1
- package/dist/frontend-app-api/src/tree/resolveAppTree.esm.js.map +1 -1
- package/dist/frontend-app-api/src/wiring/createErrorCollector.esm.js.map +1 -1
- package/dist/frontend-internal/src/routing/OpaqueExternalRouteRef.esm.js.map +1 -1
- package/dist/frontend-internal/src/wiring/InternalExtensionDefinition.esm.js.map +1 -1
- package/dist/frontend-internal/src/wiring/InternalExtensionInput.esm.js.map +1 -1
- package/dist/frontend-internal/src/wiring/InternalFrontendPlugin.esm.js.map +1 -1
- package/dist/frontend-internal/src/wiring/createExtensionDataContainer.esm.js.map +1 -1
- package/dist/frontend-plugin-api/src/translation/TranslationRef.esm.js.map +1 -1
- package/dist/frontend-plugin-api/src/wiring/createFrontendModule.esm.js.map +1 -1
- package/dist/frontend-plugin-api/src/wiring/resolveExtensionDefinition.esm.js.map +1 -1
- package/dist/opaque-internal/src/OpaqueType.esm.js.map +1 -1
- package/package.json +15 -15
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveAppTree.esm.js","sources":["../../../../../frontend-app-api/src/tree/resolveAppTree.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AppTree,\n AppNode,\n AppNodeInstance,\n AppNodeSpec,\n} from '@backstage/frontend-plugin-api';\n\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalExtension } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';\nimport { ErrorCollector } from '../wiring/createErrorCollector';\n\nfunction indent(str: string) {\n return str.replace(/^/gm, ' ');\n}\n\n/** @internal */\nclass SerializableAppNode implements AppNode {\n public readonly spec: AppNodeSpec;\n public readonly edges = {\n attachedTo: undefined as { node: AppNode; input: string } | undefined,\n attachments: new Map<string, SerializableAppNode[]>(),\n };\n public readonly instance?: AppNodeInstance;\n\n constructor(spec: AppNodeSpec) {\n this.spec = spec;\n }\n\n setParent(parent: SerializableAppNode, input: string) {\n this.edges.attachedTo = { node: parent, input };\n\n const parentInputEdges = parent.edges.attachments.get(input);\n if (parentInputEdges) {\n parentInputEdges.push(this);\n } else {\n parent.edges.attachments.set(input, [this]);\n }\n }\n\n toJSON() {\n const dataRefs = this.instance && [...this.instance.getDataRefs()];\n return {\n id: this.spec.id,\n output:\n dataRefs && dataRefs.length > 0\n ? dataRefs.map(ref => ref.id)\n : undefined,\n attachments:\n this.edges.attachments.size > 0\n ? Object.fromEntries(this.edges.attachments)\n : undefined,\n };\n }\n\n toString(): string {\n const dataRefs = this.instance && [...this.instance.getDataRefs()];\n const out =\n dataRefs && dataRefs.length > 0\n ? ` out=[${[...dataRefs].map(r => r.id).join(', ')}]`\n : '';\n\n if (this.edges.attachments.size === 0) {\n return `<${this.spec.id}${out} />`;\n }\n\n return [\n `<${this.spec.id}${out}>`,\n ...[...this.edges.attachments.entries()].map(([k, v]) =>\n indent([`${k} [`, ...v.map(e => indent(e.toString())), `]`].join('\\n')),\n ),\n `</${this.spec.id}>`,\n ].join('\\n');\n }\n}\n\nfunction makeRedirectKey(attachTo: { id: string; input: string }) {\n return `${attachTo.id}%${attachTo.input}`;\n}\n\nconst isValidAttachmentPoint = (\n attachTo: { id: string; input: string },\n nodes: Map<string, SerializableAppNode>,\n) => {\n if (!nodes.has(attachTo.id)) {\n return false;\n }\n\n return (\n attachTo.input in\n toInternalExtension(nodes.get(attachTo.id)!.spec.extension).inputs\n );\n};\n\n/**\n * Build the app tree by iterating through all node specs and constructing the app\n * tree with all attachments in the same order as they appear in the input specs array.\n * @internal\n */\nexport function resolveAppTree(\n rootNodeId: string,\n specs: AppNodeSpec[],\n errorCollector: ErrorCollector,\n): AppTree {\n const nodes = new Map<string, SerializableAppNode>();\n\n const redirectTargetsByKey = new Map<string, { id: string; input: string }>();\n\n for (const spec of specs) {\n // The main check with a helpful error message happens in resolveAppNodeSpecs\n if (nodes.has(spec.id)) {\n continue;\n }\n\n const node = new SerializableAppNode(spec);\n nodes.set(spec.id, node);\n\n const internal = toInternalExtension(spec.extension);\n for (const [inputName, input] of Object.entries(internal.inputs)) {\n if (input.replaces) {\n for (const replace of input.replaces) {\n const key = makeRedirectKey(replace);\n if (redirectTargetsByKey.has(key)) {\n errorCollector.report({\n code: 'EXTENSION_INPUT_REDIRECT_CONFLICT',\n message: `Duplicate redirect target for input '${inputName}' in extension '${spec.id}'`,\n context: {\n node,\n inputName,\n },\n });\n continue;\n }\n redirectTargetsByKey.set(key, { id: spec.id, input: inputName });\n }\n }\n }\n }\n\n const orphans = new Array<SerializableAppNode>();\n const clones = new Map<string, Array<SerializableAppNode>>();\n\n // A node with the provided rootNodeId must be found in the tree, and it must not be attached to anything\n let rootNode: AppNode | undefined = undefined;\n\n for (const node of nodes.values()) {\n const spec = node.spec;\n\n // TODO: For now we simply ignore the attachTo spec of the root node, but it'd be cleaner if we could avoid defining it\n if (spec.id === rootNodeId) {\n rootNode = node;\n } else if (Array.isArray(spec.attachTo)) {\n // eslint-disable-next-line no-console\n console.warn(\n `Extension '${spec.id}' is using multiple attachment points which is deprecated and will be removed in a future release. ` +\n `Use a Utility API instead to share functionality across multiple locations. ` +\n `See https://backstage.io/docs/frontend-system/architecture/27-sharing-extensions for migration guidance.`,\n );\n let foundFirstParent = false;\n for (const origAttachTo of spec.attachTo) {\n let attachTo = origAttachTo;\n\n if (!isValidAttachmentPoint(attachTo, nodes)) {\n attachTo =\n redirectTargetsByKey.get(makeRedirectKey(attachTo)) ?? attachTo;\n }\n\n const parent = nodes.get(attachTo.id);\n if (parent) {\n const cloneParents = clones.get(attachTo.id) ?? [];\n\n if (!foundFirstParent) {\n foundFirstParent = true;\n node.setParent(parent, attachTo.input);\n } else {\n cloneParents.unshift(parent);\n }\n\n for (const extraParent of cloneParents) {\n const clonedNode = new SerializableAppNode(spec);\n clonedNode.setParent(extraParent, attachTo.input);\n clones.set(\n spec.id,\n clones.get(spec.id)?.concat(clonedNode) ?? [clonedNode],\n );\n }\n }\n }\n if (!foundFirstParent) {\n orphans.push(node);\n }\n } else {\n let attachTo = spec.attachTo;\n if (!isValidAttachmentPoint(attachTo, nodes)) {\n attachTo =\n redirectTargetsByKey.get(makeRedirectKey(attachTo)) ?? attachTo;\n }\n\n const parent = nodes.get(attachTo.id);\n if (parent) {\n node.setParent(parent, attachTo.input);\n } else {\n orphans.push(node);\n }\n }\n }\n\n if (!rootNode) {\n throw new Error(`No root node with id '${rootNodeId}' found in app tree`);\n }\n\n return {\n root: rootNode,\n nodes,\n orphans,\n };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"resolveAppTree.esm.js","sources":["../../../../../frontend-app-api/src/tree/resolveAppTree.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AppTree,\n AppNode,\n AppNodeInstance,\n AppNodeSpec,\n} from '@backstage/frontend-plugin-api';\n\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalExtension } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';\nimport { ErrorCollector } from '../wiring/createErrorCollector';\n\nfunction indent(str: string) {\n return str.replace(/^/gm, ' ');\n}\n\n/** @internal */\nclass SerializableAppNode implements AppNode {\n public readonly spec: AppNodeSpec;\n public readonly edges = {\n attachedTo: undefined as { node: AppNode; input: string } | undefined,\n attachments: new Map<string, SerializableAppNode[]>(),\n };\n public readonly instance?: AppNodeInstance;\n\n constructor(spec: AppNodeSpec) {\n this.spec = spec;\n }\n\n setParent(parent: SerializableAppNode, input: string) {\n this.edges.attachedTo = { node: parent, input };\n\n const parentInputEdges = parent.edges.attachments.get(input);\n if (parentInputEdges) {\n parentInputEdges.push(this);\n } else {\n parent.edges.attachments.set(input, [this]);\n }\n }\n\n toJSON() {\n const dataRefs = this.instance && [...this.instance.getDataRefs()];\n return {\n id: this.spec.id,\n output:\n dataRefs && dataRefs.length > 0\n ? dataRefs.map(ref => ref.id)\n : undefined,\n attachments:\n this.edges.attachments.size > 0\n ? Object.fromEntries(this.edges.attachments)\n : undefined,\n };\n }\n\n toString(): string {\n const dataRefs = this.instance && [...this.instance.getDataRefs()];\n const out =\n dataRefs && dataRefs.length > 0\n ? ` out=[${[...dataRefs].map(r => r.id).join(', ')}]`\n : '';\n\n if (this.edges.attachments.size === 0) {\n return `<${this.spec.id}${out} />`;\n }\n\n return [\n `<${this.spec.id}${out}>`,\n ...[...this.edges.attachments.entries()].map(([k, v]) =>\n indent([`${k} [`, ...v.map(e => indent(e.toString())), `]`].join('\\n')),\n ),\n `</${this.spec.id}>`,\n ].join('\\n');\n }\n}\n\nfunction makeRedirectKey(attachTo: { id: string; input: string }) {\n return `${attachTo.id}%${attachTo.input}`;\n}\n\nconst isValidAttachmentPoint = (\n attachTo: { id: string; input: string },\n nodes: Map<string, SerializableAppNode>,\n) => {\n if (!nodes.has(attachTo.id)) {\n return false;\n }\n\n return (\n attachTo.input in\n toInternalExtension(nodes.get(attachTo.id)!.spec.extension).inputs\n );\n};\n\n/**\n * Build the app tree by iterating through all node specs and constructing the app\n * tree with all attachments in the same order as they appear in the input specs array.\n * @internal\n */\nexport function resolveAppTree(\n rootNodeId: string,\n specs: AppNodeSpec[],\n errorCollector: ErrorCollector,\n): AppTree {\n const nodes = new Map<string, SerializableAppNode>();\n\n const redirectTargetsByKey = new Map<string, { id: string; input: string }>();\n\n for (const spec of specs) {\n // The main check with a helpful error message happens in resolveAppNodeSpecs\n if (nodes.has(spec.id)) {\n continue;\n }\n\n const node = new SerializableAppNode(spec);\n nodes.set(spec.id, node);\n\n const internal = toInternalExtension(spec.extension);\n for (const [inputName, input] of Object.entries(internal.inputs)) {\n if (input.replaces) {\n for (const replace of input.replaces) {\n const key = makeRedirectKey(replace);\n if (redirectTargetsByKey.has(key)) {\n errorCollector.report({\n code: 'EXTENSION_INPUT_REDIRECT_CONFLICT',\n message: `Duplicate redirect target for input '${inputName}' in extension '${spec.id}'`,\n context: {\n node,\n inputName,\n },\n });\n continue;\n }\n redirectTargetsByKey.set(key, { id: spec.id, input: inputName });\n }\n }\n }\n }\n\n const orphans = new Array<SerializableAppNode>();\n const clones = new Map<string, Array<SerializableAppNode>>();\n\n // A node with the provided rootNodeId must be found in the tree, and it must not be attached to anything\n let rootNode: AppNode | undefined = undefined;\n\n for (const node of nodes.values()) {\n const spec = node.spec;\n\n // TODO: For now we simply ignore the attachTo spec of the root node, but it'd be cleaner if we could avoid defining it\n if (spec.id === rootNodeId) {\n rootNode = node;\n } else if (Array.isArray(spec.attachTo)) {\n // eslint-disable-next-line no-console\n console.warn(\n `Extension '${spec.id}' is using multiple attachment points which is deprecated and will be removed in a future release. ` +\n `Use a Utility API instead to share functionality across multiple locations. ` +\n `See https://backstage.io/docs/frontend-system/architecture/27-sharing-extensions for migration guidance.`,\n );\n let foundFirstParent = false;\n for (const origAttachTo of spec.attachTo) {\n let attachTo = origAttachTo;\n\n if (!isValidAttachmentPoint(attachTo, nodes)) {\n attachTo =\n redirectTargetsByKey.get(makeRedirectKey(attachTo)) ?? attachTo;\n }\n\n const parent = nodes.get(attachTo.id);\n if (parent) {\n const cloneParents = clones.get(attachTo.id) ?? [];\n\n if (!foundFirstParent) {\n foundFirstParent = true;\n node.setParent(parent, attachTo.input);\n } else {\n cloneParents.unshift(parent);\n }\n\n for (const extraParent of cloneParents) {\n const clonedNode = new SerializableAppNode(spec);\n clonedNode.setParent(extraParent, attachTo.input);\n clones.set(\n spec.id,\n clones.get(spec.id)?.concat(clonedNode) ?? [clonedNode],\n );\n }\n }\n }\n if (!foundFirstParent) {\n orphans.push(node);\n }\n } else {\n let attachTo = spec.attachTo;\n if (!isValidAttachmentPoint(attachTo, nodes)) {\n attachTo =\n redirectTargetsByKey.get(makeRedirectKey(attachTo)) ?? attachTo;\n }\n\n const parent = nodes.get(attachTo.id);\n if (parent) {\n node.setParent(parent, attachTo.input);\n } else {\n orphans.push(node);\n }\n }\n }\n\n if (!rootNode) {\n throw new Error(`No root node with id '${rootNodeId}' found in app tree`);\n }\n\n return {\n root: rootNode,\n nodes,\n orphans,\n };\n}\n"],"names":[],"mappings":";;AA2BA,SAAS,OAAO,GAAA,EAAa;AAC3B,EAAA,OAAO,GAAA,CAAI,OAAA,CAAQ,KAAA,EAAO,IAAI,CAAA;AAChC;AAGA,MAAM,mBAAA,CAAuC;AAAA,EAC3B,IAAA;AAAA,EACA,KAAA,GAAQ;AAAA,IACtB,UAAA,EAAY,MAAA;AAAA,IACZ,WAAA,sBAAiB,GAAA;AAAmC,GACtD;AAAA,EACgB,QAAA;AAAA,EAEhB,YAAY,IAAA,EAAmB;AAC7B,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACd;AAAA,EAEA,SAAA,CAAU,QAA6B,KAAA,EAAe;AACpD,IAAA,IAAA,CAAK,KAAA,CAAM,UAAA,GAAa,EAAE,IAAA,EAAM,QAAQ,KAAA,EAAM;AAE9C,IAAA,MAAM,gBAAA,GAAmB,MAAA,CAAO,KAAA,CAAM,WAAA,CAAY,IAAI,KAAK,CAAA;AAC3D,IAAA,IAAI,gBAAA,EAAkB;AACpB,MAAA,gBAAA,CAAiB,KAAK,IAAI,CAAA;AAAA,IAC5B,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,MAAM,WAAA,CAAY,GAAA,CAAI,KAAA,EAAO,CAAC,IAAI,CAAC,CAAA;AAAA,IAC5C;AAAA,EACF;AAAA,EAEA,MAAA,GAAS;AACP,IAAA,MAAM,QAAA,GAAW,KAAK,QAAA,IAAY,CAAC,GAAG,IAAA,CAAK,QAAA,CAAS,aAAa,CAAA;AACjE,IAAA,OAAO;AAAA,MACL,EAAA,EAAI,KAAK,IAAA,CAAK,EAAA;AAAA,MACd,MAAA,EACE,QAAA,IAAY,QAAA,CAAS,MAAA,GAAS,CAAA,GAC1B,SAAS,GAAA,CAAI,CAAA,GAAA,KAAO,GAAA,CAAI,EAAE,CAAA,GAC1B,MAAA;AAAA,MACN,WAAA,EACE,IAAA,CAAK,KAAA,CAAM,WAAA,CAAY,IAAA,GAAO,CAAA,GAC1B,MAAA,CAAO,WAAA,CAAY,IAAA,CAAK,KAAA,CAAM,WAAW,CAAA,GACzC;AAAA,KACR;AAAA,EACF;AAAA,EAEA,QAAA,GAAmB;AACjB,IAAA,MAAM,QAAA,GAAW,KAAK,QAAA,IAAY,CAAC,GAAG,IAAA,CAAK,QAAA,CAAS,aAAa,CAAA;AACjE,IAAA,MAAM,MACJ,QAAA,IAAY,QAAA,CAAS,SAAS,CAAA,GAC1B,CAAA,MAAA,EAAS,CAAC,GAAG,QAAQ,CAAA,CAAE,GAAA,CAAI,OAAK,CAAA,CAAE,EAAE,EAAE,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,CAAA,GAChD,EAAA;AAEN,IAAA,IAAI,IAAA,CAAK,KAAA,CAAM,WAAA,CAAY,IAAA,KAAS,CAAA,EAAG;AACrC,MAAA,OAAO,CAAA,CAAA,EAAI,IAAA,CAAK,IAAA,CAAK,EAAE,GAAG,GAAG,CAAA,GAAA,CAAA;AAAA,IAC/B;AAEA,IAAA,OAAO;AAAA,MACL,CAAA,CAAA,EAAI,IAAA,CAAK,IAAA,CAAK,EAAE,GAAG,GAAG,CAAA,CAAA,CAAA;AAAA,MACtB,GAAG,CAAC,GAAG,IAAA,CAAK,MAAM,WAAA,CAAY,OAAA,EAAS,CAAA,CAAE,GAAA;AAAA,QAAI,CAAC,CAAC,CAAA,EAAG,CAAC,CAAA,KACjD,OAAO,CAAC,CAAA,EAAG,CAAC,CAAA,EAAA,CAAA,EAAM,GAAG,CAAA,CAAE,IAAI,CAAA,CAAA,KAAK,MAAA,CAAO,CAAA,CAAE,QAAA,EAAU,CAAC,GAAG,CAAA,CAAA,CAAG,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC;AAAA,OACxE;AAAA,MACA,CAAA,EAAA,EAAK,IAAA,CAAK,IAAA,CAAK,EAAE,CAAA,CAAA;AAAA,KACnB,CAAE,KAAK,IAAI,CAAA;AAAA,EACb;AACF;AAEA,SAAS,gBAAgB,QAAA,EAAyC;AAChE,EAAA,OAAO,CAAA,EAAG,QAAA,CAAS,EAAE,CAAA,CAAA,EAAI,SAAS,KAAK,CAAA,CAAA;AACzC;AAEA,MAAM,sBAAA,GAAyB,CAC7B,QAAA,EACA,KAAA,KACG;AACH,EAAA,IAAI,CAAC,KAAA,CAAM,GAAA,CAAI,QAAA,CAAS,EAAE,CAAA,EAAG;AAC3B,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,OACE,QAAA,CAAS,KAAA,IACT,mBAAA,CAAoB,KAAA,CAAM,GAAA,CAAI,SAAS,EAAE,CAAA,CAAG,IAAA,CAAK,SAAS,CAAA,CAAE,MAAA;AAEhE,CAAA;AAOO,SAAS,cAAA,CACd,UAAA,EACA,KAAA,EACA,cAAA,EACS;AACT,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAiC;AAEnD,EAAA,MAAM,oBAAA,uBAA2B,GAAA,EAA2C;AAE5E,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AAExB,IAAA,IAAI,KAAA,CAAM,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA,EAAG;AACtB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,IAAA,GAAO,IAAI,mBAAA,CAAoB,IAAI,CAAA;AACzC,IAAA,KAAA,CAAM,GAAA,CAAI,IAAA,CAAK,EAAA,EAAI,IAAI,CAAA;AAEvB,IAAA,MAAM,QAAA,GAAW,mBAAA,CAAoB,IAAA,CAAK,SAAS,CAAA;AACnD,IAAA,KAAA,MAAW,CAAC,WAAW,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,QAAA,CAAS,MAAM,CAAA,EAAG;AAChE,MAAA,IAAI,MAAM,QAAA,EAAU;AAClB,QAAA,KAAA,MAAW,OAAA,IAAW,MAAM,QAAA,EAAU;AACpC,UAAA,MAAM,GAAA,GAAM,gBAAgB,OAAO,CAAA;AACnC,UAAA,IAAI,oBAAA,CAAqB,GAAA,CAAI,GAAG,CAAA,EAAG;AACjC,YAAA,cAAA,CAAe,MAAA,CAAO;AAAA,cACpB,IAAA,EAAM,mCAAA;AAAA,cACN,OAAA,EAAS,CAAA,qCAAA,EAAwC,SAAS,CAAA,gBAAA,EAAmB,KAAK,EAAE,CAAA,CAAA,CAAA;AAAA,cACpF,OAAA,EAAS;AAAA,gBACP,IAAA;AAAA,gBACA;AAAA;AACF,aACD,CAAA;AACD,YAAA;AAAA,UACF;AACA,UAAA,oBAAA,CAAqB,GAAA,CAAI,KAAK,EAAE,EAAA,EAAI,KAAK,EAAA,EAAI,KAAA,EAAO,WAAW,CAAA;AAAA,QACjE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,MAAM,OAAA,GAAU,IAAI,KAAA,EAA2B;AAC/C,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAwC;AAG3D,EAAA,IAAI,QAAA,GAAgC,MAAA;AAEpC,EAAA,KAAA,MAAW,IAAA,IAAQ,KAAA,CAAM,MAAA,EAAO,EAAG;AACjC,IAAA,MAAM,OAAO,IAAA,CAAK,IAAA;AAGlB,IAAA,IAAI,IAAA,CAAK,OAAO,UAAA,EAAY;AAC1B,MAAA,QAAA,GAAW,IAAA;AAAA,IACb,CAAA,MAAA,IAAW,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,QAAQ,CAAA,EAAG;AAEvC,MAAA,OAAA,CAAQ,IAAA;AAAA,QACN,CAAA,WAAA,EAAc,KAAK,EAAE,CAAA,uRAAA;AAAA,OAGvB;AACA,MAAA,IAAI,gBAAA,GAAmB,KAAA;AACvB,MAAA,KAAA,MAAW,YAAA,IAAgB,KAAK,QAAA,EAAU;AACxC,QAAA,IAAI,QAAA,GAAW,YAAA;AAEf,QAAA,IAAI,CAAC,sBAAA,CAAuB,QAAA,EAAU,KAAK,CAAA,EAAG;AAC5C,UAAA,QAAA,GACE,oBAAA,CAAqB,GAAA,CAAI,eAAA,CAAgB,QAAQ,CAAC,CAAA,IAAK,QAAA;AAAA,QAC3D;AAEA,QAAA,MAAM,MAAA,GAAS,KAAA,CAAM,GAAA,CAAI,QAAA,CAAS,EAAE,CAAA;AACpC,QAAA,IAAI,MAAA,EAAQ;AACV,UAAA,MAAM,eAAe,MAAA,CAAO,GAAA,CAAI,QAAA,CAAS,EAAE,KAAK,EAAC;AAEjD,UAAA,IAAI,CAAC,gBAAA,EAAkB;AACrB,YAAA,gBAAA,GAAmB,IAAA;AACnB,YAAA,IAAA,CAAK,SAAA,CAAU,MAAA,EAAQ,QAAA,CAAS,KAAK,CAAA;AAAA,UACvC,CAAA,MAAO;AACL,YAAA,YAAA,CAAa,QAAQ,MAAM,CAAA;AAAA,UAC7B;AAEA,UAAA,KAAA,MAAW,eAAe,YAAA,EAAc;AACtC,YAAA,MAAM,UAAA,GAAa,IAAI,mBAAA,CAAoB,IAAI,CAAA;AAC/C,YAAA,UAAA,CAAW,SAAA,CAAU,WAAA,EAAa,QAAA,CAAS,KAAK,CAAA;AAChD,YAAA,MAAA,CAAO,GAAA;AAAA,cACL,IAAA,CAAK,EAAA;AAAA,cACL,MAAA,CAAO,IAAI,IAAA,CAAK,EAAE,GAAG,MAAA,CAAO,UAAU,CAAA,IAAK,CAAC,UAAU;AAAA,aACxD;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,MAAA,IAAI,CAAC,gBAAA,EAAkB;AACrB,QAAA,OAAA,CAAQ,KAAK,IAAI,CAAA;AAAA,MACnB;AAAA,IACF,CAAA,MAAO;AACL,MAAA,IAAI,WAAW,IAAA,CAAK,QAAA;AACpB,MAAA,IAAI,CAAC,sBAAA,CAAuB,QAAA,EAAU,KAAK,CAAA,EAAG;AAC5C,QAAA,QAAA,GACE,oBAAA,CAAqB,GAAA,CAAI,eAAA,CAAgB,QAAQ,CAAC,CAAA,IAAK,QAAA;AAAA,MAC3D;AAEA,MAAA,MAAM,MAAA,GAAS,KAAA,CAAM,GAAA,CAAI,QAAA,CAAS,EAAE,CAAA;AACpC,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,IAAA,CAAK,SAAA,CAAU,MAAA,EAAQ,QAAA,CAAS,KAAK,CAAA;AAAA,MACvC,CAAA,MAAO;AACL,QAAA,OAAA,CAAQ,KAAK,IAAI,CAAA;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AAEA,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,sBAAA,EAAyB,UAAU,CAAA,mBAAA,CAAqB,CAAA;AAAA,EAC1E;AAEA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,QAAA;AAAA,IACN,KAAA;AAAA,IACA;AAAA,GACF;AACF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createErrorCollector.esm.js","sources":["../../../../../frontend-app-api/src/wiring/createErrorCollector.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AppNode, FrontendPlugin } from '@backstage/frontend-plugin-api';\n\n/**\n * @public\n */\nexport type AppErrorTypes = {\n // resolveAppNodeSpecs\n EXTENSION_IGNORED: {\n context: { plugin: FrontendPlugin; extensionId: string };\n };\n INVALID_EXTENSION_CONFIG_KEY: {\n context: { extensionId: string };\n };\n // resolveAppTree\n EXTENSION_INPUT_REDIRECT_CONFLICT: {\n context: { node: AppNode; inputName: string };\n };\n // instantiateAppNodeTree\n EXTENSION_INPUT_DATA_IGNORED: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_INPUT_DATA_MISSING: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_INPUT_INTERNAL_IGNORED: {\n context: {\n node: AppNode;\n inputName: string;\n extensionId: string;\n plugin: FrontendPlugin;\n };\n };\n EXTENSION_ATTACHMENT_CONFLICT: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_ATTACHMENT_MISSING: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_CONFIGURATION_INVALID: {\n context: { node: AppNode };\n };\n EXTENSION_INVALID: {\n context: { node: AppNode };\n };\n EXTENSION_OUTPUT_CONFLICT: {\n context: { node: AppNode; dataRefId: string };\n };\n EXTENSION_OUTPUT_MISSING: {\n context: { node: AppNode; dataRefId: string };\n };\n EXTENSION_OUTPUT_IGNORED: {\n context: { node: AppNode; dataRefId: string };\n };\n EXTENSION_FACTORY_ERROR: {\n context: { node: AppNode };\n };\n // createSpecializedApp\n API_EXTENSION_INVALID: {\n context: { node: AppNode };\n };\n API_FACTORY_CONFLICT: {\n context: {\n node: AppNode;\n apiRefId: string;\n pluginId: string;\n existingPluginId: string;\n };\n };\n EXTENSION_BOOTSTRAP_PREDICATE_IGNORED: {\n context: { node: AppNode };\n };\n EXTENSION_BOOTSTRAP_API_UNAVAILABLE: {\n context: { node: AppNode; apiRefId: string };\n };\n EXTENSION_BOOTSTRAP_API_OVERRIDE_IGNORED: {\n context: {\n node: AppNode;\n apiRefId: string;\n bootstrapNode: AppNode;\n pluginId: string;\n bootstrapPluginId: string;\n };\n };\n FEATURE_FLAG_INVALID: {\n context: { pluginId: string; flagName: string; error: Error };\n };\n // routing\n ROUTE_DUPLICATE: {\n context: { routeId: string };\n };\n ROUTE_BINDING_INVALID_VALUE: {\n context: { routeId: string };\n };\n ROUTE_NOT_FOUND: {\n context: { routeId: string };\n };\n};\n\n/**\n * @public\n */\nexport type AppError =\n keyof AppErrorTypes extends infer ICode extends keyof AppErrorTypes\n ? ICode extends any\n ? {\n code: ICode;\n message: string;\n context: AppErrorTypes[ICode]['context'];\n }\n : never\n : never;\n\n/** @internal */\nexport interface ErrorCollector<TContext extends {} = {}> {\n report<TCode extends keyof AppErrorTypes>(\n report: Omit<\n AppErrorTypes[TCode]['context'],\n keyof TContext\n > extends infer IContext extends {}\n ? {} extends IContext\n ? {\n code: TCode;\n message: string;\n }\n : {\n code: TCode;\n message: string;\n context: IContext;\n }\n : never,\n ): void;\n child<TAdditionalContext extends {}>(\n context: TAdditionalContext,\n ): ErrorCollector<TContext & TAdditionalContext>;\n collectErrors(): AppError[] | undefined;\n}\n\n/** @internal */\nexport function createErrorCollector(\n context?: Partial<AppError['context']>,\n): ErrorCollector {\n const errors: AppError[] = [];\n const children: ErrorCollector[] = [];\n return {\n report(report: { code: string; message: string; context?: {} }) {\n errors.push({\n ...report,\n context: { ...context, ...report.context },\n } as AppError);\n },\n collectErrors() {\n const allErrors = [\n ...errors,\n ...children.flatMap(child => child.collectErrors() ?? []),\n ];\n errors.length = 0;\n if (allErrors.length === 0) {\n return undefined;\n }\n return allErrors;\n },\n child(childContext) {\n const child = createErrorCollector({ ...context, ...childContext });\n children.push(child);\n return child as ErrorCollector<any>;\n },\n };\n}\n"],"names":[],"mappings":"AA0JO,SAAS,qBACd,OAAA,EACgB;AAChB,EAAA,MAAM,SAAqB,EAAC;AAC5B,EAAA,MAAM,WAA6B,EAAC;AACpC,EAAA,OAAO;AAAA,IACL,OAAO,MAAA,EAAyD;AAC9D,MAAA,MAAA,CAAO,IAAA,CAAK;AAAA,QACV,GAAG,MAAA;AAAA,QACH,SAAS,EAAE,GAAG,OAAA,EAAS,GAAG,OAAO,OAAA;AAAQ,OAC9B,CAAA;AAAA,IACf,CAAA;AAAA,IACA,aAAA,GAAgB;AACd,MAAA,MAAM,SAAA,GAAY;AAAA,QAChB,GAAG,MAAA;AAAA,QACH,GAAG,SAAS,OAAA,CAAQ,CAAA,KAAA,KAAS,MAAM,aAAA,EAAc,IAAK,EAAE;AAAA,OAC1D;AACA,MAAA,MAAA,CAAO,MAAA,GAAS,CAAA;AAChB,MAAA,IAAI,SAAA,CAAU,WAAW,CAAA,EAAG;AAC1B,QAAA,OAAO,MAAA;AAAA,MACT;AACA,MAAA,OAAO,SAAA;AAAA,IACT,CAAA;AAAA,IACA,MAAM,YAAA,EAAc;AAClB,MAAA,MAAM,QAAQ,oBAAA,CAAqB,EAAE,GAAG,OAAA,EAAS,GAAG,cAAc,CAAA;AAClE,MAAA,QAAA,CAAS,KAAK,KAAK,CAAA;AACnB,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,GACF;AACF
|
|
1
|
+
{"version":3,"file":"createErrorCollector.esm.js","sources":["../../../../../frontend-app-api/src/wiring/createErrorCollector.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AppNode, FrontendPlugin } from '@backstage/frontend-plugin-api';\n\n/**\n * @public\n */\nexport type AppErrorTypes = {\n // resolveAppNodeSpecs\n EXTENSION_IGNORED: {\n context: { plugin: FrontendPlugin; extensionId: string };\n };\n INVALID_EXTENSION_CONFIG_KEY: {\n context: { extensionId: string };\n };\n // resolveAppTree\n EXTENSION_INPUT_REDIRECT_CONFLICT: {\n context: { node: AppNode; inputName: string };\n };\n // instantiateAppNodeTree\n EXTENSION_INPUT_DATA_IGNORED: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_INPUT_DATA_MISSING: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_INPUT_INTERNAL_IGNORED: {\n context: {\n node: AppNode;\n inputName: string;\n extensionId: string;\n plugin: FrontendPlugin;\n };\n };\n EXTENSION_ATTACHMENT_CONFLICT: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_ATTACHMENT_MISSING: {\n context: { node: AppNode; inputName: string };\n };\n EXTENSION_CONFIGURATION_INVALID: {\n context: { node: AppNode };\n };\n EXTENSION_INVALID: {\n context: { node: AppNode };\n };\n EXTENSION_OUTPUT_CONFLICT: {\n context: { node: AppNode; dataRefId: string };\n };\n EXTENSION_OUTPUT_MISSING: {\n context: { node: AppNode; dataRefId: string };\n };\n EXTENSION_OUTPUT_IGNORED: {\n context: { node: AppNode; dataRefId: string };\n };\n EXTENSION_FACTORY_ERROR: {\n context: { node: AppNode };\n };\n // createSpecializedApp\n API_EXTENSION_INVALID: {\n context: { node: AppNode };\n };\n API_FACTORY_CONFLICT: {\n context: {\n node: AppNode;\n apiRefId: string;\n pluginId: string;\n existingPluginId: string;\n };\n };\n EXTENSION_BOOTSTRAP_PREDICATE_IGNORED: {\n context: { node: AppNode };\n };\n EXTENSION_BOOTSTRAP_API_UNAVAILABLE: {\n context: { node: AppNode; apiRefId: string };\n };\n EXTENSION_BOOTSTRAP_API_OVERRIDE_IGNORED: {\n context: {\n node: AppNode;\n apiRefId: string;\n bootstrapNode: AppNode;\n pluginId: string;\n bootstrapPluginId: string;\n };\n };\n FEATURE_FLAG_INVALID: {\n context: { pluginId: string; flagName: string; error: Error };\n };\n // routing\n ROUTE_DUPLICATE: {\n context: { routeId: string };\n };\n ROUTE_BINDING_INVALID_VALUE: {\n context: { routeId: string };\n };\n ROUTE_NOT_FOUND: {\n context: { routeId: string };\n };\n};\n\n/**\n * @public\n */\nexport type AppError =\n keyof AppErrorTypes extends infer ICode extends keyof AppErrorTypes\n ? ICode extends any\n ? {\n code: ICode;\n message: string;\n context: AppErrorTypes[ICode]['context'];\n }\n : never\n : never;\n\n/** @internal */\nexport interface ErrorCollector<TContext extends {} = {}> {\n report<TCode extends keyof AppErrorTypes>(\n report: Omit<\n AppErrorTypes[TCode]['context'],\n keyof TContext\n > extends infer IContext extends {}\n ? {} extends IContext\n ? {\n code: TCode;\n message: string;\n }\n : {\n code: TCode;\n message: string;\n context: IContext;\n }\n : never,\n ): void;\n child<TAdditionalContext extends {}>(\n context: TAdditionalContext,\n ): ErrorCollector<TContext & TAdditionalContext>;\n collectErrors(): AppError[] | undefined;\n}\n\n/** @internal */\nexport function createErrorCollector(\n context?: Partial<AppError['context']>,\n): ErrorCollector {\n const errors: AppError[] = [];\n const children: ErrorCollector[] = [];\n return {\n report(report: { code: string; message: string; context?: {} }) {\n errors.push({\n ...report,\n context: { ...context, ...report.context },\n } as AppError);\n },\n collectErrors() {\n const allErrors = [\n ...errors,\n ...children.flatMap(child => child.collectErrors() ?? []),\n ];\n errors.length = 0;\n if (allErrors.length === 0) {\n return undefined;\n }\n return allErrors;\n },\n child(childContext) {\n const child = createErrorCollector({ ...context, ...childContext });\n children.push(child);\n return child as ErrorCollector<any>;\n },\n };\n}\n"],"names":[],"mappings":"AA0JO,SAAS,qBACd,OAAA,EACgB;AAChB,EAAA,MAAM,SAAqB,EAAC;AAC5B,EAAA,MAAM,WAA6B,EAAC;AACpC,EAAA,OAAO;AAAA,IACL,OAAO,MAAA,EAAyD;AAC9D,MAAA,MAAA,CAAO,IAAA,CAAK;AAAA,QACV,GAAG,MAAA;AAAA,QACH,SAAS,EAAE,GAAG,OAAA,EAAS,GAAG,OAAO,OAAA;AAAQ,OAC9B,CAAA;AAAA,IACf,CAAA;AAAA,IACA,aAAA,GAAgB;AACd,MAAA,MAAM,SAAA,GAAY;AAAA,QAChB,GAAG,MAAA;AAAA,QACH,GAAG,SAAS,OAAA,CAAQ,CAAA,KAAA,KAAS,MAAM,aAAA,EAAc,IAAK,EAAE;AAAA,OAC1D;AACA,MAAA,MAAA,CAAO,MAAA,GAAS,CAAA;AAChB,MAAA,IAAI,SAAA,CAAU,WAAW,CAAA,EAAG;AAC1B,QAAA,OAAO,MAAA;AAAA,MACT;AACA,MAAA,OAAO,SAAA;AAAA,IACT,CAAA;AAAA,IACA,MAAM,YAAA,EAAc;AAClB,MAAA,MAAM,QAAQ,oBAAA,CAAqB,EAAE,GAAG,OAAA,EAAS,GAAG,cAAc,CAAA;AAClE,MAAA,QAAA,CAAS,KAAK,KAAK,CAAA;AACnB,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,GACF;AACF;;"}
|
|
@@ -1 +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
|
|
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;;"}
|
|
@@ -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 OverridableExtensionDefinition,\n ExtensionDefinitionParameters,\n ExtensionInput,\n PortableSchema,\n} from '@backstage/frontend-plugin-api';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { ResolvedExtensionInputs } from '../../../frontend-plugin-api/src/wiring/createExtension';\nimport { OpaqueType } from '@internal/opaque';\nimport { FilterPredicate } from '@backstage/filter-predicates';\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 if?: FilterPredicate;\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":";;AAgCO,MAAM,yBAAA,GAA4B,WAAW,MAAA,CAsDjD;AAAA,EACD,IAAA,EAAM,gCAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAA,EAAM,IAAI;AACvB,CAAC
|
|
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} from '@backstage/frontend-plugin-api';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { ResolvedExtensionInputs } from '../../../frontend-plugin-api/src/wiring/createExtension';\nimport { OpaqueType } from '@internal/opaque';\nimport { FilterPredicate } from '@backstage/filter-predicates';\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 if?: FilterPredicate;\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":";;AAgCO,MAAM,yBAAA,GAA4B,WAAW,MAAA,CAsDjD;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;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InternalFrontendPlugin.esm.js","sources":["../../../../../frontend-internal/src/wiring/InternalFrontendPlugin.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 Extension,\n FeatureFlagConfig,\n IconElement,\n OverridableFrontendPlugin,\n} from '@backstage/frontend-plugin-api';\nimport { FilterPredicate } from '@backstage/filter-predicates';\nimport { JsonObject } from '@backstage/types';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueFrontendPlugin = OpaqueType.create<{\n public: OverridableFrontendPlugin;\n versions: {\n readonly version: 'v1';\n readonly title?: string;\n readonly icon?: IconElement;\n readonly extensions: Extension<unknown>[];\n readonly featureFlags: FeatureFlagConfig[];\n readonly if?: FilterPredicate;\n readonly infoOptions?: {\n packageJson?: () => Promise<JsonObject>;\n manifest?: () => Promise<JsonObject>;\n };\n };\n}>({\n type: '@backstage/FrontendPlugin',\n versions: ['v1'],\n});\n"],"names":[],"mappings":";;AA0BO,MAAM,oBAAA,GAAuB,WAAW,MAAA,CAc5C;AAAA,EACD,IAAA,EAAM,2BAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAI;AACjB,CAAC
|
|
1
|
+
{"version":3,"file":"InternalFrontendPlugin.esm.js","sources":["../../../../../frontend-internal/src/wiring/InternalFrontendPlugin.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 Extension,\n FeatureFlagConfig,\n IconElement,\n OverridableFrontendPlugin,\n} from '@backstage/frontend-plugin-api';\nimport { FilterPredicate } from '@backstage/filter-predicates';\nimport { JsonObject } from '@backstage/types';\nimport { OpaqueType } from '@internal/opaque';\n\nexport const OpaqueFrontendPlugin = OpaqueType.create<{\n public: OverridableFrontendPlugin;\n versions: {\n readonly version: 'v1';\n readonly title?: string;\n readonly icon?: IconElement;\n readonly extensions: Extension<unknown>[];\n readonly featureFlags: FeatureFlagConfig[];\n readonly if?: FilterPredicate;\n readonly infoOptions?: {\n packageJson?: () => Promise<JsonObject>;\n manifest?: () => Promise<JsonObject>;\n };\n };\n}>({\n type: '@backstage/FrontendPlugin',\n versions: ['v1'],\n});\n"],"names":[],"mappings":";;AA0BO,MAAM,oBAAA,GAAuB,WAAW,MAAA,CAc5C;AAAA,EACD,IAAA,EAAM,2BAAA;AAAA,EACN,QAAA,EAAU,CAAC,IAAI;AACjB,CAAC;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createExtensionDataContainer.esm.js","sources":["../../../../../frontend-internal/src/wiring/createExtensionDataContainer.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 ExtensionDataContainer,\n ExtensionDataRef,\n ExtensionDataValue,\n} from '@backstage/frontend-plugin-api';\n\nexport function createExtensionDataContainer<UData extends ExtensionDataRef>(\n values: Iterable<\n UData extends ExtensionDataRef<infer IData, infer IId>\n ? ExtensionDataValue<IData, IId>\n : never\n >,\n contextName: string,\n declaredRefs?: ExtensionDataRef<any, any, any>[],\n): ExtensionDataContainer<UData> {\n if (typeof values !== 'object' || !values?.[Symbol.iterator]) {\n throw new Error(`${contextName} did not provide an iterable object`);\n }\n\n const container = new Map<string, ExtensionDataValue<any, any>>();\n const verifyRefs =\n declaredRefs && new Map(declaredRefs.map(ref => [ref.id, ref]));\n\n for (const output of values) {\n if (verifyRefs) {\n if (!verifyRefs.delete(output.id)) {\n throw new Error(\n `extension data '${output.id}' was provided but not declared`,\n );\n }\n }\n container.set(output.id, output);\n }\n\n const remainingRefs =\n verifyRefs &&\n Array.from(verifyRefs.values()).filter(ref => !ref.config.optional);\n if (remainingRefs && remainingRefs.length > 0) {\n throw new Error(\n `missing required extension data value(s) '${remainingRefs\n .map(ref => ref.id)\n .join(', ')}'`,\n );\n }\n\n return {\n get(ref) {\n return container.get(ref.id)?.value;\n },\n [Symbol.iterator]() {\n return container.values();\n },\n } as ExtensionDataContainer<UData>;\n}\n"],"names":[],"mappings":"AAsBO,SAAS,4BAAA,CACd,MAAA,EAKA,WAAA,EACA,YAAA,EAC+B;AAC/B,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,IAAY,CAAC,MAAA,GAAS,MAAA,CAAO,QAAQ,CAAA,EAAG;AAC5D,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,EAAG,WAAW,CAAA,mCAAA,CAAqC,CAAA;AAAA,EACrE;AAEA,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAA0C;AAIhE,EAAA,KAAA,MAAW,UAAU,MAAA,EAAQ;AAQ3B,IAAA,SAAA,CAAU,GAAA,CAAI,MAAA,CAAO,EAAA,EAAI,MAAM,CAAA;AAAA,EACjC;AAaA,EAAA,OAAO;AAAA,IACL,IAAI,GAAA,EAAK;AACP,MAAA,OAAO,SAAA,CAAU,GAAA,CAAI,GAAA,CAAI,EAAE,CAAA,EAAG,KAAA;AAAA,IAChC,CAAA;AAAA,IACA,CAAC,MAAA,CAAO,QAAQ,CAAA,GAAI;AAClB,MAAA,OAAO,UAAU,MAAA,EAAO;AAAA,IAC1B;AAAA,GACF;AACF
|
|
1
|
+
{"version":3,"file":"createExtensionDataContainer.esm.js","sources":["../../../../../frontend-internal/src/wiring/createExtensionDataContainer.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 ExtensionDataContainer,\n ExtensionDataRef,\n ExtensionDataValue,\n} from '@backstage/frontend-plugin-api';\n\nexport function createExtensionDataContainer<UData extends ExtensionDataRef>(\n values: Iterable<\n UData extends ExtensionDataRef<infer IData, infer IId>\n ? ExtensionDataValue<IData, IId>\n : never\n >,\n contextName: string,\n declaredRefs?: ExtensionDataRef<any, any, any>[],\n): ExtensionDataContainer<UData> {\n if (typeof values !== 'object' || !values?.[Symbol.iterator]) {\n throw new Error(`${contextName} did not provide an iterable object`);\n }\n\n const container = new Map<string, ExtensionDataValue<any, any>>();\n const verifyRefs =\n declaredRefs && new Map(declaredRefs.map(ref => [ref.id, ref]));\n\n for (const output of values) {\n if (verifyRefs) {\n if (!verifyRefs.delete(output.id)) {\n throw new Error(\n `extension data '${output.id}' was provided but not declared`,\n );\n }\n }\n container.set(output.id, output);\n }\n\n const remainingRefs =\n verifyRefs &&\n Array.from(verifyRefs.values()).filter(ref => !ref.config.optional);\n if (remainingRefs && remainingRefs.length > 0) {\n throw new Error(\n `missing required extension data value(s) '${remainingRefs\n .map(ref => ref.id)\n .join(', ')}'`,\n );\n }\n\n return {\n get(ref) {\n return container.get(ref.id)?.value;\n },\n [Symbol.iterator]() {\n return container.values();\n },\n } as ExtensionDataContainer<UData>;\n}\n"],"names":[],"mappings":"AAsBO,SAAS,4BAAA,CACd,MAAA,EAKA,WAAA,EACA,YAAA,EAC+B;AAC/B,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,IAAY,CAAC,MAAA,GAAS,MAAA,CAAO,QAAQ,CAAA,EAAG;AAC5D,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,EAAG,WAAW,CAAA,mCAAA,CAAqC,CAAA;AAAA,EACrE;AAEA,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAA0C;AAIhE,EAAA,KAAA,MAAW,UAAU,MAAA,EAAQ;AAQ3B,IAAA,SAAA,CAAU,GAAA,CAAI,MAAA,CAAO,EAAA,EAAI,MAAM,CAAA;AAAA,EACjC;AAaA,EAAA,OAAO;AAAA,IACL,IAAI,GAAA,EAAK;AACP,MAAA,OAAO,SAAA,CAAU,GAAA,CAAI,GAAA,CAAI,EAAE,CAAA,EAAG,KAAA;AAAA,IAChC,CAAA;AAAA,IACA,CAAC,MAAA,CAAO,QAAQ,CAAA,GAAI;AAClB,MAAA,OAAO,UAAU,MAAA,EAAO;AAAA,IAC1B;AAAA,GACF;AACF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TranslationRef.esm.js","sources":["../../../../../frontend-plugin-api/src/translation/TranslationRef.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 createTranslationResource,\n TranslationResource,\n} from './TranslationResource';\n\n/** @public */\nexport interface TranslationRef<\n TId extends string = string,\n TMessages extends { [key in string]: string } = { [key in string]: string },\n> {\n $$type: '@backstage/TranslationRef';\n\n id: TId;\n\n T: TMessages;\n}\n\n/** @internal */\ntype AnyMessages = { [key in string]: string };\n\n/** @ignore */\ntype AnyNestedMessages = { [key in string]: AnyNestedMessages | string };\n\n/**\n * Flattens a nested message declaration into a flat object with dot-separated keys.\n *\n * @ignore\n */\ntype FlattenedMessages<TMessages extends AnyNestedMessages> =\n // Flatten out object keys into a union structure of objects, e.g. { a: 'a', b: 'b' } -> { a: 'a' } | { b: 'b' }\n // Any nested object will be flattened into the individual unions, e.g. { a: 'a', b: { x: 'x', y: 'y' } } -> { a: 'a' } | { 'b.x': 'x', 'b.y': 'y' }\n // We create this structure by first nesting the desired union types into the original object, and\n // then extract them by indexing with `keyof TMessages` to form the union.\n // Throughout this the objects are wrapped up in a function parameter, which allows us to have the\n // final step of flipping this unions around to an intersection by inferring the function parameter.\n {\n [TKey in keyof TMessages]: (\n _: TMessages[TKey] extends string\n ? { [_ in TKey]: TMessages[TKey] } // String values are leaf nodes, passed through with the same key\n : TMessages[TKey] extends AnyNestedMessages\n ? FlattenedMessages<TMessages[TKey]> extends infer TNested // Recurse into nested messages, \"local variable\" for the result\n ? {\n [TNestedKey in keyof TNested as `${TKey & string}.${TNestedKey &\n string}`]: TNested[TNestedKey];\n }\n : never\n : never, // Unreachable: TMessages[TKey] is always string or AnyNestedMessages\n ) => void;\n // The `[keyof TMessages]` extracts the object values union from our flattened structure, still wrapped up in function parameters.\n // The `extends (_: infer TIntersection) => void` flips the union to an intersection, at which point we have the correct type.\n }[keyof TMessages] extends (_: infer TIntersection) => void\n ? // This object mapping just expands similar to the Expand<> utility type, providing nicer type hints\n {\n readonly [TExpandKey in keyof TIntersection]: TIntersection[TExpandKey];\n }\n : never;\n\n/** @internal */\nexport interface InternalTranslationRef<\n TId extends string = string,\n TMessages extends { [key in string]: string } = { [key in string]: string },\n> extends TranslationRef<TId, TMessages> {\n version: 'v1';\n\n getDefaultMessages(): AnyMessages;\n\n getDefaultResource(): TranslationResource | undefined;\n}\n\n/** @public */\nexport interface TranslationRefOptions<\n TId extends string,\n TNestedMessages extends AnyNestedMessages,\n TTranslations extends {\n [language in string]: () => Promise<{\n default: {\n [key in keyof FlattenedMessages<TNestedMessages>]: string | null;\n };\n }>;\n },\n> {\n id: TId;\n messages: TNestedMessages;\n translations?: TTranslations;\n}\n\nfunction flattenMessages(nested: AnyNestedMessages): AnyMessages {\n const entries = new Array<[string, string]>();\n\n function visit(obj: AnyNestedMessages, prefix: string): void {\n for (const [key, value] of Object.entries(obj)) {\n if (typeof value === 'string') {\n entries.push([prefix + key, value]);\n } else {\n visit(value, `${prefix}${key}.`);\n }\n }\n }\n\n visit(nested, '');\n\n return Object.fromEntries(entries);\n}\n\n/** @internal */\nclass TranslationRefImpl<\n TId extends string,\n TNestedMessages extends AnyNestedMessages,\n> implements InternalTranslationRef<TId, FlattenedMessages<TNestedMessages>>\n{\n #id: TId;\n #messages: FlattenedMessages<TNestedMessages>;\n #resources: TranslationResource | undefined;\n\n constructor(options: TranslationRefOptions<TId, TNestedMessages, any>) {\n this.#id = options.id;\n this.#messages = flattenMessages(\n options.messages,\n ) as FlattenedMessages<TNestedMessages>;\n }\n\n $$type = '@backstage/TranslationRef' as const;\n\n version = 'v1' as const;\n\n get id(): TId {\n return this.#id;\n }\n\n get T(): never {\n throw new Error('Not implemented');\n }\n\n getDefaultMessages(): AnyMessages {\n return this.#messages;\n }\n\n setDefaultResource(resources: TranslationResource): void {\n this.#resources = resources;\n }\n\n getDefaultResource(): TranslationResource | undefined {\n return this.#resources;\n }\n\n toString() {\n return `TranslationRef{id=${this.id}}`;\n }\n}\n\n/** @public */\nexport function createTranslationRef<\n TId extends string,\n const TNestedMessages extends AnyNestedMessages,\n TTranslations extends {\n [language in string]: () => Promise<{\n default: {\n [key in keyof FlattenedMessages<TNestedMessages>]: string | null;\n };\n }>;\n },\n>(\n config: TranslationRefOptions<TId, TNestedMessages, TTranslations>,\n): TranslationRef<TId, FlattenedMessages<TNestedMessages>> {\n const ref = new TranslationRefImpl(config);\n if (config.translations) {\n ref.setDefaultResource(\n createTranslationResource({\n ref,\n translations: config.translations as any,\n }),\n );\n }\n return ref;\n}\n\n/** @internal */\nexport function toInternalTranslationRef<\n TId extends string,\n TMessages extends AnyMessages,\n>(ref: TranslationRef<TId, TMessages>): InternalTranslationRef<TId, TMessages> {\n const r = ref as InternalTranslationRef<TId, TMessages>;\n if (r.$$type !== '@backstage/TranslationRef') {\n throw new Error(`Invalid translation ref, bad type '${r.$$type}'`);\n }\n if (r.version !== 'v1') {\n throw new Error(`Invalid translation ref, bad version '${r.version}'`);\n }\n return r;\n}\n"],"names":[],"mappings":"AAiMO,SAAS,yBAGd,GAAA,EAA6E;AAC7E,EAAA,MAAM,CAAA,GAAI,GAAA;AACV,EAAA,IAAI,CAAA,CAAE,WAAW,2BAAA,EAA6B;AAC5C,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,mCAAA,EAAsC,CAAA,CAAE,MAAM,CAAA,CAAA,CAAG,CAAA;AAAA,EACnE;AACA,EAAA,IAAI,CAAA,CAAE,YAAY,IAAA,EAAM;AACtB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,sCAAA,EAAyC,CAAA,CAAE,OAAO,CAAA,CAAA,CAAG,CAAA;AAAA,EACvE;AACA,EAAA,OAAO,CAAA;AACT
|
|
1
|
+
{"version":3,"file":"TranslationRef.esm.js","sources":["../../../../../frontend-plugin-api/src/translation/TranslationRef.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 createTranslationResource,\n TranslationResource,\n} from './TranslationResource';\n\n/** @public */\nexport interface TranslationRef<\n TId extends string = string,\n TMessages extends { [key in string]: string } = { [key in string]: string },\n> {\n $$type: '@backstage/TranslationRef';\n\n id: TId;\n\n T: TMessages;\n}\n\n/** @internal */\ntype AnyMessages = { [key in string]: string };\n\n/** @ignore */\ntype AnyNestedMessages = { [key in string]: AnyNestedMessages | string };\n\n/**\n * Flattens a nested message declaration into a flat object with dot-separated keys.\n *\n * @ignore\n */\ntype FlattenedMessages<TMessages extends AnyNestedMessages> =\n // Flatten out object keys into a union structure of objects, e.g. { a: 'a', b: 'b' } -> { a: 'a' } | { b: 'b' }\n // Any nested object will be flattened into the individual unions, e.g. { a: 'a', b: { x: 'x', y: 'y' } } -> { a: 'a' } | { 'b.x': 'x', 'b.y': 'y' }\n // We create this structure by first nesting the desired union types into the original object, and\n // then extract them by indexing with `keyof TMessages` to form the union.\n // Throughout this the objects are wrapped up in a function parameter, which allows us to have the\n // final step of flipping this unions around to an intersection by inferring the function parameter.\n {\n [TKey in keyof TMessages]: (\n _: TMessages[TKey] extends string\n ? { [_ in TKey]: TMessages[TKey] } // String values are leaf nodes, passed through with the same key\n : TMessages[TKey] extends AnyNestedMessages\n ? FlattenedMessages<TMessages[TKey]> extends infer TNested // Recurse into nested messages, \"local variable\" for the result\n ? {\n [TNestedKey in keyof TNested as `${TKey & string}.${TNestedKey &\n string}`]: TNested[TNestedKey];\n }\n : never\n : never, // Unreachable: TMessages[TKey] is always string or AnyNestedMessages\n ) => void;\n // The `[keyof TMessages]` extracts the object values union from our flattened structure, still wrapped up in function parameters.\n // The `extends (_: infer TIntersection) => void` flips the union to an intersection, at which point we have the correct type.\n }[keyof TMessages] extends (_: infer TIntersection) => void\n ? // This object mapping just expands similar to the Expand<> utility type, providing nicer type hints\n {\n readonly [TExpandKey in keyof TIntersection]: TIntersection[TExpandKey];\n }\n : never;\n\n/** @internal */\nexport interface InternalTranslationRef<\n TId extends string = string,\n TMessages extends { [key in string]: string } = { [key in string]: string },\n> extends TranslationRef<TId, TMessages> {\n version: 'v1';\n\n getDefaultMessages(): AnyMessages;\n\n getDefaultResource(): TranslationResource | undefined;\n}\n\n/** @public */\nexport interface TranslationRefOptions<\n TId extends string,\n TNestedMessages extends AnyNestedMessages,\n TTranslations extends {\n [language in string]: () => Promise<{\n default: {\n [key in keyof FlattenedMessages<TNestedMessages>]: string | null;\n };\n }>;\n },\n> {\n id: TId;\n messages: TNestedMessages;\n translations?: TTranslations;\n}\n\nfunction flattenMessages(nested: AnyNestedMessages): AnyMessages {\n const entries = new Array<[string, string]>();\n\n function visit(obj: AnyNestedMessages, prefix: string): void {\n for (const [key, value] of Object.entries(obj)) {\n if (typeof value === 'string') {\n entries.push([prefix + key, value]);\n } else {\n visit(value, `${prefix}${key}.`);\n }\n }\n }\n\n visit(nested, '');\n\n return Object.fromEntries(entries);\n}\n\n/** @internal */\nclass TranslationRefImpl<\n TId extends string,\n TNestedMessages extends AnyNestedMessages,\n> implements InternalTranslationRef<TId, FlattenedMessages<TNestedMessages>>\n{\n #id: TId;\n #messages: FlattenedMessages<TNestedMessages>;\n #resources: TranslationResource | undefined;\n\n constructor(options: TranslationRefOptions<TId, TNestedMessages, any>) {\n this.#id = options.id;\n this.#messages = flattenMessages(\n options.messages,\n ) as FlattenedMessages<TNestedMessages>;\n }\n\n $$type = '@backstage/TranslationRef' as const;\n\n version = 'v1' as const;\n\n get id(): TId {\n return this.#id;\n }\n\n get T(): never {\n throw new Error('Not implemented');\n }\n\n getDefaultMessages(): AnyMessages {\n return this.#messages;\n }\n\n setDefaultResource(resources: TranslationResource): void {\n this.#resources = resources;\n }\n\n getDefaultResource(): TranslationResource | undefined {\n return this.#resources;\n }\n\n toString() {\n return `TranslationRef{id=${this.id}}`;\n }\n}\n\n/** @public */\nexport function createTranslationRef<\n TId extends string,\n const TNestedMessages extends AnyNestedMessages,\n TTranslations extends {\n [language in string]: () => Promise<{\n default: {\n [key in keyof FlattenedMessages<TNestedMessages>]: string | null;\n };\n }>;\n },\n>(\n config: TranslationRefOptions<TId, TNestedMessages, TTranslations>,\n): TranslationRef<TId, FlattenedMessages<TNestedMessages>> {\n const ref = new TranslationRefImpl(config);\n if (config.translations) {\n ref.setDefaultResource(\n createTranslationResource({\n ref,\n translations: config.translations as any,\n }),\n );\n }\n return ref;\n}\n\n/** @internal */\nexport function toInternalTranslationRef<\n TId extends string,\n TMessages extends AnyMessages,\n>(ref: TranslationRef<TId, TMessages>): InternalTranslationRef<TId, TMessages> {\n const r = ref as InternalTranslationRef<TId, TMessages>;\n if (r.$$type !== '@backstage/TranslationRef') {\n throw new Error(`Invalid translation ref, bad type '${r.$$type}'`);\n }\n if (r.version !== 'v1') {\n throw new Error(`Invalid translation ref, bad version '${r.version}'`);\n }\n return r;\n}\n"],"names":[],"mappings":"AAiMO,SAAS,yBAGd,GAAA,EAA6E;AAC7E,EAAA,MAAM,CAAA,GAAI,GAAA;AACV,EAAA,IAAI,CAAA,CAAE,WAAW,2BAAA,EAA6B;AAC5C,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,mCAAA,EAAsC,CAAA,CAAE,MAAM,CAAA,CAAA,CAAG,CAAA;AAAA,EACnE;AACA,EAAA,IAAI,CAAA,CAAE,YAAY,IAAA,EAAM;AACtB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,sCAAA,EAAyC,CAAA,CAAE,OAAO,CAAA,CAAA,CAAG,CAAA;AAAA,EACvE;AACA,EAAA,OAAO,CAAA;AACT;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createFrontendModule.esm.js","sources":["../../../../../frontend-plugin-api/src/wiring/createFrontendModule.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 { ExtensionDefinition } from './createExtension';\nimport {\n Extension,\n resolveExtensionDefinitions,\n} from './resolveExtensionDefinition';\nimport { FeatureFlagConfig } from './types';\nimport { FilterPredicate } from '@backstage/filter-predicates';\n\n/** @public */\nexport interface CreateFrontendModuleOptions<\n TPluginId extends string,\n TExtensions extends readonly ExtensionDefinition[],\n> {\n pluginId: TPluginId;\n extensions?: TExtensions;\n featureFlags?: FeatureFlagConfig[];\n if?: FilterPredicate;\n}\n\n/** @public */\nexport interface FrontendModule {\n readonly $$type: '@backstage/FrontendModule';\n readonly pluginId: string;\n}\n\n/** @internal */\nexport interface InternalFrontendModule extends FrontendModule {\n readonly version: 'v1';\n readonly extensions: Extension<unknown>[];\n readonly featureFlags: FeatureFlagConfig[];\n readonly if?: FilterPredicate;\n}\n\n/**\n * Creates a new module that can be installed in a Backstage app.\n *\n * @remarks\n *\n * Modules are used to add or override extensions for an existing plugin. If a\n * module provides an extension with the same ID as one provided by the plugin,\n * the extension provided by the module will always take precedence.\n *\n * Every module is created for a specific plugin by providing the\n * unique ID of the plugin that the module should be installed for. If that\n * plugin is not present in the app, the module will be ignored and have no\n * effect.\n *\n * For more information on how modules work, see the\n * {@link https://backstage.io/docs/frontend-system/architecture/extension-overrides#creating-a-frontend-module | documentation for modules}\n * in the frontend system documentation.\n *\n * It is recommended to name the module variable of the form `<pluginId>Module<ModuleName>`.\n *\n * @example\n *\n * ```tsx\n * import { createFrontendModule } from '@backstage/frontend-plugin-api';\n *\n * export const exampleModuleCustomPage = createFrontendModule({\n * pluginId: 'example',\n * extensions: [\n * // Overrides the default page for the 'example' plugin\n * PageBlueprint.make({\n * path: '/example',\n * loader: () => import('./CustomPage').then(m => <m.CustomPage />),\n * }),\n * ],\n * });\n * ```\n *\n * @public\n */\nexport function createFrontendModule<\n TId extends string,\n TExtensions extends readonly ExtensionDefinition[],\n>(options: CreateFrontendModuleOptions<TId, TExtensions>): FrontendModule {\n const { pluginId } = options;\n\n const { extensions } = resolveExtensionDefinitions(options.extensions ?? [], {\n namespace: pluginId,\n featureType: 'Module',\n });\n\n return {\n $$type: '@backstage/FrontendModule',\n version: 'v1',\n pluginId,\n featureFlags: options.featureFlags ?? [],\n if: options.if,\n extensions,\n toString() {\n return `Module{pluginId=${pluginId}}`;\n },\n } as InternalFrontendModule;\n}\n\n/** @internal */\nexport function isInternalFrontendModule(opaque: {\n $$type: string;\n}): opaque is InternalFrontendModule {\n if (opaque.$$type === '@backstage/FrontendModule') {\n // Make sure we throw if invalid\n toInternalFrontendModule(opaque as FrontendModule);\n return true;\n }\n return false;\n}\n\n/** @internal */\nexport function toInternalFrontendModule(\n plugin: FrontendModule,\n): InternalFrontendModule {\n const internal = plugin as InternalFrontendModule;\n if (internal.$$type !== '@backstage/FrontendModule') {\n throw new Error(`Invalid plugin instance, bad type '${internal.$$type}'`);\n }\n if (internal.version !== 'v1') {\n throw new Error(\n `Invalid plugin instance, bad version '${internal.version}'`,\n );\n }\n return internal;\n}\n"],"names":[],"mappings":"AAiHO,SAAS,yBAAyB,MAAA,EAEJ;AACnC,EAAA,IAAI,MAAA,CAAO,WAAW,2BAAA,EAA6B;AAEjD,IAAA,wBAAA,CAAyB,MAAwB,CAAA;AACjD,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,KAAA;AACT;AAGO,SAAS,yBACd,MAAA,EACwB;AACxB,EAAA,MAAM,QAAA,GAAW,MAAA;AACjB,EAAA,IAAI,QAAA,CAAS,WAAW,2BAAA,EAA6B;AACnD,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,mCAAA,EAAsC,QAAA,CAAS,MAAM,CAAA,CAAA,CAAG,CAAA;AAAA,EAC1E;AACA,EAAA,IAAI,QAAA,CAAS,YAAY,IAAA,EAAM;AAC7B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,sCAAA,EAAyC,SAAS,OAAO,CAAA,CAAA;AAAA,KAC3D;AAAA,EACF;AACA,EAAA,OAAO,QAAA;AACT
|
|
1
|
+
{"version":3,"file":"createFrontendModule.esm.js","sources":["../../../../../frontend-plugin-api/src/wiring/createFrontendModule.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 { ExtensionDefinition } from './createExtension';\nimport {\n Extension,\n resolveExtensionDefinitions,\n} from './resolveExtensionDefinition';\nimport { FeatureFlagConfig } from './types';\nimport { FilterPredicate } from '@backstage/filter-predicates';\n\n/** @public */\nexport interface CreateFrontendModuleOptions<\n TPluginId extends string,\n TExtensions extends readonly ExtensionDefinition[],\n> {\n pluginId: TPluginId;\n extensions?: TExtensions;\n featureFlags?: FeatureFlagConfig[];\n if?: FilterPredicate;\n}\n\n/** @public */\nexport interface FrontendModule {\n readonly $$type: '@backstage/FrontendModule';\n readonly pluginId: string;\n}\n\n/** @internal */\nexport interface InternalFrontendModule extends FrontendModule {\n readonly version: 'v1';\n readonly extensions: Extension<unknown>[];\n readonly featureFlags: FeatureFlagConfig[];\n readonly if?: FilterPredicate;\n}\n\n/**\n * Creates a new module that can be installed in a Backstage app.\n *\n * @remarks\n *\n * Modules are used to add or override extensions for an existing plugin. If a\n * module provides an extension with the same ID as one provided by the plugin,\n * the extension provided by the module will always take precedence.\n *\n * Every module is created for a specific plugin by providing the\n * unique ID of the plugin that the module should be installed for. If that\n * plugin is not present in the app, the module will be ignored and have no\n * effect.\n *\n * For more information on how modules work, see the\n * {@link https://backstage.io/docs/frontend-system/architecture/extension-overrides#creating-a-frontend-module | documentation for modules}\n * in the frontend system documentation.\n *\n * It is recommended to name the module variable of the form `<pluginId>Module<ModuleName>`.\n *\n * @example\n *\n * ```tsx\n * import { createFrontendModule } from '@backstage/frontend-plugin-api';\n *\n * export const exampleModuleCustomPage = createFrontendModule({\n * pluginId: 'example',\n * extensions: [\n * // Overrides the default page for the 'example' plugin\n * PageBlueprint.make({\n * path: '/example',\n * loader: () => import('./CustomPage').then(m => <m.CustomPage />),\n * }),\n * ],\n * });\n * ```\n *\n * @public\n */\nexport function createFrontendModule<\n TId extends string,\n TExtensions extends readonly ExtensionDefinition[],\n>(options: CreateFrontendModuleOptions<TId, TExtensions>): FrontendModule {\n const { pluginId } = options;\n\n const { extensions } = resolveExtensionDefinitions(options.extensions ?? [], {\n namespace: pluginId,\n featureType: 'Module',\n });\n\n return {\n $$type: '@backstage/FrontendModule',\n version: 'v1',\n pluginId,\n featureFlags: options.featureFlags ?? [],\n if: options.if,\n extensions,\n toString() {\n return `Module{pluginId=${pluginId}}`;\n },\n } as InternalFrontendModule;\n}\n\n/** @internal */\nexport function isInternalFrontendModule(opaque: {\n $$type: string;\n}): opaque is InternalFrontendModule {\n if (opaque.$$type === '@backstage/FrontendModule') {\n // Make sure we throw if invalid\n toInternalFrontendModule(opaque as FrontendModule);\n return true;\n }\n return false;\n}\n\n/** @internal */\nexport function toInternalFrontendModule(\n plugin: FrontendModule,\n): InternalFrontendModule {\n const internal = plugin as InternalFrontendModule;\n if (internal.$$type !== '@backstage/FrontendModule') {\n throw new Error(`Invalid plugin instance, bad type '${internal.$$type}'`);\n }\n if (internal.version !== 'v1') {\n throw new Error(\n `Invalid plugin instance, bad version '${internal.version}'`,\n );\n }\n return internal;\n}\n"],"names":[],"mappings":"AAiHO,SAAS,yBAAyB,MAAA,EAEJ;AACnC,EAAA,IAAI,MAAA,CAAO,WAAW,2BAAA,EAA6B;AAEjD,IAAA,wBAAA,CAAyB,MAAwB,CAAA;AACjD,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,KAAA;AACT;AAGO,SAAS,yBACd,MAAA,EACwB;AACxB,EAAA,MAAM,QAAA,GAAW,MAAA;AACjB,EAAA,IAAI,QAAA,CAAS,WAAW,2BAAA,EAA6B;AACnD,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,mCAAA,EAAsC,QAAA,CAAS,MAAM,CAAA,CAAA,CAAG,CAAA;AAAA,EAC1E;AACA,EAAA,IAAI,QAAA,CAAS,YAAY,IAAA,EAAM;AAC7B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,sCAAA,EAAyC,SAAS,OAAO,CAAA,CAAA;AAAA,KAC3D;AAAA,EACF;AACA,EAAA,OAAO,QAAA;AACT;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveExtensionDefinition.esm.js","sources":["../../../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition.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 {\n ExtensionDefinitionAttachTo,\n ExtensionDefinition,\n ExtensionDefinitionParameters,\n ResolvedExtensionInputs,\n} from './createExtension';\nimport { PortableSchema } from '../schema';\nimport { ExtensionInput } from './createExtensionInput';\nimport { ExtensionDataRef, ExtensionDataValue } from './createExtensionDataRef';\nimport {\n OpaqueExtensionDefinition,\n OpaqueExtensionInput,\n} from '@internal/frontend';\nimport { FilterPredicate } from '@backstage/filter-predicates';\n\n/** @public */\nexport type ExtensionAttachTo = { id: string; input: string };\n\n/** @public */\nexport interface Extension<TConfig, TConfigInput = TConfig> {\n $$type: '@backstage/Extension';\n readonly id: string;\n readonly attachTo: ExtensionAttachTo;\n readonly disabled: boolean;\n readonly configSchema?: PortableSchema<TConfig, TConfigInput>;\n}\n\n/** @internal */\nexport type InternalExtension<TConfig, TConfigInput> = Extension<\n TConfig,\n TConfigInput\n> &\n (\n | {\n readonly version: 'v1';\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 apis: ApiHolder;\n node: AppNode;\n config: TConfig;\n inputs: {\n [inputName in string]: unknown;\n };\n }): {\n [inputName in string]: unknown;\n };\n }\n | {\n readonly version: 'v2';\n readonly if?: FilterPredicate;\n readonly inputs: { [inputName in string]: ExtensionInput };\n readonly output: Array<ExtensionDataRef>;\n factory(options: {\n apis: ApiHolder;\n node: AppNode;\n config: TConfig;\n inputs: ResolvedExtensionInputs<{\n [inputName in string]: ExtensionInput;\n }>;\n }): Iterable<ExtensionDataValue<any, any>>;\n }\n );\n\n/** @internal */\nexport function toInternalExtension<TConfig, TConfigInput>(\n overrides: Extension<TConfig, TConfigInput>,\n): InternalExtension<TConfig, TConfigInput> {\n const internal = overrides as InternalExtension<TConfig, TConfigInput>;\n if (internal.$$type !== '@backstage/Extension') {\n throw new Error(\n `Invalid extension instance, bad type '${internal.$$type}'`,\n );\n }\n const version = internal.version;\n if (version !== 'v1' && version !== 'v2') {\n throw new Error(`Invalid extension instance, bad version '${version}'`);\n }\n return internal;\n}\n\n/** @ignore */\nexport type ResolveExtensionId<\n TExtension extends ExtensionDefinition,\n TNamespace extends string,\n> = TExtension extends ExtensionDefinition<{\n kind: infer IKind extends string | undefined;\n name: infer IName extends string | undefined;\n params: any;\n}>\n ? [string] extends [IKind | IName]\n ? never\n : (\n undefined extends IName ? TNamespace : `${TNamespace}/${IName}`\n ) extends infer INamePart extends string\n ? IKind extends string\n ? `${IKind}:${INamePart}`\n : INamePart\n : never\n : never;\n\nfunction resolveExtensionId(\n kind?: string,\n namespace?: string,\n name?: string,\n): string {\n const namePart =\n name && namespace ? `${namespace}/${name}` : namespace || name;\n if (!namePart) {\n throw new Error(\n `Extension must declare an explicit namespace or name as it could not be resolved from context, kind=${kind} namespace=${namespace} name=${name}`,\n );\n }\n\n return kind ? `${kind}:${namePart}` : namePart;\n}\n\nfunction resolveAttachTo(\n attachTo: ExtensionDefinitionAttachTo | ExtensionDefinitionAttachTo[],\n namespace?: string,\n): ExtensionAttachTo | ExtensionAttachTo[] {\n const resolveSpec = (\n spec: ExtensionDefinitionAttachTo,\n ): { id: string; input: string } => {\n if (OpaqueExtensionInput.isType(spec)) {\n const { context } = OpaqueExtensionInput.toInternal(spec);\n if (!context) {\n throw new Error(\n 'Invalid input object without a parent extension used as attachment point',\n );\n }\n return {\n id: resolveExtensionId(context.kind, namespace, context.name),\n input: context.input,\n };\n }\n if ('relative' in spec && spec.relative) {\n return {\n id: resolveExtensionId(\n spec.relative.kind,\n namespace,\n spec.relative.name,\n ),\n input: spec.input,\n };\n }\n if ('id' in spec) {\n return { id: spec.id, input: spec.input };\n }\n throw new Error('Invalid attachment point specification');\n };\n\n if (Array.isArray(attachTo)) {\n return attachTo.map(resolveSpec);\n }\n\n return resolveSpec(attachTo);\n}\n\n/**\n * Resolves a list of extension definitions into extensions, returning both the\n * resolved extensions and a map of extension definitions keyed by resolved ID.\n * Throws if any two definitions resolve to the same ID.\n *\n * @internal\n */\nexport function resolveExtensionDefinitions(\n definitions: Iterable<ExtensionDefinition>,\n context: { namespace: string; featureType: string },\n): {\n extensions: Extension<any>[];\n extensionDefinitionsById: Map<\n string,\n typeof OpaqueExtensionDefinition.TInternal\n >;\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 definitions) {\n const internal = OpaqueExtensionDefinition.toInternal(def);\n const ext = resolveExtensionDefinition(def, {\n namespace: context.namespace,\n });\n extensions.push(ext);\n extensionDefinitionsById.set(ext.id, {\n ...internal,\n namespace: context.namespace,\n });\n }\n\n throwOnDuplicateExtensionIds(\n extensions.map(e => e.id),\n context,\n );\n\n return { extensions, extensionDefinitionsById };\n}\n\n/**\n * Throws if the provided list of resolved extension IDs contains duplicates.\n *\n * @internal\n */\nexport function throwOnDuplicateExtensionIds(\n extensionIds: string[],\n context: { namespace: string; featureType: string },\n): void {\n const seen = new Set<string>();\n const duplicates = new Set<string>();\n for (const id of extensionIds) {\n if (seen.has(id)) {\n duplicates.add(id);\n } else {\n seen.add(id);\n }\n }\n if (duplicates.size > 0) {\n throw new Error(\n `${context.featureType} '${\n context.namespace\n }' provided duplicate extensions: ${Array.from(duplicates).join(', ')}`,\n );\n }\n}\n\n/** @internal */\nexport function resolveExtensionDefinition<\n T extends ExtensionDefinitionParameters,\n>(\n definition: ExtensionDefinition<T>,\n context?: { namespace?: string },\n): Extension<T['config'], T['configInput']> {\n const internalDefinition = OpaqueExtensionDefinition.toInternal(definition);\n\n const {\n name,\n kind,\n namespace: internalNamespace,\n override: _skip2,\n attachTo,\n ...rest\n } = internalDefinition;\n\n const namespace = internalNamespace ?? context?.namespace;\n const id = resolveExtensionId(kind, namespace, name);\n\n return {\n ...rest,\n attachTo: resolveAttachTo(attachTo, namespace) as ExtensionAttachTo,\n $$type: '@backstage/Extension',\n version: internalDefinition.version,\n id,\n toString() {\n return `Extension{id=${id}}`;\n },\n } as InternalExtension<T['config'], T['configInput']> & Object;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"resolveExtensionDefinition.esm.js","sources":["../../../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition.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 {\n ExtensionDefinitionAttachTo,\n ExtensionDefinition,\n ExtensionDefinitionParameters,\n ResolvedExtensionInputs,\n} from './createExtension';\nimport { PortableSchema } from '../schema';\nimport { ExtensionInput } from './createExtensionInput';\nimport { ExtensionDataRef, ExtensionDataValue } from './createExtensionDataRef';\nimport {\n OpaqueExtensionDefinition,\n OpaqueExtensionInput,\n} from '@internal/frontend';\nimport { FilterPredicate } from '@backstage/filter-predicates';\n\n/** @public */\nexport type ExtensionAttachTo = { id: string; input: string };\n\n/** @public */\nexport interface Extension<TConfig, TConfigInput = TConfig> {\n $$type: '@backstage/Extension';\n readonly id: string;\n readonly attachTo: ExtensionAttachTo;\n readonly disabled: boolean;\n readonly configSchema?: PortableSchema<TConfig, TConfigInput>;\n}\n\n/** @internal */\nexport type InternalExtension<TConfig, TConfigInput> = Extension<\n TConfig,\n TConfigInput\n> &\n (\n | {\n readonly version: 'v1';\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 apis: ApiHolder;\n node: AppNode;\n config: TConfig;\n inputs: {\n [inputName in string]: unknown;\n };\n }): {\n [inputName in string]: unknown;\n };\n }\n | {\n readonly version: 'v2';\n readonly if?: FilterPredicate;\n readonly inputs: { [inputName in string]: ExtensionInput };\n readonly output: Array<ExtensionDataRef>;\n factory(options: {\n apis: ApiHolder;\n node: AppNode;\n config: TConfig;\n inputs: ResolvedExtensionInputs<{\n [inputName in string]: ExtensionInput;\n }>;\n }): Iterable<ExtensionDataValue<any, any>>;\n }\n );\n\n/** @internal */\nexport function toInternalExtension<TConfig, TConfigInput>(\n overrides: Extension<TConfig, TConfigInput>,\n): InternalExtension<TConfig, TConfigInput> {\n const internal = overrides as InternalExtension<TConfig, TConfigInput>;\n if (internal.$$type !== '@backstage/Extension') {\n throw new Error(\n `Invalid extension instance, bad type '${internal.$$type}'`,\n );\n }\n const version = internal.version;\n if (version !== 'v1' && version !== 'v2') {\n throw new Error(`Invalid extension instance, bad version '${version}'`);\n }\n return internal;\n}\n\n/** @ignore */\nexport type ResolveExtensionId<\n TExtension extends ExtensionDefinition,\n TNamespace extends string,\n> = TExtension extends ExtensionDefinition<{\n kind: infer IKind extends string | undefined;\n name: infer IName extends string | undefined;\n params: any;\n}>\n ? [string] extends [IKind | IName]\n ? never\n : (\n undefined extends IName ? TNamespace : `${TNamespace}/${IName}`\n ) extends infer INamePart extends string\n ? IKind extends string\n ? `${IKind}:${INamePart}`\n : INamePart\n : never\n : never;\n\nfunction resolveExtensionId(\n kind?: string,\n namespace?: string,\n name?: string,\n): string {\n const namePart =\n name && namespace ? `${namespace}/${name}` : namespace || name;\n if (!namePart) {\n throw new Error(\n `Extension must declare an explicit namespace or name as it could not be resolved from context, kind=${kind} namespace=${namespace} name=${name}`,\n );\n }\n\n return kind ? `${kind}:${namePart}` : namePart;\n}\n\nfunction resolveAttachTo(\n attachTo: ExtensionDefinitionAttachTo | ExtensionDefinitionAttachTo[],\n namespace?: string,\n): ExtensionAttachTo | ExtensionAttachTo[] {\n const resolveSpec = (\n spec: ExtensionDefinitionAttachTo,\n ): { id: string; input: string } => {\n if (OpaqueExtensionInput.isType(spec)) {\n const { context } = OpaqueExtensionInput.toInternal(spec);\n if (!context) {\n throw new Error(\n 'Invalid input object without a parent extension used as attachment point',\n );\n }\n return {\n id: resolveExtensionId(context.kind, namespace, context.name),\n input: context.input,\n };\n }\n if ('relative' in spec && spec.relative) {\n return {\n id: resolveExtensionId(\n spec.relative.kind,\n namespace,\n spec.relative.name,\n ),\n input: spec.input,\n };\n }\n if ('id' in spec) {\n return { id: spec.id, input: spec.input };\n }\n throw new Error('Invalid attachment point specification');\n };\n\n if (Array.isArray(attachTo)) {\n return attachTo.map(resolveSpec);\n }\n\n return resolveSpec(attachTo);\n}\n\n/**\n * Resolves a list of extension definitions into extensions, returning both the\n * resolved extensions and a map of extension definitions keyed by resolved ID.\n * Throws if any two definitions resolve to the same ID.\n *\n * @internal\n */\nexport function resolveExtensionDefinitions(\n definitions: Iterable<ExtensionDefinition>,\n context: { namespace: string; featureType: string },\n): {\n extensions: Extension<any>[];\n extensionDefinitionsById: Map<\n string,\n typeof OpaqueExtensionDefinition.TInternal\n >;\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 definitions) {\n const internal = OpaqueExtensionDefinition.toInternal(def);\n const ext = resolveExtensionDefinition(def, {\n namespace: context.namespace,\n });\n extensions.push(ext);\n extensionDefinitionsById.set(ext.id, {\n ...internal,\n namespace: context.namespace,\n });\n }\n\n throwOnDuplicateExtensionIds(\n extensions.map(e => e.id),\n context,\n );\n\n return { extensions, extensionDefinitionsById };\n}\n\n/**\n * Throws if the provided list of resolved extension IDs contains duplicates.\n *\n * @internal\n */\nexport function throwOnDuplicateExtensionIds(\n extensionIds: string[],\n context: { namespace: string; featureType: string },\n): void {\n const seen = new Set<string>();\n const duplicates = new Set<string>();\n for (const id of extensionIds) {\n if (seen.has(id)) {\n duplicates.add(id);\n } else {\n seen.add(id);\n }\n }\n if (duplicates.size > 0) {\n throw new Error(\n `${context.featureType} '${\n context.namespace\n }' provided duplicate extensions: ${Array.from(duplicates).join(', ')}`,\n );\n }\n}\n\n/** @internal */\nexport function resolveExtensionDefinition<\n T extends ExtensionDefinitionParameters,\n>(\n definition: ExtensionDefinition<T>,\n context?: { namespace?: string },\n): Extension<T['config'], T['configInput']> {\n const internalDefinition = OpaqueExtensionDefinition.toInternal(definition);\n\n const {\n name,\n kind,\n namespace: internalNamespace,\n override: _skip2,\n attachTo,\n ...rest\n } = internalDefinition;\n\n const namespace = internalNamespace ?? context?.namespace;\n const id = resolveExtensionId(kind, namespace, name);\n\n return {\n ...rest,\n attachTo: resolveAttachTo(attachTo, namespace) as ExtensionAttachTo,\n $$type: '@backstage/Extension',\n version: internalDefinition.version,\n id,\n toString() {\n return `Extension{id=${id}}`;\n },\n } as InternalExtension<T['config'], T['configInput']> & Object;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OpaqueType.esm.js","sources":["../../../../opaque-internal/src/OpaqueType.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\n// TODO(Rugvip): This lives here temporarily, but should be moved to a more\n// central location. It's useful for backend packages too so we'll need to have\n// it in a common package, but it might also be that we want to make it\n// available publicly too in which case it would make sense to have this be part\n// of @backstage/version-bridge. The problem with exporting it from there is\n// that it would need to be very stable at that point, so it might be a bit\n// early to put it there already.\n\n/**\n * A helper for working with opaque types.\n */\nexport class OpaqueType<\n T extends {\n public: { $$type: string };\n versions: { version: string | undefined };\n },\n> {\n /**\n * Creates a new opaque type.\n *\n * @param options.type The type identifier of the opaque type\n * @param options.versions The available versions of the opaque type\n * @returns A new opaque type helper\n */\n static create<\n T extends {\n public: { $$type: string };\n versions: { version: string | undefined };\n },\n >(options: {\n type: T['public']['$$type'];\n versions: Array<T['versions']['version']>;\n }) {\n return new OpaqueType<T>(options.type, new Set(options.versions));\n }\n\n #type: string;\n #versions: Set<string | undefined>;\n\n private constructor(type: string, versions: Set<string | undefined>) {\n this.#type = type;\n this.#versions = versions;\n }\n\n /**\n * The internal version of the opaque type, used like this: `typeof MyOpaqueType.TPublic`\n *\n * @remarks\n *\n * This property is only useful for type checking, its runtime value is `undefined`.\n */\n TPublic: T['public'] = undefined as any;\n\n /**\n * The internal version of the opaque type, used like this: `typeof MyOpaqueType.TInternal`\n *\n * @remarks\n *\n * This property is only useful for type checking, its runtime value is `undefined`.\n */\n TInternal: T['public'] & T['versions'] = undefined as any;\n\n /**\n * @param value Input value expected to be an instance of this opaque type\n * @returns True if the value matches this opaque type\n */\n isType = (value: unknown): value is T['public'] => {\n return this.#isThisInternalType(value);\n };\n\n /**\n * @param value Input value expected to be an instance of this opaque type\n * @throws If the value is not an instance of this opaque type or is of an unsupported version\n * @returns The internal version of the opaque type\n */\n toInternal = (value: unknown): T['public'] & T['versions'] => {\n if (!this.#isThisInternalType(value)) {\n throw new TypeError(\n `Invalid opaque type, expected '${\n this.#type\n }', but got '${this.#stringifyUnknown(value)}'`,\n );\n }\n\n if (!this.#versions.has(value.version)) {\n const versions = Array.from(this.#versions).map(this.#stringifyVersion);\n if (versions.length > 1) {\n versions[versions.length - 1] = `or ${versions[versions.length - 1]}`;\n }\n const expected =\n versions.length > 2 ? versions.join(', ') : versions.join(' ');\n throw new TypeError(\n `Invalid opaque type instance, got version ${this.#stringifyVersion(\n value.version,\n )}, expected ${expected}`,\n );\n }\n\n return value;\n };\n\n /**\n * Creates an instance of the opaque type, returning the public type.\n *\n * @param version The version of the instance to create\n * @param value The remaining public and internal properties of the instance\n * @returns An instance of the opaque type\n */\n createInstance<\n TVersion extends T['versions']['version'],\n TPublic extends T['public'],\n >(\n version: TVersion,\n props: Omit<T['public'], '$$type'> &\n (T['versions'] extends infer UVersion\n ? UVersion extends { version: TVersion }\n ? Omit<UVersion, 'version'>\n : never\n : never) &\n Object, // & Object to allow for object properties too, e.g. toString()\n ): TPublic {\n return Object.assign(props as object, {\n $$type: this.#type,\n ...(version && { version }),\n }) as unknown as TPublic;\n }\n\n #isThisInternalType(value: unknown): value is T['public'] & T['versions'] {\n if (value === null || typeof value !== 'object') {\n return false;\n }\n return (value as T['public']).$$type === this.#type;\n }\n\n #stringifyUnknown(value: unknown) {\n if (typeof value !== 'object') {\n return `<${typeof value}>`;\n }\n if (value === null) {\n return '<null>';\n }\n if ('$$type' in value) {\n return String(value.$$type);\n }\n return String(value);\n }\n\n #stringifyVersion = (version: string | undefined) => {\n return version ? `'${version}'` : 'undefined';\n };\n}\n"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"OpaqueType.esm.js","sources":["../../../../opaque-internal/src/OpaqueType.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\n// TODO(Rugvip): This lives here temporarily, but should be moved to a more\n// central location. It's useful for backend packages too so we'll need to have\n// it in a common package, but it might also be that we want to make it\n// available publicly too in which case it would make sense to have this be part\n// of @backstage/version-bridge. The problem with exporting it from there is\n// that it would need to be very stable at that point, so it might be a bit\n// early to put it there already.\n\n/**\n * A helper for working with opaque types.\n */\nexport class OpaqueType<\n T extends {\n public: { $$type: string };\n versions: { version: string | undefined };\n },\n> {\n /**\n * Creates a new opaque type.\n *\n * @param options.type The type identifier of the opaque type\n * @param options.versions The available versions of the opaque type\n * @returns A new opaque type helper\n */\n static create<\n T extends {\n public: { $$type: string };\n versions: { version: string | undefined };\n },\n >(options: {\n type: T['public']['$$type'];\n versions: Array<T['versions']['version']>;\n }) {\n return new OpaqueType<T>(options.type, new Set(options.versions));\n }\n\n #type: string;\n #versions: Set<string | undefined>;\n\n private constructor(type: string, versions: Set<string | undefined>) {\n this.#type = type;\n this.#versions = versions;\n }\n\n /**\n * The internal version of the opaque type, used like this: `typeof MyOpaqueType.TPublic`\n *\n * @remarks\n *\n * This property is only useful for type checking, its runtime value is `undefined`.\n */\n TPublic: T['public'] = undefined as any;\n\n /**\n * The internal version of the opaque type, used like this: `typeof MyOpaqueType.TInternal`\n *\n * @remarks\n *\n * This property is only useful for type checking, its runtime value is `undefined`.\n */\n TInternal: T['public'] & T['versions'] = undefined as any;\n\n /**\n * @param value Input value expected to be an instance of this opaque type\n * @returns True if the value matches this opaque type\n */\n isType = (value: unknown): value is T['public'] => {\n return this.#isThisInternalType(value);\n };\n\n /**\n * @param value Input value expected to be an instance of this opaque type\n * @throws If the value is not an instance of this opaque type or is of an unsupported version\n * @returns The internal version of the opaque type\n */\n toInternal = (value: unknown): T['public'] & T['versions'] => {\n if (!this.#isThisInternalType(value)) {\n throw new TypeError(\n `Invalid opaque type, expected '${\n this.#type\n }', but got '${this.#stringifyUnknown(value)}'`,\n );\n }\n\n if (!this.#versions.has(value.version)) {\n const versions = Array.from(this.#versions).map(this.#stringifyVersion);\n if (versions.length > 1) {\n versions[versions.length - 1] = `or ${versions[versions.length - 1]}`;\n }\n const expected =\n versions.length > 2 ? versions.join(', ') : versions.join(' ');\n throw new TypeError(\n `Invalid opaque type instance, got version ${this.#stringifyVersion(\n value.version,\n )}, expected ${expected}`,\n );\n }\n\n return value;\n };\n\n /**\n * Creates an instance of the opaque type, returning the public type.\n *\n * @param version The version of the instance to create\n * @param value The remaining public and internal properties of the instance\n * @returns An instance of the opaque type\n */\n createInstance<\n TVersion extends T['versions']['version'],\n TPublic extends T['public'],\n >(\n version: TVersion,\n props: Omit<T['public'], '$$type'> &\n (T['versions'] extends infer UVersion\n ? UVersion extends { version: TVersion }\n ? Omit<UVersion, 'version'>\n : never\n : never) &\n Object, // & Object to allow for object properties too, e.g. toString()\n ): TPublic {\n return Object.assign(props as object, {\n $$type: this.#type,\n ...(version && { version }),\n }) as unknown as TPublic;\n }\n\n #isThisInternalType(value: unknown): value is T['public'] & T['versions'] {\n if (value === null || typeof value !== 'object') {\n return false;\n }\n return (value as T['public']).$$type === this.#type;\n }\n\n #stringifyUnknown(value: unknown) {\n if (typeof value !== 'object') {\n return `<${typeof value}>`;\n }\n if (value === null) {\n return '<null>';\n }\n if ('$$type' in value) {\n return String(value.$$type);\n }\n return String(value);\n }\n\n #stringifyVersion = (version: string | undefined) => {\n return version ? `'${version}'` : 'undefined';\n };\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/frontend-test-utils",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.5-next.0",
|
|
4
4
|
"backstage": {
|
|
5
5
|
"role": "web-library"
|
|
6
6
|
},
|
|
@@ -31,25 +31,25 @@
|
|
|
31
31
|
"test": "backstage-cli package test"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@backstage/config": "
|
|
35
|
-
"@backstage/core-app-api": "
|
|
36
|
-
"@backstage/core-plugin-api": "
|
|
37
|
-
"@backstage/filter-predicates": "
|
|
38
|
-
"@backstage/frontend-app-api": "
|
|
39
|
-
"@backstage/frontend-plugin-api": "
|
|
40
|
-
"@backstage/plugin-app": "
|
|
41
|
-
"@backstage/plugin-app-react": "
|
|
42
|
-
"@backstage/plugin-permission-common": "
|
|
43
|
-
"@backstage/plugin-permission-react": "
|
|
44
|
-
"@backstage/test-utils": "
|
|
45
|
-
"@backstage/types": "
|
|
46
|
-
"@backstage/version-bridge": "
|
|
34
|
+
"@backstage/config": "1.3.10-next.0",
|
|
35
|
+
"@backstage/core-app-api": "1.20.6-next.0",
|
|
36
|
+
"@backstage/core-plugin-api": "1.12.11-next.0",
|
|
37
|
+
"@backstage/filter-predicates": "0.1.6-next.0",
|
|
38
|
+
"@backstage/frontend-app-api": "0.16.9-next.0",
|
|
39
|
+
"@backstage/frontend-plugin-api": "0.18.2-next.0",
|
|
40
|
+
"@backstage/plugin-app": "0.5.4-next.0",
|
|
41
|
+
"@backstage/plugin-app-react": "0.2.8-next.0",
|
|
42
|
+
"@backstage/plugin-permission-common": "0.9.12-next.0",
|
|
43
|
+
"@backstage/plugin-permission-react": "0.5.6-next.0",
|
|
44
|
+
"@backstage/test-utils": "1.7.23-next.0",
|
|
45
|
+
"@backstage/types": "1.2.2",
|
|
46
|
+
"@backstage/version-bridge": "1.0.12",
|
|
47
47
|
"i18next": "^22.4.15",
|
|
48
48
|
"zen-observable": "^0.10.0",
|
|
49
49
|
"zod": "^3.25.76 || ^4.0.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@backstage/cli": "
|
|
52
|
+
"@backstage/cli": "0.36.7-next.0",
|
|
53
53
|
"@testing-library/jest-dom": "^6.0.0",
|
|
54
54
|
"@types/jest": "*",
|
|
55
55
|
"@types/react": "^18.0.0",
|