initial commit

This commit is contained in:
paul 2024-02-27 22:09:39 +01:00
parent f7429cb3cd
commit 100d018d3c
27 changed files with 15616 additions and 2 deletions

8
.env Normal file
View file

@ -0,0 +1,8 @@
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_TEST_PORT=5433
DATABASE_USERNAME=user
DATABASE_PASSWORD=pwd
DATABASE_NAME=database
MIGRATIONS_RUN=true
NODE_ENV=development

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
node_modules
dist

10
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,10 @@
{
"editor.formatOnSave": true,
"typescript.preferences.importModuleSpecifier": "relative",
"editor.codeActionsOnSave": [
"source.fixAll",
"source.organizeImports",
"source.addMissingImports"
],
}

View file

@ -1,2 +1,94 @@
# public-hiring-test # How to use
Technical tests for hiring software engineering @Greenly
Stack: NestJs + TypeORM + Postgres
## Requirements
- Docker / Docker Compose
- Node.js 18
## Installation
```bash
$ yarn
```
## Running the app
First you need to start, migrate and seed the db :
```bash
$ yarn init-project
```
you can then start the server:
```bash
# development
$ yarn start
# watch mode
$ yarn start:dev
```
## Test
To run unit tests:
```bash
# unit tests
$ yarn test
# e2e tests
$ yarn test:e2e
# test coverage
$ yarn test:cov
```
## Database Migration
When the data schema is updated, the database needs to be synchronised with the code. This is done by creating a migration with Typeorm using the following command:
```bash
migrationName=<name> yarn migration:generate
```
##################################################################################################################################
# Hiring Test
##################################################################################################################################
When working on the following exercise, in addition to answering the product need, to give particular attention to the following points:
- Readability
- Maintainability
- Unit testing
- Handling of corner cases
- Error-handling
We want to compute the Agrybalise carbonfootprint of a foodproduct (e.g.: a hamCheesePizza) that we characterize by its ingredients as shown below
```js
const hamCheesePizza = {
ingredients: [
{ name: "ham", quantity: 0.1, unit: "kg" },
{ name: "cheese", quantity: 0.15, unit: "kg" },
{ name: "tomato", quantity: 0.4, unit: "kg" },
{ name: "floor", quantity: 0.7, unit: "kg" },
{ name: "oliveOil", quantity: 0.3, unit: "kg" },
],
};
```
The calculation of the Agrybalise carbon footprint can be described as below:
- The Agrybalise carbon footprint of one ingredient is obtained by multiplying the quantity of the ingredient by the emission of a matching emission factor (same name and same unit).
- The carbon footprint of the food product is then obtained by summing the carbon footprint of all ingredients.
- If the carbon footprint of one ingredient cannot be calculated, then the carbon footprint of the whole product is set to null.
The tasks of this exercice are as follows:
1/ Implement the carbon footprint calculation of a product and persist the results in database.
2/ Implement a GET endpoint to retrieve the result.
3/ Implement a POST endpoint to trigger the calculation and the saving in the database.

63
config/dataSource.ts Normal file
View file

@ -0,0 +1,63 @@
import { registerAs } from "@nestjs/config";
import { config as dotenvConfig } from "dotenv";
import { join } from "path";
import { DataSource, DataSourceOptions } from "typeorm";
dotenvConfig({ path: ".env" });
const dataSourceOptions: DataSourceOptions = {
type: "postgres",
port: parseInt(
`${process.env.NODE_ENV === "test" ? process.env.DATABASE_TEST_PORT : process.env.DATABASE_PORT}`
),
username: process.env.DATABASE_USERNAME,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE_NAME,
synchronize: false,
logging: false,
entities: [join(__dirname, "../src/**/*.entity.{js,ts}")],
migrations: [join(__dirname, "../migrations", "*.*")],
migrationsTableName: "migrations",
migrationsRun: process.env.MIGRATIONS_RUN === "true",
};
export const typeorm = registerAs("typeorm", () => dataSourceOptions);
export class GreenlyDataSource {
private static dataSource: DataSource;
private static testDataSource: DataSource;
public static getInstance() {
if (process.env.NODE_ENV === "test") {
if (this.testDataSource) {
console.log(`testDataSource already set for ${process.env.NODE_ENV}`);
return this.testDataSource;
}
this.testDataSource = new DataSource(dataSourceOptions);
return this.testDataSource;
}
if (this.dataSource) {
console.log(`dataSource already set for ${process.env.NODE_ENV}`);
return this.dataSource;
}
this.dataSource = new DataSource(dataSourceOptions);
return this.dataSource;
}
public static async cleanDatabase(): Promise<void> {
try {
const entities = dataSource.entityMetadatas;
const tableNames = entities
.map((entity) => `"${entity.tableName}"`)
.join(", ");
await dataSource.query(`TRUNCATE ${tableNames} CASCADE;`);
} catch (error) {
throw new Error(`ERROR: Cleaning test database: ${error}`);
}
}
}
export const dataSource = GreenlyDataSource.getInstance();

