diff --git a/.eslintrc.js b/.eslintrc.js index fb05daa..87f7bb0 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -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" }], }, }; diff --git a/src/app.controller.spec.ts b/src/app.controller.spec.ts index ab1e762..cf1e530 100644 --- a/src/app.controller.spec.ts +++ b/src/app.controller.spec.ts @@ -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([{ - name: "skillName", - category: "skillCategory", - description: "skillDescription" - }]); + const result: SkillDto[] = SkillDto.asDto([ + { + name: "skillName", + category: "skillCategory", + 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([{ - name: "experienceName", - city: "experienceCity", - jobTitle: "experienceJobTitle", - startDate: new Date(), - endDate: new Date(), - description: "experienceDescription", - skills: [] - }]); + const result: ExperienceDto[] = ExperienceDto.asDto([ + { + name: "experienceName", + city: "experienceCity", + jobTitle: "experienceJobTitle", + startDate: new Date(), + endDate: new Date(), + description: "experienceDescription", + skills: [], + }, + ]); - jest.spyOn(experiencesService, "getMany").mockImplementation(() => result) + jest.spyOn(experiencesService, "getMany").mockImplementation(() => result); expect(appController.getExperiences()).toBe(result); expect(experiencesService.getMany).toBeCalled(); }); diff --git a/src/app.controller.ts b/src/app.controller.ts index 0cfdba5..187be1c 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -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 { + getSkills(): readonly SkillDto[] { return this.skillsService.getMany(); } @@ -42,7 +45,7 @@ export class AppController { }, }, }) - getExperiences(): ReadonlyArray { + getExperiences(): readonly ExperienceDto[] { return this.experiencesService.getMany(); } } diff --git a/src/app.module.ts b/src/app.module.ts index 574bca3..b859374 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,12 +1,12 @@ -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: [], - controllers: [AppController], - providers: [AppService, SkillsService, ExperiencesService], + imports: [], + controllers: [AppController], + providers: [AppService, SkillsService, ExperiencesService], }) export class AppModule {} diff --git a/src/app.service.ts b/src/app.service.ts index efeb6b7..c60c7bc 100644 --- a/src/app.service.ts +++ b/src/app.service.ts @@ -1,8 +1,8 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable } from "@nestjs/common"; @Injectable() export class AppService { - sayHello(): string { - return 'Hello World!'; - } + sayHello(): string { + return "Hello World!"; + } } diff --git a/src/common/types.ts b/src/common/types.ts index a423b21..a56c333 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -1,9 +1,10 @@ export function DtoClass, DTO>() { return class BaseDto { + // eslint-disable-next-line @typescript-eslint/no-unused-vars constructor(type: unknown) {} - public static asDto(bases: T): DTO[] - public static asDto(types: T): T + public static asDto(bases: T): DTO[]; + public static asDto(types: T): T; public static asDto(types: T): DTO | DTO[] { if (!Array.isArray(types)) { return new this(types) as DTO; @@ -11,5 +12,5 @@ export function DtoClass, DTO>() { return types.map((base) => new this(base) as DTO); } - } + }; } diff --git a/src/experiences/experiences.service.spec.ts b/src/experiences/experiences.service.spec.ts index 3f8eeac..dfa9b76 100644 --- a/src/experiences/experiences.service.spec.ts +++ b/src/experiences/experiences.service.spec.ts @@ -1,19 +1,19 @@ -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', () => { - let service: ExperiencesService; +describe("ExperiencesService", () => { + let service: ExperiencesService; - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [ExperiencesService, SkillsService], - }).compile(); + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ExperiencesService, SkillsService], + }).compile(); - service = module.get(ExperiencesService); - }); + service = module.get(ExperiencesService); + }); - it('should be defined', () => { - expect(service).toBeDefined(); - }); + it("should be defined", () => { + expect(service).toBeDefined(); + }); }); diff --git a/src/experiences/experiences.service.ts b/src/experiences/experiences.service.ts index 55cbee5..b650982 100644 --- a/src/experiences/experiences.service.ts +++ b/src/experiences/experiences.service.ts @@ -6,30 +6,34 @@ import { SkillDto } from "@/skills/skills.types"; @Injectable() export class ExperiencesService { - private readonly experiences: ReadonlyArray; + 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>) { - const filtersValues = Object.entries(filter ?? {}).map(([key, filterValue]) => ([key, new RegExp(filterValue, "i")])) as [keyof Omit, RegExp][]; + const filtersValues = Object.entries(filter ?? {}).map(([key, filterValue]) => [ + key, + new RegExp(filterValue, "i"), + ]) as Array<[keyof Omit, 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 }> { + private linkSkills(experiences: ExperienceType[]): Array { 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(), + }; + }); } } diff --git a/src/experiences/experiences.ts b/src/experiences/experiences.ts index d91629a..39b88fb 100644 --- a/src/experiences/experiences.ts +++ b/src/experiences/experiences.ts @@ -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", }, ], }, diff --git a/src/experiences/experiences.types.ts b/src/experiences/experiences.types.ts index 5747d2f..bc7e5e6 100644 --- a/src/experiences/experiences.types.ts +++ b/src/experiences/experiences.types.ts @@ -10,8 +10,8 @@ export type ExperienceType = { description: string; startDate: Date; endDate: Date | null; - skills: Partial[]; -} + skills: Array>; +}; export class ExperienceDto extends DtoClass() implements ExperienceType { @ApiProperty() @@ -19,7 +19,7 @@ export class ExperienceDto extends DtoClass() 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() imp @ApiProperty({ type: [SkillDto], items: { - $ref: getSchemaPath(SkillDto) - } + $ref: getSchemaPath(SkillDto), + }, }) readonly skills: SkillDto[]; diff --git a/src/main.ts b/src/main.ts index 9e7dfac..60d815f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -7,21 +7,25 @@ async function bootstrap() { const app = await NestFactory.create(AppModule); const config = new DocumentBuilder() - .setTitle("Thom Werring - CV") - .setDescription("Westerstraat 83
1521ZB, Wormerveer
+31 6 37 65 08 49") - // .addApiKey({ - // type: "apiKey", - // name: "Authorization", - // bearerFormat: "bearer", - // }, "Credentials") - .setVersion("1.0.0a") - .setContact("Thom Werring", null, "cv@t-werring.nl") - .addTag("Skills", - `

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.
+ .setTitle("Thom Werring - CV") + .setDescription("Westerstraat 83
1521ZB, Wormerveer
+31 6 37 65 08 49") + // .addApiKey({ + // type: "apiKey", + // name: "Authorization", + // bearerFormat: "bearer", + // }, "Credentials") + .setVersion("1.0.0a") + .setContact("Thom Werring", null, "cv@t-werring.nl") + .addTag( + "Skills", + `

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.
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.

-`) - .addTag("Saysimple", `

Senior Developer - Haarlem
October 2018 - PRESENT

+` + ) + .addTag( + "Saysimple", + `

Senior Developer - Haarlem
October 2018 - PRESENT

  • NodeJs, TypeScript, Javascript Building scalable microservices
  • Docker and Kubernetes Containerizing and deploying microservices to AWS EKS
  • @@ -29,46 +33,54 @@ async function bootstrap() {
  • DevOps Automating deployments and CI/CD pipelines.
  • On call Handling outages and maintenance during nights & weekends
-

`) - .addTag("Blackorange", `

Junior Developer - Amsterdam
October 2014 - September 2018

+

` + ) + .addTag( + "Blackorange", + `

Junior Developer - Amsterdam
October 2014 - September 2018

  • PHP, Laravel Building websites and -applications in PHP Laravel
  • Linux System Administrator Setup & maintenance of our application hosting
-

`) - .addTag("Werring webdevelopment", `

ZZP - Middenbeemster
Januari 2012 - December 2016

+

` + ) + .addTag( + "Werring webdevelopment", + `

ZZP - Middenbeemster
Januari 2012 - December 2016

  • PHP, Wordpress Building websites in PHP & Wordpress
  • Webhosting & Email managing webhosting for companies.
-

`) - .build(); +

` + ) + .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); diff --git a/src/skills/skills.service.spec.ts b/src/skills/skills.service.spec.ts index f257ba8..84d0adf 100644 --- a/src/skills/skills.service.spec.ts +++ b/src/skills/skills.service.spec.ts @@ -16,13 +16,17 @@ describe("SkillsService", () => { expect(service).toBeDefined(); }); - describe("getMany method", () => { - it("should be defined", () => { expect(service.getMany).toBeDefined(); }); + 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 return an array", () => { + expect(Array.isArray(service.getMany())).toBe(true); + }); + it("should return an array", () => { + expect(Array.isArray(service.getMany())).toBe(true); + }); + }); }); diff --git a/src/skills/skills.service.ts b/src/skills/skills.service.ts index 4503eda..0b71144 100644 --- a/src/skills/skills.service.ts +++ b/src/skills/skills.service.ts @@ -1,18 +1,20 @@ import { Injectable } from "@nestjs/common"; import { SkillDto, SkillType } from "@/skills/skills.types"; -import {skills} from "@/skills/skills"; +import { skills } from "@/skills/skills"; @Injectable() export class SkillsService { - private readonly skills: ReadonlyArray; + 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) { - 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; } diff --git a/src/skills/skills.ts b/src/skills/skills.ts index f3c2c06..5c32d07 100644 --- a/src/skills/skills.ts +++ b/src/skills/skills.ts @@ -68,22 +68,23 @@ 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", }, { name: "Scrum Master", - description: "Facilitate the meetings, keeping track of the sprint board and refine tickets with the PO." , + description: "Facilitate the meetings, keeping track of the sprint board and refine tickets with the PO.", category: "Team Management", }, { name: "Finances", - description: "Manage the financial aspect of a student organization" , + description: "Manage the financial aspect of a student organization", category: "Finance", }, { name: "Event Organization", - description: "Organize educational events for students" , + description: "Organize educational events for students", category: "Organization", - } + }, ] satisfies SkillType[]; diff --git a/src/skills/skills.types.ts b/src/skills/skills.types.ts index 181e066..6b0b013 100644 --- a/src/skills/skills.types.ts +++ b/src/skills/skills.types.ts @@ -5,7 +5,7 @@ export type SkillType = { name: string; category: string; description: string; -} +}; export class SkillDto extends DtoClass() implements SkillType { @ApiProperty() @@ -16,11 +16,11 @@ export class SkillDto extends DtoClass() 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, }); } } diff --git a/test/app.e2e-spec.ts b/test/app.e2e-spec.ts index 50cda62..db59aa7 100644 --- a/test/app.e2e-spec.ts +++ b/test/app.e2e-spec.ts @@ -1,24 +1,21 @@ -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)', () => { - let app: INestApplication; +describe("AppController (e2e)", () => { + let app: INestApplication; - beforeEach(async () => { - const moduleFixture: TestingModule = await Test.createTestingModule({ - imports: [AppModule], - }).compile(); + beforeEach(async () => { + const moduleFixture: TestingModule = await Test.createTestingModule({ + imports: [AppModule], + }).compile(); - app = moduleFixture.createNestApplication(); - await app.init(); - }); + app = moduleFixture.createNestApplication(); + 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!"); + }); });