first working prototype of shortly

This commit is contained in:
2023-01-12 21:18:49 -03:00
parent a897ec5f95
commit 856e01d339
34 changed files with 745 additions and 100 deletions

View File

@@ -1,15 +1,10 @@
{
"env": {
"browser": true,
"commonjs": true,
"es2021": true
},
"extends": "standard",
"overrides": [
],
"parserOptions": {
"ecmaVersion": "latest"
},
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"rules": {
"semi": ["error", "never"],
"quotes": [2, "single"],
"no-unused-vars": "error",
"@typescript-eslint/no-unused-vars": "error"
}
}

5
.gitignore vendored
View File

@@ -1,2 +1,5 @@
node_modules
yarn.lock
yarn.lock
.env
dist
yarn-error.log

1
.nvmrc Normal file
View File

@@ -0,0 +1 @@
v18.12.1

6
.prettierrc Normal file
View File

@@ -0,0 +1,6 @@
{
"trailingComma": "es5",
"tabWidth": 4,
"semi": false,
"singleQuote": true
}

View File

@@ -7,4 +7,11 @@ services:
- .:/usr/src
- /usr/src/node_modules
ports:
- "3000:3000"
- 3000:3000
mongo:
image: mongo
restart: always
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGODB_LINK: ${MONGODB_LINK}
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD}

View File

@@ -1,10 +0,0 @@
{"forbidden-ids": [
"settings",
"register",
"login",
"admin",
"franp",
"github",
"linkedin",
"add"
]}

5
nodemon.json Normal file
View File

@@ -0,0 +1,5 @@
{
"watch": ["src"],
"ext": "ts, json",
"exec": "ts-node ./src/app.ts"
}

View File

@@ -1,33 +1,44 @@
{
"name": "url-shorter",
"description": "",
"version": "1.0.0",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node src/index.js",
"dev": "nodemon src/index.js"
},
"repository": {
"type": "git",
"url": "https://github.com/monatheoctocat/my_package.git"
},
"keywords": [],
"author": "FranP-Code",
"license": "ISC",
"bugs": {
"url": "https://github.com/monatheoctocat/my_package/issues"
},
"homepage": "https://github.com/monatheoctocat/my_package",
"dependencies": {
"@fastify/jwt": "^6.5.0",
"fastify": "^4.10.2"
},
"devDependencies": {
"eslint": "^8.0.1",
"eslint-config-standard": "^17.0.0",
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-n": "^15.0.0",
"eslint-plugin-promise": "^6.0.0",
"nodemon": "^2.0.20"
}
"name": "shortly",
"description": "",
"version": "1.0.0",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node dist/app.js",
"dev": "nodemon -L src/app.ts"
},
"repository": {
"type": "git",
"url": "https://github.com/monatheoctocat/my_package.git"
},
"keywords": [],
"author": "FranP-Code",
"license": "ISC",
"bugs": {
"url": "https://github.com/monatheoctocat/my_package/issues"
},
"homepage": "https://github.com/monatheoctocat/my_package",
"dependencies": {
"@types/express": "^4.17.15",
"dotenv": "^16.0.3",
"express": "^4.18.2",
"jsonwebtoken": "^9.0.0",
"metadata-scraper": "^0.2.61",
"mongoose": "5.13.14",
"ulid": "^2.3.0"
},
"devDependencies": {
"@types/jsonwebtoken": "^9.0.0",
"@types/mongodb": "^4.0.7",
"@typescript-eslint/eslint-plugin": "^5.48.0",
"@typescript-eslint/parser": "^5.48.0",
"eslint": "^8.31.0",
"eslint-config-standard": "^17.0.0",
"eslint-plugin-n": "^15.0.0",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-unused-imports": "^2.0.0",
"nodemon": "^2.0.20",
"ts-node": "^10.9.1",
"typescript": "^4.9.4"
}
}

20
src/app.ts Normal file
View File

