Skip to content

Commit b1cb5a2

Browse files
committed
Make the _getInstance() instantiator a util for the whole SDK
1 parent 2070553 commit b1cb5a2

File tree

11 files changed

+77
-55
lines changed

11 files changed

+77
-55
lines changed

packages-exp/auth-exp/src/core/auth/auth_impl.test.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,15 @@ import { FirebaseError } from '@firebase/util';
2626
import { testUser } from '../../../test/mock_auth';
2727
import { Auth } from '../../model/auth';
2828
import { User } from '../../model/user';
29-
import { _getInstance, Persistence } from '../persistence';
29+
import { Persistence } from '../persistence';
3030
import { browserLocalPersistence } from '../persistence/browser';
3131
import { inMemoryPersistence } from '../persistence/in_memory';
3232
import { PersistenceUserManager } from '../persistence/persistence_user_manager';
33+
import { _getInstance } from '../util/instantiator';
3334
import * as navigator from '../util/navigator';
3435
import { _getClientVersion, ClientPlatform } from '../util/version';
3536
import {
36-
DEFAULT_API_HOST,
37-
DEFAULT_API_SCHEME,
38-
DEFAULT_TOKEN_API_HOST,
39-
initializeAuth
37+
DEFAULT_API_HOST, DEFAULT_API_SCHEME, DEFAULT_TOKEN_API_HOST, initializeAuth
4038
} from './auth_impl';
4139