20
docker-compose.yml Normal file
View file

@ -0,0 +1,20 @@
services:
db:
image: postgres
restart: always
environment:
POSTGRES_USER: ${DATABASE_USERNAME}
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
POSTGRES_DB: ${DATABASE_NAME}
ports:
- "${DATABASE_PORT}:5432"
db_test:
image: postgres
restart: always
environment:
POSTGRES_USER: ${DATABASE_USERNAME}
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
POSTGRES_DB: ${DATABASE_NAME}
# PGPORT
ports:
- "${DATABASE_TEST_PORT}:5432"

9
jest.json Normal file
View file

@ -0,0 +1,9 @@
{
"moduleFileExtensions": ["js", "json", "ts"],
"rootDir": "./src",
"testEnvironment": "node",
"testRegex": ".test.ts",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
}
}

View file

@ -0,0 +1,15 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class CarbonEmissionFactor1708367794381 implements MigrationInterface {
name = "CarbonEmissionFactor1708367794381";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "carbon_emission_factors" ("id" SERIAL NOT NULL, "name" character varying NOT NULL, "unit" character varying NOT NULL, "emissionCO2eInKgPerUnit" float NOT NULL, "source" character varying NOT NULL, CONSTRAINT "PK_e6a201ea58a7b4cdec0ca1c0c61" PRIMARY KEY ("id"))`
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE "carbon_emission_factors"`);
}
}

8
nest-cli.json Normal file
View file

@ -0,0 +1,8 @@
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true
}
}

113
notes.txt Normal file
View file

@ -0,0 +1,113 @@
## Sources
to integrate typeorm and generate migrations
https://dev.to/amirfakour/using-typeorm-migration-in-nestjs-with-postgres-database-3c75
Technical
- Start from a boiler plate with simple database:
-postgre /Typeorm/express//jest
```js
const carbonEmissionFactors = [
{
Name: "ham",
unit: "kg",
valueInKgCO2: 0.12,
source: "Agrybalise",
},
{
name: cheese,
unit: "kg",
valueInKgCO2: 0.12,
source: "Agrybalise",
},
{
name: tomato,
unit: "kg",
valueInKgCO2: 0.12,
source: "Agrybalise",
},
{
name: oliveOil,
unit: l,
valueInKgCO2: 0.12,
source: "Agrybalise",
},
];
```
When working on the following exercise, give particular attention to the following points:
Readability of your code
Unit Testing
Architecture and organization of your functions
Handling of corner cases and errors
Overall performance of your code
1/ Create an endpoint to compute carbonFootprint of food and persist data in database.
```js
const hamCheesePizza = {
ingredients: [
{ name: "ham", value: "2", unit: "g" },
{ name: "cheese", value: "15", unit: "g" },
{ name: "tomato", value: "4", unit: "g" },
{ name: "floor", value: "7", unit: "g" },
{ name: "oliveOil", value: "0.7", unit: "l" },
],
};
```
2/Agrybalise has updated its coefficients and we want to update accordingly our knowledge base. In order to do that, we need to develop and endpoint allowing to update and/or insert new values in our referential of emission factors.
In particular, we want to add these values:
Test Criterion for technical test:
Problem solving solution: should solve efficiently the problem
Clean code aspects: readability (naming, architecture), test
Performance of code & algorithmic
Knowledge of database
Error handling & exceptions
Test Criterion for technical test:
Clarity of explanation of approach and database
General engineering culture
Reactivity on advices & inputs
Questions:
2/
Fonction buggé
Performance
Asynchronous feature
Utiliser un ORM
Rest API
Base de donnée
Bonus:
authentification

9517
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

83
package.json Normal file
View file

