From 6624354417b2db251f7a15f280da1eb869ae98b5 Mon Sep 17 00:00:00 2001 From: Demian Parkhomenko <95881717+DemianParkhomenko@users.noreply.github.com> Date: Sun, 1 Oct 2023 16:26:56 +0300 Subject: [PATCH] Add typescript and fix errors --- .github/workflows/dev.yml | 4 +-- .lintstagedrc.js | 5 +++ api/user.js | 2 +- global.d.ts | 25 +++++++++++++++ lib/db/crud.js | 58 +++++++++++++++++++---------------- lib/db/start.js | 3 -- lib/framework/fastify/http.js | 5 +-- lib/framework/headers.js | 8 ----- lib/framework/native/http.js | 9 ++++-- lib/logger/pino.js | 13 +++++--- lib/logger/winston.js | 8 ++--- lib/main.js | 2 +- lib/static/server.js | 4 +++ package.json | 15 ++++----- tsconfig.json | 27 +++++++++++----- 15 files changed, 118 insertions(+), 70 deletions(-) create mode 100644 .lintstagedrc.js create mode 100644 global.d.ts delete mode 100644 lib/framework/headers.js diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index d45d33a..3cc9a43 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -41,8 +41,8 @@ jobs: node-version: '20.x' cache: 'npm' - run: npm ci - - run: npm run format:check - - run: npm run lint:check + - run: npm run prettier:check + - run: npm run eslint:check - run: npm run test deploy: runs-on: ubuntu-latest diff --git a/.lintstagedrc.js b/.lintstagedrc.js new file mode 100644 index 0000000..7b27d47 --- /dev/null +++ b/.lintstagedrc.js @@ -0,0 +1,5 @@ +module.exports = { + '*': 'prettier --check --ignore-unknown', + '*.js': 'eslint --cache', + '*.{js,ts}': () => 'npm run typescript:check', +}; diff --git a/api/user.js b/api/user.js index 22afba7..ce22748 100644 --- a/api/user.js +++ b/api/user.js @@ -2,6 +2,6 @@ ...crud('user'), read: async () => { console.warn('🚨 This is a warning'); - return await await db.user.findMany(); + return await db.user.findMany(); }, }); diff --git a/global.d.ts b/global.d.ts new file mode 100644 index 0000000..9670bdd --- /dev/null +++ b/global.d.ts @@ -0,0 +1,25 @@ +import Prisma from '@prisma/client'; + +type ModelName = 'user' | 'message' | 'chat'; + +type PrismaModels = { + user: Prisma.User; + message: Prisma.Message; + chat: Prisma.Chat; +}; + +interface Crud { + ( + modelName: T + ): { + read(id?: number): Promise; + create(record: PrismaModels[T]): Promise; + update(id: number, record: Partial): PrismaModels[T]; + delete(id: number): PrismaModels[T]; + }; +} + +declare global { + const db: Prisma.PrismaClient; + const crud: Crud; +} diff --git a/lib/db/crud.js b/lib/db/crud.js index 5c14c81..5f59809 100644 --- a/lib/db/crud.js +++ b/lib/db/crud.js @@ -1,35 +1,41 @@ +// @ts-nocheck const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); -const crud = (model) => ({ - async read(id) { - if (!id) { - return await prisma[model].findMany(); - } - return prisma[model].findUnique({ - where: { id }, - }); - }, +const crud = (modelName) => { + const model = prisma[modelName]; + if (!model) { + throw new Error(`Model ${modelName} does not exist`); + } - async create(record) { - return prisma[model].create({ - data: record, - }); - }, + return { + async create(record) { + return await model.create({ + data: record, + }); + }, - async update(id, record) { - return prisma[model].update({ - where: { id }, - data: record, - }); - }, + async read(id) { + if (!id) return await model.findMany(); + return await model.findUnique({ + where: { id }, + }); + }, - async delete(id) { - return prisma[model].delete({ - where: { id }, - }); - }, -}); + async update(id, record) { + return await model.update({ + where: { id }, + data: record, + }); + }, + + async delete(id) { + return await model.delete({ + where: { id }, + }); + }, + }; +}; module.exports = crud; diff --git a/lib/db/start.js b/lib/db/start.js index 2ec0547..7850ead 100644 --- a/lib/db/start.js +++ b/lib/db/start.js @@ -1,8 +1,5 @@ 'use strict'; -/** - * @typedef { import("@prisma/client").User} User - */ const { PrismaClient } = require('@prisma/client'); const start = async (config) => { diff --git a/lib/framework/fastify/http.js b/lib/framework/fastify/http.js index 1423f5a..76a7673 100644 --- a/lib/framework/fastify/http.js +++ b/lib/framework/fastify/http.js @@ -2,7 +2,6 @@ const fastify = require('fastify')({ logger: false, }); const cors = require('@fastify/cors'); -const { HEADERS } = require('../headers.js'); const start = require('./start.js'); const setup = async (routing) => { @@ -17,6 +16,8 @@ const setup = async (routing) => { if (!entity) return reply.code(404).send('Not found'); const handler = entity[methodName]; if (!handler) return reply.code(404).send('Not found'); + if (!Array.isArray(request.body)) + return reply.code(400).send('Bad request'); const result = await handler(...request.body); reply.code(200).send(result); }); @@ -25,7 +26,7 @@ const setup = async (routing) => { }; module.exports = async (routing, port) => { - await fastify.register(cors, HEADERS); + await fastify.register(cors); await setup(routing); await start(fastify, port, console); console.log('Fastify HTTP 🔌'); diff --git a/lib/framework/headers.js b/lib/framework/headers.js deleted file mode 100644 index e507e69..0000000 --- a/lib/framework/headers.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - HEADERS: { - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'POST, OPTIONS', - 'Access-Control-Allow-Headers': 'Content-Type', - 'Access-Control-Max-Age': 600, - }, -}; diff --git a/lib/framework/native/http.js b/lib/framework/native/http.js index fcb2707..b45a0d4 100644 --- a/lib/framework/native/http.js +++ b/lib/framework/native/http.js @@ -1,7 +1,12 @@ 'use strict'; const http = require('node:http'); -const { HEADERS } = require('../headers.js'); +const HEADERS = { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'POST, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type', + 'Access-Control-Max-Age': 600, +}; const parseBody = async (req) => { const buffer = []; @@ -16,7 +21,7 @@ module.exports = (routing, port, console) => { res.writeHead(200, HEADERS); if (req.method !== 'POST') return void res.end('"Not found"'); const { url, socket } = req; - const [name, method] = url.substring(1).split('/'); + const [name, method] = url?.substring(1).split('/') ?? []; const entity = routing[name]; if (!entity) return void res.end('Not found'); const handler = entity[method]; diff --git a/lib/logger/pino.js b/lib/logger/pino.js index 54e25d6..8729f4f 100644 --- a/lib/logger/pino.js +++ b/lib/logger/pino.js @@ -1,4 +1,4 @@ -const pino = require('pino'); +const { pino } = require('pino'); module.exports = (config) => { const targets = []; @@ -6,6 +6,9 @@ module.exports = (config) => { targets.push({ level: 'trace', target: 'pino-pretty', + options: { + colorize: true, + }, }); } if (config.fsPath) { @@ -25,16 +28,16 @@ module.exports = (config) => { return { log(...args) { // TODO: issue https://github.com/pinojs/pino-pretty/issues/455 - logger.info(...args); + logger.info(args); }, info(...args) { - logger.info(...args); + logger.info(args); }, warn(...args) { - logger.warn(...args); + logger.warn(args); }, error(...args) { - logger.error(...args); + logger.error(args); }, }; }; diff --git a/lib/logger/winston.js b/lib/logger/winston.js index 4e65289..58bafce 100644 --- a/lib/logger/winston.js +++ b/lib/logger/winston.js @@ -27,16 +27,16 @@ module.exports = (config) => { return { log(...args) { - logger.verbose(...args); + logger.verbose(args); }, info(...args) { - logger.info(...args); + logger.info(args); }, warn(...args) { - logger.warn(...args); + logger.warn(args); }, error(...args) { - logger.error(...args); + logger.error(args); }, }; }; diff --git a/lib/main.js b/lib/main.js index 3495b65..9eb2faa 100644 --- a/lib/main.js +++ b/lib/main.js @@ -29,7 +29,7 @@ const start = async () => { const serviceName = path.basename(fileName, '.js'); routing[serviceName] = await load(filePath, sandbox); } - staticServer('./static', config.static.port, console); + staticServer('./static', config.static.port); console.info(`📦 Static server on ${config.static.port}`); server(routing, config.api.port, console); console.info(`🚀 API server no ${config.api.port}`); diff --git a/lib/static/server.js b/lib/static/server.js index 5adf9ec..15cf01a 100644 --- a/lib/static/server.js +++ b/lib/static/server.js @@ -8,6 +8,10 @@ module.exports = (root, port) => { http .createServer(async (req, res) => { const url = req.url === '/' ? '/index.html' : req.url; + if (!url) { + res.end('Invalid URL'); + return; + } const filePath = path.join(root, url); try { const data = await fs.promises.readFile(filePath); diff --git a/package.json b/package.json index 60b7785..556f6ac 100644 --- a/package.json +++ b/package.json @@ -4,21 +4,18 @@ "description": "Learn Node.js with fun🤪", "main": "index.js", "type": "commonjs", + "types": "./global.d.ts", "scripts": { "start": "node ./lib/main.js", "dev": "nodemon ./lib/main.js", "test": "echo no test specified", - "lint:check": "eslint .", - "lint:write": "eslint --fix .", - "format:check": "prettier --check .", - "format:write": "prettier --write .", + "eslint:check": "eslint .", + "eslint:write": "eslint --fix .", + "prettier:check": "prettier --check .", + "prettier:write": "prettier --write .", + "typescript:check": "tsc -p tsconfig.json", "prepare": "husky install" }, - "lint-staged": { - "*": "prettier --write --ignore-unknown", - "*.js": "eslint", - "*.ts": "eslint" - }, "author": "", "license": "MIT", "dependencies": { diff --git a/tsconfig.json b/tsconfig.json index 726daab..59ec9ca 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,13 +1,26 @@ { "compilerOptions": { - "target": "ESNext", + "noEmit": true, + "checkJs": true, + "target": "ES2022", + "module": "CommonJS", + "lib": ["ES2022"], + "esModuleInterop": true, + "isolatedModules": true, "moduleResolution": "node", + + "emitDecoratorMetadata": false, + "experimentalDecorators": false, + "strict": true, - "baseUrl": ".", - "preserveWatchOutput": true, - "allowJs": true, - "noEmit": true, - "skipLibCheck": true + "alwaysStrict": true, + "allowUnreachableCode": true, + "allowUnusedLabels": true, + "noImplicitAny": false, + "noImplicitReturns": true, + "resolveJsonModule": true, + + "declaration": true }, - "include": ["*", "**/*"] + "exclude": ["node_modules", "static"] }