From 6ef46820f4a7466a466d6959e6a7f51ce4e225fb Mon Sep 17 00:00:00 2001
From: tfkhdyt <me@tfkhdyt.my.id>
Date: Tue, 26 Sep 2023 20:18:30 +0700
Subject: [PATCH] build: fix build

---
 .dockerignore              |   1 +
 .gitignore                 |   1 +
 Dockerfile                 |  52 +++++++++++++++-------
 bun.lockb                  | Bin 87404 -> 94510 bytes
 drizzle.config.js          |   4 ++
 fly.toml                   |  16 +++----
 package.json               |   4 +-
 src/Fetcher.ts             |   2 +-
 src/Scraper.ts             |   4 +-
 src/app.ts                 |  85 +++++++++++++++++-------------------
 src/blacklist/blacklist.ts |  12 ------
 src/main.ts                |   9 ++--
 tsconfig.json              |  86 ++++++++++++++++++-------------------
 13 files changed, 142 insertions(+), 134 deletions(-)
 create mode 100644 drizzle.config.js
 delete mode 100644 src/blacklist/blacklist.ts

diff --git a/.dockerignore b/.dockerignore
index 8ec76ca..1596d6e 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -2,3 +2,4 @@ node_modules
 dist
 .env
 .env.production
+drizzle
diff --git a/.gitignore b/.gitignore
index 8ec76ca..1596d6e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@ node_modules
 dist
 .env
 .env.production
+drizzle
diff --git a/Dockerfile b/Dockerfile
index 13f6b6c..0a24ae7 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,24 +1,46 @@
-FROM oven/bun AS builder
+# syntax = docker/dockerfile:1
 
-WORKDIR /src
+# Adjust BUN_VERSION as desired
+ARG BUN_VERSION=1.0.2
+FROM oven/bun:${BUN_VERSION} as base
 
-COPY . .
+LABEL fly_launch_runtime="Bun"
 
-ENV NODE_ENV=production
+# Bun app lives here
+WORKDIR /app
 
-RUN bun i && \
-  bun run generate && \
-  bun build --target bun --outfile dist/kbbi.js ./src/main.ts
+# Set production environment
+ENV NODE_ENV="production"
 
-FROM oven/bun
 
-WORKDIR /app
+# Throw-away build stage to reduce size of final image
+FROM base as build
+
+# Install packages needed to build node modules
+RUN apt-get update -qq && \
+  apt-get install -y build-essential pkg-config python-is-python3
+
+# Install node modules
+COPY --link bun.lockb package.json ./
+RUN bun install
+
+# Copy application code
+COPY --link . .
+
+# Build application
+RUN bun run generate
+
+# Remove development dependencies
+RUN rm -rf node_modules && \
+  bun install --ci
+
 
-COPY --from=builder /src/dist/kbbi.js /app/kbbi.js
-COPY --from=builder /src/package.json /app/package.json
-COPY --from=builder /src/bun.lockb /app/bun.lockb
-COPY --from=builder /src/drizzle /app/drizzle
+# Final stage for app image
+FROM base
 
-RUN bun i -p
+# Copy built application
+COPY --from=build /app /app
 
-ENTRYPOINT [ "bun", "run", "/app/kbbi.js" ]
+# Start the server by default, this can be overwritten at runtime
+EXPOSE 3000
+CMD [ "bun", "run", "src/main.ts" ]
diff --git a/bun.lockb b/bun.lockb
index fa6efd37d7fb2752a4a1614c2859b0238e2ac25b..3722c456cc9067ad239424adb847c01e13baf7a3 100755
GIT binary patch
delta 19121
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
HY}S7PUFCBy