@ -0,0 +1,83 @@
{
"name": "food-carbon-calculator",
"version": "0.0.1",
"description": "",
"author": "",
"private": true,
"license": "UNLICENSED",
"scripts": {
"init-project": "yarn build && yarn start-docker && yarn migration:run && yarn seed",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"start-docker": "docker-compose down --remove-orphans && docker-compose up --remove-orphans -d",
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "NODE_ENV=test jest --config ./jest.json",
"test:watch": "jest --watch --config ./jest.json",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "NODE_ENV=test jest --config ./test-e2e/jest-e2e.json",
"typeorm": "ts-node ./node_modules/typeorm/cli -d ./config/dataSource.ts",
"migration:run": "yarn build && yarn typeorm migration:run",
"migration:generate": "yarn build && yarn typeorm -- migration:generate ./src/migrations/$migrationName",
"seed": "ts-node ./src/seed-dev-data.ts"
},
"dependencies": {
"@nestjs/common": "^10.0.0",
"@nestjs/config": "^3.2.0",
"@nestjs/core": "^10.0.0",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/typeorm": "^10.0.2",
"@types/lodash": "^4.14.202",
"dotenv": "^16.4.4",
"lodash": "^4.17.21",
"pg": "^8.11.3",
"postgresql": "^0.0.1",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1",
"typeorm": "^0.3.20"
},
"devDependencies": {
"@nestjs/cli": "^10.0.0",
"@nestjs/schematics": "^10.0.0",
"@nestjs/testing": "^10.0.0",
"@types/express": "^4.17.17",
"@types/jest": "^29.5.2",
"@types/node": "^20.3.1",
"@types/supertest": "^6.0.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"eslint": "^8.42.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0",
"jest": "^29.5.0",
"prettier": "^3.0.0",
"source-map-support": "^0.5.21",
"supertest": "^6.3.3",
"ts-jest": "^29.1.0",
"ts-loader": "^9.4.3",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.1.3"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}

21
src/app.module.ts Normal file
View file

@ -0,0 +1,21 @@
import { Module } from "@nestjs/common";
import { ConfigModule, ConfigService } from "@nestjs/config";
import { TypeOrmModule } from "@nestjs/typeorm";
import { typeorm } from "../config/dataSource";
import { CarbonEmissionFactorsModule } from "./carbonEmissionFactor/carbonEmissionFactors.module";
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
load: [typeorm],
}),
TypeOrmModule.forRootAsync({
inject: [ConfigService],
useFactory: async (configService: ConfigService) =>
configService.getOrThrow("typeorm"),
}),
CarbonEmissionFactorsModule,
],
})
export class AppModule {}

View file

@ -0,0 +1,37 @@
import { GreenlyDataSource, dataSource } from "../../config/dataSource";
import { CarbonEmissionFactor } from "../carbonEmissionFactor/carbonEmissionFactor.entity";
let chickenEmissionFactor: CarbonEmissionFactor;
beforeAll(async () => {
await dataSource.initialize();
chickenEmissionFactor = new CarbonEmissionFactor({
emissionCO2eInKgPerUnit: 2.4,
unit: "kg",
name: "chicken",
source: "Agrybalise",
});
});
beforeEach(async () => {
await GreenlyDataSource.cleanDatabase();
});
describe("FoodProductEntity", () => {
describe("constructor", () => {
it("should create an emission factor", () => {
expect(chickenEmissionFactor.name).toBe("chicken");
});
it("should throw an error if the source is empty", () => {
expect(() => {
const carbonEmissionFactor = new CarbonEmissionFactor({
emissionCO2eInKgPerUnit: 2.4,
unit: "kg",
name: "chicken",
source: "",
});
}).toThrow();
});
});
});
afterAll(async () => {
await dataSource.destroy();
});

View file

@ -0,0 +1,49 @@
import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from "typeorm";
@Entity("carbon_emission_factors")
export class CarbonEmissionFactor extends BaseEntity {
@PrimaryGeneratedColumn()
id: number;
@Column({
nullable: false,
})
name: string;
@Column({
nullable: false,
})
unit: string;
@Column({
type: "float",
nullable: false,
})
emissionCO2eInKgPerUnit: number;
@Column({
nullable: false,
})
source: string;
sanitize() {
if (this.source === "") {
throw new Error("Source cannot be empty");
}
}
constructor(props: {
name: string;
unit: string;
emissionCO2eInKgPerUnit: number;
source: string;
}) {
super();
this.name = props?.name;
this.unit = props?.unit;
this.emissionCO2eInKgPerUnit = props?.emissionCO2eInKgPerUnit;
this.source = props?.source;
this.sanitize();
}
}

View file

