Skip to content

Component framework implementation #2316

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 54 commits into from
Nov 14, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
14332f0
Component implementation
Feiyang1 Aug 15, 2019
85487f8
update dep version
Feiyang1 Oct 16, 2019
832b19c
[AUTOMATED]: Prettier Code Styling
Feiyang1 Oct 16, 2019
ab51efb
[AUTOMATED]: License Headers
Feiyang1 Oct 16, 2019
369cffe
rename variables
Feiyang1 Oct 16, 2019
bed9fb4
address comments
Feiyang1 Oct 16, 2019
2f13e66
[AUTOMATED]: Prettier Code Styling
Feiyang1 Oct 16, 2019
de6cc28
remove unused comment
Feiyang1 Oct 16, 2019
baab794
update code
Feiyang1 Oct 16, 2019
f68319a
[AUTOMATED]: Prettier Code Styling
Feiyang1 Oct 16, 2019
368b2a2
rename to clearInstance to have naming consistency
Feiyang1 Oct 16, 2019
7dce8de
make FirebaseApp tests work again
Feiyang1 Oct 17, 2019
89c31e1
fix node tests
Feiyang1 Oct 17, 2019
062975d
[AUTOMATED]: Prettier Code Styling
Feiyang1 Oct 17, 2019
fb6ea29
add comments for ComponentType
Feiyang1 Oct 21, 2019
766fb58
[AUTOMATED]: Prettier Code Styling
Feiyang1 Oct 21, 2019
b692476
pass Component directly into Providers
Feiyang1 Oct 21, 2019
2b78788
[AUTOMATED]: Prettier Code Styling
Feiyang1 Oct 21, 2019
6f69e1c
correct spellings
Feiyang1 Oct 21, 2019
f60cdd2
update readme
Feiyang1 Oct 21, 2019
f32b110
fix lint issue
Feiyang1 Oct 21, 2019
837c1a5
remove unused import
Feiyang1 Oct 21, 2019
c4f26f8
fix API change
Feiyang1 Oct 21, 2019
2f454ac
move types around
Feiyang1 Oct 22, 2019
ab2908e
[AUTOMATED]: Prettier Code Styling
Feiyang1 Oct 22, 2019
cb71e3c
improve provider typing
Feiyang1 Oct 22, 2019
d2d63fa
[AUTOMATED]: Prettier Code Styling
Feiyang1 Oct 22, 2019
a71cbb6
Migrate analytics to component platform (#220)
Feiyang1 Oct 23, 2019
188aa5d
allow overwriting a registered component
Feiyang1 Oct 28, 2019
7e97582
[AUTOMATED]: Prettier Code Styling
Feiyang1 Oct 28, 2019
af4fdc4
change ComponentType to string enum
Feiyang1 Oct 29, 2019
56bbdee
address comments
Feiyang1 Nov 4, 2019
3007773
[AUTOMATED]: Prettier Code Styling
Feiyang1 Nov 4, 2019
7b8439d
remove return only generics
Feiyang1 Nov 4, 2019
8c172b8
Move identifier to options object for getImmediate()
Feiyang1 Nov 4, 2019
086df99
[AUTOMATED]: Prettier Code Styling
Feiyang1 Nov 4, 2019
9971b33
Make getProvider() type safe
Feiyang1 Nov 5, 2019
e38d251
[AUTOMATED]: Prettier Code Styling
Feiyang1 Nov 5, 2019
15ec97e
define a new method to replace overwrite flag
Feiyang1 Nov 5, 2019
f425f8c
[AUTOMATED]: Prettier Code Styling
Feiyang1 Nov 5, 2019
6888f35
Make component type safe
Feiyang1 Nov 6, 2019
e84bad8
[AUTOMATED]: Prettier Code Styling
Feiyang1 Nov 6, 2019
9538682
remove the generic type from component container
Feiyang1 Nov 6, 2019
3dd9ec3
Update FirebaseApp and Analytics
Feiyang1 Nov 6, 2019
e7d7e5b
[AUTOMATED]: Prettier Code Styling
Feiyang1 Nov 6, 2019
2b1e4d4
remove unneccessary casting
Feiyang1 Nov 6, 2019
c30b9c7
[AUTOMATED]: Prettier Code Styling
Feiyang1 Nov 6, 2019
dab2486
fix typo
Feiyang1 Nov 11, 2019
2187664
address comments
Feiyang1 Nov 11, 2019
c7255b9
[AUTOMATED]: Prettier Code Styling
Feiyang1 Nov 11, 2019
777026d
update some types
Feiyang1 Nov 11, 2019
059fb5d
[AUTOMATED]: Prettier Code Styling
Feiyang1 Nov 11, 2019
917322c
handle errors from instance factory
Feiyang1 Nov 13, 2019
4e661d1
[AUTOMATED]: Prettier Code Styling
Feiyang1 Nov 13, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions packages/analytics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
import firebase from '@firebase/app';
import { FirebaseAnalytics } from '@firebase/analytics-types';
import { FirebaseAnalyticsInternal } from '@firebase/analytics-interop-types';
import { _FirebaseNamespace } from '@firebase/app-types/private';
import { factory, settings, resetGlobalVars } from './src/factory';
import { EventName } from './src/constants';
Expand All @@ -39,7 +40,7 @@ export function registerAnalytics(instance: _FirebaseNamespace): void {
ANALYTICS_TYPE,
container => {
// getImmediate for FirebaseApp will always succeed
const app = container.getProvider('app').getImmediate()!;
const app = container.getProvider('app').getImmediate();
return factory(app);
},
ComponentType.PUBLIC
Expand All @@ -59,7 +60,7 @@ export function registerAnalytics(instance: _FirebaseNamespace): void {
.getImmediate();
return {
logEvent: analytics.logEvent
};
} as FirebaseAnalyticsInternal;
} catch (e) {
throw ERROR_FACTORY.create(
AnalyticsError.INTEROP_COMPONENT_REG_FAILED,
Expand Down Expand Up @@ -89,9 +90,7 @@ declare module '@firebase/app-types' {
}

declare module '@firebase/component' {
interface ComponentContainer {
getProvider(name: typeof ANALYTICS_TYPE): Provider<FirebaseAnalytics>;
interface NameServiceMapping {
'analytics': FirebaseAnalytics;
}

interface Provider<T> {}
}
5 changes: 2 additions & 3 deletions packages/app/index.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import { FirebaseNamespace, FirebaseApp } from '@firebase/app-types';
import { _FirebaseNamespace } from '@firebase/app-types/private';
import { firebase as _firebase } from './src/firebaseNamespace';
import { Provider } from '@firebase/component';
// Node specific packages.
// @ts-ignore
import Storage from 'dom-storage';
Expand All @@ -41,7 +40,7 @@ export const firebase = _firebase as FirebaseNamespace;
export default firebase;

declare module '@firebase/component' {
interface ComponentContainer {
getProvider(name: 'app'): Provider<FirebaseApp>;
interface NameServiceMapping {
'app': FirebaseApp;
}
}
5 changes: 2 additions & 3 deletions packages/app/index.rn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import { FirebaseNamespace, FirebaseApp } from '@firebase/app-types';
import { _FirebaseNamespace } from '@firebase/app-types/private';
import { firebase as _firebase } from './src/firebaseNamespace';
import { Provider } from '@firebase/component';
/**
* To avoid having to include the @types/react-native package, which breaks
* some of our tests because of duplicate symbols, we are using require syntax
Expand All @@ -41,7 +40,7 @@ export const firebase = _firebase as FirebaseNamespace;
export default firebase;

declare module '@firebase/component' {
interface ComponentContainer {
getProvider(name: 'app'): Provider<FirebaseApp>;
interface NameServiceMapping {
'app': FirebaseApp;
}
}
5 changes: 2 additions & 3 deletions packages/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import { FirebaseNamespace, FirebaseApp } from '@firebase/app-types';
import { firebase as firebaseNamespace } from './src/firebaseNamespace';
import { isNode, isBrowser } from '@firebase/util';
import { Provider } from '@firebase/component';
import { logger } from './src/logger';

// Firebase Lite detection
Expand Down Expand Up @@ -72,7 +71,7 @@ export const firebase = firebaseNamespace;
export default firebase;

declare module '@firebase/component' {
interface ComponentContainer {
getProvider(name: 'app'): Provider<FirebaseApp>;
interface NameServiceMapping {
'app': FirebaseApp;
}
}
26 changes: 16 additions & 10 deletions packages/app/src/firebaseApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,14 @@ export class FirebaseAppImpl implements FirebaseApp {
this.checkDestroyed_();

// getImmediate will always succeed because _getService is only called for registered components.
return this.container
.getProvider(name)
.getImmediate(instanceIdentifier) as FirebaseService;
return (
(this.container
// eslint-disable-next-line @typescript-eslint/no-explicit-any
.getProvider(name as any)
.getImmediate({
identifier: instanceIdentifier
}) as unknown) as FirebaseService
);
}
/**
* Remove a service instance from the cache, so we will create a new instance for this service
Expand All @@ -141,19 +146,16 @@ export class FirebaseAppImpl implements FirebaseApp {
name: string,
instanceIdentifier: string = DEFAULT_ENTRY_NAME
): void {
this.container.getProvider(name).clearInstance(instanceIdentifier);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.container.getProvider(name as any).clearInstance(instanceIdentifier);
}

/**
*
* @param component the component being added to this app's container
* @param overwrite When a component with the same name has already been registered,
* if overwrite is true: overwrite the existing component
* if overwrite is false: throw an expection
*/
_addComponent(component: Component, overwrite = false): void {
_addComponent(component: Component): void {
try {
this.container.addComponent(component, overwrite);
this.container.addComponent(component);
} catch (e) {
logger.debug(
`Component ${component.name} failed to register with FirebaseApp ${this.name}`,
Expand All @@ -162,6 +164,10 @@ export class FirebaseAppImpl implements FirebaseApp {
}
}

_addOrOverwriteComponent(component: Component): void {
this.container.addOrOverwriteComponent(component);
}

/**
* This function will throw an Error if the App has already been deleted -
* use before performing API actions on the App.
Expand Down
3 changes: 2 additions & 1 deletion packages/app/src/firebaseNamespaceCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ export function createFirebaseNamespaceCore(
firebaseAppImpl: typeof FirebaseAppImpl | typeof FirebaseAppLiteImpl
): FirebaseNamespace {
const apps: { [name: string]: FirebaseApp } = {};
const components = new Map<string, Component>();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const components = new Map<string, Component<any>>();

// A namespace is a plain JavaScript Object.
const namespace: FirebaseNamespace = {
Expand Down
11 changes: 8 additions & 3 deletions packages/app/src/lite/firebaseAppLite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,14 @@ export class FirebaseAppLiteImpl implements FirebaseApp {
this.checkDestroyed_();

// getImmediate will always succeed because _getService is only called for registered components.
return this.container
.getProvider(name)
.getImmediate(instanceIdentifier) as FirebaseService;
return (
(this.container
// eslint-disable-next-line @typescript-eslint/no-explicit-any
.getProvider(name as any)
.getImmediate({
identifier: instanceIdentifier
}) as unknown) as FirebaseService
);
}

/**
Expand Down
3 changes: 2 additions & 1 deletion packages/app/src/lite/firebaseNamespaceLite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ export function createFirebaseNamespaceLite(): FirebaseNamespace {
* only allow performance SDK to register.
*/
function registerComponentForLite(
component: Component
// eslint-disable-next-line @typescript-eslint/no-explicit-any
component: Component<any>
): FirebaseServiceNamespace<FirebaseService> | null {
// only allow performance to register with firebase lite
if (
Expand Down
5 changes: 3 additions & 2 deletions packages/app/test/firebaseApp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,8 +336,9 @@ function createTestComponent(
type = ComponentType.PUBLIC
): Component {
const component = new Component(
name,
container => new TestService(container.getProvider('app').getImmediate()!),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
name as any,
container => new TestService(container.getProvider('app').getImmediate()),
type
);
component.setMultipleInstances(multiInstances);
Expand Down
2 changes: 1 addition & 1 deletion packages/component/src/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
/**
* Component for service name T, e.g. `auth`, `auth-internal`
*/
export class Component<T extends Name> {
export class Component<T extends Name = Name> {
multipleInstances = false;
/**
* Properties to be added to the service namespace
Expand Down
12 changes: 6 additions & 6 deletions packages/component/src/component_container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import { Name } from './types';
/**
* ComponentContainer that provides Providers for service name T, e.g. `auth`, `auth-internal`
*/
export class ComponentContainer<T extends Name = Name> {
private readonly providers = new Map<string, Provider<T>>();
export class ComponentContainer {
private readonly providers = new Map<string, Provider>();

constructor(private readonly name: string) {}

Expand All @@ -36,7 +36,7 @@ export class ComponentContainer<T extends Name = Name> {
* for different tests.
* if overwrite is false: throw an exception
*/
addComponent(component: Component<T>): void {
addComponent<T extends Name>(component: Component<T>): void {
const provider = this.getProvider(component.name);
if (provider.isComponentSet()) {
throw new Error(
Expand All @@ -47,7 +47,7 @@ export class ComponentContainer<T extends Name = Name> {
provider.setComponent(component);
}

addOrOverwriteComponent(component: Component<T>): void {
addOrOverwriteComponent<T extends Name>(component: Component<T>): void {
const provider = this.getProvider(component.name);
if (provider.isComponentSet()) {
// delete the existing provider from the container, so we can register the new component
Expand All @@ -64,7 +64,7 @@ export class ComponentContainer<T extends Name = Name> {
* Firebase SDKs providing services should extend NameServiceMapping interface to register
* themselves.
*/
getProvider(name: T): Provider<T> {
getProvider<T extends Name>(name: T): Provider<T> {
if (this.providers.has(name)) {
return this.providers.get(name) as Provider<T>;
}
Expand All @@ -76,7 +76,7 @@ export class ComponentContainer<T extends Name = Name> {
return provider as Provider<T>;
}

getProviders(): Array<Provider<T>> {
getProviders(): Provider[] {
return Array.from(this.providers.values());
}
}
14 changes: 4 additions & 10 deletions packages/component/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { Component } from './component';
* Provider for instance for service name T, e.g. 'auth', 'auth-internal'
* U is an alias for the type of the instance
*/
export class Provider<T extends Name, U = NameServiceMapping[T]> {
export class Provider<T extends Name = Name, U = NameServiceMapping[T]> {
private component: Component<T> | null = null;
private readonly instances: Map<string, U> = new Map();
private readonly instancesDeferred: Map<string, Deferred<U>> = new Map();
Expand Down Expand Up @@ -64,18 +64,12 @@ export class Provider<T extends Name, U = NameServiceMapping[T]> {
* the service is not immediately available.
* If optional is true, the method returns null if the service is not immediately available.
*/
getImmediate(options: {
identifier?: string;
optional: true;
}): NameServiceMapping[T] | null;
getImmediate(options?: {
identifier?: string;
optional?: false;
}): NameServiceMapping[T];
getImmediate(options: { identifier?: string; optional: true }): U | null;
getImmediate(options?: { identifier?: string; optional?: false }): U;
getImmediate(options?: {
identifier?: string;
optional?: boolean;
}): NameServiceMapping[T] | null {
}): U | null {
const { identifier, optional } = {
identifier: DEFAULT_ENTRY_NAME,
optional: false,
Expand Down
4 changes: 3 additions & 1 deletion packages/component/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ export interface Dictionary {
* This interface will be extended by Firebase SDKs to provide service name and service type mapping.
* It is used as a generic constraint to ensure type safety.
*/
export interface NameServiceMapping {}
export interface NameServiceMapping {
'app': string;
}

export type Name = keyof NameServiceMapping;
export type Service = NameServiceMapping[Name];