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 all 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
3 changes: 3 additions & 0 deletions packages/analytics-interop-types/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# @firebase/analytics-interop-types

**This package is not intended for direct usage, and should only be used via the officially supported [firebase](https://www.npmjs.com/package/firebase) package.**
46 changes: 46 additions & 0 deletions packages/analytics-interop-types/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* @license
* Copyright 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export interface FirebaseAnalyticsInternal {
/**
* Sends analytics event with given `eventParams`. This method
* automatically associates this logged event with this Firebase web
* app instance on this device.
* List of official event parameters can be found in
* {@link https://developers.google.com/gtagjs/reference/event
* the gtag.js reference documentation}.
*/
logEvent(
eventName: string,
eventParams?: { [key: string]: unknown },
options?: AnalyticsCallOptions
): void;
}

export interface AnalyticsCallOptions {
/**
* If true, this config or event call applies globally to all
* analytics properties on the page.
*/
global: boolean;
}

declare module '@firebase/component' {
interface NameServiceMapping {
'analytics-internal': FirebaseAnalyticsInternal;
}
}
24 changes: 24 additions & 0 deletions packages/analytics-interop-types/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "@firebase/analytics-interop-types",
"version": "0.1.0",
"description": "@firebase/analytics Types",
"author": "Firebase <[email protected]> (https://firebase.google.com/)",
"license": "Apache-2.0",
"scripts": {
"test": "tsc"
},
"files": [
"index.d.ts"
],
"repository": {
"directory": "packages/analytics-interop-types",
"type": "git",
"url": "https://github.com/firebase/firebase-js-sdk.git"
},
"bugs": {
"url": "https://github.com/firebase/firebase-js-sdk/issues"
},
"devDependencies": {
"typescript": "3.6.4"
}
}
9 changes: 9 additions & 0 deletions packages/analytics-interop-types/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../../config/tsconfig.base.json",
"compilerOptions": {
"noEmit": true
},
"exclude": [
"dist/**/*"
]
}
6 changes: 6 additions & 0 deletions packages/analytics-types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,9 @@ export interface Promotion {
id?: string;
name?: string;
}

