Skip to content

Commit 9cf46ed

Browse files
refactor!: use a union type for SignatureType (#331)
This commit refactors the SignatureType enum into an array of strings declared [as const](microsoft/TypeScript#29510). This allows the SignatureType type to be expressed as a union type, which works a bit better when parsing a users provided string. This is some simple refactoring in preparation for declarative function signatures. BREAKING CHANGE: exported SignatureType type is converted from an enum to a union type
1 parent 30bb77d commit 9cf46ed

File tree

7 files changed

+37
-33
lines changed

7 files changed

+37
-33
lines changed

src/index.ts

+9-16
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import {resolve} from 'path';
3636
import {getUserFunction} from './loader';
3737
import {ErrorHandler} from './invoker';
3838
import {getServer} from './server';
39-
import {SignatureType} from './types';
39+
import {SignatureType, isValidSignatureType} from './types';
4040

4141
// Supported command-line flags
4242
const FLAG = {
@@ -54,10 +54,6 @@ const ENV = {
5454
SOURCE: 'FUNCTION_SOURCE',
5555
};
5656

57-
enum NodeEnv {
58-
PRODUCTION = 'production',
59-
}
60-
6157
const argv = minimist(process.argv, {
6258
string: [FLAG.PORT, FLAG.TARGET, FLAG.SIGNATURE_TYPE],
6359
});
@@ -68,17 +64,14 @@ const CODE_LOCATION = resolve(
6864
const PORT = argv[FLAG.PORT] || process.env[ENV.PORT] || '8080';
6965
const TARGET = argv[FLAG.TARGET] || process.env[ENV.TARGET] || 'function';
7066

71-
const SIGNATURE_TYPE_STRING =
72-
argv[FLAG.SIGNATURE_TYPE] || process.env[ENV.SIGNATURE_TYPE] || 'http';
73-
const SIGNATURE_TYPE =
74-
SignatureType[
75-
SIGNATURE_TYPE_STRING.toUpperCase() as keyof typeof SignatureType
76-
];
77-
if (SIGNATURE_TYPE === undefined) {
67+
const SIGNATURE_TYPE = (
68+
argv[FLAG.SIGNATURE_TYPE] ||
69+
process.env[ENV.SIGNATURE_TYPE] ||
70+
'http'
71+
).toLowerCase();
72+
if (!isValidSignatureType(SIGNATURE_TYPE)) {
7873
console.error(
79-
`Function signature type must be one of: ${Object.values(
80-
SignatureType
81-
).join(', ')}.`
74+
`Function signature type must be one of: ${SignatureType.join(', ')}.`
8275
);
8376
// eslint-disable-next-line no-process-exit
8477
process.exit(1);
@@ -108,7 +101,7 @@ getUserFunction(CODE_LOCATION, TARGET).then(userFunction => {
108101

109102
SERVER.listen(PORT, () => {
110103
ERROR_HANDLER.register();
111-
if (process.env.NODE_ENV !== NodeEnv.PRODUCTION) {
104+
if (process.env.NODE_ENV !== 'production') {
112105
console.log('Serving function...');
113106
console.log(`Function: ${TARGET}`);
114107
console.log(`Signature type: ${SIGNATURE_TYPE}`);

src/router.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export function registerFunctionRoutes(
3939
userFunction: HandlerFunction,
4040
functionSignatureType: SignatureType
4141
) {
42-
if (functionSignatureType === SignatureType.HTTP) {
42+
if (functionSignatureType === 'http') {
4343
app.use('/favicon.ico|/robots.txt', (req, res) => {
4444
// Neither crawlers nor browsers attempting to pull the icon find the body
4545
// contents particularly useful, so we send nothing in the response body.
@@ -57,7 +57,7 @@ export function registerFunctionRoutes(
5757
const handler = makeHttpHandler(userFunction as HttpFunction);
5858
handler(req, res, next);
5959
});
60-
} else if (functionSignatureType === SignatureType.EVENT) {
60+
} else if (functionSignatureType === 'event') {
6161
app.post('/*', (req, res, next) => {
6262
const wrappedUserFunction = wrapEventFunction(
6363
userFunction as EventFunction | EventFunctionWithCallback

src/server.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -101,19 +101,19 @@ export function getServer(
101101
app.disable('x-powered-by');
102102

103103
if (
104-
functionSignatureType === SignatureType.EVENT ||
105-
functionSignatureType === SignatureType.CLOUDEVENT
104+
functionSignatureType === 'event' ||
105+
functionSignatureType === 'cloudevent'
106106
) {
107107
// If a Pub/Sub subscription is configured to invoke a user's function directly, the request body
108108
// needs to be marshalled into the structure that wrapEventFunction expects. This unblocks local
109109
// development with the Pub/Sub emulator
110110
app.use(legacyPubSubEventMiddleware);
111111
}
112112

113-
if (functionSignatureType === SignatureType.EVENT) {
113+
if (functionSignatureType === 'event') {
114114
app.use(cloudeventToBackgroundEventMiddleware);
115115
}
116-
if (functionSignatureType === SignatureType.CLOUDEVENT) {
116+
if (functionSignatureType === 'cloudevent') {
117117
app.use(backgroundEventToCloudEventMiddleware);
118118
}
119119

src/types.ts

+19-5
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,22 @@
1616
// executing the client function.
1717
export const FUNCTION_STATUS_HEADER_FIELD = 'X-Google-Status';
1818

19-
export enum SignatureType {
20-
HTTP = 'http',
21-
EVENT = 'event',
22-
CLOUDEVENT = 'cloudevent',
23-
}
19+
/**
20+
* List of function signature types that are supported by the framework.
21+
*/
22+
export const SignatureType = ['http', 'event', 'cloudevent'] as const;
23+
24+
/**
25+
* Union type of all valid function SignatureType values.
26+
*/
27+
export type SignatureType = typeof SignatureType[number];
28+
29+
/**
30+
* Type guard to test if a provided value is valid SignatureType
31+
* @param x the value to test
32+
* @returns true if the provided value is a valid SignatureType
33+
*/
34+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
35+
export const isValidSignatureType = (x: any): x is SignatureType => {
36+
return SignatureType.includes(x);
37+
};

test/integration/cloudevent.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import * as assert from 'assert';
1616
import * as functions from '../../src/functions';
1717
import * as sinon from 'sinon';
1818
import {getServer} from '../../src/server';
19-
import {SignatureType} from '../../src/types';
2019
import * as supertest from 'supertest';
2120

2221
const TEST_CLOUD_EVENT = {
@@ -224,7 +223,7 @@ describe('CloudEvent Function', () => {
224223
let receivedCloudEvent: functions.CloudEventsContext | null = null;
225224
const server = getServer((cloudevent: functions.CloudEventsContext) => {
226225
receivedCloudEvent = cloudevent as functions.CloudEventsContext;
227-
}, SignatureType.CLOUDEVENT);
226+
}, 'cloudevent');
228227
await supertest(server)
229228
.post('/')
230229
.set(test.headers)

test/integration/http.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import * as assert from 'assert';
1616
import * as express from 'express';
1717
import {getServer} from '../../src/server';
18-
import {SignatureType} from '../../src/types';
1918
import * as supertest from 'supertest';
2019

2120
describe('HTTP Function', () => {
@@ -73,7 +72,7 @@ describe('HTTP Function', () => {
7372
query: req.query.param,
7473
});
7574
},
76-
SignatureType.HTTP
75+
'http'
7776
);
7877
const st = supertest(server);
7978
await (test.httpVerb === 'GET'

test/integration/legacy_event.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import * as assert from 'assert';
1616
import * as functions from '../../src/functions';
1717
import {getServer} from '../../src/server';
18-
import {SignatureType} from '../../src/types';
1918
import * as supertest from 'supertest';
2019

2120
const TEST_CLOUD_EVENT = {
@@ -175,7 +174,7 @@ describe('Event Function', () => {
175174
const server = getServer((data: {}, context: functions.Context) => {
176175
receivedData = data;
177176
receivedContext = context as functions.CloudFunctionsContext;
178-
}, SignatureType.EVENT);
177+
}, 'event');
179178
const requestHeaders = {
180179
'Content-Type': 'application/json',
181180
...test.headers,

0 commit comments

Comments
 (0)