From 3ec68ce081f7a3925b07da61108be7f69c81b78d Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 26 Apr 2025 10:22:42 +0200 Subject: [PATCH] add biome to config, fix lint, use biome config file from root --- config/.eslintignore | 4 - config/.eslintrc.js | 214 ------------------------------------- config/package.json | 3 + config/src/commonSchema.ts | 96 ++++++++++------- config/src/index.ts | 6 +- config/yarn.lock | 54 ++++++++++ 6 files changed, 116 insertions(+), 261 deletions(-) delete mode 100644 config/.eslintignore delete mode 100644 config/.eslintrc.js diff --git a/config/.eslintignore b/config/.eslintignore deleted file mode 100644 index 1ae86fe5e..000000000 --- a/config/.eslintignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -**/*.min.js -build -coverage \ No newline at end of file diff --git a/config/.eslintrc.js b/config/.eslintrc.js deleted file mode 100644 index 4be107982..000000000 --- a/config/.eslintrc.js +++ /dev/null @@ -1,214 +0,0 @@ -// eslint-disable-next-line import/no-commonjs, import/unambiguous -module.exports = { - root: true, - env: { - node: true, - }, - parser: '@typescript-eslint/parser', - plugins: ['prettier', '@typescript-eslint', 'type-graphql', 'import', 'n', 'promise'], - extends: [ - 'standard', - 'eslint:recommended', - 'plugin:prettier/recommended', - 'plugin:import/recommended', - 'plugin:import/typescript', - 'plugin:security/recommended', - 'plugin:@eslint-community/eslint-comments/recommended', - ], - settings: { - 'import/parsers': { - '@typescript-eslint/parser': ['.ts', '.tsx'], - }, - 'import/resolver': { - typescript: { - project: ['./tsconfig.json', '**/tsconfig.json'], - }, - node: true, - }, - // the parser cannot handle the split sodium import - 'import/ignore': ['sodium-native'], - }, - rules: { - 'no-console': 'error', - camelcase: ['error', { allow: ['crypto_*', 'randombytes_random'] }], - 'no-debugger': 'error', - 'prettier/prettier': [ - 'error', - { - htmlWhitespaceSensitivity: 'ignore', - }, - ], - // import - 'import/export': 'error', - // 'import/no-deprecated': 'error', - 'import/no-empty-named-blocks': 'error', - 'import/no-extraneous-dependencies': 'error', - 'import/no-mutable-exports': 'error', - 'import/no-unused-modules': 'error', - 'import/no-named-as-default': 'error', - 'import/no-named-as-default-member': 'error', - 'import/no-amd': 'error', - 'import/no-commonjs': 'error', - 'import/no-import-module-exports': 'error', - 'import/no-nodejs-modules': 'off', - 'import/unambiguous': 'error', - 'import/default': 'error', - 'import/named': 'error', - 'import/namespace': 'error', - 'import/no-absolute-path': 'error', - 'import/no-cycle': 'error', - 'import/no-dynamic-require': 'error', - 'import/no-internal-modules': 'off', - 'import/no-relative-packages': 'error', - 'import/no-relative-parent-imports': [ - 'error', - { ignore: ['@/*', 'random-bigint', 'sodium-native'] }, - ], - 'import/no-self-import': 'error', - 'import/no-unresolved': 'error', - 'import/no-useless-path-segments': 'error', - 'import/no-webpack-loader-syntax': 'error', - 'import/consistent-type-specifier-style': 'error', - 'import/exports-last': 'off', - 'import/extensions': 'error', - 'import/first': 'error', - 'import/group-exports': 'off', - 'import/newline-after-import': 'error', - 'import/no-anonymous-default-export': 'error', - 'import/no-default-export': 'error', - 'import/no-duplicates': 'error', - 'import/no-named-default': 'error', - 'import/no-namespace': 'error', - 'import/no-unassigned-import': 'error', - 'import/order': [ - 'error', - { - groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'], - 'newlines-between': 'always', - pathGroups: [ - { - pattern: '@?*/**', - group: 'external', - position: 'after', - }, - { - pattern: '@/**', - group: 'external', - position: 'after', - }, - ], - alphabetize: { - order: 'asc' /* sort in ascending order. Options: ['ignore', 'asc', 'desc'] */, - caseInsensitive: true /* ignore case. Options: [true, false] */, - }, - distinctGroup: true, - }, - ], - 'import/prefer-default-export': 'off', - // n - 'n/handle-callback-err': 'error', - 'n/no-callback-literal': 'error', - 'n/no-exports-assign': 'error', - 'n/no-extraneous-import': 'error', - 'n/no-extraneous-require': 'error', - 'n/no-hide-core-modules': 'error', - 'n/no-missing-import': 'off', // not compatible with typescript - 'n/no-missing-require': 'error', - 'n/no-new-require': 'error', - 'n/no-path-concat': 'error', - 'n/no-process-exit': 'error', - 'n/no-unpublished-bin': 'error', - 'n/no-unpublished-import': 'off', // TODO need to exclude seeds - 'n/no-unpublished-require': 'error', - 'n/no-unsupported-features': ['error', { ignores: ['modules'] }], - 'n/no-unsupported-features/es-builtins': 'error', - 'n/no-unsupported-features/es-syntax': 'error', - 'n/no-unsupported-features/node-builtins': 'error', - 'n/process-exit-as-throw': 'error', - 'n/shebang': 'error', - 'n/callback-return': 'error', - 'n/exports-style': 'error', - 'n/file-extension-in-import': 'off', - 'n/global-require': 'error', - 'n/no-mixed-requires': 'error', - 'n/no-process-env': 'error', - 'n/no-restricted-import': 'error', - 'n/no-restricted-require': 'error', - 'n/no-sync': 'error', - 'n/prefer-global/buffer': 'error', - 'n/prefer-global/console': 'error', - 'n/prefer-global/process': 'error', - 'n/prefer-global/text-decoder': 'error', - 'n/prefer-global/text-encoder': 'error', - 'n/prefer-global/url': 'error', - 'n/prefer-global/url-search-params': 'error', - 'n/prefer-promises/dns': 'error', - 'n/prefer-promises/fs': 'error', - // promise - 'promise/catch-or-return': 'error', - 'promise/no-return-wrap': 'error', - 'promise/param-names': 'error', - 'promise/always-return': 'error', - 'promise/no-native': 'off', - 'promise/no-nesting': 'warn', - 'promise/no-promise-in-callback': 'warn', - 'promise/no-callback-in-promise': 'warn', - 'promise/avoid-new': 'warn', - 'promise/no-new-statics': 'error', - 'promise/no-return-in-finally': 'warn', - 'promise/valid-params': 'warn', - 'promise/prefer-await-to-callbacks': 'error', - 'promise/no-multiple-resolved': 'error', - // eslint comments - '@eslint-community/eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }], - '@eslint-community/eslint-comments/no-restricted-disable': 'error', - '@eslint-community/eslint-comments/no-use': 'off', - '@eslint-community/eslint-comments/require-description': 'off', - }, - overrides: [ - // only for ts files - { - files: ['*.ts', '*.tsx'], - extends: [ - 'plugin:@typescript-eslint/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', - 'plugin:@typescript-eslint/strict', - 'plugin:type-graphql/recommended', - ], - rules: { - // allow explicitly defined dangling promises - '@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }], - 'no-void': ['error', { allowAsStatement: true }], - // ignore prefer-regexp-exec rule to allow string.match(regex) - '@typescript-eslint/prefer-regexp-exec': 'off', - // this should not run on ts files: https://github.com/import-js/eslint-plugin-import/issues/2215#issuecomment-911245486 - 'import/unambiguous': 'off', - // this is not compatible with typeorm, due to joined tables can be null, but are not defined as nullable - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - parserOptions: { - tsconfigRootDir: __dirname, - project: ['./tsconfig.json', '**/tsconfig.json'], - // this is to properly reference the referenced project database without requirement of compiling it - // eslint-disable-next-line camelcase - EXPERIMENTAL_useSourceOfProjectReferenceRedirect: true, - }, - }, - { - files: ['*.test.ts'], - plugins: ['jest'], - env: { - jest: true, - }, - rules: { - 'jest/no-disabled-tests': 'error', - 'jest/no-focused-tests': 'error', - 'jest/no-identical-title': 'error', - 'jest/prefer-to-have-length': 'error', - 'jest/valid-expect': 'error', - '@typescript-eslint/unbound-method': 'off', - 'jest/unbound-method': 'error', - }, - }, - ], -} diff --git a/config/package.json b/config/package.json index c25e145ff..15252b532 100644 --- a/config/package.json +++ b/config/package.json @@ -11,9 +11,12 @@ "scripts": { "build": "tsc --build", "clean": "tsc --build --clean", + "lint": "biome check --error-on-warnings .", + "lint:fix": "biome check --error-on-warnings . --write", "test": "node test/index" }, "devDependencies": { + "@biomejs/biome": "1.9.4", "@types/joi": "^17.2.3", "@types/node": "^17.0.21", "typescript": "^4.9.5", diff --git a/config/src/commonSchema.ts b/config/src/commonSchema.ts index b3221491c..a208ee7dd 100644 --- a/config/src/commonSchema.ts +++ b/config/src/commonSchema.ts @@ -1,22 +1,22 @@ import Joi from 'joi' export const browserUrls = Joi.array() - .items(Joi.string().uri()) + .items(Joi.string().uri()) .sparse(true) .custom((value: string[], helpers: Joi.CustomHelpers) => { let protocol: string | undefined for (const url of value) { - if (url === undefined) { - continue + if (url === undefined) { + continue } const urlObject = new URL(url) - if(!protocol) { + if (!protocol) { protocol = urlObject.protocol - } else if(urlObject.protocol !== protocol) { + } else if (urlObject.protocol !== protocol) { return helpers.error('any.invalid') } } - return value; + return value }) .required() .description('All URLs need to have same protocol to prevent mixed block errors') @@ -29,8 +29,12 @@ export const DECAY_START_TIME = Joi.date() export const DB_VERSION = Joi.string() .pattern(/^\d{4}-[a-z0-9-_]+$/) - .message('DB_VERSION must be in the format: YYYY-description, e.g. "0087-add_index_on_user_roles".') - .description('db version string, last migration file name without ending or last folder in entity') + .message( + 'DB_VERSION must be in the format: YYYY-description, e.g. "0087-add_index_on_user_roles".', + ) + .description( + 'db version string, last migration file name without ending or last folder in entity', + ) .required() export const COMMUNITY_URL = Joi.string() @@ -39,9 +43,11 @@ export const COMMUNITY_URL = Joi.string() if (value.endsWith('/')) { return helpers.error('any.invalid', { message: 'URL should not end with a slash (/)' }) } - return value; + return value }) - .description('The base URL of the community, should have the same protocol as frontend, admin and backend api to prevent mixed contend issues.') + .description( + 'The base URL of the community, should have the same protocol as frontend, admin and backend api to prevent mixed contend issues.', + ) .default('http://0.0.0.0') .required() @@ -62,7 +68,7 @@ export const COMMUNITY_NAME = Joi.string() .max(40) .description('The name of the community') .default('Gradido Entwicklung') - .required() + .required() export const COMMUNITY_DESCRIPTION = Joi.string() .min(10) @@ -82,19 +88,19 @@ export const COMMUNITY_LOCATION = Joi.string() .when('GMS_ACTIVE', { is: true, then: Joi.string().required(), - otherwise: Joi.string().optional() + otherwise: Joi.string().optional(), }) .description('Geographical location of the community in "latitude, longitude" format') - .default('49.280377, 9.690151') - + .default('49.280377, 9.690151') + export const GRAPHIQL = Joi.boolean() - .description('Flag for enabling GraphQL playground for debugging.') - .default(false) - .when('NODE_ENV', { - is: 'development', - then: Joi.boolean().valid(true, false).required(), // only allow true in development mode - otherwise: Joi.boolean().valid(false).required() // false in any other mode - }) + .description('Flag for enabling GraphQL playground for debugging.') + .default(false) + .when('NODE_ENV', { + is: 'development', + then: Joi.boolean().valid(true, false).required(), // only allow true in development mode + otherwise: Joi.boolean().valid(false).required(), // false in any other mode + }) export const GMS_ACTIVE = Joi.boolean() .description('Flag to indicate if the GMS (Geographic Member Search) service is used.') @@ -123,20 +129,20 @@ export const HUMHUB_API_URL = Joi.string() .description('The API URL for HumHub integration') export const LOG_LEVEL = Joi.string() - .valid('all', 'mark', 'trace', 'debug', 'info', 'warn', 'error', 'fatal', 'off') + .valid('all', 'mark', 'trace', 'debug', 'info', 'warn', 'error', 'fatal', 'off') .description('set log level') .default('info') .required() export const LOG4JS_CONFIG = Joi.string() - .pattern(/^[a-zA-Z0-9-_]+\.json$/) + .pattern(/^[a-zA-Z0-9-_]+\.json$/) .message('LOG4JS_CONFIG must be a valid filename ending with .json') .description('config file name for log4js config file') .default('log4js-config.json') .required() export const LOGIN_APP_SECRET = Joi.string() - .pattern(/^[a-fA-F0-9]+$/) + .pattern(/^[a-fA-F0-9]+$/) .message('need to be valid hex') .default('21ffbbc616fe') .description('App secret for salt component for libsodium crypto_pwhash') @@ -147,7 +153,9 @@ export const LOGIN_SERVER_KEY = Joi.string() .length(32) .message('need to be valid hex and 32 character') .default('a51ef8ac7ef1abf162fb7a65261acd7a') - .description('Server key for password hashing as additional salt for libsodium crypto_shorthash_keygen') + .description( + 'Server key for password hashing as additional salt for libsodium crypto_shorthash_keygen', + ) .required() export const OPENAI_ACTIVE = Joi.boolean() @@ -156,7 +164,7 @@ export const OPENAI_ACTIVE = Joi.boolean() .required() export const TYPEORM_LOGGING_RELATIVE_PATH = Joi.string() - .pattern(new RegExp('^[a-zA-Z0-9-_\./]+\.log$')) + .pattern(/^[a-zA-Z0-9-_\.\/]+\.log$/) .message('TYPEORM_LOGGING_RELATIVE_PATH must be a valid filename ending with .log') .description('log file name for logging typeorm activities') .default('typeorm.log') @@ -168,7 +176,7 @@ export const DB_HOST = Joi.string() .description("database host like 'localhost' or 'mariadb' in docker setup") .default('localhost') .required() - + export const DB_PORT = Joi.number() .integer() .min(1024) @@ -179,10 +187,10 @@ export const DB_PORT = Joi.number() export const DB_USER = Joi.string() .pattern(/^[A-Za-z0-9]([A-Za-z0-9-_\.]*[A-Za-z0-9])?$/) // Validates MariaDB username rules - .min(1) // Minimum length 1 + .min(1) // Minimum length 1 .max(16) // Maximum length 16 .message( - 'Valid database username (letters, numbers, hyphens, underscores, dots allowed; no spaces, must not start or end with hyphen, dot, or underscore)' + 'Valid database username (letters, numbers, hyphens, underscores, dots allowed; no spaces, must not start or end with hyphen, dot, or underscore)', ) .description('database username for mariadb') .default('root') @@ -191,24 +199,26 @@ export const DB_USER = Joi.string() export const DB_PASSWORD = Joi.string() .when(Joi.ref('NODE_ENV'), { is: 'development', - then: Joi.string().allow(''), + then: Joi.string().allow(''), otherwise: Joi.string() - .min(8) + .min(8) .max(32) .pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*(),.?":{}|<>]).+$/) .message( - 'Password must be between 8 and 32 characters long, and contain at least one uppercase letter, one lowercase letter, one number, and one special character (e.g., !@#$%^&*).' - ) + 'Password must be between 8 and 32 characters long, and contain at least one uppercase letter, one lowercase letter, one number, and one special character (e.g., !@#$%^&*).', + ), }) .description( - 'Password for the database user. In development mode, an empty password is allowed. In other environments, a complex password is required.' + 'Password for the database user. In development mode, an empty password is allowed. In other environments, a complex password is required.', ) - .default('') + .default('') .required() export const DB_DATABASE = Joi.string() .pattern(/^[a-zA-Z][a-zA-Z0-9_-]{1,63}$/) - .description('Database name like gradido_community (must start with a letter, and can only contain letters, numbers, underscores, or dashes)') + .description( + 'Database name like gradido_community (must start with a letter, and can only contain letters, numbers, underscores, or dashes)', + ) .default('gradido_community') .required() @@ -221,13 +231,13 @@ export const APP_VERSION = Joi.string() export const BUILD_COMMIT = Joi.string() .pattern(/^[0-9a-f]{40}$/) .message('The commit hash must be a 40-character hexadecimal string.') - .description('The full git commit hash.') + .description('The full git commit hash.') .optional() export const BUILD_COMMIT_SHORT = Joi.string() .pattern(/^[0-9a-f]{7}$/) .message('The first 7 hexadecimal character from git commit hash.') - .description('A short version from the git commit hash.') + .description('A short version from the git commit hash.') .required() export const NODE_ENV = Joi.string() @@ -236,11 +246,15 @@ export const NODE_ENV = Joi.string() .description('Specifies the environment in which the application is running.') export const DEBUG = Joi.boolean() - .description('Indicates whether the application is in debugging mode. Set to true when NODE_ENV is not "production".') + .description( + 'Indicates whether the application is in debugging mode. Set to true when NODE_ENV is not "production".', + ) .default(false) .required() - + export const PRODUCTION = Joi.boolean() .default(false) - .description('Indicates whether the application is running in production mode. Set to true when NODE_ENV is "production".') + .description( + 'Indicates whether the application is running in production mode. Set to true when NODE_ENV is "production".', + ) .required() diff --git a/config/src/index.ts b/config/src/index.ts index 9137ead6d..3da59fa79 100644 --- a/config/src/index.ts +++ b/config/src/index.ts @@ -22,7 +22,9 @@ export function validate(schema: ObjectSchema, data: any) { ? schema.describe().keys[key].flags.description : 'No description available' if (data[key] === undefined) { - throw new Error(`Environment Variable '${key}' is missing. ${description}, details: ${details}`) + throw new Error( + `Environment Variable '${key}' is missing. ${description}, details: ${details}`, + ) } else { throw new Error( `Error on Environment Variable ${key} with value = ${value}: ${err.message}. ${description}`, @@ -30,4 +32,4 @@ export function validate(schema: ObjectSchema, data: any) { } }) } -} \ No newline at end of file +} diff --git a/config/yarn.lock b/config/yarn.lock index 8c8dcddd5..9fc387a53 100644 --- a/config/yarn.lock +++ b/config/yarn.lock @@ -2,6 +2,60 @@ # yarn lockfile v1 +"@biomejs/biome@1.9.4": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@biomejs/biome/-/biome-1.9.4.tgz#89766281cbc3a0aae865a7ff13d6aaffea2842bf" + integrity sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog== + optionalDependencies: + "@biomejs/cli-darwin-arm64" "1.9.4" + "@biomejs/cli-darwin-x64" "1.9.4" + "@biomejs/cli-linux-arm64" "1.9.4" + "@biomejs/cli-linux-arm64-musl" "1.9.4" + "@biomejs/cli-linux-x64" "1.9.4" + "@biomejs/cli-linux-x64-musl" "1.9.4" + "@biomejs/cli-win32-arm64" "1.9.4" + "@biomejs/cli-win32-x64" "1.9.4" + +"@biomejs/cli-darwin-arm64@1.9.4": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.4.tgz#dfa376d23a54a2d8f17133c92f23c1bf2e62509f" + integrity sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw== + +"@biomejs/cli-darwin-x64@1.9.4": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.4.tgz#eafc2ce3849d385fc02238aad1ca4a73395a64d9" + integrity sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg== + +"@biomejs/cli-linux-arm64-musl@1.9.4": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.9.4.tgz#d780c3e01758fc90f3268357e3f19163d1f84fca" + integrity sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA== + +"@biomejs/cli-linux-arm64@1.9.4": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.9.4.tgz#8ed1dd0e89419a4b66a47f95aefb8c46ae6041c9" + integrity sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g== + +"@biomejs/cli-linux-x64-musl@1.9.4": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.4.tgz#f36982b966bd671a36671e1de4417963d7db15fb" + integrity sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg== + +"@biomejs/cli-linux-x64@1.9.4": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.4.tgz#a0a7f56680c76b8034ddc149dbf398bdd3a462e8" + integrity sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg== + +"@biomejs/cli-win32-arm64@1.9.4": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.4.tgz#e2ef4e0084e76b7e26f0fc887c5ef1265ea56200" + integrity sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg== + +"@biomejs/cli-win32-x64@1.9.4": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.4.tgz#4c7afa90e3970213599b4095e62f87e5972b2340" + integrity sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA== + "@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0": version "9.3.0" resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb"