From 04a9594b4f4e7cd378d5caebd32f1fd24f7ccc79 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Fri, 12 May 2023 00:30:43 +0200 Subject: [PATCH] style(docs): apply standardized formatting --- examples/sam/.eslintrc.js | 77 ++++++++++++---------- examples/sam/jest.config.js | 4 +- examples/sam/package.json | 6 +- examples/sam/src/common/constants.ts | 4 +- examples/sam/src/common/dynamodb-client.ts | 4 +- examples/sam/src/common/powertools.ts | 12 ++-- examples/sam/src/get-all-items.ts | 35 ++++++---- examples/sam/src/get-by-id.ts | 47 ++++++++----- examples/sam/src/put-item.ts | 41 ++++++++---- examples/sam/tests/sam.test.ts | 18 ++--- 10 files changed, 141 insertions(+), 107 deletions(-) diff --git a/examples/sam/.eslintrc.js b/examples/sam/.eslintrc.js index b83ce24ffc..8cfae0905f 100644 --- a/examples/sam/.eslintrc.js +++ b/examples/sam/.eslintrc.js @@ -5,63 +5,68 @@ module.exports = { jest: true, node: true, }, - extends: [ 'plugin:@typescript-eslint/eslint-recommended', 'plugin:@typescript-eslint/recommended' ], + ignorePatterns: ['cdk.out', 'lib'], + extends: [ + 'plugin:@typescript-eslint/recommended', + 'plugin:prettier/recommended', + ], parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint'], + plugins: ['@typescript-eslint', 'prettier'], settings: { 'import/resolver': { node: {}, typescript: { - project: './tsconfig.es.json', + project: './tsconfig.json', alwaysTryTypes: true, }, }, }, rules: { - '@typescript-eslint/ban-ts-ignore': ['off'], - '@typescript-eslint/camelcase': ['off'], - '@typescript-eslint/explicit-function-return-type': [ 'error', { allowExpressions: true } ], - '@typescript-eslint/explicit-member-accessibility': 'error', - '@typescript-eslint/indent': [ 'error', 2, { SwitchCase: 1 } ], - '@typescript-eslint/interface-name-prefix': ['off'], - '@typescript-eslint/member-delimiter-style': [ 'error', { multiline: { delimiter: 'none' } } ], + '@typescript-eslint/explicit-function-return-type': [ + 'error', + { allowExpressions: true }, + ], // Enforce return type definitions for functions + '@typescript-eslint/explicit-member-accessibility': 'error', // Enforce explicit accessibility modifiers on class properties and methods (public, private, protected) '@typescript-eslint/member-ordering': [ + // Standardize the order of class members 'error', { default: { memberTypes: [ 'signature', - 'public-field', // = ["public-static-field", "public-instance-field"] - 'protected-field', // = ["protected-static-field", "protected-instance-field"] - 'private-field', // = ["private-static-field", "private-instance-field"] + 'public-field', + 'protected-field', + 'private-field', 'constructor', - 'public-method', // = ["public-static-method", "public-instance-method"] - 'protected-method', // = ["protected-static-method", "protected-instance-method"] - 'private-method', // = ["private-static-method", "private-instance-method"] + 'public-method', + 'protected-method', + 'private-method', ], order: 'alphabetically', }, }, ], - '@typescript-eslint/no-explicit-any': 'error', - '@typescript-eslint/no-inferrable-types': ['off'], - '@typescript-eslint/no-unused-vars': [ 'error', { argsIgnorePattern: '^_' } ], - '@typescript-eslint/no-use-before-define': ['off'], - '@typescript-eslint/semi': [ 'error', 'always' ], - 'array-bracket-spacing': [ 'error', 'always', { singleValue: false } ], - 'arrow-body-style': [ 'error', 'as-needed' ], - 'computed-property-spacing': [ 'error', 'never' ], - 'func-style': [ 'warn', 'expression' ], - indent: [ 'error', 2, { SwitchCase: 1 } ], - 'keyword-spacing': 'error', - 'newline-before-return': 2, - 'no-console': 0, - 'no-multi-spaces': [ 'error', { ignoreEOLComments: false } ], - 'no-multiple-empty-lines': [ 'error', { max: 1, maxBOF: 0 } ], - 'no-throw-literal': 'error', - 'object-curly-spacing': [ 'error', 'always' ], - 'prefer-arrow-callback': 'error', - quotes: [ 'error', 'single', { allowTemplateLiterals: true } ], - semi: [ 'error', 'always' ] + '@typescript-eslint/no-explicit-any': 'error', // Disallow usage of the any type + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], // Disallow unused variables, except for variables starting with an underscore + '@typescript-eslint/no-use-before-define': ['off'], // Check if this rule is needed + 'no-unused-vars': 'off', // Disable eslint core rule, since it's replaced by @typescript-eslint/no-unused-vars + // Rules from eslint core https://eslint.org/docs/latest/rules/ + 'array-bracket-spacing': ['error', 'never'], // Disallow spaces inside of array brackets + 'computed-property-spacing': ['error', 'never'], // Disallow spaces inside of computed properties + 'func-style': ['warn', 'expression'], // Enforce function expressions instead of function declarations + 'keyword-spacing': 'error', // Enforce spaces after keywords and before parenthesis, e.g. if (condition) instead of if(condition) + 'padding-line-between-statements': [ + // Require an empty line before return statements + 'error', + { blankLine: 'always', prev: '*', next: 'return' }, + ], + 'no-console': 0, // Allow console.log statements + 'no-multi-spaces': ['error', { ignoreEOLComments: false }], // Disallow multiple spaces except for comments + 'no-multiple-empty-lines': ['error', { max: 1, maxBOF: 0, maxEOF: 0 }], // Enforce no empty line at the beginning & end of files and max 1 empty line between consecutive statements + 'no-throw-literal': 'error', // Disallow throwing literals as exceptions, e.g. throw 'error' instead of throw new Error('error') + 'object-curly-spacing': ['error', 'always'], // Enforce spaces inside of curly braces in objects + 'prefer-arrow-callback': 'error', // Enforce arrow functions instead of anonymous functions for callbacks + quotes: ['error', 'single', { allowTemplateLiterals: true }], // Enforce single quotes except for template strings + semi: ['error', 'always'], // Require semicolons instead of ASI (automatic semicolon insertion) at the end of statements }, }; diff --git a/examples/sam/jest.config.js b/examples/sam/jest.config.js index e3795fc8b4..6cfd2c7be4 100644 --- a/examples/sam/jest.config.js +++ b/examples/sam/jest.config.js @@ -3,6 +3,6 @@ module.exports = { roots: ['/tests'], testMatch: ['**/*.test.ts'], transform: { - '^.+\\.tsx?$': 'ts-jest' - } + '^.+\\.tsx?$': 'ts-jest', + }, }; diff --git a/examples/sam/package.json b/examples/sam/package.json index 37706b155d..a8eb458c90 100644 --- a/examples/sam/package.json +++ b/examples/sam/package.json @@ -11,8 +11,8 @@ "scripts": { "build": "sam build --beta-features", "test": "npm run test:unit", - "lint": "eslint --ext .ts --no-error-on-unmatched-pattern src tests", - "lint-fix": "eslint --fix --ext .ts --fix --no-error-on-unmatched-pattern src tests", + "lint": "eslint --ext .ts,.js --no-error-on-unmatched-pattern .", + "lint-fix": "eslint --fix --ext .ts,.js --fix --no-error-on-unmatched-pattern .", "package": "echo 'Not applicable'", "package-bundle": "echo 'Not applicable'", "test:unit": "export POWERTOOLS_DEV=true && npm run build && jest --silent", @@ -46,4 +46,4 @@ "@middy/core": "^3.6.2", "phin": "^3.7.0" } -} +} \ No newline at end of file diff --git a/examples/sam/src/common/constants.ts b/examples/sam/src/common/constants.ts index 3a731e43d8..3496c50046 100644 --- a/examples/sam/src/common/constants.ts +++ b/examples/sam/src/common/constants.ts @@ -1,6 +1,4 @@ // Get the DynamoDB table name from environment variables const tableName = process.env.SAMPLE_TABLE; -export { - tableName -}; \ No newline at end of file +export { tableName }; diff --git a/examples/sam/src/common/dynamodb-client.ts b/examples/sam/src/common/dynamodb-client.ts index fe4e7cc8d5..40a7c994b8 100644 --- a/examples/sam/src/common/dynamodb-client.ts +++ b/examples/sam/src/common/dynamodb-client.ts @@ -24,6 +24,4 @@ const translateConfig = { marshallOptions, unmarshallOptions }; // Create the DynamoDB Document client. const docClient = DynamoDBDocumentClient.from(ddbClient, translateConfig); -export { - docClient -}; \ No newline at end of file +export { docClient }; diff --git a/examples/sam/src/common/powertools.ts b/examples/sam/src/common/powertools.ts index 0215708207..0b5a768326 100644 --- a/examples/sam/src/common/powertools.ts +++ b/examples/sam/src/common/powertools.ts @@ -6,7 +6,7 @@ const awsLambdaPowertoolsVersion = '1.5.0'; const defaultValues = { region: process.env.AWS_REGION || 'N/A', - executionEnv: process.env.AWS_EXECUTION_ENV || 'N/A' + executionEnv: process.env.AWS_EXECUTION_ENV || 'N/A', }; const logger = new Logger({ @@ -15,18 +15,14 @@ const logger = new Logger({ logger: { name: '@aws-lambda-powertools/logger', version: awsLambdaPowertoolsVersion, - } + }, }, }); const metrics = new Metrics({ - defaultDimensions: defaultValues + defaultDimensions: defaultValues, }); const tracer = new Tracer(); -export { - logger, - metrics, - tracer -}; \ No newline at end of file +export { logger, metrics, tracer }; diff --git a/examples/sam/src/get-all-items.ts b/examples/sam/src/get-all-items.ts index 7e4df2b081..28c7bdbebd 100644 --- a/examples/sam/src/get-all-items.ts +++ b/examples/sam/src/get-all-items.ts @@ -1,4 +1,8 @@ -import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda'; +import { + APIGatewayProxyEvent, + APIGatewayProxyResult, + Context, +} from 'aws-lambda'; import middy from '@middy/core'; import { tableName } from './common/constants'; import { logger, tracer, metrics } from './common/powertools'; @@ -12,7 +16,7 @@ import { default as request } from 'phin'; /* * * This example uses the Middy middleware instrumentation. - * It is the best choice if your existing code base relies on the Middy middleware engine. + * It is the best choice if your existing code base relies on the Middy middleware engine. * Powertools offers compatible Middy middleware to make this integration seamless. * Find more Information in the docs: https://awslabs.github.io/aws-lambda-powertools-typescript/ * @@ -23,9 +27,14 @@ import { default as request } from 'phin'; * @returns {Object} object - API Gateway Lambda Proxy Output Format * */ -const getAllItemsHandler = async (event: APIGatewayProxyEvent, context: Context): Promise => { +const getAllItemsHandler = async ( + event: APIGatewayProxyEvent, + context: Context +): Promise => { if (event.httpMethod !== 'GET') { - throw new Error(`getAllItems only accepts GET method, you tried: ${event.httpMethod}`); + throw new Error( + `getAllItems only accepts GET method, you tried: ${event.httpMethod}` + ); } // Tracer: Add awsRequestId as annotation @@ -60,14 +69,16 @@ const getAllItemsHandler = async (event: APIGatewayProxyEvent, context: Context) throw new Error('SAMPLE_TABLE environment variable is not set'); } - const data = await docClient.send(new ScanCommand({ - TableName: tableName - })); + const data = await docClient.send( + new ScanCommand({ + TableName: tableName, + }) + ); const { Items: items } = data; // Logger: All log statements are written to CloudWatch logger.debug(`retrieved items: ${items?.length || 0}`); - + logger.info(`Response ${event.path}`, { statusCode: 200, body: items, @@ -75,15 +86,15 @@ const getAllItemsHandler = async (event: APIGatewayProxyEvent, context: Context) return { statusCode: 200, - body: JSON.stringify(items) + body: JSON.stringify(items), }; } catch (err) { tracer.addErrorAsMetadata(err as Error); logger.error('Error reading from table. ' + err); - + return { statusCode: 500, - body: JSON.stringify({ 'error': 'Error reading from table.' }) + body: JSON.stringify({ error: 'Error reading from table.' }), }; } }; @@ -95,4 +106,4 @@ export const handler = middy(getAllItemsHandler) // Use the middleware by passing the Logger instance as a parameter .use(injectLambdaContext(logger, { logEvent: true })) // Use the middleware by passing the Tracer instance as a parameter - .use(captureLambdaHandler(tracer, { captureResponse: false })); // by default the tracer would add the response as metadata on the segment, but there is a chance to hit the 64kb segment size limit. Therefore set captureResponse: false \ No newline at end of file + .use(captureLambdaHandler(tracer, { captureResponse: false })); // by default the tracer would add the response as metadata on the segment, but there is a chance to hit the 64kb segment size limit. Therefore set captureResponse: false diff --git a/examples/sam/src/get-by-id.ts b/examples/sam/src/get-by-id.ts index 84dfb8ba0b..0a24f49632 100644 --- a/examples/sam/src/get-by-id.ts +++ b/examples/sam/src/get-by-id.ts @@ -1,4 +1,8 @@ -import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda'; +import { + APIGatewayProxyEvent, + APIGatewayProxyResult, + Context, +} from 'aws-lambda'; import { tableName } from './common/constants'; import { logger, tracer, metrics } from './common/powertools'; import { LambdaInterface } from '@aws-lambda-powertools/commons'; @@ -22,7 +26,6 @@ import { default as request } from 'phin'; */ class Lambda implements LambdaInterface { - @tracer.captureMethod() public async getUuid(): Promise { // Request a sample random uuid from a webservice @@ -37,11 +40,18 @@ class Lambda implements LambdaInterface { @tracer.captureLambdaHandler({ captureResponse: false }) // by default the tracer would add the response as metadata on the segment, but there is a chance to hit the 64kb segment size limit. Therefore set captureResponse: false @logger.injectLambdaContext({ logEvent: true }) - @metrics.logMetrics({ throwOnEmptyMetrics: false, captureColdStartMetric: true }) - public async handler(event: APIGatewayProxyEvent, context: Context): Promise { - + @metrics.logMetrics({ + throwOnEmptyMetrics: false, + captureColdStartMetric: true, + }) + public async handler( + event: APIGatewayProxyEvent, + context: Context + ): Promise { if (event.httpMethod !== 'GET') { - throw new Error(`getById only accepts GET method, you tried: ${event.httpMethod}`); + throw new Error( + `getById only accepts GET method, you tried: ${event.httpMethod}` + ); } // Tracer: Add awsRequestId as annotation @@ -76,34 +86,35 @@ class Lambda implements LambdaInterface { if (!event.pathParameters.id) { throw new Error('PathParameter id is missing'); } - const data = await docClient.send(new GetCommand({ - TableName: tableName, - Key: { - id: event.pathParameters.id - } - })); + const data = await docClient.send( + new GetCommand({ + TableName: tableName, + Key: { + id: event.pathParameters.id, + }, + }) + ); const item = data.Item; - + logger.info(`Response ${event.path}`, { statusCode: 200, body: item, }); - + return { statusCode: 200, - body: JSON.stringify(item) + body: JSON.stringify(item), }; } catch (err) { tracer.addErrorAsMetadata(err as Error); logger.error('Error reading from table. ' + err); - + return { statusCode: 500, - body: JSON.stringify({ 'error': 'Error reading from table.' }) + body: JSON.stringify({ error: 'Error reading from table.' }), }; } } - } const handlerClass = new Lambda(); diff --git a/examples/sam/src/put-item.ts b/examples/sam/src/put-item.ts index 675bf689b1..27ca35f06c 100644 --- a/examples/sam/src/put-item.ts +++ b/examples/sam/src/put-item.ts @@ -1,4 +1,8 @@ -import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda'; +import { + APIGatewayProxyEvent, + APIGatewayProxyResult, + Context, +} from 'aws-lambda'; import { tableName } from './common/constants'; import { logger, tracer, metrics } from './common/powertools'; import { docClient } from './common/dynamodb-client'; @@ -9,7 +13,7 @@ import type { Subsegment } from 'aws-xray-sdk-core'; /** * * This example uses the manual instrumentation. - * + * * Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format * @param {APIGatewayProxyEvent} event - API Gateway Lambda Proxy Input Format * @@ -17,9 +21,14 @@ import type { Subsegment } from 'aws-xray-sdk-core'; * @returns {Promise} object - API Gateway Lambda Proxy Output Format * */ -export const handler = async (event: APIGatewayProxyEvent, context: Context): Promise => { +export const handler = async ( + event: APIGatewayProxyEvent, + context: Context +): Promise => { if (event.httpMethod !== 'POST') { - throw new Error(`putItem only accepts POST method, you tried: ${event.httpMethod}`); + throw new Error( + `putItem only accepts POST method, you tried: ${event.httpMethod}` + ); } // Logger: Log the incoming event @@ -31,7 +40,9 @@ export const handler = async (event: APIGatewayProxyEvent, context: Context): Pr // Tracer: Create subsegment for the function & set it as active let handlerSegment: Subsegment | undefined; if (segment) { - const handlerSegment = segment.addNewSubsegment(`## ${process.env._HANDLER}`); + const handlerSegment = segment.addNewSubsegment( + `## ${process.env._HANDLER}` + ); tracer.setSegment(handlerSegment); } @@ -80,13 +91,15 @@ export const handler = async (event: APIGatewayProxyEvent, context: Context): Pr const body = JSON.parse(event.body); const { id, name } = body; - await docClient.send(new PutCommand({ - TableName: tableName, - Item: { - id, - name - } - })); + await docClient.send( + new PutCommand({ + TableName: tableName, + Item: { + id, + name, + }, + }) + ); logger.info(`Response ${event.path}`, { statusCode: 200, @@ -95,7 +108,7 @@ export const handler = async (event: APIGatewayProxyEvent, context: Context): Pr return { statusCode: 200, - body: JSON.stringify(body) + body: JSON.stringify(body), }; } catch (err) { tracer.addErrorAsMetadata(err as Error); @@ -103,7 +116,7 @@ export const handler = async (event: APIGatewayProxyEvent, context: Context): Pr return { statusCode: 500, - body: JSON.stringify({ 'error': 'Error writing data to table.' }) + body: JSON.stringify({ error: 'Error writing data to table.' }), }; } finally { if (segment && handlerSegment) { diff --git a/examples/sam/tests/sam.test.ts b/examples/sam/tests/sam.test.ts index e324d50ad9..988753f694 100644 --- a/examples/sam/tests/sam.test.ts +++ b/examples/sam/tests/sam.test.ts @@ -4,19 +4,21 @@ import { handler as getByIdHandler } from '../src/get-by-id'; import { handler as putItemHandler } from '../src/put-item'; test('getAllItemsHandler function imports & throws correctly', () => { - expect(getAllItemsHandler({} as APIGatewayProxyEvent, {} as Context)).rejects.toThrow( + expect( + getAllItemsHandler({} as APIGatewayProxyEvent, {} as Context) + ).rejects.toThrow( 'getAllItems only accepts GET method, you tried: undefined' ); }); test('getByIdHandler function imports & throws correctly', () => { - expect(getByIdHandler({} as APIGatewayProxyEvent, {} as Context)).rejects.toThrow( - 'getById only accepts GET method, you tried: undefined' - ); + expect( + getByIdHandler({} as APIGatewayProxyEvent, {} as Context) + ).rejects.toThrow('getById only accepts GET method, you tried: undefined'); }); test('putItemHandler function imports & throws correctly', () => { - expect(putItemHandler({} as APIGatewayProxyEvent, {} as Context)).rejects.toThrow( - 'putItem only accepts POST method, you tried: undefined' - ); -}); \ No newline at end of file + expect( + putItemHandler({} as APIGatewayProxyEvent, {} as Context) + ).rejects.toThrow('putItem only accepts POST method, you tried: undefined'); +});