diff --git a/.changeset/harmonize-phantom-t-getter.md b/.changeset/harmonize-phantom-t-getter.md new file mode 100644 index 0000000000..970d4f18b2 --- /dev/null +++ b/.changeset/harmonize-phantom-t-getter.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-plugin-api': patch +--- + +Harmonized the phantom `.T` getter on `ExtensionPoint` to consistently return `null` instead of throwing. diff --git a/packages/backend-plugin-api/src/services/system/types.test.ts b/packages/backend-plugin-api/src/services/system/types.test.ts index a98b8c44ee..be588f2036 100644 --- a/packages/backend-plugin-api/src/services/system/types.test.ts +++ b/packages/backend-plugin-api/src/services/system/types.test.ts @@ -25,6 +25,18 @@ const rootDep = createServiceRef({ id: 'y', scope: 'root' }); const pluginDep = createServiceRef({ id: 'z' }); function unused(..._any: any[]) {} +describe('createServiceRef', () => { + it('should create a ServiceRef', () => { + expect(ref.id).toBe('x'); + expect(ref.scope).toBe('plugin'); + expect(ref.T).toBe(null); + expect(String(ref)).toBe('serviceRef{x}'); + expect(JSON.stringify(ref)).toBe( + '{"$$type":"@backstage/ServiceRef","id":"x","scope":"plugin","multiton":false}', + ); + }); +}); + describe('createServiceFactory', () => { it('should create a plugin scoped factory', () => { const factory = createServiceFactory({ diff --git a/packages/backend-plugin-api/src/services/system/types.ts b/packages/backend-plugin-api/src/services/system/types.ts index c6425cca42..925156d3ae 100644 --- a/packages/backend-plugin-api/src/services/system/types.ts +++ b/packages/backend-plugin-api/src/services/system/types.ts @@ -144,13 +144,12 @@ export function createServiceRef< scope, multiton, get T(): TService { - throw new Error(`tried to read ServiceRef.T of ${this}`); + return null as TService; }, toString() { return `serviceRef{${options.id}}`; }, toJSON() { - // This avoids accidental calls to T happening e.g. in tests return { $$type: '@backstage/ServiceRef', id, diff --git a/packages/backend-plugin-api/src/wiring/createExtensionPoint.test.ts b/packages/backend-plugin-api/src/wiring/createExtensionPoint.test.ts index 825063e845..df29833432 100644 --- a/packages/backend-plugin-api/src/wiring/createExtensionPoint.test.ts +++ b/packages/backend-plugin-api/src/wiring/createExtensionPoint.test.ts @@ -18,10 +18,10 @@ import { createExtensionPoint } from './createExtensionPoint'; describe('createExtensionPoint', () => { it('should create an ExtensionPoint', () => { - const extensionPoint = createExtensionPoint({ id: 'x' }); + const extensionPoint = createExtensionPoint({ id: 'x' }); expect(extensionPoint).toBeDefined(); expect(extensionPoint.id).toBe('x'); - expect(() => extensionPoint.T).not.toThrow(); + expect(extensionPoint.T).toBe(null); expect(String(extensionPoint)).toBe('extensionPoint{x}'); }); }); diff --git a/packages/backend-plugin-api/src/wiring/createExtensionPoint.ts b/packages/backend-plugin-api/src/wiring/createExtensionPoint.ts index 9dbae249ea..a68196f8c8 100644 --- a/packages/backend-plugin-api/src/wiring/createExtensionPoint.ts +++ b/packages/backend-plugin-api/src/wiring/createExtensionPoint.ts @@ -44,11 +44,7 @@ export function createExtensionPoint( return { id: options.id, get T(): T { - if (process.env.NODE_ENV === 'test') { - // Avoid throwing errors so tests asserting extensions' properties cannot be easily broken - return null as T; - } - throw new Error(`tried to read ExtensionPoint.T of ${this}`); + return null as T; }, toString() { return `extensionPoint{${options.id}}`;