diff --git a/.eslintrc.js b/.eslintrc.js index cfce1b4..8918623 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,34 +1,22 @@ module.exports = { - "env": { - "browser": true, - "es6": true, - "node": true - }, - "ignorePatterns": [ - "node_modules", - "generated", - "**/__tests__/*", - "**/__mocks__/*", - "Dangerfile.*", - "*.d.ts" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "project": "tsconfig.json", - "sourceType": "module" - }, - "extends": [ - "@pagopa/eslint-config/strong", - ], - "rules": { - "import/order": "off", - "@typescript-eslint/array-type": "off", - "@typescript-eslint/explicit-member-accessibility": "off", - "functional/prefer-readonly-type": "off", - "@typescript-eslint/explicit-function-return-type": "off", - "no-invalid-this": "off", - "prefer-arrow/prefer-arrow-functions": "off", - "@typescript-eslint/prefer-optional-chain": "off", - "no-underscore-dangle": "off" - } -} + env: { + browser: true, + es6: true, + node: true + }, + ignorePatterns: [ + "node_modules", + "generated", + "**/__tests__/*", + "**/__mocks__/*", + "Dangerfile.*", + "*.d.ts" + ], + parser: "@typescript-eslint/parser", + parserOptions: { + project: "tsconfig.json", + sourceType: "module" + }, + extends: ["@pagopa/eslint-config/strong"], + rules: {} +}; diff --git a/src/ExpressAdapter.ts b/src/ExpressAdapter.ts index 0966913..94c5d54 100644 --- a/src/ExpressAdapter.ts +++ b/src/ExpressAdapter.ts @@ -1,5 +1,5 @@ -import { Context } from "@azure/functions"; import EventEmitter = require("events"); +import { Context } from "@azure/functions"; import { Application } from "express"; import IncomingMessage from "./IncomingMessage"; @@ -21,7 +21,7 @@ const isValidContext = (context: any): context is Context => context.bindings.req.originalUrl && typeof context.bindings.req.originalUrl === "string"; -export type RequestListener = (...args: readonly unknown[]) => void; +export type RequestListener = (...args: ReadonlyArray) => void; /** * Express adapter allowing to handle Azure Function requests by wrapping in request events. @@ -33,7 +33,7 @@ export default class ExpressAdapter extends EventEmitter { /** * @param {Object=} application Request listener (typically an express/connect instance) */ - public constructor(application: Application) { + constructor(application: Application) { super(); if (application !== undefined) { @@ -53,25 +53,27 @@ export default class ExpressAdapter extends EventEmitter { /** * Create function ready to be exposed to Azure Function for request handling. */ - public createAzureFunctionHandler = () => (context: Context) => { - if (!isValidContext(context)) { - return; - } + public createAzureFunctionHandler() { + return (context: Context): void => { + if (!isValidContext(context)) { + return; + } - const updateResponse = ( - updater: ( - prev: NonNullable - ) => NonNullable - ) => { - // eslint-disable-next-line functional/immutable-data - context.res = updater(context.res || {}); - }; + const updateResponse = ( + updater: ( + prev: NonNullable + ) => NonNullable + ): void => { + // eslint-disable-next-line functional/immutable-data + context.res = updater(context.res || {}); + }; - // 2. Wrapping - const req = new IncomingMessage(context); - const res = new OutgoingMessage(updateResponse, context.done); + // 2. Wrapping + const req = new IncomingMessage(context); + const res = new OutgoingMessage(updateResponse, context.done); - // 3. Synchronously calls each of the listeners registered for the event - this.emit("request", req, res); - }; + // 3. Synchronously calls each of the listeners registered for the event + this.emit("request", req, res); + }; + } } diff --git a/src/IncomingMessage.ts b/src/IncomingMessage.ts index 4118f63..965812d 100644 --- a/src/IncomingMessage.ts +++ b/src/IncomingMessage.ts @@ -1,13 +1,12 @@ -import { Context } from "@azure/functions"; import { Socket } from "net"; import { Readable } from "stream"; import { TLSSocket } from "tls"; +import { Context } from "@azure/functions"; -const NOOP = () => true; +const NOOP = (): true => true; -function removePortFromAddress(address: string): string { - return address ? address.replace(/:[0-9]*$/, "") : address; -} +const removePortFromAddress = (address: string): string => + address ? address.replace(/:[0-9]*$/, "") : address; /** * Create a fake connection object @@ -15,20 +14,19 @@ function removePortFromAddress(address: string): string { * @param {Object} context Raw Azure context object for a single HTTP request * @returns {object} Connection object */ -function createConnectionObject( +const createConnectionObject = ( context: Context -): Pick & Pick { +): Pick & Pick => { const { req } = context.bindings; const xForwardedFor = req.headers ? req.headers["x-forwarded-for"] : undefined; return { - encrypted: - req.originalUrl && req.originalUrl.toLowerCase().startsWith("https"), + encrypted: req.originalUrl?.toLowerCase().startsWith("https"), remoteAddress: removePortFromAddress(xForwardedFor) }; -} +}; /** * Copy useful context properties from the native context provided by the Azure @@ -41,15 +39,13 @@ function createConnectionObject( * @param {Object} context Raw Azure context object for a single HTTP request * @returns {Object} Filtered context */ -function sanitizeContext(context: Context): Context { - return { - ...context, - // We don't want the developer to mess up express flow - // See https://github.com/yvele/azure-function-express/pull/12#issuecomment-336733540 - done: NOOP, - log: context.log.bind(context) - }; -} +const sanitizeContext = (context: Context): Context => ({ + ...context, + // We don't want the developer to mess up express flow + // See https://github.com/yvele/azure-function-express/pull/12#issuecomment-336733540 + done: NOOP, + log: context.log.bind(context) +}); /** * Request object wrapper diff --git a/src/OutgoingMessage.ts b/src/OutgoingMessage.ts index 307b8ec..d0c3077 100644 --- a/src/OutgoingMessage.ts +++ b/src/OutgoingMessage.ts @@ -1,11 +1,11 @@ // eslint-disable camelcase -import { Context } from "@azure/functions"; import { OutgoingHttpHeaders, OutgoingMessage as NativeOutgoingMessage, ServerResponse } from "http"; +import { Context } from "@azure/functions"; import { statusCodes } from "./statusCodes"; @@ -17,12 +17,13 @@ import { statusCodes } from "./statusCodes"; * @private */ export default class OutgoingMessage extends NativeOutgoingMessage { - public _hasBody = true; - public _headerNames = {}; - public _headers = null; - public _removedHeader = {}; + public readonly _hasBody = true; + public readonly _headerNames = {}; + public readonly _headers = null; + public readonly _removedHeader = {}; + // eslint-disable-next-line functional/prefer-readonly-type public statusMessage!: string; - public statusCode!: number; + public readonly statusCode!: number; /** * Original implementation: https://github.com/nodejs/node/blob/v6.x/lib/_http_outgoing.js#L48 @@ -40,19 +41,21 @@ export default class OutgoingMessage extends NativeOutgoingMessage { // Those methods cannot be prototyped because express explicitelly overrides __proto__ // See https://github.com/expressjs/express/blob/master/lib/middleware/init.js#L29 - public end: NativeOutgoingMessage["end"] = ( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - chunkOrCb?: any + public readonly end: NativeOutgoingMessage["end"] = ( + chunkOrCb: Parameters[0] ) => { // 1. Write head + // eslint-disable-next-line no-invalid-this this.writeHead(this.statusCode); // Make jshttp/on-headers able to trigger // 2. Return raw body to Azure Function runtime + // eslint-disable-next-line no-invalid-this this.updateResponse(res => ({ ...res, body: chunkOrCb, isRaw: true })); + // eslint-disable-next-line no-invalid-this this.done(); }; @@ -60,7 +63,7 @@ export default class OutgoingMessage extends NativeOutgoingMessage { * https://nodejs.org/api/http.html#http_response_writehead_statuscode_statusmessage_headers * Original implementation: https://github.com/nodejs/node/blob/v6.x/lib/_http_server.js#L160 */ - public writeHead: ServerResponse["writeHead"] = ( + public readonly writeHead: ServerResponse["writeHead"] = ( statusCode: number, reasonOrHeaders?: string | OutgoingHttpHeaders, headersOrUndefined?: OutgoingHttpHeaders @@ -72,7 +75,7 @@ export default class OutgoingMessage extends NativeOutgoingMessage { } // 2. Status message - // eslint-disable-next-line functional/immutable-data + // eslint-disable-next-line functional/immutable-data, no-invalid-this this.statusMessage = typeof reasonOrHeaders === "string" ? reasonOrHeaders @@ -85,24 +88,28 @@ export default class OutgoingMessage extends NativeOutgoingMessage { ? reasonOrHeaders : headersOrUndefined; + // eslint-disable-next-line no-underscore-dangle, no-invalid-this if (this._headers && headers !== undefined) { // Slow-case: when progressive API and header fields are passed. Object.keys(headers).forEach(k => { const v = headers[k]; if (v) { + // eslint-disable-next-line no-invalid-this this.setHeader(k, v); } }); } // 4. Sets everything + // eslint-disable-next-line no-invalid-this this.updateResponse(res => ({ ...res, // In order to uniformize node 6 behaviour with node 8 and 10, // we want to never have undefined headers, but instead empty object headers: + // eslint-disable-next-line no-underscore-dangle, no-invalid-this this._headers && headers === undefined - ? // eslint-disable-next-line @typescript-eslint/no-explicit-any + ? // eslint-disable-next-line no-underscore-dangle, @typescript-eslint/no-explicit-any, no-invalid-this (this as any)._renderHeaders() : headers !== undefined ? headers diff --git a/src/createAzureFunctionsHandler.ts b/src/createAzureFunctionsHandler.ts index 31bbeb7..14d6de9 100644 --- a/src/createAzureFunctionsHandler.ts +++ b/src/createAzureFunctionsHandler.ts @@ -9,9 +9,11 @@ import ExpressAdapter from "./ExpressAdapter"; * @param {Object} requestListener Request listener (typically an express/connect instance) * @returns {function(context: Object)} Azure Function handle */ -export default function createAzureFunctionHandler( +const createAzureFunctionHandler = ( application: Application -): (context: Context) => void { +): ((context: Context) => void) => { const adapter = new ExpressAdapter(application); return adapter.createAzureFunctionHandler(); -} +}; + +export default createAzureFunctionHandler; diff --git a/src/statusCodes.ts b/src/statusCodes.ts index b49a779..06ef486 100644 --- a/src/statusCodes.ts +++ b/src/statusCodes.ts @@ -1,4 +1,4 @@ -export const statusCodes: { [key: number]: string | undefined } = { +export const statusCodes: { readonly [key: number]: string | undefined } = { 100: "Continue", 101: "Switching Protocols", 102: "Processing", // RFC 2518, obsoleted by RFC 4918