delta 14457
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
KTf%%>`~L=uQEsLH

diff --git a/drizzle.config.js b/drizzle.config.js
new file mode 100644
index 0000000..967446f
--- /dev/null
+++ b/drizzle.config.js
@@ -0,0 +1,4 @@
+export default {
+    schema: './src/db/postgres/schemas/*',
+    out: './drizzle',
+};
diff --git a/fly.toml b/fly.toml
index aa29732..e10c46f 100644
--- a/fly.toml
+++ b/fly.toml
@@ -1,17 +1,17 @@
-# fly.toml app configuration file generated for kbbi-bot on 2023-09-26T17:57:06+07:00
+# fly.toml app configuration file generated for kbbi-bot-v3 on 2023-09-26T19:48:53+07:00
 #
 # See https://fly.io/docs/reference/configuration/ for information about how to use this file.
 #
 
-app = "kbbi-bot"
+app = "kbbi-bot-v3"
 primary_region = "sin"
 
 [build]
 
 [http_service]
-  internal_port = 3000
-  force_https = true
-  auto_stop_machines = true
-  auto_start_machines = true
-  min_machines_running = 0
-  processes = ["app"]
+internal_port = 8080
+force_https = true
+auto_stop_machines = false
+auto_start_machines = true
+min_machines_running = 0
+processes = ["app"]
diff --git a/package.json b/package.json
index 642a7c8..654c80e 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,7 @@
     "format": "prettier -w ./src/",
     "lint": "tsc --noEmit && eslint --fix src/",
     "build": "tsc",
-    "start": "bun run ./src/main.ts",
+    "start": "bun run dist/main.js",
     "generate": "drizzle-kit generate:pg"
   },
   "keywords": [],
@@ -23,8 +23,10 @@
     "telegraf": "^4.14.0"
   },
   "devDependencies": {
+    "@flydotio/dockerfile": "latest",
     "@typescript-eslint/eslint-plugin": "^6.7.3",
     "@typescript-eslint/parser": "^6.7.3",
+    "bun-types": "^1.0.3",
     "drizzle-kit": "^0.19.13",
     "eslint": "^8.50.0",
     "prettier": "^3.0.3",
diff --git a/src/Fetcher.ts b/src/Fetcher.ts
index 83beada..d84c8f2 100644
--- a/src/Fetcher.ts
+++ b/src/Fetcher.ts
@@ -1,4 +1,4 @@
-import config from './config/config'
+import config from './config/config.js'
 
 // fetcher class
 export class Fetcher {
diff --git a/src/Scraper.ts b/src/Scraper.ts
index 51785ff..1e0ef0d 100644
--- a/src/Scraper.ts
+++ b/src/Scraper.ts
@@ -3,7 +3,7 @@ import { load, CheerioAPI } from 'cheerio'
 // import pretty from 'pretty'
 
 // interface
-import { IPengertian } from './interfaces/result.interface'
+import { IPengertian } from './interfaces/result.interface.js'
 
 // scraper class
 export class Scraper {
@@ -30,7 +30,7 @@ export class Scraper {
 
     // get prakategorial
     this.prakategorial ??= this.$(
-      'font[title="prakategorial: kata tidak dipakai dalam bentuk dasarnya"]'
+      'font[title="prakategorial: kata tidak dipakai dalam bentuk dasarnya"]',
     )
       .next()
       .text() as string
diff --git a/src/app.ts b/src/app.ts
index b9e9b61..1bd449a 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -1,18 +1,13 @@
-import { format, isFuture } from 'date-fns'
-import { id } from 'date-fns/locale'
 import { eq, sql } from 'drizzle-orm'
-import { HttpsProxyAgent } from 'https-proxy-agent'
-import { Context, Markup, Telegraf } from 'telegraf'
-import { InlineKeyboardButton } from 'telegraf/types'
-
-import { Fetcher } from './Fetcher'
-import { Scraper } from './Scraper'
-import { blackList } from './blacklist/blacklist'
-import config from './config/config'
-import { db } from './db/postgres'
-import { User, users } from './db/postgres/schemas/user.schema'
-import { CallbackQuery } from './interfaces/callback-query.interface'
-import { IResult } from './interfaces/result.interface'
+import { Context, Telegraf } from 'telegraf'
+
+import { Fetcher } from './Fetcher.js'
+import { Scraper } from './Scraper.js'
+import config from './config/config.js'
+import { db } from './db/postgres/index.js'
+import { User, users } from './db/postgres/schemas/user.schema.js'
+import { CallbackQuery } from './interfaces/callback-query.interface.js'
+import { IResult } from './interfaces/result.interface.js'
 
 interface MyContext extends Context {
   user: User
@@ -81,12 +76,12 @@ export default class App {
     return this.result
   }
 
-  private createUrlButton(keyword: string) {
-    return Markup.button.url(
-      `📕 ${keyword.toLowerCase()}`,
-      `https://kbbi.kemdikbud.go.id/entri/${keyword.toLowerCase()}`,
-    )
-  }
+  // private createUrlButton(keyword: string) {
+  //   return Markup.button.url(
+  //     `📕 ${keyword.toLowerCase()}`,
+  //     `https://kbbi.kemdikbud.go.id/entri/${keyword.toLowerCase()}`,
+  //   )
+  // }
 
   // private createReportButton(keyword: string) {
   //   return Markup.button.callback(