4240
use(sinonChai);
@@ -109,7 +107,7 @@ describe('core/auth/auth_impl', () => {
109107
describe('#setPersistence', () => {
110108
it('swaps underlying persistence', async () => {
111109
const newPersistence = browserLocalPersistence;
112-
const newStub = sinon.stub(_getInstance(newPersistence));
110+
const newStub = sinon.stub(_getInstance<Persistence>(newPersistence));
113111
persistenceStub.get.returns(
114112
Promise.resolve(testUser(auth, 'test').toPlainObject())
115113
);
@@ -308,7 +306,7 @@ describe('core/auth/initializeAuth', () => {
308306

309307
it('pulls the user from storage', async () => {
310308
sinon
311-
.stub(_getInstance(inMemoryPersistence), 'get')
309+
.stub(_getInstance<Persistence>(inMemoryPersistence), 'get')
312310
.returns(Promise.resolve(testUser({}, 'uid').toPlainObject()));
313311
const auth = await initAndWait(inMemoryPersistence);
314312
expect(auth.currentUser!.uid).to.eq('uid');

packages-exp/auth-exp/src/core/auth/auth_impl.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,16 @@ import { getApp } from '@firebase/app-exp';
1919
import { FirebaseApp } from '@firebase/app-types-exp';
2020
import * as externs from '@firebase/auth-types-exp';
2121
import {
22-
CompleteFn,
23-
createSubscribe,
24-
ErrorFn,
25-
NextFn,
26-
Observer,
27-
Subscribe,
28-
Unsubscribe
22+
CompleteFn, createSubscribe, ErrorFn, NextFn, Observer, Subscribe, Unsubscribe
2923
} from '@firebase/util';
3024

3125
import { Auth, Dependencies } from '../../model/auth';
3226
import { User } from '../../model/user';
3327
import { AuthErrorCode } from '../errors';
34-
import { _getInstance, Persistence } from '../persistence';
28+
import { Persistence } from '../persistence';
3529
import { PersistenceUserManager } from '../persistence/persistence_user_manager';
3630
import { assert } from '../util/assert';
31+
import { _getInstance } from '../util/instantiator';
3732
import { _getUserLanguage } from '../util/navigator';
3833
import { _getClientVersion, ClientPlatform } from '../util/version';
3934

@@ -218,7 +213,7 @@ export function initializeAuth(
218213
const hierarchy = (Array.isArray(persistence)
219214
? persistence
220215
: [persistence]
221-
).map(_getInstance);
216+
).map<Persistence>(_getInstance);
222217
const { apiKey, authDomain } = app.options;
223218

224219
// TODO: platform needs to be determined using heuristics

packages-exp/auth-exp/src/core/persistence/browser.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ import { expect } from 'chai';
1919
import * as sinon from 'sinon';
2020

2121
import { testUser } from '../../../test/mock_auth';
22-
import { _getInstance, PersistedBlob, Persistence, PersistenceType } from './';
22+
import { _getInstance } from '../util/instantiator';
23+
import { PersistedBlob, Persistence, PersistenceType } from './';
2324
import { browserLocalPersistence, browserSessionPersistence } from './browser';
2425

2526
describe('core/persistence/browser', () => {
@@ -74,7 +75,7 @@ describe('core/persistence/browser', () => {
7475
});
7576

7677
describe('browserSessionPersistence', () => {
77-
const persistence = _getInstance(browserSessionPersistence);
78+
const persistence: Persistence = _getInstance(browserSessionPersistence);
7879

7980
it('should work with persistence type', async () => {
8081
const key = 'my-super-special-persistence-type';

packages-exp/auth-exp/src/core/persistence/in_memory.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@
1818
import { expect } from 'chai';
1919

2020
import { testUser } from '../../../test/mock_auth';
21-
import { _getInstance, PersistenceType } from './';
21+
import { _getInstance } from '../util/instantiator';
22+
import { Persistence, PersistenceType } from './';
2223
import { inMemoryPersistence } from './in_memory';
2324

24-
const persistence = _getInstance(inMemoryPersistence);
25+
const persistence: Persistence = _getInstance(inMemoryPersistence);
2526

2627
describe('core/persistence/in_memory', () => {
2728
it('should work with persistence type', async () => {

packages-exp/auth-exp/src/core/persistence/index.ts

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
* limitations under the License.
1616
*/
1717

18-
import * as externs from '@firebase/auth-types-exp';
19-
2018
export enum PersistenceType {
2119
SESSION = 'SESSION',
2220
LOCAL = 'LOCAL',
@@ -41,28 +39,4 @@ export interface Persistence {
4139
set(key: string, value: PersistenceValue): Promise<void>;
4240
get<T extends PersistenceValue>(key: string): Promise<T | null>;
4341
remove(key: string): Promise<void>;
44-
}
45-
46-
/**
47-
* We can't directly export all of the different types of persistence as
48-
* constants: this would cause tree-shaking libraries to keep all of the
49-
* various persistence classes in the bundle, even if they're not used, since
50-
* the system can't prove those constructors don't side-effect. Instead, the
51-
* persistence classes themselves all have a static method called _getInstance()
52-
* which does the instantiation.
53-
*/
54-
export interface PersistenceInstantiator extends externs.Persistence {
55-
new (): Persistence;
56-
}
57-
58-
const persistenceCache: Map<externs.Persistence, Persistence> = new Map();
59-
60-
export function _getInstance(cls: externs.Persistence): Persistence {
61-
if (persistenceCache.has(cls)) {
62-
return persistenceCache.get(cls)!;
63-
}
64-
65-
const persistence = new (cls as PersistenceInstantiator)();
66-
persistenceCache.set(cls, persistence);
67-
return persistence;
68-
}
42+
}

packages-exp/auth-exp/src/core/persistence/indexed_db.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@ import { expect } from 'chai';
1919
import * as sinon from 'sinon';
2020

2121
import { testUser } from '../../../test/mock_auth';
22-
import { _getInstance, PersistenceType } from './';
22+
import { _getInstance } from '../util/instantiator';
23+
import { Persistence, PersistenceType } from './';
2324
import { indexedDBLocalPersistence } from './indexed_db';
2425

25-
const persistence = _getInstance(indexedDBLocalPersistence);
26+
const persistence: Persistence = _getInstance(indexedDBLocalPersistence);
2627

2728
describe('core/persistence/indexed_db', () => {
2829
afterEach(sinon.restore);

packages-exp/auth-exp/src/core/persistence/persistence_user_manager.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ import * as sinonChai from 'sinon-chai';
2323
import { testAuth, testUser } from '../../../test/mock_auth';
2424
import { Auth } from '../../model/auth';
2525
import { UserImpl } from '../user/user_impl';
26-
import { _getInstance, Persistence, PersistenceType } from './';
26+
import { _getInstance } from '../util/instantiator';
27+
import { Persistence, PersistenceType } from './';
2728
import { inMemoryPersistence } from './in_memory';
2829
import { PersistenceUserManager } from './persistence_user_manager';
2930

packages-exp/auth-exp/src/core/persistence/persistence_user_manager.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717

1818
import { ApiKey, AppName, Auth } from '../../model/auth';
1919
import { User } from '../../model/user';
20-
import { _getInstance, PersistedBlob, Persistence } from '../persistence';
20+
import { PersistedBlob, Persistence } from '../persistence';
2121
import { UserImpl } from '../user/user_impl';
22+
import { _getInstance } from '../util/instantiator';
2223
import { inMemoryPersistence } from './in_memory';
2324

2425
export const _AUTH_USER_KEY_NAME = 'authUser';

packages-exp/auth-exp/src/core/persistence/react_native.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ import { expect } from 'chai';
2020
import { ReactNativeAsyncStorage } from '@firebase/auth-types-exp';
2121

2222
import { testUser } from '../../../test/mock_auth';
23-
import { _getInstance, PersistedBlob, PersistenceType } from './';
23+
import { _getInstance } from '../util/instantiator';
24+
import { PersistedBlob, Persistence, PersistenceType } from './';
2425
import { getReactNativePersistence } from './react_native';
2526

2627
/**
@@ -48,7 +49,7 @@ class FakeAsyncStorage implements ReactNativeAsyncStorage {
4849

4950
describe('core/persistence/react', () => {
5051
const fakeAsyncStorage = new FakeAsyncStorage();
51-
const persistence = _getInstance(getReactNativePersistence(fakeAsyncStorage));
52+
const persistence: Persistence = _getInstance(getReactNativePersistence(fakeAsyncStorage));
5253

5354
beforeEach(() => {
5455
fakeAsyncStorage.clear();

packages-exp/auth-exp/src/core/persistence/index.test.ts renamed to packages-exp/auth-exp/src/core/util/instantiator.test.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717

1818
import { expect } from 'chai';
1919

20-
import { _getInstance } from './';
20+
import { _getInstance } from './instantiator';
2121

22-
describe('src/core/persistence/index', () => {
22+
describe('src/core/util/instantiator', () => {
2323
context('_getInstance', () => {
2424
// All tests define their own classes since the Class object is used in the
2525
// global map.
@@ -66,5 +66,15 @@ describe('src/core/persistence/index', () => {
6666
expect(_getInstance(PersistenceA)).to.eq(a);
6767
expect(_getInstance(PersistenceB)).to.eq(b);
6868
});
69+
70+
it('instantiates any class', () => {
71+
class Test {}
72+
73+
const a = _getInstance(Test);
74+
const b = _getInstance(Test);
75+
76+
expect(a).to.be.instanceOf(Test);
77+
expect(a).to.eq(b);
78+
});
6979
});
7080
});
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
/**
19+
* Our API has a lot of one-off constants that are used to do things.
20+
* Unfortunately we can't export these as classes instantiated directly since
21+
* the constructor may side effect and therefore can't be proven to be safely
22+
* culled. Instead, we export these classes themselves as a lowerCamelCase
23+
* constant, and instantiate them under the hood.
24+
*/
25+
export interface SingletonInstantiator<T> {
26+
new (): T;
27+
}
28+
29+
const persistenceCache: Map<unknown, unknown> = new Map();
30+
31+
export function _getInstance<T>(cls: unknown): T {
32+
if (persistenceCache.has(cls)) {
33+
return persistenceCache.get(cls)! as T;
34+
}
35+
36+
const persistence = new (cls as SingletonInstantiator<T>)();
37+
persistenceCache.set(cls, persistence);
38+
return persistence;
39+
}

0 commit comments

Comments
 (0)