feat: better server lint (#2850)

* feat: add stylistic eslint plugin

* feat: add missing line return

* feat: secure line-break style

* feat: disallow break before else

* feat: line between class members

* feat: better new line lint rule
This commit is contained in:
Jérémy M
2023-12-06 12:19:00 +01:00
committed by GitHub
parent e388d90976
commit 9df83c9a5a
75 changed files with 318 additions and 21 deletions

View File

@ -10,26 +10,31 @@ class TestClass {
describe('CastToLogLevelArray Decorator', () => {
it('should cast "log" to ["log"]', () => {
const transformedClass = plainToClass(TestClass, { logLevels: 'log' });
expect(transformedClass.logLevels).toStrictEqual(['log']);
});
it('should cast "error" to ["error"]', () => {
const transformedClass = plainToClass(TestClass, { logLevels: 'error' });
expect(transformedClass.logLevels).toStrictEqual(['error']);
});
it('should cast "warn" to ["warn"]', () => {
const transformedClass = plainToClass(TestClass, { logLevels: 'warn' });
expect(transformedClass.logLevels).toStrictEqual(['warn']);
});
it('should cast "debug" to ["debug"]', () => {
const transformedClass = plainToClass(TestClass, { logLevels: 'debug' });
expect(transformedClass.logLevels).toStrictEqual(['debug']);
});
it('should cast "verbose" to ["verbose"]', () => {
const transformedClass = plainToClass(TestClass, { logLevels: 'verbose' });
expect(transformedClass.logLevels).toStrictEqual(['verbose']);
});
@ -37,6 +42,7 @@ describe('CastToLogLevelArray Decorator', () => {
const transformedClass = plainToClass(TestClass, {
logLevels: 'verbose,error,warn',
});
expect(transformedClass.logLevels).toStrictEqual([
'verbose',
'error',
@ -46,6 +52,7 @@ describe('CastToLogLevelArray Decorator', () => {
it('should cast "toto" to undefined', () => {
const transformedClass = plainToClass(TestClass, { logLevels: 'toto' });
expect(transformedClass.logLevels).toBeUndefined();
});
@ -53,6 +60,7 @@ describe('CastToLogLevelArray Decorator', () => {
const transformedClass = plainToClass(TestClass, {
logLevels: 'verbose,error,toto',
});
expect(transformedClass.logLevels).toBeUndefined();
});
});

View File

@ -10,21 +10,25 @@ class TestClass {
describe('CastToPositiveNumber Decorator', () => {
it('should cast number to number', () => {
const transformedClass = plainToClass(TestClass, { numberProperty: 123 });
expect(transformedClass.numberProperty).toBe(123);
});
it('should cast string to number', () => {
const transformedClass = plainToClass(TestClass, { numberProperty: '123' });
expect(transformedClass.numberProperty).toBe(123);
});
it('should cast null to undefined', () => {
const transformedClass = plainToClass(TestClass, { numberProperty: null });
expect(transformedClass.numberProperty).toBe(undefined);
});
it('should cast negative number to undefined', () => {
const transformedClass = plainToClass(TestClass, { numberProperty: -12 });
expect(transformedClass.numberProperty).toBe(undefined);
});
@ -32,6 +36,7 @@ describe('CastToPositiveNumber Decorator', () => {
const transformedClass = plainToClass(TestClass, {
numberProperty: undefined,
});
expect(transformedClass.numberProperty).toBe(undefined);
});
@ -39,6 +44,7 @@ describe('CastToPositiveNumber Decorator', () => {
const transformedClass = plainToClass(TestClass, {
numberProperty: 'toto',
});
expect(transformedClass.numberProperty).toBe(undefined);
});
@ -46,6 +52,7 @@ describe('CastToPositiveNumber Decorator', () => {
const transformedClass = plainToClass(TestClass, {
numberProperty: '-123',
});
expect(transformedClass.numberProperty).toBe(undefined);
});
});

View File

@ -13,5 +13,6 @@ const toBoolean = (value: any) => {
if (['false', 'off', 'no', '0'].includes(value.toLowerCase())) {
return false;
}
return undefined;
};

View File

@ -10,5 +10,6 @@ const toNumber = (value: any) => {
if (typeof value === 'string') {
return isNaN(+value) ? undefined : toNumber(+value);
}
return undefined;
};

View File

@ -9,6 +9,7 @@ import {
export class IsAWSRegionConstraint implements ValidatorConstraintInterface {
validate(region: string) {
const regex = /^[a-z]{2}-[a-z]+-\d{1}$/;
return regex.test(region); // Returns true if region matches regex
}
}

View File

@ -10,6 +10,7 @@ export class IsDurationConstraint implements ValidatorConstraintInterface {
validate(duration: string) {
const regex =
/^-?[0-9]+(.[0-9]+)?(m(illiseconds?)?|s(econds?)?|h((ou)?rs?)?|d(ays?)?|w(eeks?)?|M(onths?)?|y(ears?)?)?$/;
return regex.test(duration); // Returns true if duration matches regex
}
}

View File

@ -159,6 +159,7 @@ export const validate = (config: Record<string, unknown>) => {
const validatedConfig = plainToClass(EnvironmentVariables, config);
const errors = validateSync(validatedConfig);
assert(!errors.length, errors.toString());
return validatedConfig;

View File

@ -33,6 +33,7 @@ export class FileStorageModule {
provide: STORAGE_DRIVER,
useFactory: async (...args: any[]) => {
const config = await options.useFactory(...args);
return config?.type === 's3'
? new S3Driver(config.options)
: new LocalDriver(config.options);

View File

@ -67,6 +67,7 @@ const loggerModuleFactory = async (
environmentService: EnvironmentService,
): Promise<LoggerModuleOptions> => {
const type = environmentService.getLoggerDriver();
switch (type) {
case LoggerDriver.Console: {
return {
@ -100,6 +101,7 @@ const messageQueueModuleFactory = async (
switch (type) {
case MessageQueueType.PgBoss: {
const connectionString = environmentService.getPGDatabaseUrl();
return {
type: MessageQueueType.PgBoss,
options: {
@ -110,6 +112,7 @@ const messageQueueModuleFactory = async (
case MessageQueueType.BullMQ: {
const host = environmentService.getRedisHost();
const port = environmentService.getRedisPort();
return {
type: MessageQueueType.BullMQ,
options: {

View File

@ -32,6 +32,7 @@ export class LoggerModule {
provide: LOGGER_DRIVER,
useFactory: async (...args: any[]) => {
const config = await options.useFactory(...args);
return config?.type === LoggerDriver.Console
? new ConsoleLogger()
: new SentryDriver(config.options);

View File

@ -7,6 +7,7 @@ export class MemoryStorageDefaultSerializer<T>
if (typeof item !== 'string') {
throw new Error('DefaultSerializer can only serialize strings');
}
return item;
}

View File

@ -27,6 +27,7 @@ export class BullMQDriver implements MessageQueueDriver {
async stop() {
const workers = Object.values(this.workerMap);
const queues = Object.values(this.queueMap);
await Promise.all([
...queues.map((q) => q.close()),
...workers.map((w) => w.close()),
@ -40,6 +41,7 @@ export class BullMQDriver implements MessageQueueDriver {
const worker = new Worker(queueName, async (job) => {
await handler(job as { data: T; id: string });
});
this.workerMap[queueName] = worker;
}

View File

@ -12,6 +12,7 @@ export class PgBossDriver implements MessageQueueDriver {
constructor(options: PgBossDriverOptions) {
this.pgBoss = new PgBoss(options);
}
async stop() {
await this.pgBoss.stop();
}

View File

@ -30,11 +30,15 @@ export class MessageQueueModule {
provide: QUEUE_DRIVER,
useFactory: async (...args: any[]) => {
const config = await options.useFactory(...args);
if (config.type === MessageQueueType.PgBoss) {
const boss = new PgBossDriver(config.options);
await boss.init();
return boss;
}
return new BullMQDriver(config.options);
},
inject: options.inject || [],