@@ -0,0 +1,20 @@
import express from 'express'
require('dotenv').config()
import databaseConnection from './models/dbConnection'
import signUp from './routes/signUp/signUp'
import getUser from './routes/getUser/getUser'
import addUrl from './routes/addUrl/addUrl'
import getUrl from './routes/get-url/getUrl'
const app = express()
const port = process.env.PORT || 3000
databaseConnection()
app.use('/get-user', getUser)
app.use('/sign-up', signUp)
app.use('/add-url', addUrl)
app.use('/', getUrl)
app.listen(port, () => {
console.log(`shortly on port ${port}`)
})

View File

@@ -1,19 +0,0 @@
const fastify = require('fastify')({ logger: true })
const addUrl = require('./routes/add-url')
const index = require('./routes/index')
const urlShortener = require('./routes/url-shortener')
fastify.register(index)
fastify.register(urlShortener)
fastify.register(addUrl)
const start = async () => {
try {
await fastify.listen({ port: process.env.PORT || 3000, host: '0.0.0.0' })
} catch (err) {
fastify.log.error(err)
process.exit(1)
}
}
start()

View File

@@ -0,0 +1,19 @@
const mongoose = require('mongoose')
export default function databaseConnection() {
mongoose
.connect(
`mongodb://root:${process.env.MONGO_INITDB_ROOT_PASSWORD}@${process.env.MONGODB_LINK}`,
{
serverSelectionTimeoutMS: 5000,
}
)
.catch((err: any) => console.log(err))
mongoose.connection.once('open', async () => {
console.log('DB connected')
})
mongoose.connection.once('error', (err: any) => {
console.log(err)
})
}

View File

@@ -0,0 +1,58 @@
/* eslint-disable quotes */
import { decrypt } from '../../scripts/crypto'
import generateId from '../../scripts/generateId'
import isUrl from '../../scripts/isUrl'
import removeEmptyProperties from '../../scripts/removeEmptyProperties'
import { IUrl, UrlModel } from '../schemas/Url.schema'
import { UserModel } from '../schemas/User.schema'
export async function createUrl(
data: {
id?: string
url: string
username?: string
email?: string
password: string
} & ({ username: string } | { email: string })
) {
const { id, url, username, email, password } = data
if (!isUrl(url)) {
throw new Error('url invalid')
}
if (process.env.ALLOW_DUPLICATED_LINKS !== 'true') {
const existingUrl = await UrlModel.findOne({
url,
})
if (existingUrl) {
return existingUrl
}
const user = await UserModel.findOne(
removeEmptyProperties({ id, username, email })
)
if (!user) {
throw new Error(JSON.stringify({ message: "user don't found" }))
}
if (
decrypt({ content: user.password, iv: user.crypto.iv }) === password
) {
const newUrl: IUrl = {
id: generateId(5),
url,
dateCreated: new Date(),
uploadedByUser: user.id,
}
return UrlModel.create(newUrl)
}
} else {
throw new Error(JSON.stringify({ message: "user don't found" }))
}
}
export async function getUrlById(data: { id: string }) {
const { id } = data
const url = await UrlModel.findOne({ id })
if (!url) {
throw new Error('no url')
}
return url
}

View File