declare module '@firebase/component' {
interface NameServiceMapping {
'analytics': FirebaseAnalytics;
}
}
10 changes: 5 additions & 5 deletions packages/analytics/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ const customDataLayerName = 'customDataLayer';
describe('FirebaseAnalytics instance tests', () => {
it('Throws if no analyticsId in config', () => {
const app = getFakeApp();
expect(() => analyticsFactory(app, () => {})).to.throw('field is empty');
expect(() => analyticsFactory(app)).to.throw('field is empty');
});
it('Throws if creating an instance with already-used analytics ID', () => {
const app = getFakeApp(analyticsId);
resetGlobalVars(false, { [analyticsId]: Promise.resolve() });
expect(() => analyticsFactory(app, () => {})).to.throw('already exists');
expect(() => analyticsFactory(app)).to.throw('already exists');
});
describe('Standard app, page already has user gtag script', () => {
let app: FirebaseApp = {} as FirebaseApp;
Expand All @@ -55,7 +55,7 @@ describe('FirebaseAnalytics instance tests', () => {
app = getFakeApp(analyticsId);
window['gtag'] = gtagStub;
window['dataLayer'] = [];
analyticsInstance = analyticsFactory(app, () => {});
analyticsInstance = analyticsFactory(app);
});
after(() => {
delete window['gtag'];
Expand Down Expand Up @@ -121,7 +121,7 @@ describe('FirebaseAnalytics instance tests', () => {
dataLayerName: customDataLayerName,
gtagName: customGtagName
});
analyticsInstance = analyticsFactory(app, () => {});
analyticsInstance = analyticsFactory(app);
});
after(() => {
delete window[customGtagName];
Expand Down Expand Up @@ -164,7 +164,7 @@ describe('FirebaseAnalytics instance tests', () => {
before(() => {
resetGlobalVars();
const app = getFakeApp(analyticsId);
analyticsInstance = analyticsFactory(app, () => {});
analyticsInstance = analyticsFactory(app);
});
after(() => {
delete window['gtag'];
Expand Down
50 changes: 37 additions & 13 deletions packages/analytics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@
*/
import firebase from '@firebase/app';
import { FirebaseAnalytics } from '@firebase/analytics-types';
import {
FirebaseServiceFactory,
_FirebaseNamespace
} from '@firebase/app-types/private';
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';
import { Component, ComponentType } from '@firebase/component';
import { ERROR_FACTORY, AnalyticsError } from './src/errors';

declare global {
interface Window {
Expand All @@ -35,17 +35,41 @@ declare global {
const ANALYTICS_TYPE = 'analytics';

export function registerAnalytics(instance: _FirebaseNamespace): void {
instance.INTERNAL.registerService(
ANALYTICS_TYPE,
factory as FirebaseServiceFactory,
{
instance.INTERNAL.registerComponent(
new Component(
ANALYTICS_TYPE,
container => {
// getImmediate for FirebaseApp will always succeed
const app = container.getProvider('app').getImmediate();
return factory(app);
},
ComponentType.PUBLIC
).setServiceProps({
settings,
EventName
},
// We don't need to wait on any AppHooks.
undefined,
// Allow multiple analytics instances per app.
false
})
);

instance.INTERNAL.registerComponent(
new Component(
'analytics-internal',
container => {
try {
const analytics = container
.getProvider(ANALYTICS_TYPE)
.getImmediate();
return {
logEvent: analytics.logEvent
};
} catch (e) {
throw ERROR_FACTORY.create(
AnalyticsError.INTEROP_COMPONENT_REG_FAILED,
{ reason: e }
);
}
},
ComponentType.PRIVATE
)
);
}

Expand Down
1 change: 1 addition & 0 deletions packages/analytics/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@firebase/analytics-types": "0.2.2",
"@firebase/installations": "0.3.2",
"@firebase/util": "0.2.31",
"@firebase/component": "0.1.0",
"tslib": "1.10.0"
},
"license": "Apache-2.0",
Expand Down
8 changes: 6 additions & 2 deletions packages/analytics/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import { ANALYTICS_ID_FIELD } from './constants';
export const enum AnalyticsError {
NO_GA_ID = 'no-ga-id',
ALREADY_EXISTS = 'already-exists',
ALREADY_INITIALIZED = 'already-initialized'
ALREADY_INITIALIZED = 'already-initialized',
INTEROP_COMPONENT_REG_FAILED = 'interop-component-reg-failed'
}

const ERRORS: ErrorMap<AnalyticsError> = {
Expand All @@ -36,11 +37,14 @@ const ERRORS: ErrorMap<AnalyticsError> = {
[AnalyticsError.ALREADY_INITIALIZED]:
'Firebase Analytics has already been initialized.' +
'settings() must be called before initializing any Analytics instance' +
'or it will have no effect.'
'or it will have no effect.',
[AnalyticsError.INTEROP_COMPONENT_REG_FAILED]:
'Firebase Analytics Interop Component failed to instantiate'
};

interface ErrorParams {
[AnalyticsError.ALREADY_EXISTS]: { id: string };
[AnalyticsError.INTEROP_COMPONENT_REG_FAILED]: { reason: Error };
}

export const ERROR_FACTORY = new ErrorFactory<AnalyticsError, ErrorParams>(
Expand Down
16 changes: 2 additions & 14 deletions packages/analytics/src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
* limitations under the License.
*/

import { FirebaseApp } from '@firebase/app-types';
import {
FirebaseAnalytics,
Gtag,
Expand All @@ -38,6 +37,7 @@ import {
} from './helpers';
import { ANALYTICS_ID_FIELD } from './constants';
import { AnalyticsError, ERROR_FACTORY } from './errors';
import { FirebaseApp } from '@firebase/app-types';

/**
* Maps gaId to FID fetch promises.
Expand Down Expand Up @@ -102,11 +102,7 @@ export function settings(options: SettingsOptions): void {
}
}

export function factory(
app: FirebaseApp,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
extendApp: (props: { [prop: string]: any }) => void
): FirebaseAnalytics {
export function factory(app: FirebaseApp): FirebaseAnalytics {
const analyticsId = app.options[ANALYTICS_ID_FIELD];
if (!analyticsId) {
throw ERROR_FACTORY.create(AnalyticsError.NO_GA_ID);
Expand Down Expand Up @@ -162,13 +158,5 @@ export function factory(
setAnalyticsCollectionEnabled(analyticsId, enabled)
};

extendApp({
INTERNAL: {
analytics: {
logEvent: analyticsInstance.logEvent
}
}
});

return analyticsInstance;
}
6 changes: 6 additions & 0 deletions packages/app-types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,9 @@ export interface FirebaseNamespace {
// The current SDK version.
SDK_VERSION: string;
}

declare module '@firebase/component' {
interface NameServiceMapping {
'app': FirebaseApp;
}
}
20 changes: 9 additions & 11 deletions packages/app-types/private.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import { FirebaseApp, FirebaseNamespace } from '@firebase/app-types';
import { Observer, Subscribe } from '@firebase/util';
import { FirebaseError, ErrorFactory } from '@firebase/util';
import { Deferred } from '../firestore/test/util/promise';
import { Component } from '@firebase/component';

export interface FirebaseServiceInternals {
/**
Expand Down Expand Up @@ -80,8 +82,8 @@ export interface FirebaseAppInternals {
}

export interface _FirebaseApp extends FirebaseApp {
INTERNAL: FirebaseAppInternals;
_removeServiceInstance: (name: string, instanceIdentifier?: string) => void;
_addComponent(component: Component): void;
_removeServiceInstance(name: string, instanceIdentifier?: string): void;
}
export interface _FirebaseNamespace extends FirebaseNamespace {
INTERNAL: {
Expand All @@ -99,13 +101,9 @@ export interface _FirebaseNamespace extends FirebaseNamespace {
* @param allowMultipleInstances Whether the registered service supports
* multiple instances per app. If not specified, the default is false.
*/
registerService(
name: string,
createService: FirebaseServiceFactory,
serviceProperties?: { [prop: string]: any },
appHook?: AppHook,
allowMultipleInstances?: boolean
): FirebaseServiceNamespace<FirebaseService>;
registerComponent(
component: Component
): FirebaseServiceNamespace<FirebaseService> | null;

/**
* Just used for testing to start from a fresh namespace.
Expand Down Expand Up @@ -139,9 +137,9 @@ export interface _FirebaseNamespace extends FirebaseNamespace {
removeApp(name: string): void;

/**
* Service factories for each registered service.
* registered components.
*/
factories: { [name: string]: FirebaseServiceFactory };
components: Map<string, Component>;

/*
* Convert service name to factory name to use.
Expand Down
6 changes: 2 additions & 4 deletions packages/app/index.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,14 @@

import { FirebaseNamespace } from '@firebase/app-types';
import { _FirebaseNamespace } from '@firebase/app-types/private';
import { createFirebaseNamespace } from './src/firebaseNamespace';
import { firebase as _firebase } from './src/firebaseNamespace';
// Node specific packages.
// @ts-ignore
import Storage from 'dom-storage';
// @ts-ignore
import { XMLHttpRequest } from 'xmlhttprequest';

const _firebase = createFirebaseNamespace() as _FirebaseNamespace;

_firebase.INTERNAL.extendNamespace({
(_firebase as _FirebaseNamespace).INTERNAL.extendNamespace({
INTERNAL: {
node: {
localStorage: new Storage(null, { strict: true }),
Expand Down
7 changes: 2 additions & 5 deletions packages/app/index.rn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@

import { FirebaseNamespace } from '@firebase/app-types';
import { _FirebaseNamespace } from '@firebase/app-types/private';
import { createFirebaseNamespace } from './src/firebaseNamespace';

import { firebase as _firebase } from './src/firebaseNamespace';
/**
* 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 @@ -27,9 +26,7 @@ import { createFirebaseNamespace } from './src/firebaseNamespace';
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { AsyncStorage } = require('react-native');

const _firebase = createFirebaseNamespace() as _FirebaseNamespace;

_firebase.INTERNAL.extendNamespace({
(_firebase as _FirebaseNamespace).INTERNAL.extendNamespace({
INTERNAL: {
reactNative: {
AsyncStorage
Expand Down
3 changes: 1 addition & 2 deletions packages/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*/

import { FirebaseNamespace } from '@firebase/app-types';
import { createFirebaseNamespace } from './src/firebaseNamespace';
import { firebase as firebaseNamespace } from './src/firebaseNamespace';
import { isNode, isBrowser } from '@firebase/util';
import { logger } from './src/logger';

Expand All @@ -38,7 +38,6 @@ if (isBrowser() && (self as any).firebase !== undefined) {
}
}

const firebaseNamespace = createFirebaseNamespace();
const initializeApp = firebaseNamespace.initializeApp;

// TODO: This disable can be removed and the 'ignoreRestArgs' option added to
Expand Down
Loading