Skip to content

Commit 9f109f8

Browse files
authored
enable eslint for functions (#1864)
* enable eslint for functions * add ignore path * [AUTOMATED]: Prettier Code Styling * address Bryan's comments * update eslint version * update types * add messaging as devDep in functions
1 parent 1804b1d commit 9f109f8

File tree

14 files changed

+82
-73
lines changed

14 files changed

+82
-73
lines changed

config/functions/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ exports.dataTest = functions.https.onRequest((request, response) => {
3535
value: '3',
3636
'@type': 'type.googleapis.com/google.protobuf.Int64Value',
3737
},*/
38-
string: 'four',
38+
str: 'four',
3939
array: [5, 6],
4040
null: null
4141
}

packages/app/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
],
1616
"scripts": {
1717
"lint": "eslint -c .eslintrc.json '**/*.ts' --ignore-path '../../.gitignore'",
18-
"lint:fix": "eslint --fix -c .eslintrc.json '**/*.ts'",
18+
"lint:fix": "eslint --fix -c .eslintrc.json '**/*.ts' --ignore-path '../../.gitignore'",
1919
"build": "rollup -c",
2020
"dev": "rollup -c -w",
2121
"test": "run-p lint test:browser test:node",

packages/functions-types/index.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export interface HttpsCallableResult {
2727
* Google Cloud Functions.
2828
*/
2929
export interface HttpsCallable {
30-
(data?: any): Promise<HttpsCallableResult>;
30+
(data?: {} | null): Promise<HttpsCallableResult>;
3131
}
3232

3333
/**

packages/functions/.eslintrc.json

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"extends": "../../config/.eslintrc.json",
3+
"parserOptions": {
4+
"project": "tsconfig.json"
5+
}
6+
}

packages/functions/index.node.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ import 'isomorphic-fetch';
2525
*/
2626
const FUNCTIONS_TYPE = 'functions';
2727

28-
function factory(app: FirebaseApp, unused: any, region?: string): Service {
28+
function factory(app: FirebaseApp, _unused: unknown, region?: string): Service {
2929
return new Service(app, region);
3030
}
3131

32-
export function registerFunctions(instance) {
33-
let namespaceExports = {
32+
export function registerFunctions(instance): void {
33+
const namespaceExports = {
3434
// no-inline
3535
Functions: Service
3636
};

packages/functions/index.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* limitations under the License.
1616
*/
1717
import firebase from '@firebase/app';
18-
import * as app_types from '@firebase/app-types';
18+
import * as appTypes from '@firebase/app-types';
1919
import { FirebaseServiceFactory } from '@firebase/app-types/private';
2020
import * as types from '@firebase/functions-types';
2121
import { Service } from './src/api/service';
@@ -26,15 +26,15 @@ import { Service } from './src/api/service';
2626
const FUNCTIONS_TYPE = 'functions';
2727

2828
function factory(
29-
app: app_types.FirebaseApp,
30-
unused: any,
29+
app: appTypes.FirebaseApp,
30+
_unused: unknown,
3131
region?: string
3232
): Service {
3333
return new Service(app, region);
3434
}
3535

36-
export function registerFunctions(instance) {
37-
let namespaceExports = {
36+
export function registerFunctions(instance): void {
37+
const namespaceExports = {
3838
// no-inline
3939
Functions: Service
4040
};

packages/functions/package.json

+9-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
"dist"
1212
],
1313
"scripts": {
14+
"lint": "eslint -c .eslintrc.json '**/*.ts' --ignore-path '../../.gitignore'",
15+
"lint:fix": "eslint --fix -c .eslintrc.json '**/*.ts' --ignore-path '../../.gitignore'",
1416
"build": "rollup -c",
1517
"dev": "rollup -c -w",
16-
"test": "run-p test:browser test:node",
18+
"test": "run-p lint test:browser test:node",
1719
"test:browser": "karma start --single-run",
1820
"test:browser:debug": "karma start --browsers=Chrome --auto-watch",
1921
"test:node": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' nyc --reporter lcovonly -- mocha 'test/{,!(browser)/**/}*.test.ts' --file index.node.ts --opts ../../config/mocha.node.opts",
@@ -52,7 +54,12 @@
5254
"tslint": "5.16.0",
5355
"typescript": "3.4.5",
5456
"webpack": "4.30.0",
55-
"yargs": "13.2.2"
57+
"yargs": "13.2.2",
58+
"eslint": "5.16.0",
59+
"@typescript-eslint/parser": "1.10.2",
60+
"@typescript-eslint/eslint-plugin": "1.10.2",
61+
"@typescript-eslint/eslint-plugin-tslint": "1.10.2",
62+
"@firebase/messaging": "0.4.2"
5663
},
5764
"repository": {
5865
"directory": "packages/functions",

packages/functions/src/api/error.ts

+12-9
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import { HttpsError, FunctionsErrorCode } from '@firebase/functions-types';
1919
import { Serializer } from '../serializer';
20+
import { HttpResponseBody } from './service';
2021

2122
/**
2223
* Standard error codes for different ways a request can fail, as defined by:
@@ -59,9 +60,9 @@ export class HttpsErrorImpl extends Error implements HttpsError {
5960
/**
6061
* Extra data to be converted to JSON and included in the error response.
6162
*/
62-
readonly details?: any;
63+
readonly details?: unknown;
6364

64-
constructor(code: FunctionsErrorCode, message?: string, details?: any) {
65+
constructor(code: FunctionsErrorCode, message?: string, details?: unknown) {
6566
super(message);
6667

6768
// This is a workaround for a bug in TypeScript when extending Error:
@@ -113,6 +114,7 @@ function codeForHTTPStatus(status: number): FunctionsErrorCode {
113114
return 'unavailable';
114115
case 504:
115116
return 'deadline-exceeded';
117+
default: // ignore
116118
}
117119
return 'unknown';
118120
}
@@ -122,19 +124,19 @@ function codeForHTTPStatus(status: number): FunctionsErrorCode {
122124
*/
123125
export function _errorForResponse(
124126
status: number,
125-
bodyJSON: any,
127+
bodyJSON: HttpResponseBody | null,
126128
serializer: Serializer
127129
): Error | null {
128130
let code = codeForHTTPStatus(status);
129131

130132
// Start with reasonable defaults from the status code.
131133
let description: string = code;
132134

133-
let details: any = undefined;
135+
let details: unknown = undefined;
134136

135137
// Then look through the body for explicit details.
136138
try {
137-
const errorJSON = bodyJSON.error;
139+
const errorJSON = bodyJSON && bodyJSON.error;
138140
if (errorJSON) {
139141
const status = errorJSON.status;
140142
if (typeof status === 'string') {
@@ -143,10 +145,11 @@ export function _errorForResponse(
143145
return new HttpsErrorImpl('internal', 'internal');
144146
}
145147
code = errorCodeMap[status];
148+
149+
// TODO(klimt): Add better default descriptions for error enums.
150+
// The default description needs to be updated for the new code.
151+
description = status;
146152
}
147-
// TODO(klimt): Add better default descriptions for error enums.
148-
// The default description needs to be updated for the new code.
149-
description = status;
150153

151154
const message = errorJSON.message;
152155
if (typeof message === 'string') {
@@ -155,7 +158,7 @@ export function _errorForResponse(
155158

156159
details = errorJSON.details;
157160
if (details !== undefined) {
158-
details = serializer.decode(details);
161+
details = serializer.decode(details as {} | null);
159162
}
160163
}
161164
} catch (e) {

packages/functions/src/api/service.ts

+22-11
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,8 @@
1717

1818
import { FirebaseApp } from '@firebase/app-types';
1919
import { FirebaseService } from '@firebase/app-types/private';
20-
import firebase from '@firebase/app';
2120
import {
2221
FirebaseFunctions,
23-
FunctionsErrorCode,
2422
HttpsCallable,
2523
HttpsCallableResult,
2624
HttpsCallableOptions
@@ -34,7 +32,21 @@ import { Serializer } from '../serializer';
3432
*/
3533
interface HttpResponse {
3634
status: number;
37-
json: any;
35+
json: HttpResponseBody | null;
36+
}
37+
/**
38+
* Describes the shape of the HttpResponse body.
39+
* It makes functions that would otherwise take {} able to access the
40+
* possible elements in the body more easily
41+
*/
42+
export interface HttpResponseBody {
43+
data?: unknown;
44+
result?: unknown;
45+
error?: {
46+
message?: unknown;
47+
status?: unknown;
48+
details?: unknown;
49+
};
3850
}
3951

4052
/**
@@ -43,7 +55,7 @@ interface HttpResponse {
4355
*
4456
* @param millis Number of milliseconds to wait before rejecting.
4557
*/
46-
function failAfter(millis: number): Promise<HttpResponse> {
58+
function failAfter(millis: number): Promise<never> {
4759
return new Promise((_, reject) => {
4860
setTimeout(() => {
4961
reject(new HttpsErrorImpl('deadline-exceeded', 'deadline-exceeded'));
@@ -110,7 +122,7 @@ export class Service implements FirebaseFunctions, FirebaseService {
110122
* @param origin The origin of the local emulator, such as
111123
* "http://localhost:5005".
112124
*/
113-
useFunctionsEmulator(origin: string) {
125+
useFunctionsEmulator(origin: string): void {
114126
this.emulatorOrigin = origin;
115127
}
116128

@@ -119,10 +131,9 @@ export class Service implements FirebaseFunctions, FirebaseService {
119131
* @param name The name of the trigger.
120132
*/
121133
httpsCallable(name: string, options?: HttpsCallableOptions): HttpsCallable {
122-
let callable = <HttpsCallable>(data?: any) => {
134+
return data => {
123135
return this.call(name, data, options || {});
124136
};
125-
return callable;
126137
}
127138

128139
/**
@@ -156,15 +167,15 @@ export class Service implements FirebaseFunctions, FirebaseService {
156167
json: null
157168
};
158169
}
159-
let json: any = null;
170+
let json: {} | null = null;
160171
try {
161172
json = await response.json();
162173
} catch (e) {
163174
// If we fail to parse JSON, it will fail the same as an empty body.
164175
}
165176
return {
166177
status: response.status,
167-
json: json
178+
json
168179
};
169180
}
170181

@@ -175,7 +186,7 @@ export class Service implements FirebaseFunctions, FirebaseService {
175186
*/
176187
private async call(
177188
name: string,
178-
data: any,
189+
data: unknown,
179190
options: HttpsCallableOptions
180191
): Promise<HttpsCallableResult> {
181192
const url = this._url(name);
@@ -240,7 +251,7 @@ export class Service implements FirebaseFunctions, FirebaseService {
240251
}
241252

242253
// Decode any special types, such as dates, in the returned data.
243-
const decodedData = this.serializer.decode(responseData);
254+
const decodedData = this.serializer.decode(responseData as {} | null);
244255

245256
return { data: decodedData };
246257
}

packages/functions/src/context.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
*/
1717
import { FirebaseApp } from '@firebase/app-types';
1818
import { _FirebaseApp } from '@firebase/app-types/private';
19-
import { firebase } from '@firebase/app';
2019
import { FirebaseMessaging } from '@firebase/messaging-types';
2120

2221
/**
@@ -50,9 +49,11 @@ export class ContextProvider {
5049
try {
5150
// HACK: Until we have a separate instanceId package, this is a quick way
5251
// to load in the messaging instance for this app.
52+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
5353
if (!(this.app as any).messaging) {
5454
return undefined;
5555
}
56+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
5657
const messaging = (this.app as any).messaging() as FirebaseMessaging;
5758
const token = await messaging.getToken();
5859
if (!token) {
@@ -68,7 +69,7 @@ export class ContextProvider {
6869
}
6970
}
7071

71-
public async getContext(): Promise<Context> {
72+
async getContext(): Promise<Context> {
7273
const authToken = await this.getAuthToken();
7374
const instanceIdToken = await this.getInstanceIdToken();
7475
return { authToken, instanceIdToken };

packages/functions/src/serializer.ts

+10-10
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
const LONG_TYPE = 'type.googleapis.com/google.protobuf.Int64Value';
1919
const UNSIGNED_LONG_TYPE = 'type.googleapis.com/google.protobuf.UInt64Value';
2020

21-
function mapValues(o: object, f: (any) => any): object {
22-
let result = {};
23-
for (var key in o) {
21+
function mapValues(o: object, f: (val: unknown) => unknown): object {
22+
const result = {};
23+
for (const key in o) {
2424
if (o.hasOwnProperty(key)) {
2525
result[key] = f(o[key]);
2626
}
@@ -31,8 +31,8 @@ function mapValues(o: object, f: (any) => any): object {
3131
export class Serializer {
3232
// Takes data and encodes it in a JSON-friendly way, such that types such as
3333
// Date are preserved.
34-
encode(data: any): any {
35-
if (data === null || data === undefined) {
34+
encode(data: unknown): unknown {
35+
if (data == null) {
3636
return null;
3737
}
3838
if (data instanceof Number) {
@@ -53,16 +53,16 @@ export class Serializer {
5353
return data.map(x => this.encode(x));
5454
}
5555
if (typeof data === 'function' || typeof data === 'object') {
56-
return mapValues(data, x => this.encode(x));
56+
return mapValues(data as object, x => this.encode(x));
5757
}
5858
// If we got this far, the data is not encodable.
5959
throw new Error('Data cannot be encoded in JSON: ' + data);
6060
}
6161

6262
// Takes data that's been encoded in a JSON-friendly form and returns a form
6363
// with richer datatypes, such as Dates, etc.
64-
decode(json: any): any {
65-
if (json === null) {
64+
decode(json: {} | null): {} | null {
65+
if (json == null) {
6666
return json;
6767
}
6868
if (json['@type']) {
@@ -73,7 +73,7 @@ export class Serializer {
7373
// Technically, this could work return a valid number for malformed
7474
// data if there was a number followed by garbage. But it's just not
7575
// worth all the extra code to detect that case.
76-
const value = parseFloat(json.value);
76+
const value = Number(json['value']);
7777
if (isNaN(value)) {
7878
throw new Error('Data cannot be decoded from JSON: ' + json);
7979
}
@@ -88,7 +88,7 @@ export class Serializer {
8888
return json.map(x => this.decode(x));
8989
}
9090
if (typeof json === 'function' || typeof json === 'object') {
91-
return mapValues(json, x => this.decode(x));
91+
return mapValues(json, x => this.decode(x as {} | null));
9292
}
9393
// Anything else is safe to return.
9494
return json;

0 commit comments

Comments
 (0)