@@ -95,32 +90,32 @@ export default class App {
   //   )
   // }
 
-  private createInlineKeyboard(
-    // reportBtn: InlineKeyboardButton.CallbackButton,
-    urlBtn: InlineKeyboardButton.UrlButton,
-  ) {
-    return Markup.inlineKeyboard([/* reportBtn, */ urlBtn])
-  }
+  // private createInlineKeyboard(
+  //   // reportBtn: InlineKeyboardButton.CallbackButton,
+  //   urlBtn: InlineKeyboardButton.UrlButton,
+  // ) {
+  //   return Markup.inlineKeyboard([/* reportBtn, */ urlBtn])
+  // }
 
-  checkBlackList(ctx: Context, next: () => Promise<void>) {
-    const username = ctx.message?.from.username
-    const result = blackList.find((value) => value.username === username)
-    if (!result) {
-      next()
-    } else {
-      if (isFuture(result.until)) {
-        ctx.replyWithMarkdown(
-          `*Anda telah dibanned dari bot ini!*
-Alasan: ${result.reason}
-
-Akses Anda akan dipulihkan pada: 
-*${format(result.until, 'EEEE, d MMMM yyyy HH:mm', { locale: id })}*`,
-        )
-      } else {
-        next()
-      }
-    }
-  }
+  //   checkBlackList(ctx: Context, next: () => Promise<void>) {
+  //     const username = ctx.message?.from.username
+  //     const result = blackList.find((value) => value.username === username)
+  //     if (!result) {
+  //       next()
+  //     } else {
+  //       if (isFuture(result.until)) {
+  //         ctx.replyWithMarkdown(
+  //           `*Anda telah dibanned dari bot ini!*
+  // Alasan: ${result.reason}
+  //
+  // Akses Anda akan dipulihkan pada:
+  // *${format(result.until, 'EEEE, d MMMM yyyy HH:mm', { locale: id })}*`,
+  //         )
+  //       } else {
+  //         next()
+  //       }
+  //     }
+  //   }
 
   async main(ctx: MyContext, keyword: string) {
     const html = await this.fetchData(keyword)
diff --git a/src/blacklist/blacklist.ts b/src/blacklist/blacklist.ts
deleted file mode 100644
index 68fb8f0..0000000
--- a/src/blacklist/blacklist.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-export const blackList = [
-  {
-    username: 'AzizNaufal',
-    reason: 'Spam report',
-    until: new Date('2022-03-22T09:00:00+07:00'),
-  },
-  /*{
-    username: 'tfkhdyt',
-    reason: 'Spam report',
-    until: new Date('2022-03-22T06:00:00+07:00'),
-  },*/
-]
diff --git a/src/main.ts b/src/main.ts
index 4678565..95b41c4 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -3,10 +3,10 @@ import { drizzle } from 'drizzle-orm/postgres-js'
 import { migrate } from 'drizzle-orm/postgres-js/migrator'
 import { message } from 'telegraf/filters'
 
-import App from './app'
-import config from './config/config'
-import { db, migrationClient } from './db/postgres'
-import { users } from './db/postgres/schemas/user.schema'
+import App from './app.js'
+import config from './config/config.js'
+import { db, migrationClient } from './db/postgres/index.js'
+import { users } from './db/postgres/schemas/user.schema.js'
 
 await migrate(drizzle(migrationClient), { migrationsFolder: 'drizzle' })
 
@@ -15,7 +15,6 @@ const app = new App(config.botToken)
 const bot = app.bot
 
 // middleware
-bot.use(app.checkBlackList)
 bot.use(async (ctx, next) => {
   try {
     const userId = ctx.from?.id
diff --git a/tsconfig.json b/tsconfig.json
index 7550e50..94f71d8 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,54 +1,56 @@
 {
   "compilerOptions": {
-    /* Visit https://aka.ms/tsconfig.json to read more about this file */
+    /* Visit https://aka.ms/tsconfig to read more about this file */
     /* Projects */
-    // "incremental": true,                              /* Enable incremental compilation */
+    // "incremental": true,                              /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
     // "composite": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */
-    // "tsBuildInfoFile": "./",                          /* Specify the folder for .tsbuildinfo incremental compilation files. */
-    // "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects */
+    // "tsBuildInfoFile": "./.tsbuildinfo",              /* Specify the path to .tsbuildinfo incremental compilation file. */
+    // "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects. */
     // "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */
     // "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */
     /* Language and Environment */
-    "target": "ESNext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
-    "lib": [
-      "dom"
-    ], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
+    "target": "ES2021" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
+    // "lib": [],                                        /* Specify a set of bundled library declaration files that describe the target runtime environment. */
     // "jsx": "preserve",                                /* Specify what JSX code is generated. */
     // "experimentalDecorators": true,                   /* Enable experimental support for TC39 stage 2 draft decorators. */
     // "emitDecoratorMetadata": true,                    /* Emit design-type metadata for decorated declarations in source files. */
-    // "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
+    // "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
     // "jsxFragmentFactory": "",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
-    // "jsxImportSource": "",                            /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
-    // "reactNamespace": "",                             /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
+    // "jsxImportSource": "",                            /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
+    // "reactNamespace": "",                             /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
     // "noLib": true,                                    /* Disable including any library files, including the default lib.d.ts. */
     // "useDefineForClassFields": true,                  /* Emit ECMAScript-standard-compliant class fields. */
+    // "moduleDetection": "auto",                        /* Control what method is used to detect module-format JS files. */
     /* Modules */
-    "module": "NodeNext",
-    "rootDir": "./src", /* Specify the root folder within your source files. */
-    "moduleResolution": "Bundler", /* Specify how TypeScript looks up a file from a given module specifier. */
+    "module": "ES2022" /* Specify what module code is generated. */,
+    // "rootDir": "./",                                  /* Specify the root folder within your source files. */
+    "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,
     // "baseUrl": "./",                                  /* Specify the base directory to resolve non-relative module names. */
     // "paths": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */
     // "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */
-    // "typeRoots": [],                                  /* Specify multiple folders that act like `./node_modules/@types`. */
-    // "types": [],                                      /* Specify type package names to be included without being referenced in a source file. */
+    // "typeRoots": [],                                  /* Specify multiple folders that act like './node_modules/@types'. */
+    "types": [
+      "bun-types"
+    ] /* Specify type package names to be included without being referenced in a source file. */,
     // "allowUmdGlobalAccess": true,                     /* Allow accessing UMD globals from modules. */
-    // "resolveJsonModule": true,                        /* Enable importing .json files */
-    // "noResolve": true,                                /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
+    // "moduleSuffixes": [],                             /* List of file name suffixes to search when resolving a module. */
+    // "resolveJsonModule": true,                        /* Enable importing .json files. */
+    // "noResolve": true,                                /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
     /* JavaScript Support */
-    // "allowJs": true,                                  /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
+    // "allowJs": true,                                  /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
     // "checkJs": true,                                  /* Enable error reporting in type-checked JavaScript files. */
-    // "maxNodeModuleJsDepth": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
+    // "maxNodeModuleJsDepth": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
     /* Emit */
     // "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
     // "declarationMap": true,                           /* Create sourcemaps for d.ts files. */
     // "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */
     // "sourceMap": true,                                /* Create source map files for emitted JavaScript files. */
-    // "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. */
-    "outDir": "./dist", /* Specify an output folder for all emitted files. */
+    // "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. */
+    // "outDir": "./",                                   /* Specify an output folder for all emitted files. */
     // "removeComments": true,                           /* Disable emitting comments. */
     // "noEmit": true,                                   /* Disable emitting files from a compilation. */
     // "importHelpers": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
-    // "importsNotUsedAsValues": "remove",               /* Specify emit/checking behavior for imports that are only used for types */
+    // "importsNotUsedAsValues": "remove",               /* Specify emit/checking behavior for imports that are only used for types. */
     // "downlevelIteration": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
     // "sourceRoot": "",                                 /* Specify the root path for debuggers to find the reference source code. */
     // "mapRoot": "",                                    /* Specify the location where debugger should locate map files instead of generated locations. */
@@ -56,46 +58,40 @@
     // "inlineSources": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */
     // "emitBOM": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
     // "newLine": "crlf",                                /* Set the newline character for emitting files. */
-    // "stripInternal": true,                            /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
-    // "noEmitHelpers": true,                            /* Disable generating custom helper functions like `__extends` in compiled output. */
+    // "stripInternal": true,                            /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
+    // "noEmitHelpers": true,                            /* Disable generating custom helper functions like '__extends' in compiled output. */
     // "noEmitOnError": true,                            /* Disable emitting files if any type checking errors are reported. */
-    // "preserveConstEnums": true,                       /* Disable erasing `const enum` declarations in generated code. */
+    // "preserveConstEnums": true,                       /* Disable erasing 'const enum' declarations in generated code. */
     // "declarationDir": "./",                           /* Specify the output directory for generated declaration files. */
     // "preserveValueImports": true,                     /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
     /* Interop Constraints */
     // "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */
     // "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */
-    "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
+    "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
     // "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
-    "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
+    "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
     /* Type Checking */
-    "strict": true, /* Enable all strict type-checking options. */
-    // "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied `any` type.. */
-    // "strictNullChecks": true,                         /* When type checking, take into account `null` and `undefined`. */
+    "strict": true /* Enable all strict type-checking options. */,
+    // "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied 'any' type. */
+    // "strictNullChecks": true,                         /* When type checking, take into account 'null' and 'undefined'. */
     // "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
-    // "strictBindCallApply": true,                      /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
+    // "strictBindCallApply": true,                      /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
     // "strictPropertyInitialization": true,             /* Check for class properties that are declared but not set in the constructor. */
-    // "noImplicitThis": true,                           /* Enable error reporting when `this` is given the type `any`. */
-    // "useUnknownInCatchVariables": true,               /* Type catch clause variables as 'unknown' instead of 'any'. */
+    // "noImplicitThis": true,                           /* Enable error reporting when 'this' is given the type 'any'. */
+    // "useUnknownInCatchVariables": true,               /* Default catch clause variables as 'unknown' instead of 'any'. */
     // "alwaysStrict": true,                             /* Ensure 'use strict' is always emitted. */
-    // "noUnusedLocals": true,                           /* Enable error reporting when a local variables aren't read. */
-    // "noUnusedParameters": true,                       /* Raise an error when a function parameter isn't read */
+    // "noUnusedLocals": true,                           /* Enable error reporting when local variables aren't read. */
+    // "noUnusedParameters": true,                       /* Raise an error when a function parameter isn't read. */
     // "exactOptionalPropertyTypes": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */
     // "noImplicitReturns": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */
     // "noFallthroughCasesInSwitch": true,               /* Enable error reporting for fallthrough cases in switch statements. */
-    // "noUncheckedIndexedAccess": true,                 /* Include 'undefined' in index signature results */
+    // "noUncheckedIndexedAccess": true,                 /* Add 'undefined' to a type when accessed using an index. */
     // "noImplicitOverride": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */
-    // "noPropertyAccessFromIndexSignature": true,       /* Enforces using indexed accessors for keys declared using an indexed type */
+    // "noPropertyAccessFromIndexSignature": true,       /* Enforces using indexed accessors for keys declared using an indexed type. */
     // "allowUnusedLabels": true,                        /* Disable error reporting for unused labels. */
     // "allowUnreachableCode": true,                     /* Disable error reporting for unreachable code. */
     /* Completeness */
     // "skipDefaultLibCheck": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */
     "skipLibCheck": true /* Skip type checking all .d.ts files. */
-  },
-  "include": [
-    "./src"
-  ],
-  "exclude": [
-    "./node_modules"
-  ]
+  }
 }