@@ -0,0 +1,111 @@
/* eslint-disable quotes */
import { IUser, UserModel } from '../schemas/User.schema'
import { ulid } from 'ulid'
import { decrypt, encrypt } from '../../scripts/crypto'
import { UserRoles } from '../../utils/constants'
import removeEmptyProperties from '../../scripts/removeEmptyProperties'
export async function getUserData(
data: {
userId?: number
username?: string
email?: string
} & ({ username: string } | { email: string })
) {
return UserModel.find(removeEmptyProperties(data))
}
export async function getUserDataWithId(
data: {
username?: string
email?: string
password?: string
} & ({ username: string } | { email: string })
) {
const { username, email, password } = data
const user = await UserModel.findOne(
removeEmptyProperties({ username, email })
)
if (!user) {
throw new Error(JSON.stringify({ message: "user don't found" }))
}
if (
decrypt({
content: user.password,
iv: user.crypto.iv,
}) === password
) {
return {
id: user.id,
username: user.username,
email: user.email,
role: user.role,
}
} else {
throw new Error(JSON.stringify({ message: "password don't match" }))
}
}
export async function createUser(data: {
email: string
password: string
username: string
role: UserRoles
sponsorUid: string
firstUserPassword?: string
}) {
const { email, password, username, role, sponsorUid } = data
const { iv, content: encryptedPassword } = encrypt(password)
const ulidSeed = process.env.ULID_SEED && parseInt(process.env.ULID_SEED)
const newUser: IUser = {
id: typeof ulidSeed === 'number' ? ulid(ulidSeed) : ulid(),
dateCreated: new Date(),
email,
password: encryptedPassword,
role,
username,
crypto: { iv },
}
const existingUsername = await UserModel.countDocuments({ username })
const existingEmail = await UserModel.countDocuments({ email })
if (existingUsername || existingEmail) {
throw new Error(
JSON.stringify({
message: 'fields duplicated',
fieldsDuplicated: [
existingUsername && 'username',
existingEmail && 'email',
],
})
)
}
const firstUserCreated = !(await UserModel.count())
if (firstUserCreated) {
if (data.firstUserPassword !== process.env.FIRST_USER_PASSWORD) {
throw new Error(
JSON.stringify({
message: 'wrong first user password',
})
)
}
} else {
console.log(sponsorUid)
if (!sponsorUid) {
throw new Error(
JSON.stringify({
message: 'no sponsor user param',
})
)
}
const sponsorUser = await UserModel.findOne({ id: sponsorUid })
if (!sponsorUser) {
throw new Error(
JSON.stringify({
message: 'no sponsor user',
})
)
}
}
const userModelCreation = new UserModel(newUser)
await userModelCreation.save()
}

View File

@@ -0,0 +1,34 @@
import { model, Model, Schema } from 'mongoose'
export interface IUrl {
id: string
url: string
dateCreated: Date
uploadedByUser: string
}
export const urlSchema = new Schema<IUrl>(
{
id: {
type: String,
unique: true,
required: true,
},
url: {
type: String,
required: true,
},
dateCreated: {
type: Date,
default: new Date(),
required: true,
},
uploadedByUser: {
type: String,
required: true,
},
},
{ collection: 'url', timestamps: true }
)
export const UrlModel: Model<IUrl> = model('Url', urlSchema)

View File

@@ -0,0 +1,52 @@
import { Schema, model, Model } from 'mongoose'
import { Crypto, UserRoles } from '../../utils/constants'
export interface IUser {
id: string
username: string
email: string
password: string
dateCreated: Date
role: UserRoles
crypto: Crypto
}
export const userSchema = new Schema<IUser>(
{
id: {
type: String,
required: true,
unique: true,
},
username: {
type: String,
required: true,
unique: true,
},
email: {
type: String,
required: true,
lowercase: true,
unique: true,
},
password: {
type: String,
required: true,
},
dateCreated: {
type: Date,
default: new Date(),
required: true,
},
role: {
type: String,
required: true,
},
crypto: {
type: Object,
required: true,
},
},
{ collection: 'user', timestamps: true }
)
export const UserModel: Model<IUser> = model('User', userSchema)

View File

@@ -0,0 +1,18 @@
export default function (metaData: any) {
return `
<!DOCTYPE html>
<html>
<head>
<title>${metaData.title}</title>
<meta name="description" content="${metaData.description}">
<meta property="og:image" content="${metaData.image}">
<meta property="og:url" content="${metaData.url}">
</head>
<body>
<script>
window.location.href = "${metaData.url}";
</script>
</body>
</html>
`
}

View File

@@ -1,16 +0,0 @@
module.exports = async function (fastify, options) {
fastify.register(require('@fastify/jwt'), {
secret: 'supersecret123'
})
fastify.post('/add', (req, reply) => {
// some code
const token = fastify.jwt.sign({ abc: 123 })
console.log(token)
reply.send({ token })
})
fastify.listen({ port: 3000 }, (err) => {
if (err) throw err
})
}

View File

