Formatted code

This commit is contained in:
Thom Werring 2023-10-21 14:18:14 +02:00
parent a73c024e0a
commit b6255cacc0
16 changed files with 181 additions and 160 deletions

View file

@ -1,33 +1,27 @@
module.exports = {
parser: '@typescript-eslint/parser',
parser: "@typescript-eslint/parser",
parserOptions: {
project: 'tsconfig.json',
project: "tsconfig.json",
tsconfigRootDir: __dirname,
sourceType: 'module',
sourceType: "module",
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
plugins: ["@typescript-eslint/eslint-plugin"],
extends: ["plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"],
root: true,
env: {
node: true,
jest: true,
},
ignorePatterns: ['.eslintrc.js'],
ignorePatterns: [".eslintrc.js"],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
strict: true,
"@typescript-eslint/interface-name-prefix": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-explicit-any": "off",
strict: 2,
curly: ["error", "all"],
"@typescript-eslint/no-unused-vars": ["error"],
"@typescript-eslint/array-type": ["error", { default: "array-simple", "read-only": "array-simple" }],
"@typescript-eslint/array-type": ["error", { default: "array-simple" }],
},
};

View file

@ -4,7 +4,7 @@ import { AppService } from "@/app.service";
import { SkillsService } from "@/skills/skills.service";
import { ExperiencesService } from "@/experiences/experiences.service";
import { SkillDto } from "@/skills/skills.types";
import { ExperienceDto, ExperienceType } from "@/experiences/experiences.types";
import { ExperienceDto } from "@/experiences/experiences.types";
describe("AppController", () => {
let appController: AppController;
@ -12,7 +12,6 @@ describe("AppController", () => {
let skillsService: SkillsService;
let experiencesService: ExperiencesService;
beforeEach(async () => {
const app: TestingModule = await Test.createTestingModule({
controllers: [AppController],
@ -27,25 +26,27 @@ describe("AppController", () => {
describe("root", () => {
it("Should call AppService", () => {
jest.spyOn(appService, "sayHello").mockImplementation(() => "Hello World!")
jest.spyOn(appService, "sayHello").mockImplementation(() => "Hello World!");
appController.sayHello();
expect(appService.sayHello).toBeCalled();
});
it("should return \"Hello World!\"", () => {
it('should return "Hello World!"', () => {
expect(appController.sayHello()).toBe("Hello World!");
});
});
describe("getSkills", () => {
it("Should return an Array of SkillDtos", () => {
const result: SkillDto[] = SkillDto.asDto([{
const result: SkillDto[] = SkillDto.asDto([
{
name: "skillName",
category: "skillCategory",
description: "skillDescription"
}]);
description: "skillDescription",
},
]);
jest.spyOn(skillsService, "getMany").mockImplementation(() => result)
jest.spyOn(skillsService, "getMany").mockImplementation(() => result);
expect(appController.getSkills()).toBe(result);
expect(skillsService.getMany).toBeCalled();
});
@ -53,17 +54,19 @@ describe("AppController", () => {
describe("getExperience", () => {
it("Should return an Array of ExperienceDtos", () => {
const result: ExperienceDto[] = ExperienceDto.asDto([{
const result: ExperienceDto[] = ExperienceDto.asDto([
{
name: "experienceName",
city: "experienceCity",
jobTitle: "experienceJobTitle",
startDate: new Date(),
endDate: new Date(),
description: "experienceDescription",
skills: []
}]);
skills: [],
},
]);
jest.spyOn(experiencesService, "getMany").mockImplementation(() => result)
jest.spyOn(experiencesService, "getMany").mockImplementation(() => result);
expect(appController.getExperiences()).toBe(result);
expect(experiencesService.getMany).toBeCalled();
});

View file

@ -9,8 +9,11 @@ import { ExperienceDto } from "@/experiences/experiences.types";
@Controller()
@ApiExtraModels(SkillDto, ExperienceDto)
export class AppController {
constructor(private readonly appService: AppService, private readonly skillsService: SkillsService, private readonly experiencesService: ExperiencesService) {
}
constructor(
private readonly appService: AppService,
private readonly skillsService: SkillsService,
private readonly experiencesService: ExperiencesService
) {}
@Get()
@ApiExcludeEndpoint()
@ -28,7 +31,7 @@ export class AppController {
},
},
})
getSkills(): ReadonlyArray<SkillDto> {
getSkills(): readonly SkillDto[] {
return this.skillsService.getMany();
}
@ -42,7 +45,7 @@ export class AppController {
},
},
})
getExperiences(): ReadonlyArray<ExperienceDto> {
getExperiences(): readonly ExperienceDto[] {
return this.experiencesService.getMany();
}
}

View file

@ -1,8 +1,8 @@
import { Module } from '@nestjs/common';
import { AppController } from '@/app.controller';
import { AppService } from '@/app.service';
import { SkillsService } from '@/skills/skills.service';
import { ExperiencesService } from '@/experiences/experiences.service';
import { Module } from "@nestjs/common";
import { AppController } from "@/app.controller";
import { AppService } from "@/app.service";
import { SkillsService } from "@/skills/skills.service";
import { ExperiencesService } from "@/experiences/experiences.service";
@Module({
imports: [],

View file

@ -1,8 +1,8 @@
import { Injectable } from '@nestjs/common';
import { Injectable } from "@nestjs/common";
@Injectable()
export class AppService {
sayHello(): string {
return 'Hello World!';
return "Hello World!";
}
}

View file

@ -1,9 +1,10 @@
export function DtoClass<Type extends Record<string, unknown>, DTO>() {
return class BaseDto {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
constructor(type: unknown) {}
public static asDto<T extends Type[]>(bases: T): DTO[]
public static asDto<T extends Type>(types: T): T
public static asDto<T extends Type[]>(bases: T): DTO[];
public static asDto<T extends Type>(types: T): T;
public static asDto<T extends Type | Type[]>(types: T): DTO | DTO[] {
if (!Array.isArray(types)) {
return new this(types) as DTO;
@ -11,5 +12,5 @@ export function DtoClass<Type extends Record<string, unknown>, DTO>() {
return types.map((base) => new this(base) as DTO);
}
}
};
}

View file

@ -1,8 +1,8 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ExperiencesService } from './experiences.service';
import { Test, TestingModule } from "@nestjs/testing";
import { ExperiencesService } from "./experiences.service";
import { SkillsService } from "@/skills/skills.service";
describe('ExperiencesService', () => {
describe("ExperiencesService", () => {
let service: ExperiencesService;
beforeEach(async () => {
@ -13,7 +13,7 @@ describe('ExperiencesService', () => {
service = module.get<ExperiencesService>(ExperiencesService);
});
it('should be defined', () => {
it("should be defined", () => {
expect(service).toBeDefined();
});
});

View file

@ -6,30 +6,34 @@ import { SkillDto } from "@/skills/skills.types";
@Injectable()
export class ExperiencesService {
private readonly experiences: ReadonlyArray<ExperienceDto>;
private readonly experiences: readonly ExperienceDto[];
constructor(
private readonly skillsService: SkillsService
) {
this.experiences = ExperienceDto.asDto(this.linkSkills(experiences))
.sort((experienceA, experienceB) => experienceA.startDate > experienceB.startDate ? 1 : -1);
constructor(private readonly skillsService: SkillsService) {
this.experiences = ExperienceDto.asDto(this.linkSkills(experiences)).sort((experienceA, experienceB) =>
experienceA.startDate > experienceB.startDate ? 1 : -1
);
}
getMany(filter?: Partial<Omit<ExperienceType, "startDate" | "endDate" | "skills">>) {
const filtersValues = Object.entries(filter ?? {}).map(([key, filterValue]) => ([key, new RegExp(filterValue, "i")])) as [keyof Omit<ExperienceType, "startDate" | "endDate" | "skills">, RegExp][];
const filtersValues = Object.entries(filter ?? {}).map(([key, filterValue]) => [
key,
new RegExp(filterValue, "i"),
]) as Array<[keyof Omit<ExperienceType, "startDate" | "endDate" | "skills">, RegExp]>;
if (!filter || filtersValues.length === 0) {
return this.experiences;
}
return this.experiences.filter((experience) => filtersValues.every(([key, filterValue]) => filterValue.test(experience[key])));
return this.experiences.filter((experience) =>
filtersValues.every(([key, filterValue]) => filterValue.test(experience[key]))
);
}
private linkSkills(experiences: ExperienceType[]): Array<ExperienceType & { skills: ReadonlyArray<SkillDto> }> {
private linkSkills(experiences: ExperienceType[]): Array<ExperienceType & { skills: readonly SkillDto[] }> {
return experiences.map((experience) => {
return {
...experience,
skills: experience.skills.map(partialSkill => this.skillsService.getMany(partialSkill)).flat()
}
})
skills: experience.skills.map((partialSkill) => this.skillsService.getMany(partialSkill)).flat(),
};
});
}
}

View file

@ -14,10 +14,10 @@ During my time
`,
skills: [
{
category: "AWS|Containerization|DevOps|Business Intelligence|Team Management"
category: "AWS|Containerization|DevOps|Business Intelligence|Team Management",
},
{
name: "NodeJs|Git"
name: "NodeJs|Git",
},
],
},
@ -31,10 +31,10 @@ During my time
description: "",
skills: [
{
category: "AWS|Containerization|DevOps"
category: "AWS|Containerization|DevOps",
},
{
name: "NodeJs|Git|Server"
name: "NodeJs|Git|Server",
},
],
},
@ -47,7 +47,7 @@ During my time
description: "",
skills: [
{
name: "PHP|Webhosting"
name: "PHP|Webhosting",
},
],
},
@ -61,10 +61,10 @@ During my time
description: "",
skills: [
{
name: "Finances"
name: "Finances",
},
{
category: "Organization"
category: "Organization",
},
],
},

View file

@ -10,8 +10,8 @@ export type ExperienceType = {
description: string;
startDate: Date;
endDate: Date | null;
skills: Partial<SkillDto>[];
}
skills: Array<Partial<SkillDto>>;
};
export class ExperienceDto extends DtoClass<ExperienceType, ExperienceDto>() implements ExperienceType {
@ApiProperty()
@ -19,7 +19,7 @@ export class ExperienceDto extends DtoClass<ExperienceType, ExperienceDto>() imp
@ApiProperty()
readonly city: string;
@ApiProperty()
readonly url?: string
readonly url?: string;
@ApiProperty()
readonly jobTitle: string;
@ApiProperty()
@ -31,8 +31,8 @@ export class ExperienceDto extends DtoClass<ExperienceType, ExperienceDto>() imp
@ApiProperty({
type: [SkillDto],
items: {
$ref: getSchemaPath(SkillDto)
}
$ref: getSchemaPath(SkillDto),
},
})
readonly skills: SkillDto[];

View file

@ -16,12 +16,16 @@ async function bootstrap() {
// }, "Credentials")
.setVersion("1.0.0a")
.setContact("Thom Werring", null, "cv@t-werring.nl")
.addTag("Skills",
.addTag(
"Skills",
`<p>I'm a software lead with 5+ years of experience in cloud-native development and Agile/Scrum methodologies. I'm passionate about building and leading high-performing teams to deliver scalable and reliable cloud-based applications. I have a proven track record of success in using Node.js, TypeScript, JavaScript, Docker, Kubernetes, AWS, DevOps, Git, microservices, and HAProxy to create and deploy innovative solutions.<br/>
I'm also a strong communicator and collaborator, and I'm always looking for ways to improve my skills and knowledge. I'm excited about the future of cloud computing, and I'm eager to use my skills and experience to help others achieve their goals.
</p>
`)
.addTag("Saysimple", `<p>Senior Developer - Haarlem<br/> October 2018 - PRESENT</p><p>
`
)
.addTag(
"Saysimple",
`<p>Senior Developer - Haarlem<br/> October 2018 - PRESENT</p><p>
<ul>
<li><strong>NodeJs, TypeScript, Javascript</strong> Building scalable microservices</li>
<li><strong>Docker and Kubernetes</strong> Containerizing and deploying microservices to AWS EKS</li>
@ -29,46 +33,54 @@ async function bootstrap() {
<li><strong>DevOps</strong> Automating deployments and CI/CD pipelines.</li>
<li><strong>On call</strong> Handling outages and maintenance during nights & weekends</li>
</ul>
</p>`)
.addTag("Blackorange", `<p>Junior Developer - Amsterdam<br/> October 2014 - September 2018</p><p>
</p>`
)
.addTag(
"Blackorange",
`<p>Junior Developer - Amsterdam<br/> October 2014 - September 2018</p><p>
<ul>
<li><strong>PHP, Laravel</strong> Building websites and -applications in PHP Laravel</li>
<li><strong>Linux System Administrator</strong> Setup & maintenance of our application hosting</li>
</ul>
</p>`)
.addTag("Werring webdevelopment", `<p>ZZP - Middenbeemster<br/> Januari 2012 - December 2016</p><p>
</p>`
)
.addTag(
"Werring webdevelopment",
`<p>ZZP - Middenbeemster<br/> Januari 2012 - December 2016</p><p>
<ul>
<li><strong>PHP, Wordpress</strong> Building websites in PHP & Wordpress</li>
<li><strong>Webhosting & Email</strong> managing webhosting for companies. </li>
</ul>
</p>`)
</p>`
)
.build();
const document = SwaggerModule.createDocument(app, config, {
operationIdFactory: (controllerKey: string, methodKey: string) => (`${methodKey[0].toUpperCase()}${methodKey.substring(1)}`)
operationIdFactory: (controllerKey: string, methodKey: string) =>
`${methodKey[0].toUpperCase()}${methodKey.substring(1)}`,
});
const redocOptions: RedocOptions = {
title: 'CV - Thom Werring',
title: "CV - Thom Werring",
logo: {
url: 'https://picsum.photos/256/128',
altText: 'Thom Werring'
url: "https://picsum.photos/256/128",
altText: "Thom Werring",
},
sortPropsAlphabetically: true,
hideDownloadButton: false,
tagGroups: [
{
name: 'Skills',
tags: ['Skills', ],
name: "Skills",
tags: ["Skills"],
},
{
name: 'Experience',
tags: ['Experience', 'Saysimple', 'Blackorange', 'Werring webdevelopment'],
name: "Experience",
tags: ["Experience", "Saysimple", "Blackorange", "Werring webdevelopment"],
},
],
};
await RedocModule.setup('/docs', app, document, redocOptions);
await RedocModule.setup("/docs", app, document, redocOptions);
SwaggerModule.setup("/api", app, document);
await app.listen(3000);

View file

@ -16,13 +16,17 @@ describe("SkillsService", () => {
expect(service).toBeDefined();
});
describe("getMany method", () => {
it("should be defined", () => { expect(service.getMany).toBeDefined(); });
it("should return an array", () => { expect(Array.isArray(service.getMany())).toBe(true); });
it("should return an array", () => { expect(Array.isArray(service.getMany())).toBe(true); });
})
it("should be defined", () => {
expect(service.getMany).toBeDefined();
});
it("should return an array", () => {
expect(Array.isArray(service.getMany())).toBe(true);
});
it("should return an array", () => {
expect(Array.isArray(service.getMany())).toBe(true);
});
});
});

View file

@ -4,15 +4,17 @@ import {skills} from "@/skills/skills";
@Injectable()
export class SkillsService {
private readonly skills: ReadonlyArray<SkillDto>;
private readonly skills: readonly SkillDto[];
constructor() {
this.skills = SkillDto.asDto(skills)
.sort((skillA, skillB) => skillA.category > skillB.category ? 1 : -1);
this.skills = SkillDto.asDto(skills).sort((skillA, skillB) => (skillA.category > skillB.category ? 1 : -1));
}
getMany(filter?: Partial<SkillType>) {
const filtersValues = Object.entries(filter ?? {}).map(([key, filterValue]) => ([key, new RegExp(filterValue, "i")])) as [keyof SkillType, RegExp][];
const filtersValues = Object.entries(filter ?? {}).map(([key, filterValue]) => [
key,
new RegExp(filterValue, "i"),
]) as Array<[keyof SkillType, RegExp]>;
if (!filter || filtersValues.length === 0) {
return this.skills;
}

View file

@ -68,7 +68,8 @@ export const skills: SkillType[] = [
},
{
name: "One-on-ones",
description: "Periodic meetings with junior developers and interns in my team to discuss their personal growth progress.",
description:
"Periodic meetings with junior developers and interns in my team to discuss their personal growth progress.",
category: "Team Management",
},
{
@ -85,5 +86,5 @@ export const skills: SkillType[] = [
name: "Event Organization",
description: "Organize educational events for students",
category: "Organization",
}
},
] satisfies SkillType[];

View file

@ -5,7 +5,7 @@ export type SkillType = {
name: string;
category: string;
description: string;
}
};
export class SkillDto extends DtoClass<SkillType, SkillDto>() implements SkillType {
@ApiProperty()
@ -16,11 +16,11 @@ export class SkillDto extends DtoClass<SkillType, SkillDto>() implements SkillTy
readonly description: string;
constructor(skill: SkillType) {
super(skill)
super(skill);
Object.assign(this, {
name: skill.name,
category: skill.category,
descriptions: skill.description
descriptions: skill.description,
});
}
}

View file

@ -1,9 +1,9 @@
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import * as request from 'supertest';
import { AppModule } from './../src/app.module';
import { Test, TestingModule } from "@nestjs/testing";
import { INestApplication } from "@nestjs/common";
import * as request from "supertest";
import { AppModule } from "./../src/app.module";
describe('AppController (e2e)', () => {
describe("AppController (e2e)", () => {
let app: INestApplication;
beforeEach(async () => {
@ -15,10 +15,7 @@ describe('AppController (e2e)', () => {
await app.init();
});
it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(200)
.expect('Hello World!');
it("/ (GET)", () => {
return request(app.getHttpServer()).get("/").expect(200).expect("Hello World!");
});
});