@backstage/core-plugin-api 1.10.7 → 1.10.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @backstage/core-plugin-api
2
2
 
3
+ ## 1.10.8
4
+
5
+ ### Patch Changes
6
+
7
+ - c83cd8b: Fixed some circular or otherwise unclear imports
8
+ - 0169b23: Internal tweak to avoid circular dependencies
9
+ - Updated dependencies
10
+ - @backstage/config@1.3.2
11
+ - @backstage/errors@1.2.7
12
+ - @backstage/types@1.2.1
13
+ - @backstage/version-bridge@1.0.11
14
+
3
15
  ## 1.10.7
4
16
 
5
17
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"Tracker.esm.js","sources":["../../src/analytics/Tracker.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { getOrCreateGlobalSingleton } from '@backstage/version-bridge';\nimport {\n AnalyticsApi,\n AnalyticsEventAttributes,\n AnalyticsTracker,\n} from '../apis';\nimport { AnalyticsContextValue } from './';\n\ntype TempGlobalEvents = {\n /**\n * Stores the most recent \"gathered\" mountpoint navigation.\n */\n mostRecentGatheredNavigation?: {\n action: string;\n subject: string;\n value?: number;\n attributes?: AnalyticsEventAttributes;\n context: AnalyticsContextValue;\n };\n /**\n * Stores the most recent routable extension render.\n */\n mostRecentRoutableExtensionRender?: {\n context: AnalyticsContextValue;\n };\n /**\n * Tracks whether or not a beforeunload event listener has already been\n * registered.\n */\n beforeUnloadRegistered: boolean;\n};\n\n/**\n * Temporary global store for select event data. Used to make `navigate` events\n * more accurate when gathered mountpoints are used.\n */\nconst globalEvents = getOrCreateGlobalSingleton<TempGlobalEvents>(\n 'core-plugin-api:analytics-tracker-events',\n () => ({\n mostRecentGatheredNavigation: undefined,\n mostRecentRoutableExtensionRender: undefined,\n beforeUnloadRegistered: false,\n }),\n);\n\n/**\n * Internal-only event representing when a routable extension is rendered.\n */\nexport const routableExtensionRenderedEvent = '_ROUTABLE-EXTENSION-RENDERED';\n\nexport class Tracker implements AnalyticsTracker {\n constructor(\n private readonly analyticsApi: AnalyticsApi,\n private context: AnalyticsContextValue = {\n routeRef: 'unknown',\n pluginId: 'root',\n extension: 'App',\n },\n ) {\n // Only register a single beforeunload event across all trackers.\n if (!globalEvents.beforeUnloadRegistered) {\n // Before the page unloads, attempt to capture any deferred navigation\n // events that haven't yet been captured.\n addEventListener(\n 'beforeunload',\n () => {\n if (globalEvents.mostRecentGatheredNavigation) {\n this.analyticsApi.captureEvent({\n ...globalEvents.mostRecentGatheredNavigation,\n ...globalEvents.mostRecentRoutableExtensionRender,\n });\n globalEvents.mostRecentGatheredNavigation = undefined;\n globalEvents.mostRecentRoutableExtensionRender = undefined;\n }\n },\n { once: true, passive: true },\n );\n\n // Prevent duplicate handlers from being registered.\n globalEvents.beforeUnloadRegistered = true;\n }\n }\n\n setContext(context: AnalyticsContextValue) {\n this.context = context;\n }\n\n captureEvent(\n action: string,\n subject: string,\n {\n value,\n attributes,\n }: { value?: number; attributes?: AnalyticsEventAttributes } = {},\n ) {\n // Never pass internal \"_routeNodeType\" context value.\n const { _routeNodeType, ...context } = this.context;\n\n // Never fire the special \"_routable-extension-rendered\" internal event.\n if (action === routableExtensionRenderedEvent) {\n // But keep track of it if we're delaying a `navigate` event for a\n // a gathered route node type.\n if (globalEvents.mostRecentGatheredNavigation) {\n globalEvents.mostRecentRoutableExtensionRender = {\n context: {\n ...context,\n extension: 'App',\n },\n };\n }\n return;\n }\n\n // If we are about to fire a real event, and we have an un-fired gathered\n // mountpoint navigation on the global store, we need to fire the navigate\n // event first, so this real event happens accurately after the navigation.\n if (globalEvents.mostRecentGatheredNavigation) {\n try {\n this.analyticsApi.captureEvent({\n ...globalEvents.mostRecentGatheredNavigation,\n ...globalEvents.mostRecentRoutableExtensionRender,\n });\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn('Error during analytics event capture. %o', e);\n }\n\n // Clear the global stores.\n globalEvents.mostRecentGatheredNavigation = undefined;\n globalEvents.mostRecentRoutableExtensionRender = undefined;\n }\n\n // Never directly fire a navigation event on a gathered route with default\n // contextual details.\n if (\n action === 'navigate' &&\n _routeNodeType === 'gathered' &&\n context.pluginId === 'root'\n ) {\n // Instead, set it on the global store.\n globalEvents.mostRecentGatheredNavigation = {\n action,\n subject,\n value,\n attributes,\n context,\n };\n return;\n }\n\n try {\n this.analyticsApi.captureEvent({\n action,\n subject,\n value,\n attributes,\n context,\n });\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn('Error during analytics event capture. %o', e);\n }\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Tracker.esm.js","sources":["../../src/analytics/Tracker.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { getOrCreateGlobalSingleton } from '@backstage/version-bridge';\nimport {\n AnalyticsApi,\n AnalyticsEventAttributes,\n AnalyticsTracker,\n} from '../apis';\nimport { AnalyticsContextValue } from './types';\n\ntype TempGlobalEvents = {\n /**\n * Stores the most recent \"gathered\" mountpoint navigation.\n */\n mostRecentGatheredNavigation?: {\n action: string;\n subject: string;\n value?: number;\n attributes?: AnalyticsEventAttributes;\n context: AnalyticsContextValue;\n };\n /**\n * Stores the most recent routable extension render.\n */\n mostRecentRoutableExtensionRender?: {\n context: AnalyticsContextValue;\n };\n /**\n * Tracks whether or not a beforeunload event listener has already been\n * registered.\n */\n beforeUnloadRegistered: boolean;\n};\n\n/**\n * Temporary global store for select event data. Used to make `navigate` events\n * more accurate when gathered mountpoints are used.\n */\nconst globalEvents = getOrCreateGlobalSingleton<TempGlobalEvents>(\n 'core-plugin-api:analytics-tracker-events',\n () => ({\n mostRecentGatheredNavigation: undefined,\n mostRecentRoutableExtensionRender: undefined,\n beforeUnloadRegistered: false,\n }),\n);\n\n/**\n * Internal-only event representing when a routable extension is rendered.\n */\nexport const routableExtensionRenderedEvent = '_ROUTABLE-EXTENSION-RENDERED';\n\nexport class Tracker implements AnalyticsTracker {\n constructor(\n private readonly analyticsApi: AnalyticsApi,\n private context: AnalyticsContextValue = {\n routeRef: 'unknown',\n pluginId: 'root',\n extension: 'App',\n },\n ) {\n // Only register a single beforeunload event across all trackers.\n if (!globalEvents.beforeUnloadRegistered) {\n // Before the page unloads, attempt to capture any deferred navigation\n // events that haven't yet been captured.\n addEventListener(\n 'beforeunload',\n () => {\n if (globalEvents.mostRecentGatheredNavigation) {\n this.analyticsApi.captureEvent({\n ...globalEvents.mostRecentGatheredNavigation,\n ...globalEvents.mostRecentRoutableExtensionRender,\n });\n globalEvents.mostRecentGatheredNavigation = undefined;\n globalEvents.mostRecentRoutableExtensionRender = undefined;\n }\n },\n { once: true, passive: true },\n );\n\n // Prevent duplicate handlers from being registered.\n globalEvents.beforeUnloadRegistered = true;\n }\n }\n\n setContext(context: AnalyticsContextValue) {\n this.context = context;\n }\n\n captureEvent(\n action: string,\n subject: string,\n {\n value,\n attributes,\n }: { value?: number; attributes?: AnalyticsEventAttributes } = {},\n ) {\n // Never pass internal \"_routeNodeType\" context value.\n const { _routeNodeType, ...context } = this.context;\n\n // Never fire the special \"_routable-extension-rendered\" internal event.\n if (action === routableExtensionRenderedEvent) {\n // But keep track of it if we're delaying a `navigate` event for a\n // a gathered route node type.\n if (globalEvents.mostRecentGatheredNavigation) {\n globalEvents.mostRecentRoutableExtensionRender = {\n context: {\n ...context,\n extension: 'App',\n },\n };\n }\n return;\n }\n\n // If we are about to fire a real event, and we have an un-fired gathered\n // mountpoint navigation on the global store, we need to fire the navigate\n // event first, so this real event happens accurately after the navigation.\n if (globalEvents.mostRecentGatheredNavigation) {\n try {\n this.analyticsApi.captureEvent({\n ...globalEvents.mostRecentGatheredNavigation,\n ...globalEvents.mostRecentRoutableExtensionRender,\n });\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn('Error during analytics event capture. %o', e);\n }\n\n // Clear the global stores.\n globalEvents.mostRecentGatheredNavigation = undefined;\n globalEvents.mostRecentRoutableExtensionRender = undefined;\n }\n\n // Never directly fire a navigation event on a gathered route with default\n // contextual details.\n if (\n action === 'navigate' &&\n _routeNodeType === 'gathered' &&\n context.pluginId === 'root'\n ) {\n // Instead, set it on the global store.\n globalEvents.mostRecentGatheredNavigation = {\n action,\n subject,\n value,\n attributes,\n context,\n };\n return;\n }\n\n try {\n this.analyticsApi.captureEvent({\n action,\n subject,\n value,\n attributes,\n context,\n });\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn('Error during analytics event capture. %o', e);\n }\n }\n}\n"],"names":[],"mappings":";;AAoDA,MAAM,YAAe,GAAA,0BAAA;AAAA,EACnB,0CAAA;AAAA,EACA,OAAO;AAAA,IACL,4BAA8B,EAAA,KAAA,CAAA;AAAA,IAC9B,iCAAmC,EAAA,KAAA,CAAA;AAAA,IACnC,sBAAwB,EAAA;AAAA,GAC1B;AACF,CAAA;AAKO,MAAM,8BAAiC,GAAA;AAEvC,MAAM,OAAoC,CAAA;AAAA,EAC/C,WAAA,CACmB,cACT,OAAiC,GAAA;AAAA,IACvC,QAAU,EAAA,SAAA;AAAA,IACV,QAAU,EAAA,MAAA;AAAA,IACV,SAAW,EAAA;AAAA,GAEb,EAAA;AANiB,IAAA,IAAA,CAAA,YAAA,GAAA,YAAA;AACT,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAOR,IAAI,IAAA,CAAC,aAAa,sBAAwB,EAAA;AAGxC,MAAA,gBAAA;AAAA,QACE,cAAA;AAAA,QACA,MAAM;AACJ,UAAA,IAAI,aAAa,4BAA8B,EAAA;AAC7C,YAAA,IAAA,CAAK,aAAa,YAAa,CAAA;AAAA,cAC7B,GAAG,YAAa,CAAA,4BAAA;AAAA,cAChB,GAAG,YAAa,CAAA;AAAA,aACjB,CAAA;AACD,YAAA,YAAA,CAAa,4BAA+B,GAAA,KAAA,CAAA;AAC5C,YAAA,YAAA,CAAa,iCAAoC,GAAA,KAAA,CAAA;AAAA;AACnD,SACF;AAAA,QACA,EAAE,IAAA,EAAM,IAAM,EAAA,OAAA,EAAS,IAAK;AAAA,OAC9B;AAGA,MAAA,YAAA,CAAa,sBAAyB,GAAA,IAAA;AAAA;AACxC;AACF,EAEA,WAAW,OAAgC,EAAA;AACzC,IAAA,IAAA,CAAK,OAAU,GAAA,OAAA;AAAA;AACjB,EAEA,YAAA,CACE,QACA,OACA,EAAA;AAAA,IACE,KAAA;AAAA,IACA;AAAA,GACF,GAA+D,EAC/D,EAAA;AAEA,IAAA,MAAM,EAAE,cAAA,EAAgB,GAAG,OAAA,KAAY,IAAK,CAAA,OAAA;AAG5C,IAAA,IAAI,WAAW,8BAAgC,EAAA;AAG7C,MAAA,IAAI,aAAa,4BAA8B,EAAA;AAC7C,QAAA,YAAA,CAAa,iCAAoC,GAAA;AAAA,UAC/C,OAAS,EAAA;AAAA,YACP,GAAG,OAAA;AAAA,YACH,SAAW,EAAA;AAAA;AACb,SACF;AAAA;AAEF,MAAA;AAAA;AAMF,IAAA,IAAI,aAAa,4BAA8B,EAAA;AAC7C,MAAI,IAAA;AACF,QAAA,IAAA,CAAK,aAAa,YAAa,CAAA;AAAA,UAC7B,GAAG,YAAa,CAAA,4BAAA;AAAA,UAChB,GAAG,YAAa,CAAA;AAAA,SACjB,CAAA;AAAA,eACM,CAAG,EAAA;AAEV,QAAQ,OAAA,CAAA,IAAA,CAAK,4CAA4C,CAAC,CAAA;AAAA;AAI5D,MAAA,YAAA,CAAa,4BAA+B,GAAA,KAAA,CAAA;AAC5C,MAAA,YAAA,CAAa,iCAAoC,GAAA,KAAA,CAAA;AAAA;AAKnD,IAAA,IACE,WAAW,UACX,IAAA,cAAA,KAAmB,UACnB,IAAA,OAAA,CAAQ,aAAa,MACrB,EAAA;AAEA,MAAA,YAAA,CAAa,4BAA+B,GAAA;AAAA,QAC1C,MAAA;AAAA,QACA,OAAA;AAAA,QACA,KAAA;AAAA,QACA,UAAA;AAAA,QACA;AAAA,OACF;AACA,MAAA;AAAA;AAGF,IAAI,IAAA;AACF,MAAA,IAAA,CAAK,aAAa,YAAa,CAAA;AAAA,QAC7B,MAAA;AAAA,QACA,OAAA;AAAA,QACA,KAAA;AAAA,QACA,UAAA;AAAA,QACA;AAAA,OACD,CAAA;AAAA,aACM,CAAG,EAAA;AAEV,MAAQ,OAAA,CAAA,IAAA,CAAK,4CAA4C,CAAC,CAAA;AAAA;AAC5D;AAEJ;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"TranslationApi.esm.js","sources":["../../../src/apis/definitions/TranslationApi.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 { ApiRef, createApiRef } from '@backstage/core-plugin-api';\nimport { Expand, ExpandRecursive, Observable } from '@backstage/types';\nimport { TranslationRef } from '../../translation';\nimport { JSX } from 'react';\n\n/**\n * Base translation options.\n *\n * @alpha\n */\ninterface BaseOptions {\n interpolation?: {\n /** Whether to HTML escape provided values, defaults to false */\n escapeValue?: boolean;\n };\n}\n\n/**\n * All pluralization suffixes supported by i18next\n *\n * @ignore\n */\ntype TranslationPlural = 'zero' | 'one' | 'two' | 'few' | 'many' | 'other';\n\n/**\n * A mapping of i18n formatting types to their corresponding types and options.\n * @ignore\n */\ntype I18nextFormatMap = {\n number: {\n type: number;\n options: Intl.NumberFormatOptions;\n };\n currency: {\n type: number;\n options: Intl.NumberFormatOptions;\n };\n datetime: {\n type: Date;\n options: Intl.DateTimeFormatOptions;\n };\n relativetime: {\n type: number;\n options: {\n range?: Intl.RelativeTimeFormatUnit;\n } & Intl.RelativeTimeFormatOptions;\n };\n list: {\n type: string[];\n options: Intl.ListFormatOptions;\n };\n};\n\n/**\n * Extracts all pluralized keys from the message map.\n *\n * @example\n * ```\n * { foo: 'foo', bar_one: 'bar', bar_other: 'bars' } -> 'bar'\n * ```\n *\n * @ignore\n */\ntype PluralKeys<TMessages extends { [key in string]: string }> = {\n [Key in keyof TMessages]: Key extends `${infer K}_${TranslationPlural}`\n ? K\n : never;\n}[keyof TMessages];\n\n/**\n * Collapses a message map into normalized keys with union values.\n *\n * @example\n * ```\n * { foo_one: 'foo', foo_other: 'foos' } -> { foo: 'foo' | 'foos' }\n * ```\n *\n * @ignore\n */\ntype CollapsedMessages<TMessages extends { [key in string]: string }> = {\n [key in keyof TMessages as key extends `${infer K}_${TranslationPlural}`\n ? K\n : key]: TMessages[key];\n};\n\n/**\n * Trim away whitespace\n *\n * @ignore\n */\ntype Trim<T> = T extends ` ${infer U}`\n ? Trim<U>\n : T extends `${infer U} `\n ? Trim<U>\n : T;\n\n/**\n * Extracts the key and format from a replacement string.\n *\n * @example\n * ```\n * 'foo, number' -> { foo: number }, 'foo' -> { foo: undefined }\n * ```\n */\ntype ExtractFormat<Replacement extends string> =\n Replacement extends `${infer Key},${infer FullFormat}`\n ? {\n [key in Trim<Key>]: Lowercase<\n Trim<\n FullFormat extends `${infer Format}(${string})${string}`\n ? Format\n : FullFormat\n >\n >;\n }\n : { [key in Trim<Replacement>]: undefined };\n\n/**\n * Expand the keys in a flat map to nested objects.\n *\n * @example\n * ```\n * { 'a.b': 'foo', 'a.c': 'bar' } -> { a: { b: 'foo', c: 'bar' }\n * ```\n *\n * @ignore\n */\ntype ExpandKeys<TMap extends {}> = {\n [Key in keyof TMap as Key extends `${infer Prefix}.${string}`\n ? Prefix\n : Key]: Key extends `${string}.${infer Rest}`\n ? ExpandKeys<{ [key in Rest]: TMap[Key] }>\n : TMap[Key];\n};\n\n/**\n * Extracts all option keys and their format from a message string.\n *\n * @example\n * ```\n * 'foo {{bar}} {{baz, number}}' -> { 'bar': undefined, 'baz': 'number' }\n * ```\n *\n * @ignore\n */\ntype ReplaceFormatsFromMessage<TMessage> =\n TMessage extends `${string}{{${infer Replacement}}}${infer Tail}` // no formatting, e.g. {{foo}}\n ? ExpandKeys<ExtractFormat<Replacement>> & ReplaceFormatsFromMessage<Tail>\n : {};\n\n/**\n * Generates the replace options structure\n *\n * @ignore\n */\ntype ReplaceOptionsFromFormats<TFormats extends {}, TValueType> = {\n [Key in keyof TFormats]: TFormats[Key] extends keyof I18nextFormatMap\n ? I18nextFormatMap[TFormats[Key]]['type']\n : TFormats[Key] extends {}\n ? Expand<ReplaceOptionsFromFormats<TFormats[Key], TValueType>>\n : TValueType;\n};\n\n/**\n * Generates the formatParams options structure\n *\n * @ignore\n */\ntype ReplaceFormatParamsFromFormats<TFormats extends {}> = {\n [Key in keyof TFormats]?: TFormats[Key] extends keyof I18nextFormatMap\n ? I18nextFormatMap[TFormats[Key]]['options']\n : TFormats[Key] extends {}\n ? Expand<ReplaceFormatParamsFromFormats<TFormats[Key]>>\n : undefined;\n};\n\n/**\n * Extracts all nesting keys from a message string.\n *\n * @example\n * ```\n * 'foo $t(bar) $t(baz)' -> 'bar' | 'baz'\n * ```\n *\n * @ignore\n */\ntype NestingKeysFromMessage<TMessage extends string> =\n TMessage extends `${string}$t(${infer Key})${infer Tail}` // nesting options are not supported\n ? Trim<Key> | NestingKeysFromMessage<Tail>\n : never;\n\n/**\n * Find all referenced keys, given a starting key and the full set of messages.\n *\n * This will only discover keys up to 3 levels deep.\n *\n * @example\n * ```\n * <'x', { x: '$t(y) $t(z)', y: 'y', z: '$t(w)', w: 'w', foo: 'foo' }> -> 'x' | 'y' | 'z' | 'w'\n * ```\n *\n * @ignore\n */\ntype NestedMessageKeys<\n TKey extends keyof TMessages,\n TMessages extends { [key in string]: string },\n> =\n | TKey\n | NestedMessageKeys2<NestingKeysFromMessage<TMessages[TKey]>, TMessages>;\n// Can't recursively reference ourself, so instead we got this beauty\ntype NestedMessageKeys2<\n TKey extends keyof TMessages,\n TMessages extends { [key in string]: string },\n> =\n | TKey\n | NestedMessageKeys3<NestingKeysFromMessage<TMessages[TKey]>, TMessages>;\n// Only support 3 levels of nesting\ntype NestedMessageKeys3<\n TKey extends keyof TMessages,\n TMessages extends { [key in string]: string },\n> = TKey | NestingKeysFromMessage<TMessages[TKey]>;\n\n/**\n * Converts a union type to an intersection type.\n *\n * @example\n * ```\n * { foo: 'foo' } | { bar: 'bar' } -> { foo: 'foo' } & { bar: 'bar' }\n * ```\n *\n * @ignore\n */\ntype UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never;\n\n/**\n * Collects different types of options into a single object\n *\n * @ignore\n */\ntype CollectOptions<\n TCount extends { count?: number },\n TFormats extends {},\n TValueType,\n> = TCount &\n // count is special, omit it from the replacements\n (keyof Omit<TFormats, 'count'> extends never\n ? {}\n : (\n | Expand<Omit<ReplaceOptionsFromFormats<TFormats, TValueType>, 'count'>>\n | {\n replace: Expand<\n Omit<ReplaceOptionsFromFormats<TFormats, TValueType>, 'count'>\n >;\n }\n ) & {\n formatParams?: Expand<ReplaceFormatParamsFromFormats<TFormats>>;\n });\n\n/**\n * Helper type to only require options argument if needed\n *\n * @ignore\n */\ntype OptionArgs<TOptions extends {}> = keyof TOptions extends never\n ? [options?: Expand<BaseOptions>]\n : [options: Expand<BaseOptions & TOptions>];\n\n/**\n * @ignore\n */\ntype TranslationFunctionOptions<\n TKeys extends keyof TMessages, // All normalized message keys to be considered, i.e. included nested ones\n TPluralKeys extends keyof TMessages, // All keys in the message map that are pluralized\n TMessages extends { [key in string]: string }, // Collapsed message map with normalized keys and union values\n TValueType,\n> = OptionArgs<\n Expand<\n CollectOptions<\n TKeys & TPluralKeys extends never ? {} : { count: number },\n ExpandRecursive<\n UnionToIntersection<ReplaceFormatsFromMessage<TMessages[TKeys]>>\n >,\n TValueType\n >\n >\n>;\n\n/** @alpha */\nexport type TranslationFunction<TMessages extends { [key in string]: string }> =\n CollapsedMessages<TMessages> extends infer IMessages extends {\n [key in string]: string;\n }\n ? {\n /**\n * A translation function that returns a string.\n */\n <TKey extends keyof IMessages>(\n key: TKey,\n ...[args]: TranslationFunctionOptions<\n NestedMessageKeys<TKey, IMessages>,\n PluralKeys<TMessages>,\n IMessages,\n string\n >\n ): IMessages[TKey];\n /**\n * A translation function where at least one JSX.Element has been\n * provided as an interpolation value, and will therefore return a\n * JSX.Element.\n */\n <TKey extends keyof IMessages>(\n key: TKey,\n ...[args]: TranslationFunctionOptions<\n NestedMessageKeys<TKey, IMessages>,\n PluralKeys<TMessages>,\n IMessages,\n string | JSX.Element\n >\n ): JSX.Element;\n }\n : never;\n\n/** @alpha */\nexport type TranslationSnapshot<TMessages extends { [key in string]: string }> =\n { ready: false } | { ready: true; t: TranslationFunction<TMessages> };\n\n/** @alpha */\nexport type TranslationApi = {\n getTranslation<TMessages extends { [key in string]: string }>(\n translationRef: TranslationRef<string, TMessages>,\n ): TranslationSnapshot<TMessages>;\n\n translation$<TMessages extends { [key in string]: string }>(\n translationRef: TranslationRef<string, TMessages>,\n ): Observable<TranslationSnapshot<TMessages>>;\n};\n\n/**\n * @alpha\n */\nexport const translationApiRef: ApiRef<TranslationApi> = createApiRef({\n id: 'core.translation',\n});\n"],"names":[],"mappings":";;AAwWO,MAAM,oBAA4C,YAAa,CAAA;AAAA,EACpE,EAAI,EAAA;AACN,CAAC;;;;"}
1
+ {"version":3,"file":"TranslationApi.esm.js","sources":["../../../src/apis/definitions/TranslationApi.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 { ApiRef, createApiRef } from '@backstage/core-plugin-api';\nimport { Expand, ExpandRecursive, Observable } from '@backstage/types';\nimport { TranslationRef } from '../../translation/TranslationRef';\nimport { JSX } from 'react';\n\n/**\n * Base translation options.\n *\n * @alpha\n */\ninterface BaseOptions {\n interpolation?: {\n /** Whether to HTML escape provided values, defaults to false */\n escapeValue?: boolean;\n };\n}\n\n/**\n * All pluralization suffixes supported by i18next\n *\n * @ignore\n */\ntype TranslationPlural = 'zero' | 'one' | 'two' | 'few' | 'many' | 'other';\n\n/**\n * A mapping of i18n formatting types to their corresponding types and options.\n * @ignore\n */\ntype I18nextFormatMap = {\n number: {\n type: number;\n options: Intl.NumberFormatOptions;\n };\n currency: {\n type: number;\n options: Intl.NumberFormatOptions;\n };\n datetime: {\n type: Date;\n options: Intl.DateTimeFormatOptions;\n };\n relativetime: {\n type: number;\n options: {\n range?: Intl.RelativeTimeFormatUnit;\n } & Intl.RelativeTimeFormatOptions;\n };\n list: {\n type: string[];\n options: Intl.ListFormatOptions;\n };\n};\n\n/**\n * Extracts all pluralized keys from the message map.\n *\n * @example\n * ```\n * { foo: 'foo', bar_one: 'bar', bar_other: 'bars' } -> 'bar'\n * ```\n *\n * @ignore\n */\ntype PluralKeys<TMessages extends { [key in string]: string }> = {\n [Key in keyof TMessages]: Key extends `${infer K}_${TranslationPlural}`\n ? K\n : never;\n}[keyof TMessages];\n\n/**\n * Collapses a message map into normalized keys with union values.\n *\n * @example\n * ```\n * { foo_one: 'foo', foo_other: 'foos' } -> { foo: 'foo' | 'foos' }\n * ```\n *\n * @ignore\n */\ntype CollapsedMessages<TMessages extends { [key in string]: string }> = {\n [key in keyof TMessages as key extends `${infer K}_${TranslationPlural}`\n ? K\n : key]: TMessages[key];\n};\n\n/**\n * Trim away whitespace\n *\n * @ignore\n */\ntype Trim<T> = T extends ` ${infer U}`\n ? Trim<U>\n : T extends `${infer U} `\n ? Trim<U>\n : T;\n\n/**\n * Extracts the key and format from a replacement string.\n *\n * @example\n * ```\n * 'foo, number' -> { foo: number }, 'foo' -> { foo: undefined }\n * ```\n */\ntype ExtractFormat<Replacement extends string> =\n Replacement extends `${infer Key},${infer FullFormat}`\n ? {\n [key in Trim<Key>]: Lowercase<\n Trim<\n FullFormat extends `${infer Format}(${string})${string}`\n ? Format\n : FullFormat\n >\n >;\n }\n : { [key in Trim<Replacement>]: undefined };\n\n/**\n * Expand the keys in a flat map to nested objects.\n *\n * @example\n * ```\n * { 'a.b': 'foo', 'a.c': 'bar' } -> { a: { b: 'foo', c: 'bar' }\n * ```\n *\n * @ignore\n */\ntype ExpandKeys<TMap extends {}> = {\n [Key in keyof TMap as Key extends `${infer Prefix}.${string}`\n ? Prefix\n : Key]: Key extends `${string}.${infer Rest}`\n ? ExpandKeys<{ [key in Rest]: TMap[Key] }>\n : TMap[Key];\n};\n\n/**\n * Extracts all option keys and their format from a message string.\n *\n * @example\n * ```\n * 'foo {{bar}} {{baz, number}}' -> { 'bar': undefined, 'baz': 'number' }\n * ```\n *\n * @ignore\n */\ntype ReplaceFormatsFromMessage<TMessage> =\n TMessage extends `${string}{{${infer Replacement}}}${infer Tail}` // no formatting, e.g. {{foo}}\n ? ExpandKeys<ExtractFormat<Replacement>> & ReplaceFormatsFromMessage<Tail>\n : {};\n\n/**\n * Generates the replace options structure\n *\n * @ignore\n */\ntype ReplaceOptionsFromFormats<TFormats extends {}, TValueType> = {\n [Key in keyof TFormats]: TFormats[Key] extends keyof I18nextFormatMap\n ? I18nextFormatMap[TFormats[Key]]['type']\n : TFormats[Key] extends {}\n ? Expand<ReplaceOptionsFromFormats<TFormats[Key], TValueType>>\n : TValueType;\n};\n\n/**\n * Generates the formatParams options structure\n *\n * @ignore\n */\ntype ReplaceFormatParamsFromFormats<TFormats extends {}> = {\n [Key in keyof TFormats]?: TFormats[Key] extends keyof I18nextFormatMap\n ? I18nextFormatMap[TFormats[Key]]['options']\n : TFormats[Key] extends {}\n ? Expand<ReplaceFormatParamsFromFormats<TFormats[Key]>>\n : undefined;\n};\n\n/**\n * Extracts all nesting keys from a message string.\n *\n * @example\n * ```\n * 'foo $t(bar) $t(baz)' -> 'bar' | 'baz'\n * ```\n *\n * @ignore\n */\ntype NestingKeysFromMessage<TMessage extends string> =\n TMessage extends `${string}$t(${infer Key})${infer Tail}` // nesting options are not supported\n ? Trim<Key> | NestingKeysFromMessage<Tail>\n : never;\n\n/**\n * Find all referenced keys, given a starting key and the full set of messages.\n *\n * This will only discover keys up to 3 levels deep.\n *\n * @example\n * ```\n * <'x', { x: '$t(y) $t(z)', y: 'y', z: '$t(w)', w: 'w', foo: 'foo' }> -> 'x' | 'y' | 'z' | 'w'\n * ```\n *\n * @ignore\n */\ntype NestedMessageKeys<\n TKey extends keyof TMessages,\n TMessages extends { [key in string]: string },\n> =\n | TKey\n | NestedMessageKeys2<NestingKeysFromMessage<TMessages[TKey]>, TMessages>;\n// Can't recursively reference ourself, so instead we got this beauty\ntype NestedMessageKeys2<\n TKey extends keyof TMessages,\n TMessages extends { [key in string]: string },\n> =\n | TKey\n | NestedMessageKeys3<NestingKeysFromMessage<TMessages[TKey]>, TMessages>;\n// Only support 3 levels of nesting\ntype NestedMessageKeys3<\n TKey extends keyof TMessages,\n TMessages extends { [key in string]: string },\n> = TKey | NestingKeysFromMessage<TMessages[TKey]>;\n\n/**\n * Converts a union type to an intersection type.\n *\n * @example\n * ```\n * { foo: 'foo' } | { bar: 'bar' } -> { foo: 'foo' } & { bar: 'bar' }\n * ```\n *\n * @ignore\n */\ntype UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never;\n\n/**\n * Collects different types of options into a single object\n *\n * @ignore\n */\ntype CollectOptions<\n TCount extends { count?: number },\n TFormats extends {},\n TValueType,\n> = TCount &\n // count is special, omit it from the replacements\n (keyof Omit<TFormats, 'count'> extends never\n ? {}\n : (\n | Expand<Omit<ReplaceOptionsFromFormats<TFormats, TValueType>, 'count'>>\n | {\n replace: Expand<\n Omit<ReplaceOptionsFromFormats<TFormats, TValueType>, 'count'>\n >;\n }\n ) & {\n formatParams?: Expand<ReplaceFormatParamsFromFormats<TFormats>>;\n });\n\n/**\n * Helper type to only require options argument if needed\n *\n * @ignore\n */\ntype OptionArgs<TOptions extends {}> = keyof TOptions extends never\n ? [options?: Expand<BaseOptions>]\n : [options: Expand<BaseOptions & TOptions>];\n\n/**\n * @ignore\n */\ntype TranslationFunctionOptions<\n TKeys extends keyof TMessages, // All normalized message keys to be considered, i.e. included nested ones\n TPluralKeys extends keyof TMessages, // All keys in the message map that are pluralized\n TMessages extends { [key in string]: string }, // Collapsed message map with normalized keys and union values\n TValueType,\n> = OptionArgs<\n Expand<\n CollectOptions<\n TKeys & TPluralKeys extends never ? {} : { count: number },\n ExpandRecursive<\n UnionToIntersection<ReplaceFormatsFromMessage<TMessages[TKeys]>>\n >,\n TValueType\n >\n >\n>;\n\n/** @alpha */\nexport type TranslationFunction<TMessages extends { [key in string]: string }> =\n CollapsedMessages<TMessages> extends infer IMessages extends {\n [key in string]: string;\n }\n ? {\n /**\n * A translation function that returns a string.\n */\n <TKey extends keyof IMessages>(\n key: TKey,\n ...[args]: TranslationFunctionOptions<\n NestedMessageKeys<TKey, IMessages>,\n PluralKeys<TMessages>,\n IMessages,\n string\n >\n ): IMessages[TKey];\n /**\n * A translation function where at least one JSX.Element has been\n * provided as an interpolation value, and will therefore return a\n * JSX.Element.\n */\n <TKey extends keyof IMessages>(\n key: TKey,\n ...[args]: TranslationFunctionOptions<\n NestedMessageKeys<TKey, IMessages>,\n PluralKeys<TMessages>,\n IMessages,\n string | JSX.Element\n >\n ): JSX.Element;\n }\n : never;\n\n/** @alpha */\nexport type TranslationSnapshot<TMessages extends { [key in string]: string }> =\n { ready: false } | { ready: true; t: TranslationFunction<TMessages> };\n\n/** @alpha */\nexport type TranslationApi = {\n getTranslation<TMessages extends { [key in string]: string }>(\n translationRef: TranslationRef<string, TMessages>,\n ): TranslationSnapshot<TMessages>;\n\n translation$<TMessages extends { [key in string]: string }>(\n translationRef: TranslationRef<string, TMessages>,\n ): Observable<TranslationSnapshot<TMessages>>;\n};\n\n/**\n * @alpha\n */\nexport const translationApiRef: ApiRef<TranslationApi> = createApiRef({\n id: 'core.translation',\n});\n"],"names":[],"mappings":";;AAwWO,MAAM,oBAA4C,YAAa,CAAA;AAAA,EACpE,EAAI,EAAA;AACN,CAAC;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/core-plugin-api",
3
- "version": "1.10.7",
3
+ "version": "1.10.8",
4
4
  "description": "Core API used by Backstage plugins",
5
5
  "backstage": {
6
6
  "role": "web-library"
@@ -64,9 +64,9 @@
64
64
  "history": "^5.0.0"
65
65
  },
66
66
  "devDependencies": {
67
- "@backstage/cli": "^0.32.1",
68
- "@backstage/core-app-api": "^1.17.0",
69
- "@backstage/test-utils": "^1.7.8",
67
+ "@backstage/cli": "^0.33.0",
68
+ "@backstage/core-app-api": "^1.17.1",
69
+ "@backstage/test-utils": "^1.7.9",
70
70
  "@testing-library/dom": "^10.0.0",
71
71
  "@testing-library/jest-dom": "^6.0.0",
72
72
  "@testing-library/react": "^16.0.0",