@@ -0,0 +1,33 @@
import { Router, Request, Response } from 'express'
import { createUrl } from '../../models/queries/Url.queries'
import checkMissingData from '../../scripts/checkMissingData'
import checkUsernameOrEmail from '../../scripts/checkUsernameOrEmail'
import mongoErrorService from '../../services/mongoErrorService'
const router = Router()
router.post('/', async (req: Request, res: Response) => {
const values = ['url', 'password']
const { url, email, username, password } = req.headers
try {
checkMissingData(values, req)
checkUsernameOrEmail(<string>username, <string>email, res)
const createdUrl = await createUrl({
email: <string>email,
password: <string>password,
url: <string>url,
username: <string>username,
})
res.status(200).json({
message: 'url created',
url: createdUrl,
})
} catch (error) {
console.log(error)
res.status(400).json({
error: mongoErrorService(error),
})
}
return
})
export default router

View File

@@ -0,0 +1,12 @@
{
"ids": [
"settings",
"register",
"login",
"admin",
"franp",
"github",
"linkedin",
"add"
]
}

View File

@@ -0,0 +1,30 @@
import { Router, Request, Response } from 'express'
import getMetaData from 'metadata-scraper'
import { getUrlById } from '../../models/queries/Url.queries'
import generateGetUrlPage from '../../pages/getUrl/generateGetUrlPage'
import mongoErrorService from '../../services/mongoErrorService'
import { ids as forbiddenIds } from './forbidden-ids.json'
const router = Router()
router.get('/:urlId', async (req: Request, res: Response) => {
const { urlId } = req.params
if (!urlId || forbiddenIds.includes(urlId)) {
res.status(400).json({
message: 'forbidden id',
})
}
try {
const { url } = await getUrlById({
id: urlId,
})
const metaData = await getMetaData(url)
res.send(generateGetUrlPage(metaData))
} catch (error) {
console.log(error)
res.status(400).json({
error: mongoErrorService(error),
})
}
})
export default router

View File

@@ -0,0 +1,30 @@
import { Router, Request, Response } from 'express'
import { getUserDataWithId } from '../../models/queries/User.queries'
import checkMissingData from '../../scripts/checkMissingData'
import checkUsernameOrEmail from '../../scripts/checkUsernameOrEmail'
import mongoErrorService from '../../services/mongoErrorService'
const router = Router()
router.get('/', async (req: Request, res: Response) => {
const values = ['password']
const { email, username, password } = req.headers
try {
checkMissingData(values, req)
checkUsernameOrEmail(<string>username, <string>email, res)
const user = await getUserDataWithId({
email: <string>email,
username: <string>username,
password: <string>password,
})
res.status(201).json({
message: 'user found',
user,
})
} catch (error) {
console.log(error)
res.status(400).json({
error: mongoErrorService(error),
})
}
})
export default router

View File

@@ -1,5 +0,0 @@
module.exports = async function (fastify, options) {
fastify.get('/', async (request, reply) => {
return { test: 'testValue' }
})
}

View File

@@ -0,0 +1,39 @@
import { Router, Request, Response } from 'express'
import { createUser } from '../../models/queries/User.queries'
import checkMissingData from '../../scripts/checkMissingData'
import mongoErrorService from '../../services/mongoErrorService'
import { UserRoles } from '../../utils/constants'
const router = Router()
router.post('/', async (req: Request, res: Response) => {
const values = ['email', 'password', 'username', 'role']
const {
email,
first_user_password,
password,
role,
sponsor_uid,
username,
} = req.headers
try {
checkMissingData(values, req)
await createUser({
email: <string>email,
password: <string>password,
username: <string>username,
role: <UserRoles>role,
sponsorUid: <string>sponsor_uid,
firstUserPassword: <string>first_user_password,
})
res.status(201).json({
message: 'user added',
})
} catch (error) {
console.log(error)
res.status(400).json({
error: mongoErrorService(error),
})
}
})
export default router

View File

@@ -1,6 +0,0 @@
module.exports = async function (fastify, options) {
fastify.get('/:id', async (request, reply) => {
const { id } = request.params
return { test: id }
})
}

