@next-k8s/tickets 1.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. package/.dockerignore +1 -0
  2. package/CHANGELOG.md +72 -0
  3. package/Dockerfile +7 -0
  4. package/build/__mocks__/nats-client.js +12 -0
  5. package/build/app.js +31 -0
  6. package/build/events/publishers/tickets/created.js +12 -0
  7. package/build/events/publishers/tickets/updated.js +12 -0
  8. package/build/index.js +45 -0
  9. package/build/models/ticket.js +37 -0
  10. package/build/nats-client.js +42 -0
  11. package/build/routes/__test__/create.test.js +85 -0
  12. package/build/routes/__test__/find.test.js +30 -0
  13. package/build/routes/__test__/get.test.js +43 -0
  14. package/build/routes/__test__/update.test.js +95 -0
  15. package/build/routes/create.js +33 -0
  16. package/build/routes/find.js +22 -0
  17. package/build/routes/get.js +28 -0
  18. package/build/routes/index.js +10 -0
  19. package/build/routes/update.js +41 -0
  20. package/build/test/setup.js +34 -0
  21. package/build/test/utils.js +33 -0
  22. package/package.json +53 -0
  23. package/pnpm-lock.yaml +3641 -0
  24. package/src/__mocks__/nats-client.ts +10 -0
  25. package/src/app.ts +21 -0
  26. package/src/events/publishers/tickets/created.ts +7 -0
  27. package/src/events/publishers/tickets/updated.ts +7 -0
  28. package/src/index.ts +31 -0
  29. package/src/models/ticket.ts +42 -0
  30. package/src/nats-client.ts +30 -0
  31. package/src/routes/__test__/create.test.ts +83 -0
  32. package/src/routes/__test__/find.test.ts +18 -0
  33. package/src/routes/__test__/get.test.ts +34 -0
  34. package/src/routes/__test__/update.test.ts +101 -0
  35. package/src/routes/create.ts +24 -0
  36. package/src/routes/find.ts +11 -0
  37. package/src/routes/get.ts +16 -0
  38. package/src/routes/index.ts +8 -0
  39. package/src/routes/update.ts +29 -0
  40. package/src/test/setup.ts +24 -0
  41. package/src/test/utils.ts +18 -0
  42. package/tsconfig.json +101 -0
