├── .nvmrc ├── apps ├── web │ ├── public │ │ └── .gitkeep │ ├── types.ts │ ├── rpc │ │ ├── index.ts │ │ ├── withSession.ts │ │ └── ensureAuthenticated.ts │ ├── components │ │ ├── analyse │ │ │ └── index.ts │ │ ├── codeHighLighter │ │ │ ├── index.ts │ │ │ └── CodeHighLighter.tsx │ │ ├── Required.tsx │ │ ├── ErrorMessage.tsx │ │ ├── Label.tsx │ │ ├── Link.tsx │ │ ├── Sidebar.tsx │ │ ├── index.ts │ │ ├── ButtonLink.tsx │ │ ├── LabeledInput.tsx │ │ ├── AsyncInfo.tsx │ │ ├── NavLink.tsx │ │ ├── LabeledSelect.tsx │ │ ├── LabeledTextarea.tsx │ │ ├── Input.tsx │ │ ├── Layout.tsx │ │ └── Navigation.tsx │ ├── utils │ │ ├── index.ts │ │ ├── CamelCaseUtil.ts │ │ ├── StatusColourPicker.tsx │ │ └── PluralizeUtil.ts │ ├── schemas │ │ ├── ProgrammingLanguageSchema.ts │ │ ├── LineDtoSchema.ts │ │ └── ContentDtoSchema.ts │ ├── stores │ │ └── ModalStore.ts │ ├── index.d.ts │ ├── next-env.d.ts │ ├── hooks │ │ ├── useIsFirstRender.ts │ │ ├── index.ts │ │ ├── useLoginRedirect.ts │ │ ├── useModal.ts │ │ ├── useLocalStorage.ts │ │ ├── useLanguagesQueryString.ts │ │ ├── useAuth.ts │ │ ├── useInfectedLineNumbers.ts │ │ └── useAuthError.ts │ ├── global.css │ ├── container.ts │ ├── @types │ │ └── next-auth │ │ │ └── index.d.ts │ ├── jest.config.ts │ ├── prisma.ts │ ├── tsconfig.spec.json │ ├── pages │ │ └── api │ │ │ ├── getAllProgrammingLanguages.ts │ │ │ ├── getAnalysisDetails.ts │ │ │ ├── getMyAnalysisReports.ts │ │ │ ├── getFileContentFromGithub.ts │ │ │ ├── voteOnAnalysis.ts │ │ │ ├── startKata.ts │ │ │ ├── submitKata.ts │ │ │ ├── submitAnalysis.ts │ │ │ └── auth │ │ │ └── [...nextauth].ts │ ├── next.config.js │ ├── tsconfig.json │ ├── .eslintrc.json │ └── project.json ├── build-kata │ ├── src │ │ ├── app │ │ │ ├── .gitkeep │ │ │ ├── katas │ │ │ │ ├── index.ts │ │ │ │ ├── js │ │ │ │ │ ├── 01.txt │ │ │ │ │ ├── 01.ts │ │ │ │ │ └── 02.ts │ │ │ │ └── ts │ │ │ │ │ ├── 01.ts │ │ │ │ │ └── 02.ts │ │ │ ├── FileReader.ts │ │ │ └── KataFactory.ts │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── environments │ │ │ ├── environment.ts │ │ │ └── environment.prod.ts │ │ └── main.ts │ ├── tsconfig.json │ ├── tsconfig.spec.json │ ├── tsconfig.app.json │ ├── .eslintrc.json │ ├── jest.config.ts │ └── project.json └── web-e2e │ ├── src │ ├── support │ │ ├── app.po.ts │ │ ├── index.ts │ │ └── commands.ts │ ├── fixtures │ │ └── example.json │ └── integration │ │ └── app.spec.ts │ ├── tsconfig.json │ ├── .eslintrc.json │ ├── cypress.json │ └── project.json ├── tools ├── generators │ └── .gitkeep └── tsconfig.tools.json ├── .prettierrc ├── libs ├── domain │ ├── src │ │ ├── index.ts │ │ └── lib │ │ │ ├── vote │ │ │ ├── index.ts │ │ │ └── Vote.ts │ │ │ ├── user │ │ │ ├── enums │ │ │ │ ├── index.ts │ │ │ │ └── UserRole.ts │ │ │ ├── valueObjects │ │ │ │ ├── index.ts │ │ │ │ ├── UserId.ts │ │ │ │ ├── UserEmail.ts │ │ │ │ └── UserName.ts │ │ │ ├── index.ts │ │ │ ├── IUserRepository.ts │ │ │ └── User.ts │ │ │ ├── kata │ │ │ ├── valueObjects │ │ │ │ ├── index.ts │ │ │ │ └── KataId.ts │ │ │ ├── index.ts │ │ │ ├── IKataRepository.ts │ │ │ └── Kata.ts │ │ │ ├── answer │ │ │ ├── valueObjects │ │ │ │ ├── index.ts │ │ │ │ └── AnswerId.ts │ │ │ ├── index.ts │ │ │ └── Answer.ts │ │ │ ├── solution │ │ │ ├── valueObjects │ │ │ │ ├── index.ts │ │ │ │ └── SolutionId.ts │ │ │ ├── index.ts │ │ │ └── Solution.ts │ │ │ ├── analysis │ │ │ ├── AnalysisType.ts │ │ │ ├── AnalysisStatus.ts │ │ │ ├── valueObjects │ │ │ │ ├── AnalysisId.ts │ │ │ │ ├── index.ts │ │ │ │ ├── AnalysisSha.ts │ │ │ │ ├── AnalysisAuthor.ts │ │ │ │ ├── AnalysisReason.ts │ │ │ │ ├── AnalysisFileDir.ts │ │ │ │ └── AnalysisRepositoryName.ts │ │ │ ├── HasAlreadyVotedException.ts │ │ │ ├── CannotVoteOnAnalysisException.ts │ │ │ ├── OwnersCannotVoteOnTheirOwnAnalysisException.ts │ │ │ ├── index.ts │ │ │ └── IAnalysisRepository.ts │ │ │ ├── IPaginate.ts │ │ │ ├── IWrite.ts │ │ │ ├── IRead.ts │ │ │ ├── index.ts │ │ │ ├── ProgrammingLanguage.ts │ │ │ ├── Content.ts │ │ │ ├── Smell.ts │ │ │ └── Line.ts │ ├── .babelrc │ ├── README.md │ ├── .eslintrc.json │ ├── tsconfig.json │ ├── jest.config.ts │ ├── tsconfig.lib.json │ ├── tsconfig.spec.json │ └── project.json ├── shared │ ├── src │ │ ├── lib │ │ │ ├── guard │ │ │ │ ├── IClause.ts │ │ │ │ ├── GuardProps.ts │ │ │ │ ├── index.ts │ │ │ │ ├── Guard.ts │ │ │ │ ├── AgainstClause.ts │ │ │ │ └── IsClause.ts │ │ │ ├── inversify │ │ │ │ ├── index.ts │ │ │ │ └── TestingFactory.ts │ │ │ ├── github │ │ │ │ ├── index.ts │ │ │ │ └── GithubRepositoryUrlParser.ts │ │ │ ├── interfaces │ │ │ │ ├── IEntity.ts │ │ │ │ └── IUseCase.ts │ │ │ ├── exceptions │ │ │ │ ├── DomainException.ts │ │ │ │ ├── index.ts │ │ │ │ ├── DomainExceptionMixin.ts │ │ │ │ └── InvalidArgumentException.ts │ │ │ ├── Utils.ts │ │ │ ├── ValueObject.ts │ │ │ ├── types.ts │ │ │ └── EntityId.ts │ │ └── index.ts │ ├── .babelrc │ ├── README.md │ ├── tsconfig.lib.json │ ├── .eslintrc.json │ ├── tsconfig.json │ ├── jest.config.ts │ ├── tsconfig.spec.json │ ├── project.json │ └── tests │ │ ├── guard │ │ └── AgainstClause.spec.ts │ │ ├── ValueObject.spec.ts │ │ └── github │ │ └── GithubRepositoryUrlParser.spec.ts ├── application │ ├── src │ │ ├── lib │ │ │ ├── exceptions │ │ │ │ ├── index.ts │ │ │ │ └── UnknownProgrammingLanguageException.ts │ │ │ ├── interfaces │ │ │ │ ├── index.ts │ │ │ │ ├── ILogger.ts │ │ │ │ └── IGithubApi.ts │ │ │ ├── useCases │ │ │ │ ├── submitAnalysisUseCase │ │ │ │ │ ├── index.ts │ │ │ │ │ └── ISubmitAnalysisRequest.ts │ │ │ │ ├── getProgrammingLanguagesUseCase │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── GetProgrammingLanguagesResponse.ts │ │ │ │ │ └── GetProgrammingLanguagesUseCase.ts │ │ │ │ ├── getAnalysisDetailsUseCase │ │ │ │ │ ├── IGetAnalysisDetailsRequest.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── NoAvailableAnalysisForUserException.ts │ │ │ │ │ └── GetAnalysisDetailsUseCase.ts │ │ │ │ ├── voteOnAnalysisUseCase │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── IVoteOnAnalysisRequest.ts │ │ │ │ │ └── AnalysisDoesNotExistException.ts │ │ │ │ ├── getMyAnalysisReportsUseCase │ │ │ │ │ ├── IGetMyAnalysisReportsRequest.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── GetMyAnalysisReportsResponse.ts │ │ │ │ │ └── GetMyAnalysisReportsUseCase.ts │ │ │ │ ├── submitKataUsecase │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── ISubmitKataRequest.ts │ │ │ │ │ ├── UnknownKataException.ts │ │ │ │ │ └── SubmitKataResponse.ts │ │ │ │ ├── startKataUseCase │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── IStartKataRequest.ts │ │ │ │ │ ├── NoAvailableKatasException.ts │ │ │ │ │ └── StartKataResponse.ts │ │ │ │ ├── getFileContentFromGithubUseCase │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── IGetFileContentFromGithubRequest.ts │ │ │ │ │ ├── GetFileContentFromGithubResponse.ts │ │ │ │ │ └── GetFileContentFromGithubUseCase.ts │ │ │ │ └── index.ts │ │ │ ├── dtos │ │ │ │ ├── index.ts │ │ │ │ ├── LineDto.ts │ │ │ │ ├── ContentDto.ts │ │ │ │ ├── UserDto.ts │ │ │ │ ├── ProgrammingLanguageDto.ts │ │ │ │ └── InvestigateDto.ts │ │ │ └── ApplicationModule.ts │ │ └── index.ts │ ├── .babelrc │ ├── tsconfig.lib.json │ ├── README.md │ ├── tests │ │ ├── utils │ │ │ ├── SolutionFactory.ts │ │ │ ├── GetMyAnalysisReportsRequestFactory.ts │ │ │ ├── ContentFactory.ts │ │ │ ├── ProgrammingLanguageFactory.ts │ │ │ ├── VoteOnAnalysisRequestFactory.ts │ │ │ ├── index.ts │ │ │ ├── UserFactory.ts │ │ │ ├── KataFactory.ts │ │ │ ├── AnswerFactory.ts │ │ │ ├── VoteFactory.ts │ │ │ ├── SubmitAnalysisRequestFactory.ts │ │ │ ├── AnalysisDetailsFactory.ts │ │ │ └── AnalysisFactory.ts │ │ └── useCases │ │ │ └── getProgrammingLangaugesUseCase │ │ │ └── GetProgrammingLanguagesUseCase.spec.ts │ ├── .eslintrc.json │ ├── tsconfig.json │ ├── jest.config.ts │ ├── tsconfig.spec.json │ └── project.json ├── infrastructure │ ├── .babelrc │ ├── src │ │ ├── index.ts │ │ └── lib │ │ │ ├── index.ts │ │ │ ├── InfraException.ts │ │ │ ├── drivers │ │ │ └── prisma │ │ │ │ ├── index.ts │ │ │ │ ├── models │ │ │ │ ├── UserModel.ts │ │ │ │ ├── AnswerModel.ts │ │ │ │ ├── SolutionModel.ts │ │ │ │ ├── KataModel.ts │ │ │ │ ├── AnalysisModel.ts │ │ │ │ └── ContentModel.ts │ │ │ │ ├── PrismaUrlParser.ts │ │ │ │ ├── mappers │ │ │ │ ├── UserMapper.ts │ │ │ │ ├── SolutionMapper.ts │ │ │ │ ├── KataMapper.ts │ │ │ │ ├── AnswerMapper.ts │ │ │ │ ├── AnalysisDetailsMapper.ts │ │ │ │ └── ContentMapper.ts │ │ │ │ ├── PrismaUrlFactory.ts │ │ │ │ ├── PrismaUrlParser.spec.ts │ │ │ │ └── PrismaService.ts │ │ │ ├── logger │ │ │ ├── LoggerLogTailImpl.ts │ │ │ └── DevelopmentLoggerImpl.ts │ │ │ ├── ConfigService.ts │ │ │ └── InfrastructureModule.ts │ ├── tsconfig.lib.json │ ├── README.md │ ├── .eslintrc.json │ ├── jest.integration-config.ts │ ├── tsconfig.json │ ├── jest.config.ts │ ├── tsconfig.spec.json │ ├── project.json │ └── tests │ │ ├── drivers │ │ └── prisma │ │ │ └── repositories │ │ │ └── PrismaKataRepositoryImpl.spec.ts │ │ └── utils │ │ └── UserBuilder.ts ├── testing-utils │ ├── .babelrc │ ├── tsconfig.lib.json │ ├── README.md │ ├── .eslintrc.json │ ├── tsconfig.json │ ├── jest.config.ts │ ├── tsconfig.spec.json │ ├── project.json │ └── src │ │ └── index.ts └── components │ ├── .storybook │ ├── preview.js │ ├── tsconfig.json │ └── main.js │ ├── README.md │ ├── .babelrc │ ├── jest.config.ts │ ├── src │ ├── index.ts │ └── lib │ │ ├── buttons │ │ ├── IconButton.tsx │ │ ├── IconButtonConfig.ts │ │ ├── Button.tsx │ │ ├── IconButton.stories.tsx │ │ ├── Button.stories.tsx │ │ └── ButtonConfig.ts │ │ ├── header │ │ └── Header.stories.tsx │ │ ├── Theme.ts │ │ └── dropdown │ │ └── Dropdown.tsx │ ├── .eslintrc.json │ ├── tsconfig.spec.json │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── project.json ├── babel.config.json ├── setupJest.ts ├── .prettierignore ├── .dockerignore ├── jest.config.ts ├── jest.preset.js ├── .husky └── pre-commit ├── prisma ├── migrations │ └── migration_lock.toml └── seeds.ts ├── run-tests.sh ├── .vscode └── extensions.json ├── Dockerfile ├── .editorconfig ├── .storybook ├── tsconfig.json └── main.js ├── .env ├── docker-compose.yml ├── env.d.ts ├── .github ├── workflows │ └── CI.yml └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── Makefile ├── workspace.json ├── docker-compose.test.yml ├── .gitignore ├── tsconfig.base.json ├── nx.json ├── LICENSE └── README.md /.nvmrc: -------------------------------------------------------------------------------- 1 | v16.15.0 2 | -------------------------------------------------------------------------------- /apps/web/public/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools/generators/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/build-kata/src/app/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/build-kata/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /libs/domain/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "babelrcRoots": ["*"] 3 | } 4 | -------------------------------------------------------------------------------- /libs/domain/src/lib/vote/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Vote'; 2 | -------------------------------------------------------------------------------- /libs/shared/src/lib/guard/IClause.ts: -------------------------------------------------------------------------------- 1 | export interface IClause {} 2 | -------------------------------------------------------------------------------- /libs/domain/src/lib/user/enums/index.ts: -------------------------------------------------------------------------------- 1 | export * from './UserRole'; 2 | -------------------------------------------------------------------------------- /libs/domain/src/lib/kata/valueObjects/index.ts: -------------------------------------------------------------------------------- 1 | export * from './KataId'; 2 | -------------------------------------------------------------------------------- /libs/shared/src/lib/inversify/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TestingFactory'; 2 | -------------------------------------------------------------------------------- /setupJest.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | 3 | jest.setTimeout(20_000); 4 | -------------------------------------------------------------------------------- /libs/domain/src/lib/answer/valueObjects/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AnswerId'; 2 | -------------------------------------------------------------------------------- /libs/domain/src/lib/solution/valueObjects/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SolutionId'; 2 | -------------------------------------------------------------------------------- /libs/shared/src/lib/github/index.ts: -------------------------------------------------------------------------------- 1 | export * from './GithubRepositoryUrlParser'; 2 | -------------------------------------------------------------------------------- /apps/web/types.ts: -------------------------------------------------------------------------------- 1 | export type Option = { 2 | value: string; 3 | label: string; 4 | }; 5 | -------------------------------------------------------------------------------- /libs/shared/src/lib/guard/GuardProps.ts: -------------------------------------------------------------------------------- 1 | export type GuardProps = Record; 2 | -------------------------------------------------------------------------------- /apps/web/rpc/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ensureAuthenticated'; 2 | export * from './withSession'; 3 | -------------------------------------------------------------------------------- /libs/application/src/lib/exceptions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './UnknownProgrammingLanguageException'; 2 | -------------------------------------------------------------------------------- /libs/domain/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] 3 | } 4 | -------------------------------------------------------------------------------- /libs/domain/src/lib/answer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Answer'; 2 | export * from './valueObjects'; 3 | -------------------------------------------------------------------------------- /libs/shared/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] 3 | } 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Add files here to ignore them from prettier formatting 2 | 3 | /dist 4 | /coverage 5 | -------------------------------------------------------------------------------- /apps/web-e2e/src/support/app.po.ts: -------------------------------------------------------------------------------- 1 | export const getGreeting = (): Cypress.Chainable => cy.get('h1'); 2 | -------------------------------------------------------------------------------- /libs/application/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] 3 | } 4 | -------------------------------------------------------------------------------- /libs/domain/src/lib/solution/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Solution'; 2 | export * from './valueObjects'; 3 | -------------------------------------------------------------------------------- /libs/domain/src/lib/user/enums/UserRole.ts: -------------------------------------------------------------------------------- 1 | export enum UserRole { 2 | Guest = 0, 3 | User, 4 | } 5 | -------------------------------------------------------------------------------- /libs/infrastructure/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] 3 | } 4 | -------------------------------------------------------------------------------- /libs/testing-utils/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] 3 | } 4 | -------------------------------------------------------------------------------- /apps/build-kata/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: false, 3 | }; 4 | -------------------------------------------------------------------------------- /libs/application/src/lib/interfaces/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ILogger'; 2 | export * from './IGithubApi'; 3 | -------------------------------------------------------------------------------- /libs/domain/src/lib/analysis/AnalysisType.ts: -------------------------------------------------------------------------------- 1 | export enum AnalysisType { 2 | Agree, 3 | Disagree, 4 | } 5 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile* 2 | .env 3 | dist 4 | .github 5 | .vscode 6 | coverage 7 | .env.local 8 | yarn-error.log 9 | -------------------------------------------------------------------------------- /apps/build-kata/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | }; 4 | -------------------------------------------------------------------------------- /libs/domain/src/lib/IPaginate.ts: -------------------------------------------------------------------------------- 1 | export interface IPaginate { 2 | count: number; 3 | hasMore: boolean; 4 | } 5 | -------------------------------------------------------------------------------- /apps/web/components/analyse/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AnalysingStep'; 2 | export * from './FetchFileFromGithubStep'; 3 | -------------------------------------------------------------------------------- /apps/web/components/codeHighLighter/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CodeHighLighter'; 2 | export * from './InteractiveCodeHighlighter'; 3 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import { getJestProjects } from '@nrwl/jest'; 2 | 3 | export default { 4 | projects: getJestProjects(), 5 | }; 6 | -------------------------------------------------------------------------------- /libs/domain/src/lib/analysis/AnalysisStatus.ts: -------------------------------------------------------------------------------- 1 | export enum AnalysisStatus { 2 | Pending, 3 | Declined, 4 | Accepted, 5 | } 6 | -------------------------------------------------------------------------------- /apps/web-e2e/src/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io" 4 | } 5 | -------------------------------------------------------------------------------- /libs/domain/src/lib/kata/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IKataRepository'; 2 | export * from './Kata'; 3 | export * from './valueObjects'; 4 | -------------------------------------------------------------------------------- /libs/infrastructure/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/InfrastructureModule'; 2 | export * from './lib/drivers/prisma/PrismaService'; 3 | -------------------------------------------------------------------------------- /apps/web/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CamelCaseUtil'; 2 | export * from './StatusColourPicker'; 3 | export * from './PluralizeUtil'; 4 | -------------------------------------------------------------------------------- /libs/domain/src/lib/user/valueObjects/index.ts: -------------------------------------------------------------------------------- 1 | export * from './UserEmail'; 2 | export * from './UserId'; 3 | export * from './UserName'; 4 | -------------------------------------------------------------------------------- /jest.preset.js: -------------------------------------------------------------------------------- 1 | const nxPreset = require('@nrwl/jest/preset').default; 2 | 3 | module.exports = { ...nxPreset, setupFiles: ['./setupJest.ts'] }; 4 | -------------------------------------------------------------------------------- /libs/domain/src/lib/user/valueObjects/UserId.ts: -------------------------------------------------------------------------------- 1 | import { EntityId } from '@codebarker/shared'; 2 | 3 | export class UserId extends EntityId {} 4 | -------------------------------------------------------------------------------- /libs/shared/src/lib/interfaces/IEntity.ts: -------------------------------------------------------------------------------- 1 | import { EntityId } from '../EntityId'; 2 | 3 | export interface IEntity { 4 | id: EntityId; 5 | } 6 | -------------------------------------------------------------------------------- /libs/shared/src/lib/interfaces/IUseCase.ts: -------------------------------------------------------------------------------- 1 | export interface IUseCase { 2 | execute(input: TInput): Promise; 3 | } 4 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | 5 | nx affected:lint --fix 6 | nx run-many --target=test --all 7 | -------------------------------------------------------------------------------- /libs/domain/src/lib/answer/valueObjects/AnswerId.ts: -------------------------------------------------------------------------------- 1 | import { EntityId } from '@codebarker/shared'; 2 | 3 | export class AnswerId extends EntityId {} 4 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/submitAnalysisUseCase/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ISubmitAnalysisRequest'; 2 | export * from './SubmitAnalysisUseCase'; 3 | -------------------------------------------------------------------------------- /libs/domain/src/lib/kata/valueObjects/KataId.ts: -------------------------------------------------------------------------------- 1 | import { EntityId } from '@codebarker/shared'; 2 | 3 | export class KataId extends EntityId {} 4 | 5 | 6 | -------------------------------------------------------------------------------- /libs/infrastructure/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ConfigService'; 2 | export * from './InfraException'; 3 | export * from './InfrastructureModule'; 4 | -------------------------------------------------------------------------------- /apps/build-kata/src/app/katas/index.ts: -------------------------------------------------------------------------------- 1 | export * from './js/01'; 2 | export * from './js/02'; 3 | 4 | export * from './ts/01'; 5 | export * from './ts/02'; 6 | -------------------------------------------------------------------------------- /libs/domain/src/lib/analysis/valueObjects/AnalysisId.ts: -------------------------------------------------------------------------------- 1 | import { EntityId } from '@codebarker/shared'; 2 | 3 | export class AnalysisId extends EntityId {} 4 | -------------------------------------------------------------------------------- /libs/domain/src/lib/solution/valueObjects/SolutionId.ts: -------------------------------------------------------------------------------- 1 | import { EntityId } from '@codebarker/shared'; 2 | 3 | export class SolutionId extends EntityId {} 4 | -------------------------------------------------------------------------------- /libs/components/.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import { theme } from '../src/lib/Theme'; 2 | 3 | export const parameters = { 4 | chakra: { 5 | theme, 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /libs/domain/src/lib/user/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IUserRepository'; 2 | export * from './User'; 3 | export * from './enums'; 4 | export * from './valueObjects'; 5 | -------------------------------------------------------------------------------- /libs/infrastructure/src/lib/InfraException.ts: -------------------------------------------------------------------------------- 1 | import { DomainException } from '@codebarker/shared'; 2 | 3 | export class InfraException extends DomainException {} 4 | -------------------------------------------------------------------------------- /libs/infrastructure/src/lib/drivers/prisma/index.ts: -------------------------------------------------------------------------------- 1 | export * from './PrismaService'; 2 | export * from './PrismaUrlFactory'; 3 | export * from './PrismaUrlParser'; 4 | -------------------------------------------------------------------------------- /prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "mysql" -------------------------------------------------------------------------------- /run-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | npx nx run-many --target=test --all 4 | npx prisma migrate dev 5 | sleep 2 6 | npx nx run infrastructure:test-integration --runInBand -------------------------------------------------------------------------------- /libs/shared/src/lib/exceptions/DomainException.ts: -------------------------------------------------------------------------------- 1 | export class DomainException extends Error { 2 | public constructor(msg: string) { 3 | super(msg); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /libs/shared/src/lib/exceptions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './DomainException'; 2 | export * from './DomainExceptionMixin'; 3 | export * from './InvalidArgumentException'; 4 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/getProgrammingLanguagesUseCase/index.ts: -------------------------------------------------------------------------------- 1 | export * from './GetProgrammingLanguagesResponse'; 2 | export * from './GetProgrammingLanguagesUseCase'; 3 | -------------------------------------------------------------------------------- /apps/web/schemas/ProgrammingLanguageSchema.ts: -------------------------------------------------------------------------------- 1 | import z from 'zod'; 2 | 3 | export const programmingLanguageSchema = z.object({ 4 | name: z.string(), 5 | extension: z.string(), 6 | }); 7 | -------------------------------------------------------------------------------- /libs/domain/src/lib/IWrite.ts: -------------------------------------------------------------------------------- 1 | import { IEntity } from '@codebarker/shared'; 2 | 3 | export interface IWrite { 4 | save(entity: TEntity): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/getAnalysisDetailsUseCase/IGetAnalysisDetailsRequest.ts: -------------------------------------------------------------------------------- 1 | export interface IGetAnalysisDetailsRequest { 2 | userId: string; 3 | languages: string[]; 4 | } 5 | -------------------------------------------------------------------------------- /libs/shared/src/lib/guard/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AgainstClause'; 2 | export * from './Guard'; 3 | export * from './GuardProps'; 4 | export * from './IClause'; 5 | export * from './IsClause'; 6 | -------------------------------------------------------------------------------- /apps/web/schemas/LineDtoSchema.ts: -------------------------------------------------------------------------------- 1 | import z from 'zod'; 2 | 3 | export const lineDtoSchema = z.object({ 4 | lineNumber: z.number(), 5 | value: z.string(), 6 | isInfected: z.boolean(), 7 | }); 8 | -------------------------------------------------------------------------------- /libs/domain/src/lib/IRead.ts: -------------------------------------------------------------------------------- 1 | import { EntityId, IEntity } from '@codebarker/shared'; 2 | 3 | export interface IRead { 4 | findById(id: EntityId): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /apps/web/stores/ModalStore.ts: -------------------------------------------------------------------------------- 1 | import { proxy } from 'valtio'; 2 | 3 | type Props = { 4 | isOpen: boolean; 5 | }; 6 | 7 | export const ModalStore = proxy({ 8 | isOpen: false, 9 | }); 10 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/voteOnAnalysisUseCase/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AnalysisDoesNotExistException'; 2 | export * from './IVoteOnAnalysisRequest'; 3 | export * from './VoteOnAnalysisUseCase'; 4 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "nrwl.angular-console", 4 | "esbenp.prettier-vscode", 5 | "firsttris.vscode-jest-runner", 6 | "dbaeumer.vscode-eslint" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:16 as base 2 | 3 | WORKDIR /app 4 | COPY ./package.json . 5 | RUN yarn 6 | COPY . . 7 | RUN yarn prisma generate 8 | 9 | FROM base as test 10 | ENTRYPOINT ["/app/run-tests.sh"] 11 | -------------------------------------------------------------------------------- /apps/build-kata/src/app/FileReader.ts: -------------------------------------------------------------------------------- 1 | import { readFileSync } from 'fs'; 2 | 3 | export class FileReader { 4 | public static readSync(path: string): Buffer { 5 | return readFileSync(path); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /apps/web/index.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | declare module '*.svg' { 3 | const content: any; 4 | export const ReactComponent: any; 5 | export default content; 6 | } 7 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/getMyAnalysisReportsUseCase/IGetMyAnalysisReportsRequest.ts: -------------------------------------------------------------------------------- 1 | export interface IGetMyAnalysisReportsRequest { 2 | userId: string; 3 | offset: number; 4 | amount?: number; 5 | } 6 | -------------------------------------------------------------------------------- /libs/application/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/ApplicationModule'; 2 | export * from './lib/useCases'; 3 | export * from './lib/interfaces'; 4 | export * from './lib/dtos'; 5 | export * from './lib/exceptions/index'; 6 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/getMyAnalysisReportsUseCase/index.ts: -------------------------------------------------------------------------------- 1 | export * from './GetMyAnalysisReportsResponse'; 2 | export * from './GetMyAnalysisReportsUseCase'; 3 | export * from './IGetMyAnalysisReportsRequest'; 4 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/submitKataUsecase/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ISubmitKataRequest'; 2 | export * from './SubmitKataResponse'; 3 | export * from './SubmitKataUseCase'; 4 | export * from './UnknownKataException' 5 | -------------------------------------------------------------------------------- /libs/components/README.md: -------------------------------------------------------------------------------- 1 | # components 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test components` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/startKataUseCase/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IStartKataRequest'; 2 | export * from './NoAvailableKatasException'; 3 | export * from './StartKataResponse'; 4 | export * from './StartKataUseCase'; 5 | -------------------------------------------------------------------------------- /apps/web/components/Required.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | 3 | export const Required = (): JSX.Element => ( 4 | 5 | * 6 | 7 | ); 8 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/startKataUseCase/IStartKataRequest.ts: -------------------------------------------------------------------------------- 1 | export interface IStartKataRequest { 2 | userId: string; 3 | excludeCompletedKatas: boolean; 4 | previousKataId?: string; 5 | languages: string[]; 6 | } 7 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/submitKataUsecase/ISubmitKataRequest.ts: -------------------------------------------------------------------------------- 1 | import { Smell } from '@codebarker/domain'; 2 | 3 | export interface ISubmitKataRequest { 4 | kataId: string; 5 | userId: string; 6 | smell: Smell; 7 | } 8 | -------------------------------------------------------------------------------- /apps/web/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/getFileContentFromGithubUseCase/index.ts: -------------------------------------------------------------------------------- 1 | export * from './GetFileContentFromGithubResponse'; 2 | export * from './GetFileContentFromGithubUseCase'; 3 | export * from './IGetFileContentFromGithubRequest'; 4 | -------------------------------------------------------------------------------- /libs/components/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@nrwl/react/babel", 5 | { 6 | "runtime": "automatic", 7 | "useBuiltIns": "usage" 8 | } 9 | ] 10 | ], 11 | "plugins": [] 12 | } 13 | -------------------------------------------------------------------------------- /libs/domain/src/lib/user/IUserRepository.ts: -------------------------------------------------------------------------------- 1 | import { User } from './User'; 2 | import { IRead } from '../IRead'; 3 | 4 | export interface IUserRepository extends IRead {} 5 | 6 | export const UserRepositoryToken = Symbol('User Repository'); 7 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/getFileContentFromGithubUseCase/IGetFileContentFromGithubRequest.ts: -------------------------------------------------------------------------------- 1 | export interface IGetFileContentFromGithubRequest { 2 | author: string; 3 | repositoryName: string; 4 | fileDir: string; 5 | sha?: string 6 | } 7 | -------------------------------------------------------------------------------- /libs/shared/src/lib/guard/Guard.ts: -------------------------------------------------------------------------------- 1 | import { AgainstClause } from './AgainstClause'; 2 | import { IsClause } from './IsClause'; 3 | 4 | export class Guard { 5 | public static Against = new AgainstClause(); 6 | public static Is = new IsClause(); 7 | } 8 | -------------------------------------------------------------------------------- /apps/web/utils/CamelCaseUtil.ts: -------------------------------------------------------------------------------- 1 | export class CamelCaseUtil { 2 | public static toReadableString(text: string): string { 3 | const result = text.replace(/([A-Z])/g, ' $1'); 4 | return result.charAt(0).toUpperCase() + result.slice(1); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /libs/application/src/lib/dtos/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ContentDto'; 2 | export * from './LineDto'; 3 | export * from './ProgrammingLanguageDto'; 4 | export * from './InvestigateDto'; 5 | export * from './UserDto'; 6 | export * from './AnalysisDetailsDto'; 7 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/voteOnAnalysisUseCase/IVoteOnAnalysisRequest.ts: -------------------------------------------------------------------------------- 1 | import { AnalysisType } from '@codebarker/domain'; 2 | 3 | export interface IVoteOnAnalysisRequest { 4 | id: string; 5 | userId: string; 6 | type: AnalysisType; 7 | } 8 | -------------------------------------------------------------------------------- /libs/infrastructure/src/lib/drivers/prisma/models/UserModel.ts: -------------------------------------------------------------------------------- 1 | import { Prisma } from '@prisma/client'; 2 | 3 | const user = Prisma.validator()({ 4 | include: {}, 5 | }); 6 | 7 | export type UserModel = Prisma.UserGetPayload; 8 | -------------------------------------------------------------------------------- /libs/shared/src/lib/Utils.ts: -------------------------------------------------------------------------------- 1 | import { NullOr } from './types'; 2 | 3 | export function isNull(value: NullOr): value is null { 4 | return value === null; 5 | } 6 | 7 | export function cast(target: any): T { 8 | return target as T; 9 | } 10 | -------------------------------------------------------------------------------- /apps/web/components/ErrorMessage.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | 3 | type Props = { 4 | message: string; 5 | }; 6 | 7 | export const ErrorMessage = ({ message }: Props): JSX.Element => ( 8 | {message} 9 | ); 10 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/getAnalysisDetailsUseCase/index.ts: -------------------------------------------------------------------------------- 1 | export * from './GetAnalysisDetailsResponse'; 2 | export * from './GetAnalysisDetailsUseCase'; 3 | export * from './IGetAnalysisDetailsRequest'; 4 | export * from './NoAvailableAnalysisForUserException'; 5 | -------------------------------------------------------------------------------- /libs/infrastructure/src/lib/drivers/prisma/models/AnswerModel.ts: -------------------------------------------------------------------------------- 1 | import { Prisma } from '@prisma/client'; 2 | 3 | const answer = Prisma.validator()({ 4 | include: {}, 5 | }); 6 | 7 | export type AnswerModel = Prisma.AnswerGetPayload; 8 | -------------------------------------------------------------------------------- /libs/domain/src/lib/analysis/valueObjects/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AnalysisAuthor'; 2 | export * from './AnalysisFileDir'; 3 | export * from './AnalysisId'; 4 | export * from './AnalysisReason'; 5 | export * from './AnalysisRepositoryName'; 6 | export * from './AnalysisSha'; 7 | -------------------------------------------------------------------------------- /libs/domain/src/lib/analysis/HasAlreadyVotedException.ts: -------------------------------------------------------------------------------- 1 | import { DomainException } from '@codebarker/shared'; 2 | 3 | export class HasAlreadyVotedException extends DomainException { 4 | public constructor() { 5 | super('You have already voted on this Analysis'); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /libs/infrastructure/src/lib/drivers/prisma/models/SolutionModel.ts: -------------------------------------------------------------------------------- 1 | import { Prisma } from '@prisma/client'; 2 | 3 | const solution = Prisma.validator()({ 4 | include: {}, 5 | }); 6 | 7 | export type SolutionModel = Prisma.SolutionGetPayload; 8 | -------------------------------------------------------------------------------- /apps/build-kata/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.app.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/application/src/lib/interfaces/ILogger.ts: -------------------------------------------------------------------------------- 1 | export interface ILogger { 2 | info(msg: string, ctx?: unknown): void; 3 | error(msg: string, ctx?: unknown): void; 4 | warn(msg: string): void; 5 | debug(msg: string): void; 6 | } 7 | 8 | export const LoggerToken = Symbol('logger-token'); 9 | -------------------------------------------------------------------------------- /apps/web-e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "sourceMap": false, 5 | "outDir": "../../dist/out-tsc", 6 | "allowJs": true, 7 | "types": ["cypress", "node"] 8 | }, 9 | "include": ["src/**/*.ts", "src/**/*.js"] 10 | } 11 | -------------------------------------------------------------------------------- /apps/build-kata/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /apps/web/hooks/useIsFirstRender.ts: -------------------------------------------------------------------------------- 1 | import { useRef } from 'react'; 2 | 3 | export function useIsFirstRender(): boolean { 4 | const isFirst = useRef(true); 5 | 6 | if (isFirst.current) { 7 | isFirst.current = false; 8 | 9 | return true; 10 | } 11 | 12 | return isFirst.current; 13 | } 14 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/startKataUseCase/NoAvailableKatasException.ts: -------------------------------------------------------------------------------- 1 | import { DomainException } from '@codebarker/shared'; 2 | 3 | export class NoAvailableKatasException extends DomainException { 4 | public constructor() { 5 | super('There are no available katas at this moment'); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /libs/domain/src/lib/analysis/CannotVoteOnAnalysisException.ts: -------------------------------------------------------------------------------- 1 | import { DomainException } from '@codebarker/shared'; 2 | 3 | export class CannotVoteOnAnalysisException extends DomainException { 4 | public constructor() { 5 | super(`You cannot vote on analysis because it is not in Pending.`); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /apps/build-kata/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["node"] 7 | }, 8 | "exclude": ["jest.config.ts", "**/*.spec.ts", "**/*.test.ts"], 9 | "include": ["**/*.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /libs/domain/src/lib/analysis/OwnersCannotVoteOnTheirOwnAnalysisException.ts: -------------------------------------------------------------------------------- 1 | import { DomainException } from '@codebarker/shared'; 2 | 3 | export class OwnersCannotVoteOnTheirOwnAnalysisException extends DomainException { 4 | public constructor() { 5 | super('An owner cannot vote on his own analysis'); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/submitKataUsecase/UnknownKataException.ts: -------------------------------------------------------------------------------- 1 | import { DomainException } from '@codebarker/shared'; 2 | 3 | export class UnknownKataException extends DomainException { 4 | public constructor(id: string) { 5 | super(`The kata you tried to access with id '${id}' is unknown`); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /libs/shared/src/lib/exceptions/DomainExceptionMixin.ts: -------------------------------------------------------------------------------- 1 | import { DomainException } from './DomainException'; 2 | 3 | export function DomainExceptionMixin(msg: string): typeof DomainException { 4 | return class extends DomainException { 5 | public constructor() { 6 | super(msg); 7 | } 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /libs/domain/README.md: -------------------------------------------------------------------------------- 1 | # domain 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test domain` to execute the unit tests via [Jest](https://jestjs.io). 8 | 9 | ## Running lint 10 | 11 | Run `nx lint domain` to execute the lint via [ESLint](https://eslint.org/). 12 | -------------------------------------------------------------------------------- /libs/shared/README.md: -------------------------------------------------------------------------------- 1 | # shared 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test shared` to execute the unit tests via [Jest](https://jestjs.io). 8 | 9 | ## Running lint 10 | 11 | Run `nx lint shared` to execute the lint via [ESLint](https://eslint.org/). 12 | -------------------------------------------------------------------------------- /tools/tsconfig.tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "../dist/out-tsc/tools", 5 | "rootDir": ".", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": ["node"], 9 | "importHelpers": false 10 | }, 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/application/src/lib/exceptions/UnknownProgrammingLanguageException.ts: -------------------------------------------------------------------------------- 1 | import { DomainException } from '@codebarker/shared'; 2 | 3 | export class UnknownProgrammingLanguageException extends DomainException { 4 | public constructor(extension: string) { 5 | super(`We do not what language belongs to '${extension}'`); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/voteOnAnalysisUseCase/AnalysisDoesNotExistException.ts: -------------------------------------------------------------------------------- 1 | import { DomainException } from '@codebarker/shared'; 2 | 3 | export class AnalysisDoesNotExistException extends DomainException { 4 | public constructor(id: string) { 5 | super(`The analysis with the id: '${id} does not exist'`); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /libs/components/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'components', 4 | preset: '../../jest.preset.js', 5 | transform: { 6 | '^.+\\.[tj]sx?$': 'babel-jest', 7 | }, 8 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 9 | coverageDirectory: '../../coverage/libs/components', 10 | }; 11 | -------------------------------------------------------------------------------- /libs/shared/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../dist/out-tsc", 6 | "declaration": true, 7 | "types": ["node"] 8 | }, 9 | "exclude": ["jest.config.ts", "**/*.spec.ts", "**/*.test.ts"], 10 | "include": ["**/*.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/getAnalysisDetailsUseCase/NoAvailableAnalysisForUserException.ts: -------------------------------------------------------------------------------- 1 | import { DomainException } from '@codebarker/shared'; 2 | 3 | export class NoAvailableAnalysisForUserException extends DomainException { 4 | public constructor() { 5 | super('You have already voted on all available analyses'); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /libs/application/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../dist/out-tsc", 6 | "declaration": true, 7 | "types": ["node"] 8 | }, 9 | "exclude": ["jest.config.ts", "**/*.spec.ts", "**/*.test.ts"], 10 | "include": ["**/*.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /libs/components/src/index.ts: -------------------------------------------------------------------------------- 1 | export { theme } from './lib/Theme'; 2 | 3 | export { IconButton } from './lib/buttons/IconButton'; 4 | export { Header } from './lib/header/Header'; 5 | export { Dropdown } from './lib/dropdown/Dropdown'; 6 | export { Button } from './lib/buttons/Button'; 7 | export type { ButtonVariant } from './lib/buttons/Button'; 8 | -------------------------------------------------------------------------------- /libs/infrastructure/src/lib/drivers/prisma/models/KataModel.ts: -------------------------------------------------------------------------------- 1 | import { Prisma } from '@prisma/client'; 2 | 3 | const kata = Prisma.validator()({ 4 | include: { 5 | answers: true, 6 | solution: true, 7 | content: true, 8 | }, 9 | }); 10 | 11 | export type KataModel = Prisma.KataGetPayload; 12 | -------------------------------------------------------------------------------- /apps/web/schemas/ContentDtoSchema.ts: -------------------------------------------------------------------------------- 1 | import z from 'zod'; 2 | 3 | import { lineDtoSchema } from './LineDtoSchema'; 4 | import { programmingLanguageSchema } from './ProgrammingLanguageSchema'; 5 | 6 | export const contentDtoSchema = z.object({ 7 | lines: z.array(lineDtoSchema), 8 | programmingLanguage: programmingLanguageSchema, 9 | }); 10 | -------------------------------------------------------------------------------- /libs/application/README.md: -------------------------------------------------------------------------------- 1 | # application 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test application` to execute the unit tests via [Jest](https://jestjs.io). 8 | 9 | ## Running lint 10 | 11 | Run `nx lint application` to execute the lint via [ESLint](https://eslint.org/). 12 | -------------------------------------------------------------------------------- /libs/infrastructure/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../dist/out-tsc", 6 | "declaration": true, 7 | "types": ["node"] 8 | }, 9 | "exclude": ["jest.config.ts", "**/*.spec.ts", "**/*.test.ts"], 10 | "include": ["**/*.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /libs/testing-utils/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../dist/out-tsc", 6 | "declaration": true, 7 | "types": ["node"] 8 | }, 9 | "exclude": ["jest.config.ts", "**/*.spec.ts", "**/*.test.ts"], 10 | "include": ["**/*.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /libs/testing-utils/README.md: -------------------------------------------------------------------------------- 1 | # testing-utils 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test testing-utils` to execute the unit tests via [Jest](https://jestjs.io). 8 | 9 | ## Running lint 10 | 11 | Run `nx lint testing-utils` to execute the lint via [ESLint](https://eslint.org/). 12 | -------------------------------------------------------------------------------- /.storybook/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "exclude": [ 4 | "../**/*.spec.js", 5 | "../**/*.test.js", 6 | "../**/*.spec.ts", 7 | "../**/*.test.ts", 8 | "../**/*.spec.tsx", 9 | "../**/*.test.tsx", 10 | "../**/*.spec.jsx", 11 | "../**/*.test.jsx" 12 | ], 13 | "include": ["../**/*"] 14 | } 15 | -------------------------------------------------------------------------------- /libs/infrastructure/README.md: -------------------------------------------------------------------------------- 1 | # infrastructure 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test infrastructure` to execute the unit tests via [Jest](https://jestjs.io). 8 | 9 | ## Running lint 10 | 11 | Run `nx lint infrastructure` to execute the lint via [ESLint](https://eslint.org/). 12 | -------------------------------------------------------------------------------- /libs/infrastructure/src/lib/drivers/prisma/models/AnalysisModel.ts: -------------------------------------------------------------------------------- 1 | import { Prisma } from '@prisma/client'; 2 | 3 | const analysis = Prisma.validator()({ 4 | include: { 5 | user: true, 6 | content: true, 7 | votes: true, 8 | }, 9 | }); 10 | 11 | export type AnalysisModel = Prisma.AnalysisGetPayload; 12 | -------------------------------------------------------------------------------- /libs/application/src/lib/interfaces/IGithubApi.ts: -------------------------------------------------------------------------------- 1 | import { Content } from '@codebarker/domain'; 2 | 3 | export interface IGithubApi { 4 | getFileContents( 5 | author: string, 6 | repositoryName: string, 7 | fileDir: string, 8 | sha?: string 9 | ): Promise; 10 | } 11 | 12 | export const GithubApiToken = Symbol('GithubApiToken'); 13 | -------------------------------------------------------------------------------- /libs/components/src/lib/buttons/IconButton.tsx: -------------------------------------------------------------------------------- 1 | import { IconButton as ChakraIconButton } from '@chakra-ui/react'; 2 | 3 | export type Props = { 4 | 'aria-label': string; 5 | icon: JSX.Element; 6 | }; 7 | 8 | export const IconButton = (props: Props): JSX.Element => { 9 | return ; 10 | }; 11 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | NODE_ENV=development 2 | DATABASE_URL="mysql://root:root@localhost:3306/codebarker" 3 | 4 | # Auth 5 | GITHUB_ID= 6 | GITHUB_SECRET= 7 | 8 | DISCORD_ID= 9 | DISCORD_SECRET= 10 | 11 | GOOGLE_ID= 12 | GOOGLE_SECRET= 13 | 14 | NEXTAUTH_URL=http://localhost:4200/ 15 | 16 | # Github Integration 17 | GITHUB_ACCESS_TOKEN= 18 | 19 | # Logging 20 | SOURCE_TOKEN= 21 | -------------------------------------------------------------------------------- /libs/components/src/lib/buttons/IconButtonConfig.ts: -------------------------------------------------------------------------------- 1 | import { ComponentStyleConfig } from '@chakra-ui/react'; 2 | 3 | export const IconButtonConfig: ComponentStyleConfig = { 4 | variants: { 5 | icon: { 6 | borderRadius: 'full', 7 | bgColor: 'brand.headerShade', 8 | _hover: { 9 | opacity: 0.8, 10 | }, 11 | }, 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /libs/domain/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Content'; 2 | export * from './IPaginate'; 3 | export * from './Line'; 4 | export * from './ProgrammingLanguage'; 5 | export * from './Smell'; 6 | export * from './analysis'; 7 | export * from './answer'; 8 | export * from './kata'; 9 | export * from './solution'; 10 | export * from './user'; 11 | export * from './vote'; 12 | -------------------------------------------------------------------------------- /libs/infrastructure/src/lib/drivers/prisma/models/ContentModel.ts: -------------------------------------------------------------------------------- 1 | import { Prisma } from '@prisma/client'; 2 | 3 | const content = Prisma.validator()({ 4 | include: { 5 | programmingLanguage: true, 6 | kata: false, 7 | analysis: false, 8 | }, 9 | }); 10 | 11 | export type ContentModel = Prisma.ContentGetPayload; 12 | -------------------------------------------------------------------------------- /apps/web/global.css: -------------------------------------------------------------------------------- 1 | /** 2 | Should move this to the theme later on 3 | **/ 4 | 5 | html, 6 | body { 7 | margin: 0; 8 | } 9 | 10 | body { 11 | background: linear-gradient( 12 | 178.51deg, 13 | #272443 74.65%, 14 | hsl(243, 19%, 38%) 133.87% 15 | ) !important; 16 | min-height: 100vh !important; 17 | } 18 | 19 | .app { 20 | min-height: 100%; 21 | } 22 | -------------------------------------------------------------------------------- /apps/web/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useAuth'; 2 | export * from './useAuthError'; 3 | export * from './useLoginRedirect'; 4 | export * from './useModal'; 5 | export * from './useLocalStorage'; 6 | export * from './useIsFirstRender'; 7 | export * from './useInfectedLineNumbers'; 8 | export * from './useLanguagesQueryString'; 9 | export * from './useAnalysisReportsTable'; 10 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.3' 2 | services: 3 | db: 4 | image: mysql 5 | restart: always 6 | environment: 7 | MYSQL_DATABASE: 'codebarker' 8 | MYSQL_ROOT_PASSWORD: 'root' 9 | ports: 10 | - '3306:3306' 11 | expose: 12 | - '3306' 13 | adminer: 14 | image: adminer 15 | restart: "no" 16 | ports: 17 | - 5051:8080 18 | -------------------------------------------------------------------------------- /env.d.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | namespace NodeJS { 3 | interface ProcessEnv { 4 | DATABASE_URL: string; 5 | GITHUB_ID: string; 6 | GITHUB_SECRET: string; 7 | DISCORD_ID: string; 8 | DISCORD_SECRET: string; 9 | GOOGLE_ID: string; 10 | GOOGLE_SECRET: string; 11 | NEXTAUTH_URL: string; 12 | } 13 | } 14 | } 15 | 16 | export {} 17 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/submitKataUsecase/SubmitKataResponse.ts: -------------------------------------------------------------------------------- 1 | export class SubmitKataResponse { 2 | public readonly isCorrect: boolean; 3 | 4 | private constructor(isCorrect: boolean) { 5 | this.isCorrect = isCorrect; 6 | } 7 | 8 | public static from(isCorrect: boolean): SubmitKataResponse { 9 | return new SubmitKataResponse(isCorrect); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: CI/CD 2 | 3 | on: push 4 | 5 | env: 6 | NODE_ENV: test 7 | MYSQL_DATABASE: 'codebarker' 8 | MYSQL_ROOT_PASSWORD: 'root' 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: tests 17 | run: docker-compose -f docker-compose.test.yml up --exit-code-from=test 18 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | branch ?= staging 2 | 3 | pscale-up: 4 | pscale connect codebarker $(branch) --port 3309 5 | 6 | db-push: 7 | yarn prisma db push 8 | 9 | db-reset: 10 | yarn prisma migrate reset --force --skip-generate 11 | 12 | db-new: 13 | $(MAKE) db-reset 14 | $(MAKE) db-push 15 | yarn db:seed 16 | 17 | cloc: 18 | cloc --exclude-dir=node_modules,dist --exclude-lang=JavaScript,JSON,HTML . -------------------------------------------------------------------------------- /libs/shared/src/lib/exceptions/InvalidArgumentException.ts: -------------------------------------------------------------------------------- 1 | import { DomainException } from './DomainException'; 2 | 3 | export class InvalidArgumentException< 4 | TProps extends Record 5 | > extends DomainException { 6 | public constructor(arg: keyof TProps, reason: string) { 7 | super(`the argument '${arg as string}' is invalid because '${reason}'.`); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /apps/web/rpc/withSession.ts: -------------------------------------------------------------------------------- 1 | import { Session } from 'next-auth'; 2 | import { getSession } from 'next-auth/react'; 3 | import { getContext } from 'next-rpc/context'; 4 | 5 | export async function withSession( 6 | cb: (session: Session) => Promise 7 | ): ReturnType { 8 | const session = (await getSession(getContext())) as Session; 9 | 10 | return cb(session); 11 | } 12 | -------------------------------------------------------------------------------- /apps/web/container.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | 3 | import { Container } from 'inversify'; 4 | 5 | import { InfrastructureModule } from '@codebarker/infrastructure'; 6 | import { ApplicationModule } from '@codebarker/application'; 7 | 8 | export const container = new Container({ 9 | skipBaseClassChecks: true, 10 | }); 11 | 12 | container.load(new ApplicationModule(), new InfrastructureModule()); 13 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/index.ts: -------------------------------------------------------------------------------- 1 | export * from './startKataUseCase'; 2 | export * from './submitKataUsecase'; 3 | export * from './getFileContentFromGithubUseCase'; 4 | export * from './submitAnalysisUseCase'; 5 | export * from './getProgrammingLanguagesUseCase'; 6 | export * from './voteOnAnalysisUseCase'; 7 | export * from './getAnalysisDetailsUseCase'; 8 | export * from './getMyAnalysisReportsUseCase'; 9 | -------------------------------------------------------------------------------- /libs/application/tests/utils/SolutionFactory.ts: -------------------------------------------------------------------------------- 1 | import { Smell, Solution, SolutionId, SolutionProps } from '@codebarker/domain'; 2 | 3 | export class SolutionFactory { 4 | public static make(props?: Partial): Solution { 5 | return Solution.make({ 6 | id: SolutionId.make({ value: 'kataId' }), 7 | type: Smell.LongParameterList, 8 | ...props, 9 | }); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /libs/domain/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/shared/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /apps/build-kata/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/application/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /apps/web/components/Label.tsx: -------------------------------------------------------------------------------- 1 | import { Box, BoxProps } from '@chakra-ui/react'; 2 | 3 | type Props = React.PropsWithChildren<{ 4 | htmlFor: string; 5 | _styles?: BoxProps; 6 | }>; 7 | 8 | export const Label = ({ htmlFor, children, _styles }: Props): JSX.Element => { 9 | return ( 10 | 11 | {children} 12 | 13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /libs/application/tests/utils/GetMyAnalysisReportsRequestFactory.ts: -------------------------------------------------------------------------------- 1 | import { IGetMyAnalysisReportsRequest } from '../../src'; 2 | 3 | export class GetMyAnalysisReportsRequestFactory { 4 | public static make( 5 | props?: Partial 6 | ): IGetMyAnalysisReportsRequest { 7 | return { 8 | offset: 0, 9 | userId: 'userId', 10 | ...props, 11 | }; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /libs/infrastructure/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/testing-utils/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /apps/build-kata/src/app/katas/js/01.txt: -------------------------------------------------------------------------------- 1 | import db from 'db' 2 | 3 | async function createUser(id, firstName, lastName, email, age, country) { 4 | try { 5 | await db.users.create({ 6 | data: { 7 | id, 8 | firstName, 9 | lastName, 10 | email, 11 | age, 12 | country 13 | } 14 | }) 15 | return true 16 | } catch(err) { 17 | return false 18 | } 19 | } -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/submitAnalysisUseCase/ISubmitAnalysisRequest.ts: -------------------------------------------------------------------------------- 1 | import { Smell } from '@codebarker/domain'; 2 | 3 | import { ContentDto } from '../../dtos'; 4 | 5 | export interface ISubmitAnalysisRequest { 6 | sha?: string; 7 | smell: Smell; 8 | reason: string; 9 | userId: string; 10 | repositoryName: string; 11 | author: string; 12 | fileDir: string; 13 | content: ContentDto; 14 | } 15 | -------------------------------------------------------------------------------- /apps/web/@types/next-auth/index.d.ts: -------------------------------------------------------------------------------- 1 | import 'next-auth'; 2 | 3 | declare module 'next-auth' { 4 | // eslint-disable-next-line @typescript-eslint/naming-convention 5 | interface User { 6 | id: string; 7 | role: number; 8 | email: string; 9 | image: ?string; 10 | } 11 | 12 | // eslint-disable-next-line @typescript-eslint/naming-convention 13 | interface Session { 14 | user?: User; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /apps/web/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'web', 4 | preset: '../../jest.preset.js', 5 | transform: { 6 | '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest', 7 | '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nrwl/next/babel'] }], 8 | }, 9 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 10 | coverageDirectory: '../../coverage/apps/web', 11 | }; 12 | -------------------------------------------------------------------------------- /apps/web/prisma.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from '@prisma/client'; 2 | 3 | let prisma: PrismaClient; 4 | 5 | if (process.env.NODE_ENV === 'production') { 6 | prisma = new PrismaClient(); 7 | } else { 8 | // @ts-ignore 9 | if (!global.prisma) { 10 | // @ts-ignore 11 | global.prisma = new PrismaClient(); 12 | } 13 | 14 | // @ts-ignore 15 | prisma = global.prisma; 16 | } 17 | 18 | export default prisma; 19 | -------------------------------------------------------------------------------- /apps/web/utils/StatusColourPicker.tsx: -------------------------------------------------------------------------------- 1 | import { AnalysisStatus } from '@codebarker/domain'; 2 | 3 | export class StatusColourPickerUtil { 4 | public static getColour(status: AnalysisStatus): string { 5 | if (status === AnalysisStatus.Pending) { 6 | return '#615c94'; 7 | } 8 | 9 | if (status === AnalysisStatus.Declined) { 10 | return '#945c7b'; 11 | } 12 | 13 | return '#5c946d'; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /libs/domain/src/lib/analysis/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Analysis'; 2 | export * from './AnalysisDetails'; 3 | export * from './AnalysisStatus'; 4 | export * from './AnalysisType'; 5 | export * from './CannotVoteOnAnalysisException'; 6 | export * from './HasAlreadyVotedException'; 7 | export * from './IAnalysisRepository'; 8 | export * from './OwnersCannotVoteOnTheirOwnAnalysisException'; 9 | export * from './valueObjects'; 10 | -------------------------------------------------------------------------------- /libs/components/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /apps/web/components/Link.tsx: -------------------------------------------------------------------------------- 1 | import { ChakraProps, Link as ChakraLink } from '@chakra-ui/react'; 2 | import NextLink from 'next/link'; 3 | 4 | type Props = React.PropsWithChildren<{ 5 | href: string; 6 | _styles?: ChakraProps; 7 | }>; 8 | 9 | export const Link = ({ href, children, _styles }: Props): JSX.Element => ( 10 | 11 | {children} 12 | 13 | ); 14 | -------------------------------------------------------------------------------- /apps/web/utils/PluralizeUtil.ts: -------------------------------------------------------------------------------- 1 | type Predicate = () => boolean; 2 | 3 | export class PluralizeUtil { 4 | public static pluralize(value: string, suffix = 's'): string { 5 | return value + suffix; 6 | } 7 | 8 | public static maybePluralize( 9 | predicate: Predicate, 10 | value: string, 11 | suffix = 's' 12 | ): string { 13 | if (!predicate()) return value; 14 | 15 | return this.pluralize(value, suffix); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libs/infrastructure/src/lib/drivers/prisma/PrismaUrlParser.ts: -------------------------------------------------------------------------------- 1 | export class PrismaUrlParser { 2 | public static parse(url: string): string { 3 | const hasSchema = url.includes('?schema='); 4 | 5 | if (!hasSchema) { 6 | return url; 7 | } 8 | 9 | return this.removeSchemaAndReturnUrl(url); 10 | } 11 | 12 | private static removeSchemaAndReturnUrl(url: string): string { 13 | return url.split('?schema=')[0]!; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /apps/web-e2e/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:cypress/recommended", "../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["src/plugins/index.js"], 11 | "rules": { 12 | "@typescript-eslint/no-var-requires": "off", 13 | "no-undef": "off" 14 | } 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /apps/web-e2e/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileServerFolder": ".", 3 | "fixturesFolder": "./src/fixtures", 4 | "integrationFolder": "./src/integration", 5 | "modifyObstructiveCode": false, 6 | "supportFile": "./src/support/index.ts", 7 | "pluginsFile": false, 8 | "video": true, 9 | "videosFolder": "../../dist/cypress/apps/web-e2e/videos", 10 | "screenshotsFolder": "../../dist/cypress/apps/web-e2e/screenshots", 11 | "chromeWebSecurity": false 12 | } 13 | -------------------------------------------------------------------------------- /libs/domain/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "forceConsistentCasingInFileNames": true, 15 | "strict": true, 16 | "noImplicitReturns": true, 17 | "noFallthroughCasesInSwitch": true, 18 | } 19 | } -------------------------------------------------------------------------------- /libs/shared/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "forceConsistentCasingInFileNames": true, 15 | "strict": true, 16 | "noImplicitReturns": true, 17 | "noFallthroughCasesInSwitch": true 18 | } 19 | } -------------------------------------------------------------------------------- /libs/application/tests/utils/ContentFactory.ts: -------------------------------------------------------------------------------- 1 | import { Content, ContentProps, ProgrammingLanguage } from '@codebarker/domain'; 2 | 3 | export class ContentFactory { 4 | public static make(props?: Partial): Content { 5 | return Content.make({ 6 | lines: [], 7 | programmingLanguage: ProgrammingLanguage.make({ 8 | name: 'name', 9 | extension: 'extension', 10 | }), 11 | ...props, 12 | }); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /libs/application/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "forceConsistentCasingInFileNames": true, 15 | "strict": true, 16 | "noImplicitReturns": true, 17 | "noFallthroughCasesInSwitch": true 18 | } 19 | } -------------------------------------------------------------------------------- /libs/domain/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'domain', 4 | preset: '../../jest.preset.js', 5 | globals: { 6 | 'ts-jest': { 7 | tsconfig: '/tsconfig.spec.json', 8 | }, 9 | }, 10 | testEnvironment: 'node', 11 | transform: { 12 | '^.+\\.[tj]sx?$': 'ts-jest', 13 | }, 14 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 15 | coverageDirectory: '../../coverage/libs/domain', 16 | }; 17 | -------------------------------------------------------------------------------- /libs/shared/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'shared', 4 | preset: '../../jest.preset.js', 5 | globals: { 6 | 'ts-jest': { 7 | tsconfig: '/tsconfig.spec.json', 8 | }, 9 | }, 10 | testEnvironment: 'node', 11 | transform: { 12 | '^.+\\.[tj]sx?$': 'ts-jest', 13 | }, 14 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 15 | coverageDirectory: '../../coverage/libs/shared', 16 | }; 17 | -------------------------------------------------------------------------------- /apps/build-kata/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'build-kata', 4 | preset: '../../jest.preset.js', 5 | globals: { 6 | 'ts-jest': { 7 | tsconfig: '/tsconfig.spec.json', 8 | }, 9 | }, 10 | testEnvironment: 'node', 11 | transform: { 12 | '^.+\\.[tj]s$': 'ts-jest', 13 | }, 14 | moduleFileExtensions: ['ts', 'js', 'html'], 15 | coverageDirectory: '../../coverage/apps/build-kata', 16 | }; 17 | -------------------------------------------------------------------------------- /libs/application/tests/utils/ProgrammingLanguageFactory.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ProgrammingLanguage, 3 | ProgrammingLanguageProps, 4 | } from '@codebarker/domain'; 5 | 6 | export class ProgrammingLanguageFactory { 7 | public static make( 8 | props?: Partial 9 | ): ProgrammingLanguage { 10 | return ProgrammingLanguage.make({ 11 | extension: 'extension', 12 | name: 'name', 13 | ...props, 14 | }); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libs/infrastructure/jest.integration-config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'infrastructure', 4 | preset: '../../jest.preset.js', 5 | testMatch: ['**/tests/**/*.integration-spec.ts'], 6 | globals: { 7 | 'ts-jest': { 8 | tsconfig: '/tsconfig.spec.json', 9 | }, 10 | }, 11 | testEnvironment: 'node', 12 | transform: { 13 | '^.+\\.[tj]s$': 'ts-jest', 14 | }, 15 | moduleFileExtensions: ['ts', 'js'], 16 | }; 17 | -------------------------------------------------------------------------------- /libs/infrastructure/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "forceConsistentCasingInFileNames": true, 15 | "strict": true, 16 | "noImplicitReturns": true, 17 | "noFallthroughCasesInSwitch": true 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /libs/testing-utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "forceConsistentCasingInFileNames": true, 15 | "strict": true, 16 | "noImplicitReturns": true, 17 | "noFallthroughCasesInSwitch": true 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /libs/application/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'application', 4 | preset: '../../jest.preset.js', 5 | globals: { 6 | 'ts-jest': { 7 | tsconfig: '/tsconfig.spec.json', 8 | }, 9 | }, 10 | testEnvironment: 'node', 11 | transform: { 12 | '^.+\\.[tj]sx?$': 'ts-jest', 13 | }, 14 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 15 | coverageDirectory: '../../coverage/libs/application', 16 | }; 17 | -------------------------------------------------------------------------------- /apps/build-kata/src/main.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from '@prisma/client'; 2 | import * as Assets from './app/katas'; 3 | 4 | async function main(run: boolean): Promise { 5 | if (!run) return; 6 | 7 | const prisma = new PrismaClient(); 8 | const queries: any[] = Object.values(Assets).map((item) => 9 | prisma.kata.create({ 10 | data: item, 11 | }) 12 | ); 13 | 14 | await prisma.$transaction(queries).catch(console.error); 15 | } 16 | 17 | main(true); 18 | -------------------------------------------------------------------------------- /apps/web-e2e/src/integration/app.spec.ts: -------------------------------------------------------------------------------- 1 | import { getGreeting } from '../support/app.po'; 2 | 3 | describe('web', () => { 4 | beforeEach(() => cy.visit('/')); 5 | 6 | it('should display welcome message', () => { 7 | // Custom command example, see `../support/commands.ts` file 8 | cy.login('my-email@something.com', 'myPassword'); 9 | 10 | // Function helper example, see `../support/app.po.ts` file 11 | getGreeting().contains('Welcome web'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /libs/application/tests/utils/VoteOnAnalysisRequestFactory.ts: -------------------------------------------------------------------------------- 1 | import { AnalysisType } from '@codebarker/domain'; 2 | 3 | import { IVoteOnAnalysisRequest } from '../../src'; 4 | 5 | export class VoteOnAnalysisRequestFactory { 6 | public static make( 7 | props?: Partial 8 | ): IVoteOnAnalysisRequest { 9 | return { 10 | id: 'id', 11 | type: AnalysisType.Agree, 12 | userId: 'userId', 13 | ...props, 14 | }; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libs/testing-utils/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'testing-utils', 4 | preset: '../../jest.preset.js', 5 | globals: { 6 | 'ts-jest': { 7 | tsconfig: '/tsconfig.spec.json', 8 | }, 9 | }, 10 | testEnvironment: 'node', 11 | transform: { 12 | '^.+\\.[tj]sx?$': 'ts-jest', 13 | }, 14 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 15 | coverageDirectory: '../../coverage/libs/testing-utils', 16 | }; 17 | -------------------------------------------------------------------------------- /libs/infrastructure/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'infrastructure', 4 | preset: '../../jest.preset.js', 5 | globals: { 6 | 'ts-jest': { 7 | tsconfig: '/tsconfig.spec.json', 8 | }, 9 | }, 10 | testEnvironment: 'node', 11 | transform: { 12 | '^.+\\.[tj]sx?$': 'ts-jest', 13 | }, 14 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 15 | coverageDirectory: '../../coverage/libs/infrastructure', 16 | }; 17 | -------------------------------------------------------------------------------- /libs/shared/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "**/*.test.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.tsx", 13 | "**/*.spec.tsx", 14 | "**/*.test.js", 15 | "**/*.spec.js", 16 | "**/*.test.jsx", 17 | "**/*.spec.jsx", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /workspace.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/nx/schemas/workspace-schema.json", 3 | "version": 2, 4 | "projects": { 5 | "application": "libs/application", 6 | "build-kata": "apps/build-kata", 7 | "components": "libs/components", 8 | "domain": "libs/domain", 9 | "infrastructure": "libs/infrastructure", 10 | "shared": "libs/shared", 11 | "testing-utils": "libs/testing-utils", 12 | "web": "apps/web", 13 | "web-e2e": "apps/web-e2e" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /libs/application/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "**/*.test.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.tsx", 13 | "**/*.spec.tsx", 14 | "**/*.test.js", 15 | "**/*.spec.js", 16 | "**/*.test.jsx", 17 | "**/*.spec.jsx", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /libs/components/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "**/*.test.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.tsx", 13 | "**/*.spec.tsx", 14 | "**/*.test.js", 15 | "**/*.spec.js", 16 | "**/*.test.jsx", 17 | "**/*.spec.jsx", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /libs/domain/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../dist/out-tsc", 6 | "declaration": true, 7 | "types": [ 8 | "node" 9 | ] 10 | }, 11 | "exclude": [ 12 | "jest.config.ts", 13 | "**/*.spec.ts", 14 | "**/*.test.ts" 15 | ], 16 | "include": [ 17 | "**/*.ts", 18 | "../shared/tests/validator/Validator.spec.ts", 19 | "../shared/src/lib/Validator.ts" 20 | ] 21 | } -------------------------------------------------------------------------------- /libs/shared/src/lib/ValueObject.ts: -------------------------------------------------------------------------------- 1 | import { shallowEqual } from 'shallow-equal-object'; 2 | 3 | export abstract class ValueObject> { 4 | protected props: TProps; 5 | 6 | protected constructor(props: TProps) { 7 | this.props = props; 8 | } 9 | 10 | public equals(valueObject: ValueObject): boolean { 11 | return shallowEqual( 12 | Object.values(this.props), 13 | Object.values(valueObject.props) 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libs/testing-utils/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "**/*.test.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.tsx", 13 | "**/*.spec.tsx", 14 | "**/*.test.js", 15 | "**/*.spec.js", 16 | "**/*.test.jsx", 17 | "**/*.spec.jsx", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /libs/shared/src/lib/inversify/TestingFactory.ts: -------------------------------------------------------------------------------- 1 | import { Container, ContainerModule } from 'inversify'; 2 | 3 | import { Constructor } from '../types'; 4 | 5 | export class TestingFactory { 6 | public static createContainer( 7 | ...modules: Constructor[] 8 | ): Container { 9 | const container = new Container({ 10 | skipBaseClassChecks: true, 11 | }); 12 | 13 | container.load(...modules.map((m) => new m())); 14 | 15 | return container; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libs/application/tests/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AnswerFactory'; 2 | export * from './KataFactory'; 3 | export * from './SolutionFactory'; 4 | export * from './SubmitAnalysisRequestFactory'; 5 | export * from './AnalysisFactory'; 6 | export * from './ProgrammingLanguageFactory'; 7 | export * from './VoteOnAnalysisRequestFactory'; 8 | export * from './VoteFactory'; 9 | export * from './UserFactory'; 10 | export * from './AnalysisDetailsFactory'; 11 | export * from './GetMyAnalysisReportsRequestFactory'; 12 | -------------------------------------------------------------------------------- /libs/infrastructure/src/lib/drivers/prisma/mappers/UserMapper.ts: -------------------------------------------------------------------------------- 1 | import { User, UserEmail, UserId, UserName } from '@codebarker/domain'; 2 | 3 | import { UserModel } from '../models/UserModel'; 4 | 5 | export class UserMapper { 6 | public static toDomain(model: UserModel): User { 7 | return User.make({ 8 | id: UserId.make({ value: model.id! }), 9 | email: UserEmail.make(model.email!), 10 | name: UserName.make(model.name!), 11 | role: model.role, 12 | }); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /apps/web/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"], 7 | "jsx": "react" 8 | }, 9 | "include": [ 10 | "jest.config.ts", 11 | "**/*.test.ts", 12 | "**/*.spec.ts", 13 | "**/*.test.tsx", 14 | "**/*.spec.tsx", 15 | "**/*.test.js", 16 | "**/*.spec.js", 17 | "**/*.test.jsx", 18 | "**/*.spec.jsx", 19 | "**/*.d.ts" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /libs/application/tests/utils/UserFactory.ts: -------------------------------------------------------------------------------- 1 | import { 2 | User, 3 | UserEmail, 4 | UserId, 5 | UserName, 6 | UserProps, 7 | UserRole, 8 | } from '@codebarker/domain'; 9 | 10 | export class UserFactory { 11 | public static make(props?: Partial): User { 12 | return User.make({ 13 | email: UserEmail.make('john@test.com'), 14 | id: UserId.make({ value: 'id' }), 15 | name: UserName.make('name'), 16 | role: UserRole.User, 17 | ...props, 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /libs/domain/src/lib/user/valueObjects/UserEmail.ts: -------------------------------------------------------------------------------- 1 | import { Guard, ValueObject } from '@codebarker/shared'; 2 | 3 | import { UserProps } from '../User'; 4 | 5 | type UserEmailProps = { 6 | value: string; 7 | }; 8 | 9 | export class UserEmail extends ValueObject { 10 | public get value(): string { 11 | return this.props.value; 12 | } 13 | 14 | public static make(email: string): UserEmail { 15 | return new UserEmail({ value: Guard.Is.email('email', email) }); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /apps/web/hooks/useLoginRedirect.ts: -------------------------------------------------------------------------------- 1 | import { useRouter } from 'next/router'; 2 | import { useEffect } from 'react'; 3 | import { useModal } from './useModal'; 4 | 5 | export function useRedirectLogin(): void { 6 | const router = useRouter(); 7 | const { onOpen } = useModal(); 8 | 9 | useEffect(() => { 10 | if (!router.query.redirect) return; 11 | 12 | onOpen(); 13 | 14 | router.replace(router.pathname, undefined, { 15 | shallow: true, 16 | }); 17 | }, [router.query, onOpen, router]); 18 | } 19 | -------------------------------------------------------------------------------- /libs/domain/src/lib/analysis/valueObjects/AnalysisSha.ts: -------------------------------------------------------------------------------- 1 | import { Guard, ValueObject } from '@codebarker/shared'; 2 | 3 | type AnalysisShaProps = { 4 | value: string; 5 | }; 6 | 7 | export class AnalysisSha extends ValueObject { 8 | public get value(): string { 9 | return this.props.value; 10 | } 11 | 12 | public static make(props: AnalysisShaProps): AnalysisSha { 13 | Guard.Is.string('value', props.value); 14 | 15 | return new AnalysisSha(props); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stories: [], 3 | addons: ['@storybook/addon-essentials', '@chakra-ui/storybook-addon'], 4 | features: { 5 | emotionAlias: false, 6 | }, 7 | // uncomment the property below if you want to apply some webpack config globally 8 | // webpackFinal: async (config, { configType }) => { 9 | // // Make whatever fine-grained changes you need that should apply to all storybook configs 10 | 11 | // // Return the altered config 12 | // return config; 13 | // }, 14 | }; 15 | -------------------------------------------------------------------------------- /apps/web/components/Sidebar.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | import { Navigation } from './Navigation'; 3 | 4 | export const Sidebar = (): JSX.Element => { 5 | return ( 6 | 14 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /apps/build-kata/src/app/katas/ts/01.ts: -------------------------------------------------------------------------------- 1 | import { Smell } from '@codebarker/domain'; 2 | 3 | import { KataFactory } from '../../KataFactory'; 4 | import { FileReader } from '../../FileReader'; 5 | import { cwd } from 'process'; 6 | 7 | export const CommentsTypescript01 = KataFactory.make({ 8 | name: 'typescript', 9 | extension: 'ts', 10 | highlightedLines: [12, 16, 38], 11 | solutionType: Smell.Comments, 12 | code: FileReader.readSync( 13 | cwd() + '/apps/build-kata/src/app/katas/ts/01.txt' 14 | ).toString(), 15 | }); 16 | -------------------------------------------------------------------------------- /apps/build-kata/src/app/katas/ts/02.ts: -------------------------------------------------------------------------------- 1 | import { Smell } from '@codebarker/domain'; 2 | 3 | import { KataFactory } from '../../KataFactory'; 4 | import { FileReader } from '../../FileReader'; 5 | import { cwd } from 'process'; 6 | 7 | export const LargeClassTypescript02 = KataFactory.make({ 8 | name: 'typescript', 9 | extension: 'ts', 10 | highlightedLines: [28, 147], 11 | solutionType: Smell.LargeClass, 12 | code: FileReader.readSync( 13 | cwd() + '/apps/build-kata/src/app/katas/ts/02.txt' 14 | ).toString(), 15 | }); 16 | -------------------------------------------------------------------------------- /libs/domain/src/lib/analysis/valueObjects/AnalysisAuthor.ts: -------------------------------------------------------------------------------- 1 | import { Guard, ValueObject } from '@codebarker/shared'; 2 | 3 | type AnalysisAuthorProps = { 4 | value: string; 5 | }; 6 | 7 | export class AnalysisAuthor extends ValueObject { 8 | public get value(): string { 9 | return this.props.value; 10 | } 11 | 12 | public static make(props: AnalysisAuthorProps): AnalysisAuthor { 13 | Guard.Is.string('value', props.value); 14 | 15 | return new AnalysisAuthor(props); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libs/domain/src/lib/analysis/valueObjects/AnalysisReason.ts: -------------------------------------------------------------------------------- 1 | import { Guard, ValueObject } from '@codebarker/shared'; 2 | 3 | type AnalysisReasonProps = { 4 | value: string; 5 | }; 6 | 7 | export class AnalysisReason extends ValueObject { 8 | public get value(): string { 9 | return this.props.value; 10 | } 11 | 12 | public static make(props: AnalysisReasonProps): AnalysisReason { 13 | Guard.Is.string('value', props.value); 14 | 15 | return new AnalysisReason(props); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /apps/web/pages/api/getAllProgrammingLanguages.ts: -------------------------------------------------------------------------------- 1 | import { 2 | GetProgrammingLanguagesResponse, 3 | GetProgrammingLanguagesUseCase, 4 | } from '@codebarker/application'; 5 | 6 | import { ensureAuthenticated } from '../../rpc'; 7 | import { container } from '../../container'; 8 | 9 | export const config = { 10 | rpc: true, 11 | wrapMethod: ensureAuthenticated, 12 | }; 13 | 14 | export const getAllProgrammingLanguages = 15 | async (): Promise => 16 | container.get(GetProgrammingLanguagesUseCase).execute(); 17 | -------------------------------------------------------------------------------- /libs/application/tests/utils/KataFactory.ts: -------------------------------------------------------------------------------- 1 | import { Kata, KataId, KataProps } from '@codebarker/domain'; 2 | 3 | import { ContentFactory } from './ContentFactory'; 4 | import { SolutionFactory } from './SolutionFactory'; 5 | 6 | export class KataFactory { 7 | public static make(props?: Partial): Kata { 8 | return Kata.make({ 9 | id: KataId.make({ value: 'kataId' }), 10 | content: ContentFactory.make(), 11 | solution: SolutionFactory.make(), 12 | answers: [], 13 | ...props, 14 | }); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libs/components/src/lib/header/Header.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { ComponentMeta, Story } from '@storybook/react'; 4 | 5 | import { Header, Props } from './Header'; 6 | 7 | export default { 8 | title: 'Header', 9 | component: Header, 10 | argTypes: { 11 | name: { 12 | defaultValue: 'Donny R.', 13 | }, 14 | }, 15 | } as ComponentMeta; 16 | 17 | const Template: Story = (args): JSX.Element =>
; 18 | 19 | export const Default: Story = Template.bind({}); 20 | -------------------------------------------------------------------------------- /libs/domain/src/lib/analysis/valueObjects/AnalysisFileDir.ts: -------------------------------------------------------------------------------- 1 | import { Guard, ValueObject } from '@codebarker/shared'; 2 | 3 | type AnalysisFileDirProps = { 4 | value: string; 5 | }; 6 | 7 | export class AnalysisFileDir extends ValueObject { 8 | public get value(): string { 9 | return this.props.value; 10 | } 11 | 12 | public static make(props: AnalysisFileDirProps): AnalysisFileDir { 13 | Guard.Is.string('value', props.value); 14 | 15 | return new AnalysisFileDir(props); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libs/shared/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/exceptions/DomainException'; 2 | export * from './lib/exceptions/DomainExceptionMixin'; 3 | export * from './lib/exceptions/InvalidArgumentException'; 4 | export * from './lib/interfaces/IEntity'; 5 | export * from './lib/interfaces/IUseCase'; 6 | export * from './lib/types'; 7 | export * from './lib/inversify'; 8 | export * from './lib/Utils'; 9 | export * from './lib/ValueObject'; 10 | export * from './lib/github'; 11 | export * from './lib/EntityId'; 12 | export * from './lib/guard/Guard'; 13 | -------------------------------------------------------------------------------- /apps/web/next.config.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-var-requires 2 | const withNx = require('@nrwl/next/plugins/with-nx'); 3 | const withRpc = require('next-rpc')({ 4 | experimentalContext: true, 5 | }); 6 | 7 | /** 8 | * @type {import('@nrwl/next/plugins/with-nx').WithNxOptions} 9 | **/ 10 | const nextConfig = { 11 | nx: { 12 | // Set this to true if you would like to to use SVGR 13 | // See: https://github.com/gregberge/svgr 14 | svgr: false, 15 | }, 16 | }; 17 | 18 | module.exports = withNx(withRpc(nextConfig)); 19 | -------------------------------------------------------------------------------- /libs/domain/src/lib/user/valueObjects/UserName.ts: -------------------------------------------------------------------------------- 1 | import { Guard, ValueObject } from '@codebarker/shared'; 2 | 3 | import { UserProps } from '../User'; 4 | 5 | type UserNameProps = { 6 | value: string; 7 | }; 8 | 9 | export class UserName extends ValueObject { 10 | public get value(): string { 11 | return this.props.value; 12 | } 13 | 14 | public static make(userName: string): UserName { 15 | return new UserName({ 16 | value: Guard.Against.nullOrWhiteSpace('name', userName), 17 | }); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /apps/build-kata/src/app/katas/js/01.ts: -------------------------------------------------------------------------------- 1 | import { Smell } from '@codebarker/domain'; 2 | 3 | import { KataFactory } from '../../KataFactory'; 4 | import { FileReader } from '../../FileReader'; 5 | import { cwd } from 'process'; 6 | 7 | export const LongParameterTypeJavascript01 = KataFactory.make({ 8 | name: 'javascript', 9 | extension: 'js', 10 | highlightedLines: [2, 6, 7, 8, 9, 10, 11], 11 | solutionType: Smell.LongParameterList, 12 | code: FileReader.readSync( 13 | cwd() + '/apps/build-kata/src/app/katas/js/01.txt' 14 | ).toString(), 15 | }); 16 | -------------------------------------------------------------------------------- /apps/web/hooks/useModal.ts: -------------------------------------------------------------------------------- 1 | import { useSnapshot } from 'valtio'; 2 | import { ModalStore } from '../stores/ModalStore'; 3 | 4 | type Props = { 5 | isOpen: boolean; 6 | onOpen(): void; 7 | onClose(): void; 8 | }; 9 | 10 | export function useModal(): Props { 11 | const { isOpen } = useSnapshot(ModalStore); 12 | 13 | function onOpen(): void { 14 | ModalStore.isOpen = true; 15 | } 16 | 17 | function onClose(): void { 18 | ModalStore.isOpen = false; 19 | } 20 | 21 | return { 22 | isOpen, 23 | onOpen, 24 | onClose, 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /libs/application/tests/utils/AnswerFactory.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Answer, 3 | AnswerId, 4 | AnswerProps, 5 | KataId, 6 | Smell, 7 | UserId, 8 | } from '@codebarker/domain'; 9 | 10 | export class AnswerFactory { 11 | public static make(props?: Partial): Answer { 12 | return Answer.make({ 13 | id: AnswerId.make({ value: 'id' }), 14 | kataId: KataId.make({ value: 'kataId' }), 15 | userId: UserId.make({ value: 'userId' }), 16 | smell: Smell.DataClump, 17 | isCorrect: false, 18 | ...props, 19 | }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /libs/domain/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": [ 7 | "jest", 8 | "node" 9 | ] 10 | }, 11 | "include": [ 12 | "jest.config.ts", 13 | "**/*.test.ts", 14 | "**/*.spec.ts", 15 | "**/*.test.tsx", 16 | "**/*.spec.tsx", 17 | "**/*.test.js", 18 | "**/*.spec.js", 19 | "**/*.test.jsx", 20 | "**/*.spec.jsx", 21 | "**/*.d.ts", 22 | "../shared/tests/validator/Validator.spec.ts" 23 | ] 24 | } -------------------------------------------------------------------------------- /libs/shared/src/lib/types.ts: -------------------------------------------------------------------------------- 1 | export type NullOr = T | null; 2 | export type NullOrAsync = Promise>; 3 | 4 | export type ExcludeMethods = Pick< 5 | TClass, 6 | { 7 | // eslint-disable-next-line @typescript-eslint/ban-types 8 | [K in keyof TClass]: TClass[K] extends Function ? never : K; 9 | }[keyof TClass] 10 | >; 11 | 12 | export type Constructor = new (...args: any[]) => T; 13 | 14 | export type PartialBy = Omit & Partial>; 15 | export type Writeable = { -readonly [P in keyof T]: T[P] }; 16 | -------------------------------------------------------------------------------- /apps/build-kata/src/app/katas/js/02.ts: -------------------------------------------------------------------------------- 1 | import { Smell } from '@codebarker/domain'; 2 | 3 | import { KataFactory } from '../../KataFactory'; 4 | import { FileReader } from '../../FileReader'; 5 | import { cwd } from 'process'; 6 | import { range } from 'lodash'; 7 | 8 | export const LongMethodJavascript02 = KataFactory.make({ 9 | name: 'javascript', 10 | extension: 'js', 11 | highlightedLines: range(92, 162), 12 | solutionType: Smell.LongMethod, 13 | code: FileReader.readSync( 14 | cwd() + '/apps/build-kata/src/app/katas/js/02.txt' 15 | ).toString(), 16 | }); 17 | -------------------------------------------------------------------------------- /libs/application/src/lib/dtos/LineDto.ts: -------------------------------------------------------------------------------- 1 | import { Line } from '@codebarker/domain'; 2 | 3 | export class LineDto { 4 | public readonly lineNumber: number; 5 | public readonly value: string; 6 | public readonly isInfected: boolean; 7 | 8 | private constructor(lineNumber: number, value: string, isInfected: boolean) { 9 | this.lineNumber = lineNumber; 10 | this.value = value; 11 | this.isInfected = isInfected; 12 | } 13 | 14 | public static from(line: Line): LineDto { 15 | return new LineDto(line.lineNumber, line.value, line.isInfected); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /apps/web/rpc/ensureAuthenticated.ts: -------------------------------------------------------------------------------- 1 | import { WrapMethod } from 'next-rpc'; 2 | import { getSession } from 'next-auth/react'; 3 | import { getContext } from 'next-rpc/context'; 4 | 5 | export const ensureAuthenticated: WrapMethod = (method, _meta) => { 6 | return async (...args) => { 7 | const ctx = getContext(); 8 | const session = await getSession(ctx); 9 | 10 | if (!session?.user) { 11 | // TODO: How to propogate this to the client? 12 | throw new Error('You are not authenticated'); 13 | } 14 | 15 | return await method(...args); 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /libs/components/.storybook/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "emitDecoratorMetadata": true, 5 | "outDir": "" 6 | }, 7 | "files": [ 8 | "../../../node_modules/@nrwl/react/typings/styled-jsx.d.ts", 9 | "../../../node_modules/@nrwl/react/typings/cssmodule.d.ts", 10 | "../../../node_modules/@nrwl/react/typings/image.d.ts" 11 | ], 12 | "exclude": [ 13 | "../**/*.spec.ts", 14 | "../**/*.spec.js", 15 | "../**/*.spec.tsx", 16 | "../**/*.spec.jsx" 17 | ], 18 | "include": ["../src/**/*", "*.js"] 19 | } 20 | -------------------------------------------------------------------------------- /libs/shared/src/lib/EntityId.ts: -------------------------------------------------------------------------------- 1 | import { Guard } from './guard'; 2 | import { ValueObject } from './ValueObject'; 3 | 4 | type EntityIdProps = { 5 | value: string; 6 | }; 7 | 8 | export class EntityId extends ValueObject { 9 | protected constructor(props: EntityIdProps) { 10 | super(props); 11 | } 12 | 13 | public get value(): string { 14 | return this.props.value; 15 | } 16 | 17 | public static make(props: EntityIdProps): EntityId { 18 | return new this({ 19 | value: Guard.Against.nullOrWhiteSpace('value', props.value), 20 | }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /libs/domain/src/lib/ProgrammingLanguage.ts: -------------------------------------------------------------------------------- 1 | import { ValueObject } from '@codebarker/shared'; 2 | 3 | export type ProgrammingLanguageProps = { 4 | name: string; 5 | extension: string; 6 | }; 7 | 8 | export class ProgrammingLanguage extends ValueObject { 9 | public get name(): string { 10 | return this.props.name; 11 | } 12 | 13 | public get extension(): string { 14 | return this.props.extension; 15 | } 16 | 17 | public static make(props: ProgrammingLanguageProps): ProgrammingLanguage { 18 | return new ProgrammingLanguage(props); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /libs/infrastructure/src/lib/drivers/prisma/mappers/SolutionMapper.ts: -------------------------------------------------------------------------------- 1 | import { Solution, SolutionId } from '@codebarker/domain'; 2 | 3 | import { SolutionModel } from '../models/SolutionModel'; 4 | 5 | export class SolutionMapper { 6 | public static toDomain(model: SolutionModel): Solution { 7 | return Solution.make({ 8 | id: SolutionId.make({ value: model.id }), 9 | type: model.type, 10 | }); 11 | } 12 | 13 | public static toModel(entity: Solution): SolutionModel { 14 | return { 15 | id: entity.id.value, 16 | type: entity.type, 17 | }; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /libs/components/.storybook/main.js: -------------------------------------------------------------------------------- 1 | const rootMain = require('../../../.storybook/main'); 2 | 3 | module.exports = { 4 | ...rootMain, 5 | core: { ...rootMain.core, builder: 'webpack5' }, 6 | stories: [ 7 | ...rootMain.stories, 8 | '../src/**/*.stories.mdx', 9 | '../src/**/*.stories.tsx', 10 | ], 11 | addons: [...rootMain.addons, '@nrwl/react/plugins/storybook'], 12 | webpackFinal: async (config, { configType }) => { 13 | if (rootMain.webpackFinal) { 14 | config = await rootMain.webpackFinal(config, { configType }); 15 | } 16 | 17 | return config; 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /libs/domain/src/lib/vote/Vote.ts: -------------------------------------------------------------------------------- 1 | import { ValueObject } from '@codebarker/shared'; 2 | 3 | import { AnalysisType } from '../analysis/AnalysisType'; 4 | import { UserId } from '../user'; 5 | 6 | export type VoteProps = { 7 | type: AnalysisType; 8 | userId: UserId; 9 | }; 10 | 11 | export class Vote extends ValueObject { 12 | public get type(): AnalysisType { 13 | return this.props.type; 14 | } 15 | 16 | public get userId(): UserId { 17 | return this.props.userId; 18 | } 19 | 20 | public static make(props: VoteProps): Vote { 21 | return new Vote(props); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /libs/components/src/lib/buttons/Button.tsx: -------------------------------------------------------------------------------- 1 | import { Button as ChakraButton, ButtonProps } from '@chakra-ui/react'; 2 | 3 | export type ButtonVariant = 'primary' | 'secondary' | 'outline'; 4 | export type Props = React.PropsWithChildren< 5 | ButtonProps & { 6 | variant?: ButtonVariant; 7 | } 8 | >; 9 | 10 | export const Button = ({ children, variant, ...props }: Props): JSX.Element => { 11 | return ( 12 | 17 | {children} 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /libs/domain/src/lib/analysis/valueObjects/AnalysisRepositoryName.ts: -------------------------------------------------------------------------------- 1 | import { Guard, ValueObject } from '@codebarker/shared'; 2 | 3 | type AnalysisRepositoryNameProps = { 4 | value: string; 5 | }; 6 | 7 | export class AnalysisRepositoryName extends ValueObject { 8 | public get value(): string { 9 | return this.props.value; 10 | } 11 | 12 | public static make( 13 | props: AnalysisRepositoryNameProps 14 | ): AnalysisRepositoryName { 15 | Guard.Is.string('value', props.value); 16 | 17 | return new AnalysisRepositoryName(props); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /libs/infrastructure/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "**/*.test.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.tsx", 13 | "**/*.spec.tsx", 14 | "**/*.integration-spec.ts", 15 | "**/*.test.js", 16 | "**/*.spec.js", 17 | "**/*.test.jsx", 18 | "**/*.spec.jsx", 19 | "**/*.d.ts" 20 | , 21 | "tests/drivers/prisma/repositories/PrismaKataRepositoryImpl.integration-spec.ts" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /libs/components/src/lib/buttons/IconButton.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { ComponentMeta, Story } from '@storybook/react'; 4 | import { FaRegBell } from 'react-icons/fa'; 5 | 6 | import { IconButton, Props } from './IconButton'; 7 | 8 | export default { 9 | title: 'IconButton', 10 | component: IconButton, 11 | argTypes: { 12 | icon: { 13 | defaultValue: , 14 | }, 15 | }, 16 | } as ComponentMeta; 17 | 18 | const Template: Story = (args): JSX.Element => ; 19 | 20 | export const Default: Story = Template.bind({}); 21 | -------------------------------------------------------------------------------- /libs/application/tests/utils/VoteFactory.ts: -------------------------------------------------------------------------------- 1 | import { AnalysisType, UserId, Vote, VoteProps } from '@codebarker/domain'; 2 | 3 | export class VoteFactory { 4 | public static make(props?: Partial): Vote { 5 | return Vote.make({ 6 | type: AnalysisType.Agree, 7 | userId: UserId.make({ value: 'userId' }), 8 | ...props, 9 | }); 10 | } 11 | public static makeMany(amount: number): Vote[] { 12 | return Array.from({ length: amount }).map((_, i) => 13 | this.make({ 14 | userId: UserId.make({ value: 'userId-' + i }), 15 | type: AnalysisType.Agree, 16 | }) 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /libs/domain/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 3 | "sourceRoot": "libs/domain/src", 4 | "projectType": "library", 5 | "targets": { 6 | "lint": { 7 | "executor": "@nrwl/linter:eslint", 8 | "outputs": ["{options.outputFile}"], 9 | "options": { 10 | "lintFilePatterns": ["libs/domain/**/*.ts"] 11 | } 12 | }, 13 | "test": { 14 | "executor": "@nrwl/jest:jest", 15 | "outputs": ["coverage/libs/domain"], 16 | "options": { 17 | "jestConfig": "libs/domain/jest.config.ts", 18 | "passWithNoTests": true 19 | } 20 | } 21 | }, 22 | "tags": [] 23 | } 24 | -------------------------------------------------------------------------------- /libs/domain/src/lib/Content.ts: -------------------------------------------------------------------------------- 1 | import { ValueObject } from '@codebarker/shared'; 2 | 3 | import { Line } from './Line'; 4 | import { ProgrammingLanguage } from './ProgrammingLanguage'; 5 | 6 | export type ContentProps = { 7 | lines: Line[]; 8 | programmingLanguage: ProgrammingLanguage; 9 | }; 10 | 11 | export class Content extends ValueObject { 12 | public get lines(): Line[] { 13 | return this.props.lines; 14 | } 15 | 16 | public get programmingLanguage(): ProgrammingLanguage { 17 | return this.props.programmingLanguage; 18 | } 19 | 20 | public static make(props: ContentProps): Content { 21 | return new Content(props); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /libs/shared/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 3 | "sourceRoot": "libs/shared/src", 4 | "projectType": "library", 5 | "targets": { 6 | "lint": { 7 | "executor": "@nrwl/linter:eslint", 8 | "outputs": ["{options.outputFile}"], 9 | "options": { 10 | "lintFilePatterns": ["libs/shared/**/*.ts"] 11 | } 12 | }, 13 | "test": { 14 | "executor": "@nrwl/jest:jest", 15 | "outputs": ["coverage/libs/shared"], 16 | "options": { 17 | "jestConfig": "libs/shared/jest.config.ts", 18 | "passWithNoTests": true 19 | } 20 | } 21 | }, 22 | "tags": [] 23 | } 24 | -------------------------------------------------------------------------------- /apps/web-e2e/src/support/index.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands'; 18 | -------------------------------------------------------------------------------- /libs/application/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 3 | "sourceRoot": "libs/application/src", 4 | "projectType": "library", 5 | "targets": { 6 | "lint": { 7 | "executor": "@nrwl/linter:eslint", 8 | "outputs": ["{options.outputFile}"], 9 | "options": { 10 | "lintFilePatterns": ["libs/application/**/*.ts"] 11 | } 12 | }, 13 | "test": { 14 | "executor": "@nrwl/jest:jest", 15 | "outputs": ["coverage/libs/application"], 16 | "options": { 17 | "jestConfig": "libs/application/jest.config.ts", 18 | "passWithNoTests": true 19 | } 20 | } 21 | }, 22 | "tags": [] 23 | } 24 | -------------------------------------------------------------------------------- /docker-compose.test.yml: -------------------------------------------------------------------------------- 1 | version: "3.6" 2 | services: 3 | test: 4 | environment: 5 | - DATABASE_URL=mysql://root:root@db:3306/codebarker 6 | - NODE_ENV=test 7 | container_name: integration 8 | build: 9 | context: . 10 | dockerfile: Dockerfile 11 | target: test 12 | depends_on: 13 | db: 14 | condition: service_healthy 15 | db: 16 | image: mysql 17 | restart: always 18 | environment: 19 | MYSQL_DATABASE: 'codebarker' 20 | MYSQL_ROOT_PASSWORD: 'root' 21 | healthcheck: 22 | test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"] 23 | timeout: 20s 24 | retries: 10 25 | ports: 26 | - 3306:3306 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /libs/testing-utils/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 3 | "sourceRoot": "libs/testing-utils/src", 4 | "projectType": "library", 5 | "targets": { 6 | "lint": { 7 | "executor": "@nrwl/linter:eslint", 8 | "outputs": ["{options.outputFile}"], 9 | "options": { 10 | "lintFilePatterns": ["libs/testing-utils/**/*.ts"] 11 | } 12 | }, 13 | "test": { 14 | "executor": "@nrwl/jest:jest", 15 | "outputs": ["coverage/libs/testing-utils"], 16 | "options": { 17 | "jestConfig": "libs/testing-utils/jest.config.ts", 18 | "passWithNoTests": true 19 | } 20 | } 21 | }, 22 | "tags": [] 23 | } 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | 41 | .todo 42 | .env.local 43 | -------------------------------------------------------------------------------- /apps/web/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Banner'; 2 | export * from './ButtonLink'; 3 | export * from './Label'; 4 | export * from './LabeledInput'; 5 | export * from './LabeledSelect'; 6 | export * from './LabeledTextarea'; 7 | export * from './Layout'; 8 | export * from './Link'; 9 | export * from './NavLink'; 10 | export * from './Navigation'; 11 | export * from './Sidebar'; 12 | export * from './SignInModal'; 13 | export * from './Required'; 14 | export * from './Input'; 15 | export * from './ErrorMessage'; 16 | export * from './codeHighLighter'; 17 | export * from './AsyncInfo'; 18 | export * from './Table'; 19 | export { Select } from './Select'; 20 | 21 | // Page Components 22 | export * from './analyse'; 23 | -------------------------------------------------------------------------------- /libs/application/tests/utils/SubmitAnalysisRequestFactory.ts: -------------------------------------------------------------------------------- 1 | import { Smell } from '@codebarker/domain'; 2 | 3 | import { ContentDto, ISubmitAnalysisRequest } from '../../src'; 4 | import { ContentFactory } from './ContentFactory'; 5 | 6 | export class SubmitAnalysisRequestFactory { 7 | public static make( 8 | props?: Partial 9 | ): ISubmitAnalysisRequest { 10 | return { 11 | author: 'author', 12 | content: ContentDto.from(ContentFactory.make()), 13 | fileDir: 'fileDir', 14 | reason: 'reason', 15 | repositoryName: 'repositoryName', 16 | smell: Smell.ShotgunSurgery, 17 | userId: 'userId', 18 | sha: 'sha', 19 | ...props, 20 | }; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /apps/web/pages/api/getAnalysisDetails.ts: -------------------------------------------------------------------------------- 1 | import z from 'zod'; 2 | 3 | import { 4 | GetAnalysisDetailsResponse, 5 | GetAnalysisDetailsUseCase, 6 | IGetAnalysisDetailsRequest, 7 | } from '@codebarker/application'; 8 | 9 | import { ensureAuthenticated } from '../../rpc'; 10 | import { container } from '../../container'; 11 | 12 | export const config = { 13 | rpc: true, 14 | wrapMethod: ensureAuthenticated, 15 | }; 16 | 17 | const schema = z.object({ 18 | userId: z.string(), 19 | languages: z.array(z.string()), 20 | }); 21 | 22 | export const getAnalysisDetails = async ( 23 | request: IGetAnalysisDetailsRequest 24 | ): Promise => 25 | container.get(GetAnalysisDetailsUseCase).execute(schema.parse(request)); 26 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/startKataUseCase/StartKataResponse.ts: -------------------------------------------------------------------------------- 1 | import { Kata, Smell } from '@codebarker/domain'; 2 | 3 | import { ContentDto } from '../../dtos/ContentDto'; 4 | 5 | export class StartKataResponse { 6 | public readonly id: string; 7 | public readonly content: ContentDto; 8 | public readonly options: Smell[]; 9 | 10 | private constructor(id: string, content: ContentDto, options: Smell[]) { 11 | this.id = id; 12 | this.content = content; 13 | this.options = options; 14 | } 15 | 16 | public static from(kata: Kata, options: Smell[]): StartKataResponse { 17 | return new StartKataResponse( 18 | kata.id.value, 19 | ContentDto.from(kata.content), 20 | options 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /apps/web/components/ButtonLink.tsx: -------------------------------------------------------------------------------- 1 | import { ChakraProps } from '@chakra-ui/react'; 2 | import { Button, ButtonVariant } from '@codebarker/components'; 3 | import NextLink from 'next/link'; 4 | 5 | type Props = React.PropsWithChildren<{ 6 | href: string; 7 | variant?: ButtonVariant; 8 | _style?: ChakraProps; 9 | }>; 10 | 11 | export const ButtonLink = ({ 12 | href, 13 | children, 14 | variant, 15 | _style, 16 | }: Props): JSX.Element => ( 17 | 18 | 19 | 27 | 28 | 29 | ); 30 | -------------------------------------------------------------------------------- /libs/components/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "allowJs": true, 6 | "esModuleInterop": true, 7 | "allowSyntheticDefaultImports": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "strict": true, 10 | "noImplicitOverride": true, 11 | "noPropertyAccessFromIndexSignature": true, 12 | "noImplicitReturns": true, 13 | "noFallthroughCasesInSwitch": true 14 | }, 15 | "files": [], 16 | "include": [], 17 | "references": [ 18 | { 19 | "path": "./tsconfig.lib.json" 20 | }, 21 | { 22 | "path": "./tsconfig.spec.json" 23 | }, 24 | { 25 | "path": "./.storybook/tsconfig.json" 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /libs/infrastructure/src/lib/logger/LoggerLogTailImpl.ts: -------------------------------------------------------------------------------- 1 | import { Logtail } from '@logtail/node'; 2 | import { injectable } from 'inversify'; 3 | 4 | import { ILogger } from '@codebarker/application'; 5 | 6 | @injectable() 7 | export class LoggerLogTailImpl implements ILogger { 8 | private readonly _logTail = new Logtail(process.env.SOURCE_TOKEN!); 9 | 10 | public debug(msg: string): void { 11 | this._logTail.debug(msg); 12 | } 13 | 14 | public warn(msg: string): void { 15 | this._logTail.warn(msg); 16 | } 17 | 18 | public info(msg: string): void { 19 | this._logTail.info(msg); 20 | } 21 | 22 | public error(msg: string, ctx: Record = {}): void { 23 | this._logTail.error(msg, ctx as any); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /libs/components/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": ["node"] 6 | }, 7 | "files": [ 8 | "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", 9 | "../../node_modules/@nrwl/react/typings/image.d.ts" 10 | ], 11 | "exclude": [ 12 | "jest.config.ts", 13 | "**/*.spec.ts", 14 | "**/*.test.ts", 15 | "**/*.spec.tsx", 16 | "**/*.test.tsx", 17 | "**/*.spec.js", 18 | "**/*.test.js", 19 | "**/*.spec.jsx", 20 | "**/*.test.jsx", 21 | "**/*.stories.ts", 22 | "**/*.stories.js", 23 | "**/*.stories.jsx", 24 | "**/*.stories.tsx" 25 | ], 26 | "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] 27 | } 28 | -------------------------------------------------------------------------------- /libs/domain/src/lib/Smell.ts: -------------------------------------------------------------------------------- 1 | // WIll probably need to refactor this into it's own entities 2 | // Since we might want to store some more information about smells 3 | 4 | // TODO: Create script that syncs current smells to persistence 5 | export enum Smell { 6 | LongMethod = 0, 7 | LargeClass, 8 | PrimitiveObsession, 9 | LongParameterList, 10 | DataClump, 11 | RefusedBequest, 12 | SwitchStatements, 13 | TemporaryField, 14 | DivergentChange, 15 | ParallelInheritanceHierarchies, 16 | ShotgunSurgery, 17 | Comments, 18 | DuplicateCode, 19 | DataClass, 20 | DeadCode, 21 | LazyClass, 22 | SpeculativeGenerality, 23 | FeatureEnvy, 24 | InappropiateIntimacy, 25 | IncompleteLibraryClass, 26 | MessageChains, 27 | MiddleMan, 28 | } 29 | -------------------------------------------------------------------------------- /apps/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "jsx": "preserve", 5 | "allowJs": true, 6 | "esModuleInterop": true, 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "noEmit": true, 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "incremental": true, 14 | "types": [ 15 | "jest", 16 | "node" 17 | ] 18 | }, 19 | "include": [ 20 | "**/*.ts", 21 | "**/*.tsx", 22 | "**/*.js", 23 | "**/*.jsx", 24 | "next-env.d.ts", 25 | "../../libs/components/src/lib/dropdown/Dropdown.tsx" 26 | ], 27 | "exclude": [ 28 | "node_modules", 29 | "jest.config.ts" 30 | ] 31 | } -------------------------------------------------------------------------------- /apps/web/hooks/useLocalStorage.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react'; 2 | 3 | export enum LocalStorageItem { 4 | ExcludeFilter = 'cod-excludeFilter', 5 | } 6 | 7 | export function useLocalStorage( 8 | key: LocalStorageItem, 9 | defaultValue: T 10 | ): [T, (data: T) => void] { 11 | const [value, setValue] = useState(() => { 12 | let currentValue: T; 13 | 14 | try { 15 | currentValue = JSON.parse( 16 | localStorage.getItem(key) || String(defaultValue) 17 | ); 18 | } catch (error) { 19 | currentValue = defaultValue; 20 | } 21 | 22 | return currentValue; 23 | }); 24 | 25 | useEffect(() => { 26 | localStorage.setItem(key, JSON.stringify(value)); 27 | }, [value, key]); 28 | 29 | return [value, setValue]; 30 | } 31 | -------------------------------------------------------------------------------- /libs/application/src/lib/dtos/ContentDto.ts: -------------------------------------------------------------------------------- 1 | import { Content } from '@codebarker/domain'; 2 | 3 | import { LineDto } from './LineDto'; 4 | import { ProgrammingLanguageDto } from './ProgrammingLanguageDto'; 5 | 6 | export class ContentDto { 7 | public readonly lines: LineDto[]; 8 | public readonly programmingLanguage: ProgrammingLanguageDto; 9 | 10 | private constructor( 11 | lines: LineDto[], 12 | programmingLanguage: ProgrammingLanguageDto 13 | ) { 14 | this.lines = lines; 15 | this.programmingLanguage = programmingLanguage; 16 | } 17 | 18 | public static from(props: Content): ContentDto { 19 | return new ContentDto( 20 | props.lines.map(LineDto.from), 21 | ProgrammingLanguageDto.make(props.programmingLanguage) 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /apps/web/hooks/useLanguagesQueryString.ts: -------------------------------------------------------------------------------- 1 | import { useRouter } from 'next/router'; 2 | 3 | import { cast } from '@codebarker/shared'; 4 | 5 | type Props = { 6 | languages: string[]; 7 | clearQueryString: () => void; 8 | }; 9 | 10 | // https://github.com/vercel/next.js/discussions/11484#discussioncomment-60563 11 | export function useLanguagesQueryString(): Props { 12 | const { isReady, query, replace, pathname } = useRouter(); 13 | 14 | const languages = 15 | isReady && query.languages 16 | ? cast(query.languages).split(',') 17 | : ['all']; 18 | 19 | function clearQueryString(): void { 20 | replace(pathname, undefined, { 21 | shallow: true, 22 | }); 23 | } 24 | 25 | return { 26 | languages, 27 | clearQueryString, 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /libs/application/src/lib/dtos/UserDto.ts: -------------------------------------------------------------------------------- 1 | import { User, UserRole } from '@codebarker/domain'; 2 | 3 | export type UserDtoProps = { 4 | readonly id: string; 5 | readonly name: string; 6 | readonly email: string; 7 | readonly role: UserRole; 8 | }; 9 | 10 | export class UserDto { 11 | public readonly name: string; 12 | public readonly email: string; 13 | public readonly role: UserRole; 14 | 15 | private constructor(props: UserDtoProps) { 16 | this.name = props.name; 17 | this.email = props.email; 18 | this.role = props.role; 19 | } 20 | 21 | public static from(user: User): UserDto { 22 | return new UserDto({ 23 | email: user.email.value, 24 | id: user.id.value, 25 | name: user.name.value, 26 | role: user.role, 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /libs/application/src/lib/useCases/getProgrammingLanguagesUseCase/GetProgrammingLanguagesResponse.ts: -------------------------------------------------------------------------------- 1 | import { ProgrammingLanguage } from '@codebarker/domain'; 2 | 3 | import { ProgrammingLanguageDto } from '../../dtos'; 4 | 5 | export class GetProgrammingLanguagesResponse { 6 | public readonly programmingLanguages: ProgrammingLanguageDto[]; 7 | 8 | private constructor(programmingLanguages: ProgrammingLanguageDto[]) { 9 | this.programmingLanguages = programmingLanguages; 10 | } 11 | 12 | public static from( 13 | programmingLanguages: ProgrammingLanguage[] 14 | ): GetProgrammingLanguagesResponse { 15 | return new GetProgrammingLanguagesResponse( 16 | programmingLanguages.map((p) => ({ 17 | extension: p.extension, 18 | name: p.name, 19 | })) 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /libs/domain/src/lib/solution/Solution.ts: -------------------------------------------------------------------------------- 1 | import { Guard, IEntity } from '@codebarker/shared'; 2 | 3 | import { Smell } from '../Smell'; 4 | import { SolutionId } from './valueObjects'; 5 | 6 | export type SolutionProps = { 7 | id: SolutionId; 8 | type: Smell; 9 | }; 10 | 11 | export class Solution implements IEntity { 12 | private _props: SolutionProps; 13 | 14 | public get id(): SolutionId { 15 | return this._props.id; 16 | } 17 | 18 | public get type(): Smell { 19 | return this._props.type; 20 | } 21 | 22 | private constructor(props: SolutionProps) { 23 | this._props = props; 24 | } 25 | 26 | public static make(props: SolutionProps): Solution { 27 | Guard.Is.enum('type', props.type, Smell); 28 | 29 | return new Solution(props); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /libs/domain/src/lib/Line.ts: -------------------------------------------------------------------------------- 1 | import { Guard, ValueObject } from '@codebarker/shared'; 2 | 3 | type LineProps = { 4 | lineNumber: number; 5 | value: string; 6 | isInfected: boolean; 7 | }; 8 | 9 | export class Line extends ValueObject { 10 | public get lineNumber(): number { 11 | return this.props.lineNumber; 12 | } 13 | 14 | public get value(): string { 15 | return this.props.value; 16 | } 17 | 18 | public get isInfected(): boolean { 19 | return this.props.isInfected; 20 | } 21 | 22 | public static make(props: LineProps): Line { 23 | Guard.Is.number('lineNumber', props.lineNumber); 24 | Guard.Is.string('value', props.value); 25 | Guard.Is.boolean('isInfected', props.isInfected); 26 | 27 | return new Line(props); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /apps/web/pages/api/getMyAnalysisReports.ts: -------------------------------------------------------------------------------- 1 | import z from 'zod'; 2 | 3 | import { 4 | GetMyAnalysisReportsResponse, 5 | GetMyAnalysisReportsUseCase, 6 | IGetMyAnalysisReportsRequest, 7 | } from '@codebarker/application'; 8 | 9 | import { ensureAuthenticated } from '../../rpc'; 10 | import { container } from '../../container'; 11 | 12 | export const config = { 13 | rpc: true, 14 | wrapMethod: ensureAuthenticated, 15 | }; 16 | 17 | const schema = z.object({ 18 | userId: z.string(), 19 | offset: z.number(), 20 | amount: z.number().optional(), 21 | }); 22 | 23 | export const getMyAnalysisReports = async ( 24 | request: IGetMyAnalysisReportsRequest 25 | ): Promise => { 26 | return container 27 | .get(GetMyAnalysisReportsUseCase) 28 | .execute(schema.parse(request)); 29 | }; 30 | -------------------------------------------------------------------------------- /apps/web-e2e/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 3 | "sourceRoot": "apps/web-e2e/src", 4 | "projectType": "application", 5 | "targets": { 6 | "e2e": { 7 | "executor": "@nrwl/cypress:cypress", 8 | "options": { 9 | "cypressConfig": "apps/web-e2e/cypress.json", 10 | "devServerTarget": "web:serve:development" 11 | }, 12 | "configurations": { 13 | "production": { 14 | "devServerTarget": "web:serve:production" 15 | } 16 | } 17 | }, 18 | "lint": { 19 | "executor": "@nrwl/linter:eslint", 20 | "outputs": ["{options.outputFile}"], 21 | "options": { 22 | "lintFilePatterns": ["apps/web-e2e/**/*.{js,ts}"] 23 | } 24 | } 25 | }, 26 | "tags": [], 27 | "implicitDependencies": ["web"] 28 | } 29 | -------------------------------------------------------------------------------- /libs/infrastructure/src/lib/logger/DevelopmentLoggerImpl.ts: -------------------------------------------------------------------------------- 1 | import { injectable } from 'inversify'; 2 | 3 | import { ILogger } from '@codebarker/application'; 4 | 5 | @injectable() 6 | export class DevelopmentLoggerImpl implements ILogger { 7 | public debug(msg: string): void { 8 | console.debug(msg); 9 | } 10 | 11 | public warn(msg: string): void { 12 | console.warn(msg); 13 | } 14 | 15 | public info(msg: string, ctx: Record = {}): void { 16 | console.info(this.createEntry(msg, ctx)); 17 | } 18 | 19 | public error(msg: string, ctx: Record = {}): void { 20 | console.error(this.createEntry(msg, ctx)); 21 | } 22 | 23 | private createEntry(msg: string, ctx: unknown): any { 24 | return { 25 | msg, 26 | ctx: JSON.stringify(ctx, null, 2), 27 | }; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /apps/web/pages/api/getFileContentFromGithub.ts: -------------------------------------------------------------------------------- 1 | import z from 'zod'; 2 | 3 | import { 4 | GetFileContentFromGithubResponse, 5 | GetFileContentFromGithubUseCase, 6 | IGetFileContentFromGithubRequest, 7 | } from '@codebarker/application'; 8 | 9 | import { ensureAuthenticated } from '../../rpc'; 10 | import { container } from '../../container'; 11 | 12 | export const config = { 13 | rpc: true, 14 | wrapMethod: ensureAuthenticated, 15 | }; 16 | 17 | const schema = z.object({ 18 | author: z.string(), 19 | repositoryName: z.string(), 20 | fileDir: z.string(), 21 | sha: z.string().optional(), 22 | }); 23 | 24 | export const getFileContentFromGithub = async ( 25 | request: IGetFileContentFromGithubRequest 26 | ): Promise => 27 | container.get(GetFileContentFromGithubUseCase).execute(schema.parse(request)); 28 | -------------------------------------------------------------------------------- /apps/web/components/LabeledInput.tsx: -------------------------------------------------------------------------------- 1 | import { ChakraProps } from '@chakra-ui/react'; 2 | import { HTMLInputTypeAttribute } from 'react'; 3 | 4 | import { Label } from './Label'; 5 | import { Input } from './Input'; 6 | 7 | type Props = { 8 | name: string; 9 | value: string; 10 | type: HTMLInputTypeAttribute; 11 | placeholder?: string; 12 | onChange: any; 13 | _labelStyles?: ChakraProps; 14 | _styles?: ChakraProps; 15 | labelName: string; 16 | }; 17 | 18 | export const LabeledInput = ({ 19 | name, 20 | _labelStyles, 21 | labelName, 22 | ...rest 23 | }: Props): JSX.Element => { 24 | return ( 25 | 35 | ); 36 | }; 37 | -------------------------------------------------------------------------------- /libs/components/src/lib/buttons/Button.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { ComponentMeta, Story } from '@storybook/react'; 4 | 5 | import { Button, Props } from './Button'; 6 | 7 | export default { 8 | title: 'Button', 9 | component: Button, 10 | argTypes: { 11 | children: { 12 | defaultValue: 'Sign In', 13 | }, 14 | }, 15 | } as ComponentMeta; 16 | 17 | const Template: Story = (args): JSX.Element =>