@ -0,0 +1,30 @@
import { Body, Controller, Get, Logger, Post } from "@nestjs/common";
import { CarbonEmissionFactor } from "./carbonEmissionFactor.entity";
import { CarbonEmissionFactorsService } from "./carbonEmissionFactors.service";
import { CreateCarbonEmissionFactorDto } from "./dto/create-carbonEmissionFactor.dto";
@Controller("carbon-emission-factors")
export class CarbonEmissionFactorsController {
constructor(
private readonly carbonEmissionFactorService: CarbonEmissionFactorsService
) {}
@Get()
getCarbonEmissionFactors(): Promise<CarbonEmissionFactor[]> {
Logger.log(
`[carbon-emission-factors] [GET] CarbonEmissionFactor: getting all CarbonEmissionFactors`
);
return this.carbonEmissionFactorService.findAll();
}
@Post()
createCarbonEmissionFactors(
@Body() carbonEmissionFactors: CreateCarbonEmissionFactorDto[]
): Promise<CarbonEmissionFactor[] | null> {
``;
Logger.log(
`[carbon-emission-factors] [POST] CarbonEmissionFactor: ${carbonEmissionFactors} created`
);
return this.carbonEmissionFactorService.save(carbonEmissionFactors);
}
}

View file

@ -0,0 +1,12 @@
import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { CarbonEmissionFactor } from "./carbonEmissionFactor.entity";
import { CarbonEmissionFactorsService } from "./carbonEmissionFactors.service";
import { CarbonEmissionFactorsController } from "./carbonEmissionFactors.controller";
@Module({
imports: [TypeOrmModule.forFeature([CarbonEmissionFactor])],
providers: [CarbonEmissionFactorsService],
controllers: [CarbonEmissionFactorsController],
})
export class CarbonEmissionFactorsModule {}

View file

@ -0,0 +1,44 @@
import { GreenlyDataSource, dataSource } from "../../config/dataSource";
import { getTestEmissionFactor } from "../seed-dev-data";
import { CarbonEmissionFactor } from "./carbonEmissionFactor.entity";
import { CarbonEmissionFactorsService } from "./carbonEmissionFactors.service";
let flourEmissionFactor = getTestEmissionFactor("flour");
let hamEmissionFactor = getTestEmissionFactor("ham");
let olivedOilEmissionFactor = getTestEmissionFactor("oliveOil");
let carbonEmissionFactorService: CarbonEmissionFactorsService;
beforeAll(async () => {
await dataSource.initialize();
carbonEmissionFactorService = new CarbonEmissionFactorsService(
dataSource.getRepository(CarbonEmissionFactor)
);
});
beforeEach(async () => {
await GreenlyDataSource.cleanDatabase();
await dataSource
.getRepository(CarbonEmissionFactor)
.save(olivedOilEmissionFactor);
});
describe("CarbonEmissionFactors.service", () => {
it("should save new emissionFactors", async () => {
await carbonEmissionFactorService.save([
hamEmissionFactor,
flourEmissionFactor,
]);
const retrieveChickenEmissionFactor = await dataSource
.getRepository(CarbonEmissionFactor)
.findOne({ where: { name: "flour" } });
expect(retrieveChickenEmissionFactor?.name).toBe("flour");
});
it("should retrieve emission Factors", async () => {
const carbonEmissionFactors = await carbonEmissionFactorService.findAll();
expect(carbonEmissionFactors).toHaveLength(1);
});
});
afterAll(async () => {
await dataSource.destroy();
});

View file

@ -0,0 +1,23 @@
import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { CarbonEmissionFactor } from "./carbonEmissionFactor.entity";
import { CreateCarbonEmissionFactorDto } from "./dto/create-carbonEmissionFactor.dto";
@Injectable()
export class CarbonEmissionFactorsService {
constructor(
@InjectRepository(CarbonEmissionFactor)
private carbonEmissionFactorRepository: Repository<CarbonEmissionFactor>
) {}
findAll(): Promise<CarbonEmissionFactor[]> {
return this.carbonEmissionFactorRepository.find();
}
save(
carbonEmissionFactor: CreateCarbonEmissionFactorDto[]
): Promise<CarbonEmissionFactor[] | null> {
return this.carbonEmissionFactorRepository.save(carbonEmissionFactor);
}
}

View file

@ -0,0 +1,6 @@
export class CreateCarbonEmissionFactorDto {
name: string;
unit: string;
emissionCO2eInKgPerUnit: number;
source: string;
}

17
src/main.ts Normal file
View file

@ -0,0 +1,17 @@
import { Logger } from "@nestjs/common";
import { NestFactory } from "@nestjs/core";
import { dataSource } from "../config/dataSource";
import { AppModule } from "./app.module";
async function bootstrap() {
if (!dataSource.isInitialized) {
await dataSource.initialize();
}
const app = await NestFactory.create(AppModule, {
logger: ["error", "warn", "log"],
});
await app.listen(3000);
}
Logger.log(`Server running on http://localhost:3000`, "Bootstrap");
bootstrap();

86
src/seed-dev-data.ts Normal file
View file