@@ -0,0 +1,10 @@
1
+ export const natsClient = {
2
+ client: {
3
+ publish: jest.fn()
4
+ .mockImplementation((subject: string, data: string, callback: () => void) => {
5
+ callback()
6
+ })
7
+ }
8
+ }
9
+
10
+ export default natsClient
package/src/app.ts ADDED
@@ -0,0 +1,21 @@
1
+ import express from 'express'
2
+ import 'express-async-errors'
3
+ import { json } from 'body-parser'
4
+ import cookieSession from 'cookie-session'
5
+
6
+ import { currentUser, errorHandler, NotFoundError } from '@next-k8s/common'
7
+ import routes from './routes'
8
+
9
+ const app = express()
10
+
11
+ app.disable('x-powered-by')
12
+ app.set('trust proxy', true)
13
+ app.use(json())
14
+ app.use(cookieSession({ signed: false, secure: process.env.NODE_ENV !== 'test' }))
15
+
16
+ app.use(currentUser)
17
+ for (const route of routes) app.use(route)
18
+ app.use('*', async (req, res) => { throw new NotFoundError() })
19
+ app.use(errorHandler)
20
+
21
+ export default app
@@ -0,0 +1,7 @@
1
+ import { Publisher, Subjects, TicketCreatedEvent } from '@next-k8s/common'
2
+
3
+ export class TicketCreatedPublisher extends Publisher<TicketCreatedEvent> {
4
+ readonly subject = Subjects.TicketCreated
5
+ }
6
+
7
+ export default TicketCreatedPublisher
@@ -0,0 +1,7 @@
1
+ import { Publisher, Subjects, TicketUpdatedEvent } from '@next-k8s/common'
2
+
3
+ export class TicketUpdatedPublisher extends Publisher<TicketUpdatedEvent> {
4
+ readonly subject = Subjects.TicketUpdated
5
+ }
6
+
7
+ export default TicketUpdatedPublisher
package/src/index.ts ADDED
@@ -0,0 +1,31 @@
1
+ import mongoose from 'mongoose'
2
+
3
+ import natsClient from './nats-client'
4
+ import app from './app'
5
+
6
+ const start = async () => {
7
+ if (!process.env.JWT_KEY) throw new Error('JWT_KEY is undefined')
8
+ if (!process.env.MONGO_URI) throw new Error('MONGO_URI is undefined')
9
+ if (!process.env.NATS_URL) throw new Error('NATS_URL is undefined')
10
+ if (!process.env.NATS_CLUSTER_ID) throw new Error('NATS_CLUSTER_ID is undefined')
11
+ if (!process.env.NATS_CLIENT_ID) throw new Error('NATS_CLIENT_ID is undefined')
12
+
13
+ await natsClient.connect(process.env.NATS_CLUSTER_ID, process.env.NATS_CLIENT_ID, process.env.NATS_URL)
14
+
15
+ natsClient.client.on('close', () => {
16
+ if (!process.env.NODE_ENV?.includes('test')) console.log('NATS connection closed')
17
+ process.exit()
18
+ })
19
+
20
+ process.on('SIGINT', () => natsClient.client.close())
21
+ process.on('SIGTERM', () => natsClient.client.close())
22
+
23
+ await mongoose.connect(process.env.MONGO_URI)
24
+ console.log('Database connected!')
25
+ const port = process.env.PORT || 3000
26
+ app.listen(port, () => {
27
+ console.log('Service running on port:', port)
28
+ })
29
+ }
30
+
31
+ start()
@@ -0,0 +1,42 @@
1
+ import mongoose from 'mongoose'
2
+
3
+ interface TicketAttributes {
4
+ title: String;
5
+ price: Number;
6
+ owner: String;
7
+ createdAt?: Date;
8
+ updatedAt?: Date;
9
+ }
10
+
11
+ const ticketSchema = new mongoose.Schema({
12
+ title: {
13
+ type: String,
14
+ required: true
15
+ },
16
+
17
+ price: {
18
+ type: Number,
19
+ required: true
20
+ },
21
+
22
+ owner: {
23
+ type: String,
24
+ required: true
25
+ }
26
+ }, {
27
+ toJSON: {
28
+ versionKey: false,
29
+ transform (doc, ret) {
30
+ ret.id = ret._id
31
+ delete ret._id
32
+ delete ret.password
33
+ }
34
+ }
35
+ })
36
+
37
+ export const TicketModel = mongoose.model('Ticket', ticketSchema)
38
+ export default class Ticket extends TicketModel {
39
+ constructor(attributes: TicketAttributes) {
40
+ super(attributes)
41
+ }
42
+ }
@@ -0,0 +1,30 @@
1
+ import type { Stan } from 'node-nats-streaming'
2
+ import nats from 'node-nats-streaming'
3
+
4
+ class NatsClient {
5
+ private _client?: Stan
6
+
7
+ get client () {
8
+ if (!this._client) throw new Error('Cannot access NATS client before connecting')
9
+ return this._client
10
+ }
11
+
12
+ async connect (clusterId: string, clientId: string, url: string) {
13
+ this._client = nats.connect(clusterId, clientId, { url })
14
+
15
+ return new Promise<void>((resolve, reject) => {
16
+ this.client.on('connect', () => {
17
+ if (!process.env.NODE_ENV?.includes('test')) console.log('Connected to NATS')
18
+ resolve()
19
+ })
20
+
21
+ this.client.on('error', (err: any) => {
22
+ console.error(err)
23
+ reject(err)
24
+ })
25
+ })
26
+ }
27
+ }
28
+
29
+ export const natsClient = new NatsClient()
30
+ export default natsClient
@@ -0,0 +1,83 @@
1
+ import request from 'supertest'
2
+ import app from '../../app'
3
+ import Ticket from '../../models/ticket'
4
+ import natsClient from '../../nats-client'
5
+ import { createTicket, getTokenCookie } from '../../test/utils'
6
+
7
+ // const createTicket = (cookie?: string, title = 'Test Event', price = 20000, expectedStatusCode = 201) => {
8
+ // return request(app)
9
+ // .post('/api/tickets')
10
+ // .set('Cookie', cookie ? [cookie] : [])
11
+ // .send({ title, price })
12
+ // .expect(expectedStatusCode)
13
+ // }
14
+
15
+ describe('[Create New Ticket] Route: /api/tickets', () => {
16
+ it('should be a valid route', async () => {
17
+ const response = await request(app).post('/api/tickets').send({})
18
+ expect(response.status).not.toEqual(404)
19
+ })
20
+
21
+ it('should throw UnauthorizedError if unauthenticated', async () => {
22
+ const response = await request(app).post('/api/tickets').send({})
23
+ expect(response.status).toEqual(401)
24
+ })
25
+
26
+ it('should not get UnauthorizedError if authenticated', async () => {
27
+ const cookie = await getTokenCookie()
28
+ const response = await request(app)
29
+ .post('/api/tickets')
30
+ .set('Cookie', [cookie])
31
+ .send({})
32
+
33
+ expect(response.status).not.toEqual(401)
34
+ })
35
+
36
+ it('should throw error if new ticket has invalid title', async () => {
37
+ const cookie = await getTokenCookie()
38
+ await request(app)
39
+ .post('/api/tickets')
40
+ .set('Cookie', [cookie])
41
+ .send({ title: '', price: 10 })
42
+ .expect(400)
43
+ })
44
+
45
+ it('should throw error if new ticket has invalid price', async () => {
46
+ const cookie = await getTokenCookie()
47
+ await request(app)
48
+ .post('/api/tickets')
49
+ .set('Cookie', [cookie])
50
+ .send({ title: 'Test Event', price: -10 })
51
+ .expect(400)
52
+
53
+ await request(app)
54
+ .post('/api/tickets')
55
+ .set('Cookie', [cookie])
56
+ .send({ title: 'Test Event' })
57
+ .expect(400)
58
+ })
59
+
60
+ it('should create a new ticket', async () => {
61
+ let tickets = await Ticket.find({})
62
+ const cookie = await getTokenCookie()
63
+
64
+ await request(app)
65
+ .post('/api/tickets')
66
+ .set('Cookie', [cookie])
67
+ .send({
68
+ title: 'Test Event',
69
+ price: 20000
70
+ })
71
+
72
+ tickets = await Ticket.find({})
73
+ expect(tickets.length).toEqual(1)
74
+ expect(tickets[0].title).toEqual('Test Event')
75
+ expect(tickets[0].price).toEqual(20000)
76
+ })
77
+
78
+ it('should publish a ticket:created event', async () => {
79
+ const cookie = await getTokenCookie()
80
+ await createTicket(app, cookie)
81
+ expect(natsClient.client.publish).toHaveBeenCalled()
82
+ })
83
+ })
@@ -0,0 +1,18 @@
1
+ import request from 'supertest'
2
+ import app from '../../app'
3
+ import { createTicket, getTokenCookie } from '../../test/utils'
4
+
5
+ describe('[List Tickets] Route: /api/tickets', () => {
6
+ it('should return a list of tickets', async () => {
7
+ const cookie = await getTokenCookie()
8
+ await createTicket(app, cookie)
9
+ await createTicket(app, cookie, 'Test Event 2', 40000)
10
+ const list = await request(app)
11
+ .get('/api/tickets')
12
+ .send()
13
+ .expect(200)
14
+
15
+ expect(list.body.tickets).toBeDefined()
16
+ expect(list.body.tickets.length).toEqual(2)
17
+ })
18
+ })
@@ -0,0 +1,34 @@
1
+ import request from 'supertest'
2
+ import mongoose from 'mongoose'
3
+ import app from '../../app'
4
+ import { createTicket, getTokenCookie } from '../../test/utils'
5
+
6
+ describe('[Get Ticket] Route: /api/tickets/:id', () => {
7
+ it('should throw a BadRequestError if ticket ID is invalid', async () => {
8
+ await request(app)
9
+ .get('/api/tickets/notarealid')
10
+ .send()
11
+ .expect(400)
12
+ })
13
+
14
+ it('should throw a NotFoundError if ticket not found', async () => {
15
+ const id = new mongoose.Types.ObjectId().toHexString()
16
+ await request(app)
17
+ .get(`/api/tickets/${id}`)
18
+ .send()
19
+ .expect(404)
20
+ })
21
+
22
+ it('should return the fetched ticket', async () => {
23
+ const cookie = await getTokenCookie()
24
+ const response = await createTicket(app, cookie)
25
+
26
+ const ticket = await request(app)
27
+ .get(`/api/tickets/${response.body.ticket.id}`)
28
+ .send()
29
+ .expect(200)
30
+
31
+ expect(ticket.body.ticket.title).toEqual('Test Event')
32
+ expect(ticket.body.ticket.price).toEqual(20000)
33
+ })
34
+ })
@@ -0,0 +1,101 @@
1
+ import request from 'supertest'
2
+ import mongoose from 'mongoose'
3
+
4
+ import app from '../../app'
5
+ import { createTicket, getTokenCookie } from '../../test/utils'
6
+ import natsClient from '../../nats-client'
7
+
8
+ describe('[Update Ticket] Route: /api/tickets/:id', () => {
9
+ it('should throw a NotFoundError if the ticket does not exist', async () => {
10
+ const id = new mongoose.Types.ObjectId().toHexString()
11
+ const cookie = await getTokenCookie()
12
+
13
+ await request(app)
14
+ .put(`/api/tickets/${id}`)
15
+ .set('Cookie', [cookie])
16
+ .send({ title: 'Test Event', price: 23000 })
17
+ .expect(404)
18
+ })
19
+
20
+ it('should throw an UnauthorizedError if not authenticated', async () => {
21
+ const cookie = await getTokenCookie()
22
+
23
+ const response = await request(app)
24
+ .post(`/api/tickets`)
25
+ .set('Cookie', [cookie])
26
+ .send({ title: 'Test Event', price: 20000 })
27
+ .expect(201)
28
+
29
+ await request(app)
30
+ .put(`/api/tickets/${response.body.ticket.id}`)
31
+ .send({ title: 'Test Event', price: 23000 })
32
+ .expect(401)
33
+ })
34
+
35
+ it('should throw an UnauthorizedError if user does not own the ticket', async () => {
36
+ const cookie = await getTokenCookie()
37
+
38
+ const response = await request(app)
39
+ .post(`/api/tickets`)
40
+ .set('Cookie', [cookie])
41
+ .send({ title: 'Test Event', price: 20000 })
42
+ .expect(201)
43
+
44
+ const newCookie = await getTokenCookie()
45
+
46
+ await request(app)
47
+ .put(`/api/tickets/${response.body.ticket.id}`)
48
+ .set('Cookie', [newCookie])
49
+ .send({ title: 'Test Event', price: 23000 })
50
+ .expect(401)
51
+ })
52
+
53
+ it('should throw a BadRequestError if an invalid ticket is provided', async () => {
54
+ const cookie = await getTokenCookie()
55
+
56
+ await request(app)
57
+ .put(`/api/tickets/notarealid`)
58
+ .set('Cookie', [cookie])
59
+ .send({ title: 'Test Event', price: 20000 })
60
+ .expect(400)
61
+ })
62
+
63
+ it('should throw an error on invalid ticket data', async () => {
64
+ const cookie = await getTokenCookie()
65
+ const response = await createTicket(app, cookie)
66
+
67
+ await request(app)
68
+ .put(`/api/tickets/${response.body.ticket.id}`)
69
+ .set('Cookie', [cookie])
70
+ .send({ title: '', price: 23000 })
71
+ .expect(400)
72
+
73
+ await request(app)
74
+ .put(`/api/tickets/${response.body.ticket.id}`)
75
+ .set('Cookie', [cookie])
76
+ .send({ title: 'Test Event 2', price: -33 })
77
+ .expect(400)
78
+ })
79
+
80
+ it('should update a ticket', async () => {
81
+ const cookie = await getTokenCookie()
82
+ const response = await createTicket(app, cookie)
83
+
84
+ const updated = await request(app)
85
+ .put(`/api/tickets/${response.body.ticket.id}`)
86
+ .set('Cookie', [cookie])
87
+ .send({ title: 'New Event', price: 23000 })
88
+ .expect(200)
89
+
90
+ const ticket = await request(app).get(`/api/tickets/${response.body.ticket.id}`).send()
91
+
92
+ expect(ticket.body.ticket.title).toEqual('New Event')
93
+ expect(ticket.body.ticket.price).toEqual(23000)
94
+ })
95
+
96
+ it('should publish a ticket:updated event', async () => {
97
+ const cookie = await getTokenCookie()
98
+ await createTicket(app, cookie)
99
+ expect(natsClient.client.publish).toHaveBeenCalled()
100
+ })
101
+ })
@@ -0,0 +1,24 @@
1
+ import express, { Request, Response } from 'express'
2
+ import { body } from 'express-validator'
3
+ import { requireAuth, validateRequest } from '@next-k8s/common'
4
+
5
+ import Ticket from '../models/ticket'
6
+ import { TicketCreatedPublisher } from '../events/publishers/tickets/created'
7
+ import natsClient from '../nats-client'
8
+
9
+ const router = express.Router()
10
+
11
+ const validateInput = [
12
+ body('title').not().isEmpty().withMessage('Title is required'),
13
+ body('price').isInt({ gt: -1, lt: Number.MAX_SAFE_INTEGER }).withMessage('Price must be an integer of cents or units')
14
+ ]
15
+
16
+ router.post('/api/tickets', requireAuth, validateInput, validateRequest, async (req: Request, res: Response) => {
17
+ const { title, price } = req.body
18
+ const ticket = new Ticket({ title, price, owner: req.currentUser!.id })
19
+ await ticket.save()
20
+ new TicketCreatedPublisher(natsClient.client).publish({ id: ticket.id, title: ticket.title, price: ticket.price, owner: ticket.owner })
21
+ res.status(201).send({ ticket })
22
+ })
23
+
24
+ export default router
@@ -0,0 +1,11 @@
1
+ import express, { Request, Response } from 'express'
2
+ import Ticket from '../models/ticket'
3
+
4
+ const router = express.Router()
5
+
6
+ router.get('/api/tickets', async (req: Request, res: Response) => {
7
+ const tickets = await Ticket.find({})
8
+ res.send({ tickets })
9
+ })
10
+
11
+ export default router
@@ -0,0 +1,16 @@
1
+ import { BadRequestError, NotFoundError } from '@next-k8s/common'
2
+ import express, { Request, Response } from 'express'
3
+ import { isValidObjectId } from 'mongoose'
4
+
5
+ import Ticket from '../models/ticket'
6
+
7
+ const router = express.Router()
8
+
9
+ router.get('/api/tickets/:id', async (req: Request, res: Response) => {
10
+ if (!isValidObjectId(req.params.id)) throw new BadRequestError('Invalid Ticket ID')
11
+ const ticket = await Ticket.findById(req.params.id)
12
+ if (!ticket) throw new NotFoundError()
13
+ res.json({ ticket })
14
+ })
15
+
16
+ export default router
@@ -0,0 +1,8 @@
1
+ import express, { Request, Response } from 'express'
2
+
3
+ import getTicket from './get'
4
+ import findTickets from './find'
5
+ import createTicket from './create'
6
+ import updateTicket from './update'
7
+
8
+ export default [findTickets, getTicket, createTicket, updateTicket]
@@ -0,0 +1,29 @@
1
+ import { BadRequestError, NotFoundError, UnauthorizedError, validateRequest, requireAuth } from '@next-k8s/common'
2
+ import express, { Request, Response } from 'express'
3
+ import { body } from 'express-validator'
4
+ import { isValidObjectId } from 'mongoose'
5
+
6
+ import Ticket from '../models/ticket'
7
+ import TicketUpdatedPublisher from '../events/publishers/tickets/updated'
8
+ import natsClient from '../nats-client'
9
+
10
+ const router = express.Router()
11
+
12
+ const validateInput = [
13
+ body('title').not().isEmpty().withMessage('Title is required'),
14
+ body('price').isInt({ gt: -1, lt: Number.MAX_SAFE_INTEGER }).withMessage('Price must be an integer of cents or units')
15
+ ]
16
+
17
+ router.put('/api/tickets/:id', requireAuth, validateInput, validateRequest, async (req: Request, res: Response) => {
18
+ if (!isValidObjectId(req.params.id)) throw new BadRequestError('Invalid Ticket ID')
19
+ const ticket = await Ticket.findById(req.params.id)
20
+ if (!ticket) throw new NotFoundError()
21
+ if (ticket.owner !== req.currentUser!.id) throw new UnauthorizedError()
22
+ const { title, price } = req.body
23
+ ticket.set({ title, price })
24
+ await ticket.save()
25
+ await new TicketUpdatedPublisher(natsClient.client).publish({ id: ticket.id, title: ticket.title, price: ticket.price, owner: ticket.owner })
26
+ res.json(ticket)
27
+ })
28
+
29
+ export default router
@@ -0,0 +1,24 @@
1
+ import { MongoMemoryServer } from 'mongodb-memory-server'
2
+ import mongoose from 'mongoose'
3
+
4
+ jest.mock('../nats-client.ts')
5
+
6
+ let mongo: any
7
+ process.env.JWT_KEY = '!SuperSecretDevToken!'
8
+
9
+ beforeAll(async () => {
10
+ mongo = await MongoMemoryServer.create()
11
+ const uri = await mongo.getUri()
12
+ await mongoose.connect(uri)
13
+ })
14
+
15
+ beforeEach(async () => {
16
+ jest.clearAllMocks()
17
+ const collections = await mongoose.connection.db.collections()
18
+ for (const collection of collections) await collection.deleteMany({})
19
+ })
20
+
21
+ afterAll(async () => {
22
+ await mongoose.connection.close()
23
+ await mongo.stop()
24
+ })
@@ -0,0 +1,18 @@
1
+ import jwt from 'jsonwebtoken'
2
+ import mongoose from 'mongoose'
3
+ import request from 'supertest'
4
+
5
+ export const getTokenCookie = async () => {
6
+ const payload = { id: new mongoose.Types.ObjectId().toHexString(), email: 'test@test.com' }
7
+ const token = jwt.sign(payload, process.env.JWT_KEY!)
8
+ const cookie = Buffer.from(JSON.stringify({ jwt: token })).toString('base64')
9
+ return `session=${cookie}`
10
+ }
11
+
12
+ export const createTicket = (app: Express.Application, cookie?: string, title = 'Test Event', price = 20000, expectedStatusCode = 201) => {
13
+ return request(app)
14
+ .post('/api/tickets')
15
+ .set('Cookie', cookie ? [cookie] : [])
16
+ .send({ title, price })
17
+ .expect(expectedStatusCode)
18
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,101 @@
1
+ {
2
+ "compilerOptions": {
3
+ /* Visit https://aka.ms/tsconfig.json to read more about this file */
4
+
5
+ /* Projects */
6
+ // "incremental": true, /* Enable incremental compilation */
7
+ // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
8
+ // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
9
+ // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
10
+ // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
11
+ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
12
+
13
+ /* Language and Environment */
14
+ "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
15
+ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
16
+ // "jsx": "preserve", /* Specify what JSX code is generated. */
17
+ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
18
+ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
19
+ // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
20
+ // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
21
+ // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
22
+ // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
23
+ // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
24
+ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
25
+
26
+ /* Modules */
27
+ "module": "commonjs", /* Specify what module code is generated. */
28
+ // "rootDir": "./", /* Specify the root folder within your source files. */
29
+ // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
30
+ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
31
+ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
32
+ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
33
+ "typeRoots": ["./src/types", "./node_modules/@types"], /* Specify multiple folders that act like `./node_modules/@types`. */
34
+ // "types": [], /* Specify type package names to be included without being referenced in a source file. */
35
+ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
36
+ // "resolveJsonModule": true, /* Enable importing .json files */
37
+ // "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
38
+
39
+ /* JavaScript Support */
40
+ // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
41
+ // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
42
+ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
43
+
44
+ /* Emit */
45
+ // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
46
+ // "declarationMap": true, /* Create sourcemaps for d.ts files. */
47
+ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
48
+ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
49
+ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
50
+ "outDir": "./build", /* Specify an output folder for all emitted files. */
51
+ // "removeComments": true, /* Disable emitting comments. */
52
+ // "noEmit": true, /* Disable emitting files from a compilation. */
53
+ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
54
+ // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
55
+ // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
56
+ // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
57
+ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
58
+ // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
59
+ // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
60
+ // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
61
+ // "newLine": "crlf", /* Set the newline character for emitting files. */
62
+ // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
63
+ // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
64
+ // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
65
+ // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
66
+ // "declarationDir": "./", /* Specify the output directory for generated declaration files. */
67
+ // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
68
+
69
+ /* Interop Constraints */
70
+ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
71
+ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
72
+ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
73
+ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
74
+ "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
75
+
76
+ /* Type Checking */
77
+ "strict": true, /* Enable all strict type-checking options. */
78
+ // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
79
+ // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
80
+ // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
81
+ // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
82
+ // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
83
+ // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
84
+ // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
85
+ // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
86
+ // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
87
+ // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
88
+ // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
89
+ // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
90
+ // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
91
+ // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
92
+ // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
93
+ // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
94
+ // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
95
+ // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
96
+
97
+ /* Completeness */
98
+ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
99
+ "skipLibCheck": true /* Skip type checking all .d.ts files. */
100
+ }
101
+ }