View File

@@ -0,0 +1,19 @@
import { Request } from 'express'
export default function (values: string[], req: Request) {
const missingData = values.reduce((arr: string[], valueName) => {
if (!req.headers[valueName]) {
return [...arr, valueName]
} else {
return arr
}
}, [])
if (missingData.length) {
throw new Error(
JSON.stringify({
mesasage: 'no data from user',
properties: missingData,
})
)
}
}

View File

@@ -0,0 +1,10 @@
import { Response } from 'express'
export default function (username: string, email: string, res: Response) {
if (![username, email].filter((value) => value).length) {
res.status(400).json({
message: 'not username or email',
})
return
}
}

27
src/scripts/crypto.ts Normal file
View File

@@ -0,0 +1,27 @@
import crypto from 'crypto'
import { CryptoWithContent } from '../utils/constants'
const algorithm = 'aes-256-ctr'
const secretKey = <string>process.env.ENCRYPT_KEY
const iv = crypto.randomBytes(16)
export const encrypt = (text: string) => {
const cipher = crypto.createCipheriv(algorithm, secretKey, iv)
const encrypted = Buffer.concat([cipher.update(text), cipher.final()])
return {
iv: iv.toString('hex'),
content: encrypted.toString('hex'),
}
}
export const decrypt = (hash: CryptoWithContent) => {
const decipher = crypto.createDecipheriv(
algorithm,
secretKey,
Buffer.from(hash.iv, 'hex')
)
const decrpyted = Buffer.concat([
decipher.update(Buffer.from(hash.content, 'hex')),
decipher.final(),
])
return decrpyted.toString()
}

12
src/scripts/generateId.ts Normal file
View File

@@ -0,0 +1,12 @@
import { charactersForIdGeneration } from '../utils/constants'
export default function (length: number) {
let result = ''
const charactersLength = charactersForIdGeneration.length
for (let i = 0; i < length; i++) {
result += charactersForIdGeneration.charAt(
Math.floor(Math.random() * charactersLength)
)
}
return result
}

5
src/scripts/isUrl.ts Normal file
View File

@@ -0,0 +1,5 @@
import { isUrlRegex } from '../utils/constants'
export default function (url: string) {
return !!isUrlRegex.test(url)
}

View File

@@ -0,0 +1,5 @@
export default function (obj: Object) {
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
const nonEmptyEntries = Object.entries(obj).filter(([key, value]) => value)
return Object.fromEntries(nonEmptyEntries)
}

View File

@@ -0,0 +1,23 @@
import { MongoServerError } from 'mongodb'
export default function mongoErrorService(error: any) {
let responseMessage: any
if (error instanceof MongoServerError) {
switch (error.code) {
case 1:
responseMessage = '1'
break
default:
responseMessage = error.message
break
}
} else {
try {
responseMessage = JSON.parse(error.message)
} catch {
responseMessage = error
}
}
return responseMessage
}

View File

13
src/utils/constants.ts Normal file
View File

@@ -0,0 +1,13 @@
export type Crypto = {
iv: string
}
export type CryptoWithContent = {
iv: string
content: string
}
export type UserRoles = 'admin' | 'user'
export const charactersForIdGeneration =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-()!_><'
export const isUrlRegex = new RegExp(
'^(http[s]?:\\/\\/(www\\.)?|ftp:\\/\\/(www\\.)?|www\\.){1}([0-9A-Za-z-\\.@:%_+~#=]+)+((\\.[a-zA-Z]{2,3})+)(/(.)*)?(\\?(.)*)?'
)

103
tsconfig.json Normal file
View File

@@ -0,0 +1,103 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "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": "./.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": "es2016" /* 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'. */
// "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. */
// "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": "commonjs" /* Specify what module code is generated. */,
"rootDir": "./src" /* 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. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "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. */
// "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'. */
/* 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. */,
// "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. */
// "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. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "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. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "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. */,
// "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. */,
/* 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'. */
// "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. */
// "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, /* Default catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "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, /* 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. */
// "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. */
}
}