@ -0,0 +1,86 @@
import { dataSource } from "../config/dataSource";
import { CarbonEmissionFactor } from "./carbonEmissionFactor/carbonEmissionFactor.entity";
export const TEST_CARBON_EMISSION_FACTORS = [
{
name: "ham",
unit: "kg",
emissionCO2eInKgPerUnit: 0.11,
source: "Agrybalise",
},
{
name: "cheese",
unit: "kg",
emissionCO2eInKgPerUnit: 0.12,
source: "Agrybalise",
},
{
name: "tomato",
unit: "kg",
emissionCO2eInKgPerUnit: 0.13,
source: "Agrybalise",
},
{
name: "flour",
unit: "kg",
emissionCO2eInKgPerUnit: 0.14,
source: "Agrybalise",
},
{
name: "blueCheese",
unit: "kg",
emissionCO2eInKgPerUnit: 0.34,
source: "Agrybalise",
},
{
name: "vinegar",
unit: "kg",
emissionCO2eInKgPerUnit: 0.14,
source: "Agrybalise",
},
{
name: "beef",
unit: "kg",
emissionCO2eInKgPerUnit: 14,
source: "Agrybalise",
},
{
name: "oliveOil",
unit: "kg",
emissionCO2eInKgPerUnit: 0.15,
source: "Agrybalise",
},
].map((args) => {
return new CarbonEmissionFactor({
name: args.name,
unit: args.unit,
emissionCO2eInKgPerUnit: args.emissionCO2eInKgPerUnit,
source: args.source,
});
});
export const getTestEmissionFactor = (name: string) => {
const emissionFactor = TEST_CARBON_EMISSION_FACTORS.find(
(ef) => ef.name === name
);
if (!emissionFactor) {
throw new Error(
`test emission factor with name ${name} could not be found`
);
}
return emissionFactor;
};
export const seedTestCarbonEmissionFactors = async () => {
if (!dataSource.isInitialized) {
await dataSource.initialize();
}
const carbonEmissionFactorsService =
dataSource.getRepository(CarbonEmissionFactor);
await carbonEmissionFactorsService.save(TEST_CARBON_EMISSION_FACTORS);
};
if (require.main === module) {
seedTestCarbonEmissionFactors().catch((e) => console.error(e));
}

View file

@ -0,0 +1,63 @@
import { INestApplication } from "@nestjs/common";
import { Test, TestingModule } from "@nestjs/testing";
import * as request from "supertest";
import { dataSource } from "../config/dataSource";
import { AppModule } from "../src/app.module";
import { CarbonEmissionFactor } from "../src/carbonEmissionFactor/carbonEmissionFactor.entity";
import { getTestEmissionFactor } from "../src/seed-dev-data";
beforeAll(async () => {
await dataSource.initialize();
});
afterAll(async () => {
await dataSource.destroy();
});
describe("CarbonEmissionFactorsController", () => {
let app: INestApplication;
let defaultCarbonEmissionFactors: CarbonEmissionFactor[];
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
await dataSource
.getRepository(CarbonEmissionFactor)
.save([getTestEmissionFactor("ham"), getTestEmissionFactor("beef")]);
defaultCarbonEmissionFactors = await dataSource
.getRepository(CarbonEmissionFactor)
.find();
});
it("GET /carbon-emission-factors", async () => {
return request(app.getHttpServer())
.get("/carbon-emission-factors")
.expect(200)
.expect(({ body }) => {
expect(body).toEqual(defaultCarbonEmissionFactors);
});
});
it("POST /carbon-emission-factors", async () => {
const carbonEmissionFactorArgs = {
name: "Test Carbon Emission Factor",
unit: "kg",
emissionCO2eInKgPerUnit: 12,
source: "Test Source",
};
return request(app.getHttpServer())
.post("/carbon-emission-factors")
.send([carbonEmissionFactorArgs])
.expect(201)
.expect(({ body }) => {
expect(body.length).toEqual(1);
expect(body[0]).toMatchObject(carbonEmissionFactorArgs);
});
});
});

9
test-e2e/jest-e2e.json Normal file
View file

@ -0,0 +1,9 @@
{
"moduleFileExtensions": ["js", "json", "ts"],
"rootDir": ".",
"testEnvironment": "node",
"testRegex": ".e2e-test.ts",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
}
}

4
tsconfig.build.json Normal file
View file

@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
}

21
tsconfig.json Normal file
View file

@ -0,0 +1,21 @@
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"target": "ES2021",
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"incremental": true,
"skipLibCheck": true,
"strictNullChecks": true,
"noImplicitAny": true,
"strictBindCallApply": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true
}
}

5252
yarn.lock Normal file

File diff suppressed because it is too large Load diff