From 266301e36b3349d1e5dc9bd3f95cd45ea27b264c Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Mon, 22 Jul 2024 13:12:42 +0200 Subject: [PATCH 1/3] chore(maintenance): add biome.js --- biome.json | 26 ++++++++ package-lock.json | 156 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 3 files changed, 183 insertions(+) create mode 100644 biome.json diff --git a/biome.json b/biome.json new file mode 100644 index 0000000000..19d23a030d --- /dev/null +++ b/biome.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json", + "organizeImports": { + "enabled": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 2, + "lineEnding": "lf" + }, + "javascript": { + "formatter": { + "semicolons": "always", + "bracketSpacing": true, + "quoteStyle": "single", + "trailingComma": "es5" + } + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index ea890dc6e3..80d5733127 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "examples/app" ], "devDependencies": { + "@biomejs/biome": "^1.8.3", "@types/aws-lambda": "^8.10.141", "@types/jest": "^29.5.12", "@types/node": "^20.14.10", @@ -1848,6 +1849,161 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@biomejs/biome": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.8.3.tgz", + "integrity": "sha512-/uUV3MV+vyAczO+vKrPdOW0Iaet7UnJMU4bNMinggGJTAnBPjCoLEYcyYtYHNnUNYlv4xZMH6hVIQCAozq8d5w==", + "dev": true, + "hasInstallScript": true, + "bin": { + "biome": "bin/biome" + }, + "engines": { + "node": ">=14.21.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/biome" + }, + "optionalDependencies": { + "@biomejs/cli-darwin-arm64": "1.8.3", + "@biomejs/cli-darwin-x64": "1.8.3", + "@biomejs/cli-linux-arm64": "1.8.3", + "@biomejs/cli-linux-arm64-musl": "1.8.3", + "@biomejs/cli-linux-x64": "1.8.3", + "@biomejs/cli-linux-x64-musl": "1.8.3", + "@biomejs/cli-win32-arm64": "1.8.3", + "@biomejs/cli-win32-x64": "1.8.3" + } + }, + "node_modules/@biomejs/cli-darwin-arm64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.8.3.tgz", + "integrity": "sha512-9DYOjclFpKrH/m1Oz75SSExR8VKvNSSsLnVIqdnKexj6NwmiMlKk94Wa1kZEdv6MCOHGHgyyoV57Cw8WzL5n3A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-darwin-x64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.8.3.tgz", + "integrity": "sha512-UeW44L/AtbmOF7KXLCoM+9PSgPo0IDcyEUfIoOXYeANaNXXf9mLUwV1GeF2OWjyic5zj6CnAJ9uzk2LT3v/wAw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.8.3.tgz", + "integrity": "sha512-fed2ji8s+I/m8upWpTJGanqiJ0rnlHOK3DdxsyVLZQ8ClY6qLuPc9uehCREBifRJLl/iJyQpHIRufLDeotsPtw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64-musl": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.8.3.tgz", + "integrity": "sha512-9yjUfOFN7wrYsXt/T/gEWfvVxKlnh3yBpnScw98IF+oOeCYb5/b/+K7YNqKROV2i1DlMjg9g/EcN9wvj+NkMuQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.8.3.tgz", + "integrity": "sha512-I8G2QmuE1teISyT8ie1HXsjFRz9L1m5n83U1O6m30Kw+kPMPSKjag6QGUn+sXT8V+XWIZxFFBoTDEDZW2KPDDw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64-musl": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.8.3.tgz", + "integrity": "sha512-UHrGJX7PrKMKzPGoEsooKC9jXJMa28TUSMjcIlbDnIO4EAavCoVmNQaIuUSH0Ls2mpGMwUIf+aZJv657zfWWjA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-arm64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.8.3.tgz", + "integrity": "sha512-J+Hu9WvrBevfy06eU1Na0lpc7uR9tibm9maHynLIoAjLZpQU3IW+OKHUtyL8p6/3pT2Ju5t5emReeIS2SAxhkQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-x64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.8.3.tgz", + "integrity": "sha512-/PJ59vA1pnQeKahemaQf4Nyj7IKUvGQSc3Ze1uIGi+Wvr1xF7rGobSrAAG01T/gUDG21vkDsZYM03NAmPiVkqg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", diff --git a/package.json b/package.json index 66fcd8ef7d..4efd18859e 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ }, "homepage": "https://github.com/aws-powertools/powertools-lambda-typescript#readme", "devDependencies": { + "@biomejs/biome": "^1.8.3", "@types/aws-lambda": "^8.10.141", "@types/jest": "^29.5.12", "@types/node": "^20.14.10", From 0ed3e1c55fb81bf175a5129cfab99c4109861dfb Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Mon, 22 Jul 2024 15:52:41 +0200 Subject: [PATCH 2/3] chore(maintenance): add biome to project --- biome.json | 15 +++++++++++++-- examples/app/cdk/example-stack.ts | 4 ++-- .../app/functions/commons/helpers/get-item.ts | 4 ++-- .../app/functions/commons/helpers/put-item.ts | 6 +++--- .../app/functions/commons/helpers/scan-items.ts | 4 ++-- examples/app/package.json | 10 +++------- package.json | 4 ++-- 7 files changed, 27 insertions(+), 20 deletions(-) diff --git a/biome.json b/biome.json index 19d23a030d..46c5a0c5d5 100644 --- a/biome.json +++ b/biome.json @@ -13,14 +13,25 @@ "enabled": true, "indentStyle": "space", "indentWidth": 2, - "lineEnding": "lf" + "lineEnding": "lf", + "lineWidth": 80 }, "javascript": { "formatter": { "semicolons": "always", "bracketSpacing": true, "quoteStyle": "single", - "trailingComma": "es5" + "trailingCommas": "es5" } + }, + "files": { + "ignore": [ + "node_modules", + "coverage", + "lib", + "cdk.out", + "site", + ".aws-sam" + ] } } \ No newline at end of file diff --git a/examples/app/cdk/example-stack.ts b/examples/app/cdk/example-stack.ts index b5e7f66284..067ef6752f 100644 --- a/examples/app/cdk/example-stack.ts +++ b/examples/app/cdk/example-stack.ts @@ -1,4 +1,4 @@ -import { RemovalPolicy, Stack, StackProps } from 'aws-cdk-lib'; +import { RemovalPolicy, Stack, type StackProps } from 'aws-cdk-lib'; import { LambdaIntegration, RestApi } from 'aws-cdk-lib/aws-apigateway'; import { AttributeType, @@ -18,7 +18,7 @@ import { DynamoEventSource } from 'aws-cdk-lib/aws-lambda-event-sources'; import { OutputFormat } from 'aws-cdk-lib/aws-lambda-nodejs'; import { Queue } from 'aws-cdk-lib/aws-sqs'; import { StringParameter } from 'aws-cdk-lib/aws-ssm'; -import { Construct } from 'constructs'; +import type { Construct } from 'constructs'; import { FunctionWithLogGroup } from './function-with-logstream-construct.js'; export class PowertoolsExampleStack extends Stack { diff --git a/examples/app/functions/commons/helpers/get-item.ts b/examples/app/functions/commons/helpers/get-item.ts index 3ce1030ea7..165b01f0d0 100644 --- a/examples/app/functions/commons/helpers/get-item.ts +++ b/examples/app/functions/commons/helpers/get-item.ts @@ -1,7 +1,7 @@ +import { GetCommand, type GetCommandOutput } from '@aws-sdk/lib-dynamodb'; import { docClient } from '#clients/dynamodb'; import { itemsTableName } from '#constants'; import type { DebugLogger } from '#types'; -import { GetCommand, type GetCommandOutput } from '@aws-sdk/lib-dynamodb'; /** * Fetch an item from the DynamoDB table. @@ -22,7 +22,7 @@ const getItemDynamoDB = async ( }) ); - logger.debug(`ddb response`, { + logger.debug('ddb response', { response, }); diff --git a/examples/app/functions/commons/helpers/put-item.ts b/examples/app/functions/commons/helpers/put-item.ts index a978e0382c..853756899d 100644 --- a/examples/app/functions/commons/helpers/put-item.ts +++ b/examples/app/functions/commons/helpers/put-item.ts @@ -1,8 +1,8 @@ +import { randomUUID } from 'node:crypto'; +import { PutCommand } from '@aws-sdk/lib-dynamodb'; import { docClient } from '#clients/dynamodb'; import { itemsTableName } from '#constants'; import type { DebugLogger } from '#types'; -import { PutCommand } from '@aws-sdk/lib-dynamodb'; -import { randomUUID } from 'node:crypto'; /** * Put an item in the DynamoDB table. @@ -28,7 +28,7 @@ const putItemInDynamoDB = async ( }) ); - logger.debug(`ddb response`, { + logger.debug('ddb response', { response, }); diff --git a/examples/app/functions/commons/helpers/scan-items.ts b/examples/app/functions/commons/helpers/scan-items.ts index 858b752c1d..d528085f28 100644 --- a/examples/app/functions/commons/helpers/scan-items.ts +++ b/examples/app/functions/commons/helpers/scan-items.ts @@ -1,7 +1,7 @@ +import { ScanCommand, type ScanCommandOutput } from '@aws-sdk/lib-dynamodb'; import { docClient } from '#clients/dynamodb'; import { itemsTableName } from '#constants'; import type { DebugLogger } from '#types'; -import { ScanCommand, type ScanCommandOutput } from '@aws-sdk/lib-dynamodb'; /** * Scan the DynamoDB table and return all items. @@ -19,7 +19,7 @@ const scanItemsDynamoDB = async ( }) ); - logger.debug(`ddb response`, { + logger.debug('ddb response', { response, }); diff --git a/examples/app/package.json b/examples/app/package.json index 30b84d438e..8f6c790d63 100644 --- a/examples/app/package.json +++ b/examples/app/package.json @@ -11,16 +11,12 @@ "scripts": { "build": "echo 'Not applicable, run `npx cdk synth` instead to build the stack'", "test": "npm run test:unit", - "lint": "eslint --ext .ts,.js --no-error-on-unmatched-pattern .", - "lint-fix": "eslint --fix --ext .ts,.js --fix --no-error-on-unmatched-pattern .", + "lint": "biome lint .", + "lint:fix": "biome check --write .", "test:unit": "export POWERTOOLS_DEV=true && jest --silent", "test:e2e": "echo 'To be implemented ...'", "cdk": "cdk" }, - "lint-staged": { - "*.ts": "npm run lint-fix", - "*.js": "npm run lint-fix" - }, "type": "module", "imports": { "#types": "./functions/commons/types.js", @@ -64,4 +60,4 @@ "ts-node": "^10.9.2", "typescript": "^5.4.5" } -} +} \ No newline at end of file diff --git a/package.json b/package.json index 4efd18859e..c1f422af13 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "typescript": "^5.4.5" }, "lint-staged": { - "*.{js,ts}": "eslint --fix", + "*.{js,ts}": "biome check --write", "*.md": "markdownlint-cli2 --fix" }, "engines": { @@ -89,4 +89,4 @@ "tar": "6.2.1" } } -} +} \ No newline at end of file From bcda56aaec87610883cf6c231b9c76469c46b7c4 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Mon, 22 Jul 2024 16:31:37 +0200 Subject: [PATCH 3/3] chore(maintenance): migrate jmespath utility to biome --- packages/jmespath/package.json | 18 +-- packages/jmespath/src/Functions.ts | 61 ++++---- packages/jmespath/src/Lexer.ts | 26 ++-- packages/jmespath/src/ParsedResult.ts | 2 +- packages/jmespath/src/Parser.ts | 131 ++++++++---------- packages/jmespath/src/TreeInterpreter.ts | 29 ++-- packages/jmespath/src/constants.ts | 4 +- packages/jmespath/src/envelopes.ts | 12 +- packages/jmespath/src/types.ts | 4 +- packages/jmespath/src/utils.ts | 25 ++-- .../tests/unit/compliance/functions.test.ts | 2 +- packages/jmespath/tests/unit/index.test.ts | 18 +-- packages/jmespath/tsconfig.esm.json | 6 +- packages/jmespath/tsconfig.json | 6 +- packages/jmespath/typedoc.json | 8 +- 15 files changed, 161 insertions(+), 191 deletions(-) diff --git a/packages/jmespath/package.json b/packages/jmespath/package.json index a4a9651f4e..0cc8c8912e 100644 --- a/packages/jmespath/package.json +++ b/packages/jmespath/package.json @@ -18,8 +18,8 @@ "build:cjs": "tsc --build tsconfig.json && echo '{ \"type\": \"commonjs\" }' > lib/cjs/package.json", "build:esm": "tsc --build tsconfig.esm.json && echo '{ \"type\": \"module\" }' > lib/esm/package.json", "build": "npm run build:esm & npm run build:cjs", - "lint": "eslint --ext .ts,.js --no-error-on-unmatched-pattern .", - "lint-fix": "eslint --fix --ext .ts,.js --no-error-on-unmatched-pattern .", + "lint": "biome lint .", + "lint:fix": "biome check --write .", "prepack": "node ../../.github/scripts/release_patch_package_json.js ." }, "homepage": "https://github.com/aws-powertools/powertools-lambda-typescript", @@ -51,25 +51,17 @@ }, "typesVersions": { "*": { - "envelopes": [ - "lib/cjs/envelopes.d.ts", - "lib/esm/envelopes.d.ts" - ], + "envelopes": ["lib/cjs/envelopes.d.ts", "lib/esm/envelopes.d.ts"], "functions": [ "lib/cjs/PowertoolsFunctions.d.ts", "lib/esm/PowertoolsFunctions.d.ts" ], - "types": [ - "lib/cjs/types.d.ts", - "lib/esm/types.d.ts" - ] + "types": ["lib/cjs/types.d.ts", "lib/esm/types.d.ts"] } }, "types": "./lib/cjs/index.d.ts", "main": "./lib/cjs/index.js", - "files": [ - "lib" - ], + "files": ["lib"], "dependencies": { "@aws-lambda-powertools/commons": "^2.5.0" }, diff --git a/packages/jmespath/src/Functions.ts b/packages/jmespath/src/Functions.ts index 972c649849..9b012dff08 100644 --- a/packages/jmespath/src/Functions.ts +++ b/packages/jmespath/src/Functions.ts @@ -159,9 +159,8 @@ class Functions { ): number { if (isRecord(arg)) { return Object.keys(arg).length; - } else { - return arg.length; } + return arg.length; } /** @@ -194,12 +193,12 @@ class Functions { if (arg.length === 0) { return null; // The signature decorator already enforces that all elements are of the same type - } else if (isNumber(arg[0])) { + } + if (isNumber(arg[0])) { return Math.max(...(arg as number[])); - } else { - // local compare function to handle string comparison - return arg.reduce((a, b) => (a > b ? a : b)); } + // local compare function to handle string comparison + return arg.reduce((a, b) => (a > b ? a : b)); } /** @@ -236,14 +235,13 @@ class Functions { if (max.visited === current.visited) { return max; - } else { - // We can safely cast visited to number | string here because we've already - // checked the type at runtime above and we know that it's either a number or a string - return (max.visited as number | string) > - (current.visited as number | string) - ? max - : current; } + // We can safely cast visited to number | string here because we've already + // checked the type at runtime above and we know that it's either a number or a string + return (max.visited as number | string) > + (current.visited as number | string) + ? max + : current; }, visitedArgs[0]); return max.arg; @@ -261,6 +259,7 @@ class Functions { variadic: true, }) public funcMerge(...args: Array): JSONObject { + // biome-ignore lint/performance/noAccumulatingSpread: This is a shallow merge so the tradeoff is acceptable return args.reduce((a, b) => ({ ...a, ...b }), {}); } @@ -276,11 +275,11 @@ class Functions { if (arg.length === 0) { return null; // The signature decorator already enforces that all elements are of the same type - } else if (isNumber(arg[0])) { + } + if (isNumber(arg[0])) { return Math.min(...arg); - } else { - return arg.reduce((a, b) => (a < b ? a : b)); } + return arg.reduce((a, b) => (a < b ? a : b)); } /** @@ -317,14 +316,13 @@ class Functions { if (min.visited === current.visited) { return min; - } else { - // We can safely cast visited to number | string here because we've already - // checked the type at runtime above and we know that it's either a number or a string - return (min.visited as string | number) < - (current.visited as string | number) - ? min - : current; } + // We can safely cast visited to number | string here because we've already + // checked the type at runtime above and we know that it's either a number or a string + return (min.visited as string | number) < + (current.visited as string | number) + ? min + : current; }, visitedArgs[0]); return min.arg; @@ -415,13 +413,12 @@ class Functions { .sort((a, b) => { if (a.visited === b.visited) { return a.index - b.index; // Make the sort stable - } else { - // We can safely cast visited to number | string here because we've already - // checked the type at runtime above and we know that it's either a number or a string - return (a.visited as string | number) > (b.visited as string | number) - ? 1 - : -1; } + // We can safely cast visited to number | string here because we've already + // checked the type at runtime above and we know that it's either a number or a string + return (a.visited as string | number) > (b.visited as string | number) + ? 1 + : -1; }) .map(({ value }) => value); // Extract the original values } @@ -484,13 +481,13 @@ class Functions { public funcToNumber(arg: JSONValue): number | null { if (typeof arg === 'number') { return arg; - } else if (typeof arg === 'string') { + } + if (typeof arg === 'string') { const num = Number(arg); return Number.isNaN(num) ? null : num; - } else { - return null; } + return null; } /** diff --git a/packages/jmespath/src/Lexer.ts b/packages/jmespath/src/Lexer.ts index e4cdf1aaa2..313cc271df 100644 --- a/packages/jmespath/src/Lexer.ts +++ b/packages/jmespath/src/Lexer.ts @@ -32,9 +32,7 @@ class Lexer { while (this.#current !== '' && this.#current !== undefined) { if (SIMPLE_TOKENS.has(this.#current)) { yield { - // We know that SIMPLE_TOKENS has this.#current as a key because - // we checked for that above. - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + // biome-ignore lint/style/noNonNullAssertion: We know that SIMPLE_TOKENS has this.#current as a key because we checked for that above. type: SIMPLE_TOKENS.get(this.#current)!, value: this.#current, start: this.#position, @@ -57,7 +55,7 @@ class Lexer { const buff = this.#consumeNumber(); yield { type: 'number', - value: parseInt(buff), + value: Number.parseInt(buff), start: start, end: start + buff.length, }; @@ -119,9 +117,8 @@ class Lexer { start: this.#position - 1, end: this.#position, }; - } else { - throw new LexerError(this.#position - 1, '='); } + throw new LexerError(this.#position - 1, '='); } /** @@ -158,14 +155,13 @@ class Lexer { if (buff.length > 1) { return { type: 'number', - value: parseInt(buff), + value: Number.parseInt(buff), start: start, end: start + buff.length, }; - } else { - // If the negative sign is not followed by a number, it is an error. - throw new LexerError(start, 'Unknown token after "-"'); } + // If the negative sign is not followed by a number, it is an error. + throw new LexerError(start, 'Unknown token after "-"'); } /** @@ -194,17 +190,17 @@ class Lexer { #consumeSquareBracket(): Token { const start = this.#position; const nextChar = this.#next(); - if (nextChar == ']') { + if (nextChar === ']') { this.#next(); return { type: 'flatten', value: '[]', start: start, end: start + 2 }; - } else if (nextChar == '?') { + } + if (nextChar === '?') { this.#next(); return { type: 'filter', value: '[?', start: start, end: start + 2 }; - } else { - return { type: 'lbracket', value: '[', start: start, end: start + 1 }; } + return { type: 'lbracket', value: '[', start: start, end: start + 1 }; } /** @@ -301,7 +297,7 @@ class Lexer { */ #consumeQuotedIdentifier(): Token { const start = this.#position; - const lexeme = '"' + this.#consumeUntil('"') + '"'; + const lexeme = `"${this.#consumeUntil('"')}"`; const tokenLen = this.#position - start; return { diff --git a/packages/jmespath/src/ParsedResult.ts b/packages/jmespath/src/ParsedResult.ts index 4d6733dbcc..0ed9a2d4ca 100644 --- a/packages/jmespath/src/ParsedResult.ts +++ b/packages/jmespath/src/ParsedResult.ts @@ -5,7 +5,7 @@ import { UnknownFunctionError, VariadicArityError, } from './errors.js'; -import type { Node, JMESPathParsingOptions, JSONObject } from './types.js'; +import type { JMESPathParsingOptions, JSONObject, Node } from './types.js'; class ParsedResult { public expression: string; diff --git a/packages/jmespath/src/Parser.ts b/packages/jmespath/src/Parser.ts index 0047de8952..208aa45314 100644 --- a/packages/jmespath/src/Parser.ts +++ b/packages/jmespath/src/Parser.ts @@ -15,8 +15,8 @@ import { indexExpression, keyValPair, literal, - multiSelectObject, multiSelectList, + multiSelectObject, notExpression, orExpression, pipe, @@ -175,13 +175,13 @@ class Parser { case 'flatten': return this.#processFlattenTokenNud(); case 'not': - return notExpression(this.#expression(BINDING_POWER['not'])); + return notExpression(this.#expression(BINDING_POWER.not)); case 'lbracket': return this.#processLBracketTokenNud(); case 'current': return currentNode(); case 'expref': - return expref(this.#expression(BINDING_POWER['expref'])); + return expref(this.#expression(BINDING_POWER.expref)); default: return this.#processDefaultToken(token); } @@ -218,11 +218,11 @@ class Parser { */ #processStarToken(): Node { const left = identity(); - let right; + let right: Node; if (this.#currentToken() === 'rbracket') { right = identity(); } else { - right = this.#parseProjectionRhs(BINDING_POWER['star']); + right = this.#parseProjectionRhs(BINDING_POWER.star); } return valueProjection(left, right); @@ -253,7 +253,7 @@ class Parser { */ #processFlattenTokenNud(): Node { const left = flatten(identity()); - const right = this.#parseProjectionRhs(BINDING_POWER['flatten']); + const right = this.#parseProjectionRhs(BINDING_POWER.flatten); return projection(left, right); } @@ -271,18 +271,15 @@ class Parser { const right = this.#parseIndexExpression(); return this.#projectIfSlice(identity(), right); - } else if ( - this.#currentToken() === 'star' && - this.#lookahead(1) === 'rbracket' - ) { + } + if (this.#currentToken() === 'star' && this.#lookahead(1) === 'rbracket') { this.#advance(); this.#advance(); - const right = this.#parseProjectionRhs(BINDING_POWER['star']); + const right = this.#parseProjectionRhs(BINDING_POWER.star); return projection(identity(), right); - } else { - return this.#parseMultiSelectList(); } + return this.#parseMultiSelectList(); } /** @@ -357,21 +354,19 @@ class Parser { */ #processDotToken(leftNode: Node): Node { if (this.#currentToken() !== 'star') { - const right = this.#parseDotRhs(BINDING_POWER['dot']); + const right = this.#parseDotRhs(BINDING_POWER.dot); if (leftNode.type === 'subexpression') { leftNode.children.push(right); return leftNode; - } else { - return subexpression([leftNode, right]); } - } else { - // We are creating a value projection - this.#advance(); - const right = this.#parseProjectionRhs(BINDING_POWER['dot']); - - return valueProjection(leftNode, right); + return subexpression([leftNode, right]); } + // We are creating a value projection + this.#advance(); + const right = this.#parseProjectionRhs(BINDING_POWER.dot); + + return valueProjection(leftNode, right); } /** @@ -385,7 +380,7 @@ class Parser { * @param leftNode The left hand side of the expression. */ #processPipeToken(leftNode: Node): Node { - const right = this.#expression(BINDING_POWER['pipe']); + const right = this.#expression(BINDING_POWER.pipe); return pipe(leftNode, right); } @@ -401,7 +396,7 @@ class Parser { * @param leftNode The left hand side of the expression. */ #processOrToken(leftNode: Node): Node { - const right = this.#expression(BINDING_POWER['or']); + const right = this.#expression(BINDING_POWER.or); return orExpression(leftNode, right); } @@ -417,7 +412,7 @@ class Parser { * @param leftNode The left hand side of the expression. */ #processAndToken(leftNode: Node): Node { - const right = this.#expression(BINDING_POWER['and']); + const right = this.#expression(BINDING_POWER.and); return andExpression(leftNode, right); } @@ -445,7 +440,7 @@ class Parser { if (this.#currentToken() === 'flatten') { right = identity(); } else { - right = this.#parseProjectionRhs(BINDING_POWER['flatten']); + right = this.#parseProjectionRhs(BINDING_POWER.flatten); } return filterProjection(leftNode, right, condition); @@ -453,7 +448,7 @@ class Parser { #processFlattenToken(leftNode: Node): Node { const left = flatten(leftNode); - const right = this.#parseProjectionRhs(BINDING_POWER['flatten']); + const right = this.#parseProjectionRhs(BINDING_POWER.flatten); return projection(left, right); } @@ -469,17 +464,15 @@ class Parser { leftNode.children.push(right); return leftNode; - } else { - return this.#projectIfSlice(leftNode, right); } - } else { - // We have a projection - this.#match('star'); - this.#match('rbracket'); - const right = this.#parseProjectionRhs(BINDING_POWER['star']); - - return projection(leftNode, right); + return this.#projectIfSlice(leftNode, right); } + // We have a projection + this.#match('star'); + this.#match('rbracket'); + const right = this.#parseProjectionRhs(BINDING_POWER.star); + + return projection(leftNode, right); } /** @@ -523,14 +516,13 @@ class Parser { // | (currentToken) if (this.#lookahead(0) === 'colon' || this.#lookahead(1) === 'colon') { return this.#parseSliceExpression(); - } else { - // Parse the syntax [number] - const node = index(this.#lookaheadToken(0).value); - this.#advance(); - this.#match('rbracket'); - - return node; } + // Parse the syntax [number] + const node = index(this.#lookaheadToken(0).value); + this.#advance(); + this.#match('rbracket'); + + return node; } /** @@ -591,11 +583,10 @@ class Parser { if (right.type === 'slice') { return projection( idxExpression, - this.#parseProjectionRhs(BINDING_POWER['star']) + this.#parseProjectionRhs(BINDING_POWER.star) ); - } else { - return idxExpression; } + return idxExpression; } /** @@ -630,9 +621,8 @@ class Parser { expressions.push(expression); if (this.#currentToken() === 'rbracket') { break; - } else { - this.#match('comma'); } + this.#match('comma'); } this.#match('rbracket'); @@ -654,14 +644,14 @@ class Parser { // Before getting the token value, verify it's // an identifier. this.#matchMultipleTokens(['quoted_identifier', 'unquoted_identifier']); // token types - const keyName = keyToken['value']; + const keyName = keyToken.value; this.#match('colon'); const value = this.#expression(0); const node = keyValPair(keyName, value); pairs.push(node); - if (this.#currentToken() == 'comma') { + if (this.#currentToken() === 'comma') { this.#match('comma'); - } else if (this.#currentToken() == 'rbrace') { + } else if (this.#currentToken() === 'rbrace') { this.#match('rbrace'); break; } @@ -677,15 +667,15 @@ class Parser { */ #parseProjectionRhs(bindingPower: number): Node { // Parse the right hand side of the projection. - let right; + let right: Node; if (BINDING_POWER[this.#currentToken()] < this.#projectionStop) { // BP of 10 are all the tokens that stop a projection. right = identity(); - } else if (this.#currentToken() == 'lbracket') { + } else if (this.#currentToken() === 'lbracket') { right = this.#expression(bindingPower); - } else if (this.#currentToken() == 'filter') { + } else if (this.#currentToken() === 'filter') { right = this.#expression(bindingPower); - } else if (this.#currentToken() == 'dot') { + } else if (this.#currentToken() === 'dot') { this.#match('dot'); right = this.#parseDotRhs(bindingPower); } else { @@ -715,17 +705,18 @@ class Parser { ['quoted_identifier', 'unquoted_identifier', 'star'].includes(lookahead) ) { return this.#expression(bindingPower); - } else if (lookahead == 'lbracket') { + } + if (lookahead === 'lbracket') { this.#match('lbracket'); return this.#parseMultiSelectList(); - } else if (lookahead == 'lbrace') { + } + if (lookahead === 'lbrace') { this.#match('lbrace'); return this.#parseMultiSelectHash(); - } else { - this.#throwParseError(); } + this.#throwParseError(); } /** @@ -745,13 +736,12 @@ class Parser { tokenValue: token.value, tokenType: token.type, }); - } else { - throw new ParseError({ - lexPosition: token.start, - tokenValue: token.value, - tokenType: token.type, - }); } + throw new ParseError({ + lexPosition: token.start, + tokenValue: token.value, + tokenType: token.type, + }); } } @@ -770,13 +760,12 @@ class Parser { tokenValue: token.value, tokenType: token.type, }); - } else { - throw new ParseError({ - lexPosition: token.start, - tokenValue: token.value, - tokenType: token.type, - }); } + throw new ParseError({ + lexPosition: token.start, + tokenValue: token.value, + tokenType: token.type, + }); } this.#advance(); } diff --git a/packages/jmespath/src/TreeInterpreter.ts b/packages/jmespath/src/TreeInterpreter.ts index ee2292bd99..559e7055d9 100644 --- a/packages/jmespath/src/TreeInterpreter.ts +++ b/packages/jmespath/src/TreeInterpreter.ts @@ -3,6 +3,8 @@ import { isRecord, isStrictEqual, } from '@aws-lambda-powertools/commons/typeutils'; +import { Expression } from './Expression.js'; +import { Functions } from './Functions.js'; import { ArityError, JMESPathError, @@ -10,9 +12,7 @@ import { UnknownFunctionError, VariadicArityError, } from './errors.js'; -import { Expression } from './Expression.js'; -import { Functions } from './Functions.js'; -import type { Node, JMESPathParsingOptions, JSONObject } from './types.js'; +import type { JMESPathParsingOptions, JSONObject, Node } from './types.js'; import { isTruthy, sliceArray } from './utils.js'; /** @@ -79,11 +79,8 @@ class TreeInterpreter { const visitMethod = visitMethods[nodeType]; if (visitMethod) { return visitMethod.call(this, node, value); - } else { - throw new JMESPathError( - `Not Implemented: Invalid node type: ${node.type}` - ); } + throw new JMESPathError(`Not Implemented: Invalid node type: ${node.type}`); } /** @@ -122,9 +119,8 @@ class TreeInterpreter { node.value in value ) { return value[node.value] as JSONObject; - } else { - return null; } + return null; } /** @@ -144,20 +140,23 @@ class TreeInterpreter { // Common cases: comparator is == or != if (comparator === 'eq') { return isStrictEqual(left, right); - } else if (comparator === 'ne') { + } + if (comparator === 'ne') { return !isStrictEqual(left, right); - } else if (typeof left === 'number' && typeof right === 'number') { + } + if (typeof left === 'number' && typeof right === 'number') { // Ordering operators only work on numbers. Evaluating them on other // types will return null. if (comparator === 'lt') { return left < right; - } else if (comparator === 'lte') { + } + if (comparator === 'lte') { return left <= right; - } else if (comparator === 'gt') { + } + if (comparator === 'gt') { return left > right; - } else { - return left >= right; } + return left >= right; } } else { throw new JMESPathError(`Invalid comparator: ${comparator}`); diff --git a/packages/jmespath/src/constants.ts b/packages/jmespath/src/constants.ts index 642e3eb3f9..de078f8754 100644 --- a/packages/jmespath/src/constants.ts +++ b/packages/jmespath/src/constants.ts @@ -57,11 +57,11 @@ const DIGITS = '0123456789'; /** * The set of ASCII letters and digits allowed in JMESPath identifiers. */ -const START_IDENTIFIER = new Set(ASCII_LETTERS + '_'); +const START_IDENTIFIER = new Set(`${ASCII_LETTERS}_`); /** * The set of ASCII letters and digits allowed in JMESPath identifiers. */ -const VALID_IDENTIFIER = new Set(ASCII_LETTERS + DIGITS + '_'); +const VALID_IDENTIFIER = new Set(`${ASCII_LETTERS}${DIGITS}_`); /** * The set of ASCII digits allowed in JMESPath identifiers. */ diff --git a/packages/jmespath/src/envelopes.ts b/packages/jmespath/src/envelopes.ts index 2fa2607c85..32107f0a5d 100644 --- a/packages/jmespath/src/envelopes.ts +++ b/packages/jmespath/src/envelopes.ts @@ -1,5 +1,5 @@ -import { search } from './search.js'; import { PowertoolsFunctions } from './PowertoolsFunctions.js'; +import { search } from './search.js'; import type { JMESPathParsingOptions, JSONObject } from './types.js'; /** @@ -59,11 +59,11 @@ const extractDataFromEnvelope = ( envelope: string, options?: JMESPathParsingOptions ): T => { - if (!options) { - options = { customFunctions: new PowertoolsFunctions() }; - } - - return search(envelope, data, options) as T; + return search( + envelope, + data, + options || { customFunctions: new PowertoolsFunctions() } + ) as T; }; const API_GATEWAY_REST = 'powertools_json(body)'; diff --git a/packages/jmespath/src/types.ts b/packages/jmespath/src/types.ts index 19d102e6b3..92e3e7ffff 100644 --- a/packages/jmespath/src/types.ts +++ b/packages/jmespath/src/types.ts @@ -1,9 +1,9 @@ import type { - JSONValue, JSONArray, + JSONValue, } from '@aws-lambda-powertools/commons/types'; import type { Functions } from './Functions.js'; -import { BINDING_POWER } from './constants.js'; +import type { BINDING_POWER } from './constants.js'; /** * A token in the JMESPath AST. diff --git a/packages/jmespath/src/utils.ts b/packages/jmespath/src/utils.ts index fe115f3098..113d3f30f7 100644 --- a/packages/jmespath/src/utils.ts +++ b/packages/jmespath/src/utils.ts @@ -1,9 +1,9 @@ import { getType, isIntegerNumber, + isNumber, isRecord, isTruthy as isTruthyJS, - isNumber, } from '@aws-lambda-powertools/commons/typeutils'; import { Expression } from './Expression.js'; import { ArityError, JMESPathTypeError, VariadicArityError } from './errors.js'; @@ -21,9 +21,8 @@ import { ArityError, JMESPathTypeError, VariadicArityError } from './errors.js'; const isTruthy = (value: unknown): boolean => { if (isNumber(value)) { return true; - } else { - return isTruthyJS(value); } + return isTruthyJS(value); }; /** @@ -40,16 +39,17 @@ const capSliceRange = ( value: number, isStepNegative: boolean ): number => { - if (value < 0) { - value += arrayLength; - if (value < 0) { - value = isStepNegative ? -1 : 0; + let capValue = value; + if (capValue < 0) { + capValue += arrayLength; + if (capValue < 0) { + capValue = isStepNegative ? -1 : 0; } - } else if (value >= arrayLength) { - value = isStepNegative ? arrayLength - 1 : arrayLength; + } else if (capValue >= arrayLength) { + capValue = isStepNegative ? arrayLength - 1 : arrayLength; } - return value; + return capValue; }; /** @@ -227,8 +227,10 @@ const checkIfArgumentTypeIsValid = ( checkExpressionType(arg, argumentSpec, hasMoreTypesToCheck); return true; - } else if (['string', 'number', 'boolean'].includes(type)) { + } + if (['string', 'number', 'boolean'].includes(type)) { typeCheckType(arg, type, argumentSpec, hasMoreTypesToCheck); + // biome-ignore lint/suspicious/useValidTypeof: we know that `type` is one of 'string', 'number', or 'boolean' because we checked for that above if (typeof arg === type) return true; } else if (type === 'object') { checkObjectType(arg, argumentSpec, hasMoreTypesToCheck); @@ -253,6 +255,7 @@ const typeCheckType = ( argumentSpec: string[], hasMoreTypesToCheck: boolean ): void => { + // biome-ignore lint/suspicious/useValidTypeof: we know that `type` is one of 'string', 'number', or 'boolean' because we checked before calling this function if (typeof arg !== type && !hasMoreTypesToCheck) { throw new JMESPathTypeError({ currentValue: arg, diff --git a/packages/jmespath/tests/unit/compliance/functions.test.ts b/packages/jmespath/tests/unit/compliance/functions.test.ts index df4f311e61..2eeb3ada6c 100644 --- a/packages/jmespath/tests/unit/compliance/functions.test.ts +++ b/packages/jmespath/tests/unit/compliance/functions.test.ts @@ -307,7 +307,7 @@ describe('Functions tests', () => { }, { // prettier-ignore - expression: 'contains(strings, \'a\')', + expression: "contains(strings, 'a')", expected: true, }, { diff --git a/packages/jmespath/tests/unit/index.test.ts b/packages/jmespath/tests/unit/index.test.ts index a8cb33201c..9522e526c9 100644 --- a/packages/jmespath/tests/unit/index.test.ts +++ b/packages/jmespath/tests/unit/index.test.ts @@ -3,21 +3,21 @@ * * @group unit/jmespath/coverage */ +import { brotliDecompressSync } from 'node:zlib'; import { fromBase64 } from '@aws-lambda-powertools/commons/utils/base64'; +import { Functions } from '../../src/Functions.js'; +import { Parser } from '../../src/Parser.js'; +import { PowertoolsFunctions } from '../../src/PowertoolsFunctions.js'; +import { TreeInterpreter } from '../../src/TreeInterpreter.js'; +import { SQS, extractDataFromEnvelope } from '../../src/envelopes.js'; import { - search, - EmptyExpressionError, ArityError, - LexerError, + EmptyExpressionError, JMESPathError, + LexerError, VariadicArityError, + search, } from '../../src/index.js'; -import { Functions } from '../../src/Functions.js'; -import { Parser } from '../../src/Parser.js'; -import { TreeInterpreter } from '../../src/TreeInterpreter.js'; -import { brotliDecompressSync } from 'node:zlib'; -import { PowertoolsFunctions } from '../../src/PowertoolsFunctions.js'; -import { extractDataFromEnvelope, SQS } from '../../src/envelopes.js'; describe('Coverage tests', () => { // These expressions tests are not part of the compliance suite, but are added to ensure coverage diff --git a/packages/jmespath/tsconfig.esm.json b/packages/jmespath/tsconfig.esm.json index 123291b0cf..82486b64fa 100644 --- a/packages/jmespath/tsconfig.esm.json +++ b/packages/jmespath/tsconfig.esm.json @@ -6,7 +6,5 @@ "rootDir": "./src", "tsBuildInfoFile": ".tsbuildinfo/esm.json" }, - "include": [ - "./src/**/*" - ] -} \ No newline at end of file + "include": ["./src/**/*"] +} diff --git a/packages/jmespath/tsconfig.json b/packages/jmespath/tsconfig.json index d56a564ef6..4923c4f6f4 100644 --- a/packages/jmespath/tsconfig.json +++ b/packages/jmespath/tsconfig.json @@ -5,7 +5,5 @@ "rootDir": "./src", "tsBuildInfoFile": ".tsbuildinfo/cjs.json" }, - "include": [ - "./src/**/*" - ] -} \ No newline at end of file + "include": ["./src/**/*"] +} diff --git a/packages/jmespath/typedoc.json b/packages/jmespath/typedoc.json index da81672090..480beba0f8 100644 --- a/packages/jmespath/typedoc.json +++ b/packages/jmespath/typedoc.json @@ -1,13 +1,11 @@ { - "extends": [ - "../../typedoc.base.json" - ], + "extends": ["../../typedoc.base.json"], "entryPoints": [ "./src/index.ts", "./src/types.ts", "./src/envelopes.ts", "./src/Functions.ts", - "./src/PowertoolsFunctions.ts", + "./src/PowertoolsFunctions.ts" ], "readme": "README.md" -} \ No newline at end of file +}