@avelardelarosa/core-util 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc +4 -0
- package/README.md +37 -0
- package/eslint.config.mjs +34 -0
- package/nest-cli.json +8 -0
- package/package.json +81 -0
- package/src/api/response/ApiResponse.ts +40 -0
- package/src/app.controller.spec.ts +22 -0
- package/src/app.controller.ts +12 -0
- package/src/app.module.ts +10 -0
- package/src/app.service.ts +8 -0
- package/src/dto/AuditoryDTO.ts +8 -0
- package/src/entities/Auditory.ts +25 -0
- package/src/interfaces/IGenericCrud.ts +11 -0
- package/src/main.ts +8 -0
- package/src/util/Validation.ts +63 -0
- package/test/app.e2e-spec.ts +25 -0
- package/test/jest-e2e.json +9 -0
- package/tsconfig.build.json +4 -0
- package/tsconfig.json +21 -0
package/.prettierrc
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# 🧱 core-util
|
|
2
|
+
|
|
3
|
+
**core-util** es una librería personal de utilidades para proyectos **NestJS**, diseñada para centralizar componentes clave y facilitar el desarrollo backend mediante recursos reutilizables y estructurados.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🔍 Propósito
|
|
8
|
+
|
|
9
|
+
Este proyecto actúa como una **capa base** para múltiples servicios NestJS, ofreciendo:
|
|
10
|
+
|
|
11
|
+
- ✅ **Clases abstractas comunes**
|
|
12
|
+
Por ejemplo, entidades base con campos de auditoría o herencia reutilizable.
|
|
13
|
+
|
|
14
|
+
- 📦 **Modelos de respuesta estándar**
|
|
15
|
+
Para mantener consistencia en las respuestas de tus APIs.
|
|
16
|
+
|
|
17
|
+
- 🛡️ **Decoradores y validaciones personalizadas**
|
|
18
|
+
Para mejorar la legibilidad y control de tus DTOs.
|
|
19
|
+
|
|
20
|
+
- 🔧 **Funciones utilitarias**
|
|
21
|
+
Manejo de fechas, formateo de datos, utilidades comunes, etc.
|
|
22
|
+
|
|
23
|
+
- 🧪 **DTOs, constantes y helpers compartidos**
|
|
24
|
+
Que se pueden reutilizar entre distintos microservicios.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 🚀 Beneficios
|
|
29
|
+
|
|
30
|
+
- 🔁 **Reduce el código repetitivo**
|
|
31
|
+
- 🧩 **Aporta consistencia entre proyectos**
|
|
32
|
+
- 📈 **Mejora la escalabilidad y mantenimiento**
|
|
33
|
+
- ♻️ **Fácil de extender y reutilizar**
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
> Este proyecto forma parte de una arquitectura modular para uso personal, y está pensado para integrarse fácilmente en cualquier backend desarrollado con NestJS.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import eslint from '@eslint/js';
|
|
3
|
+
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
|
|
4
|
+
import globals from 'globals';
|
|
5
|
+
import tseslint from 'typescript-eslint';
|
|
6
|
+
|
|
7
|
+
export default tseslint.config(
|
|
8
|
+
{
|
|
9
|
+
ignores: ['eslint.config.mjs'],
|
|
10
|
+
},
|
|
11
|
+
eslint.configs.recommended,
|
|
12
|
+
...tseslint.configs.recommendedTypeChecked,
|
|
13
|
+
eslintPluginPrettierRecommended,
|
|
14
|
+
{
|
|
15
|
+
languageOptions: {
|
|
16
|
+
globals: {
|
|
17
|
+
...globals.node,
|
|
18
|
+
...globals.jest,
|
|
19
|
+
},
|
|
20
|
+
sourceType: 'commonjs',
|
|
21
|
+
parserOptions: {
|
|
22
|
+
projectService: true,
|
|
23
|
+
tsconfigRootDir: import.meta.dirname,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
rules: {
|
|
29
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
30
|
+
'@typescript-eslint/no-floating-promises': 'warn',
|
|
31
|
+
'@typescript-eslint/no-unsafe-argument': 'warn'
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
);
|
package/nest-cli.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@avelardelarosa/core-util",
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "Librería de utilidades comunes para servicios backend desarrollados con NestJS",
|
|
5
|
+
"author": "Alexander Junior Velarde La Rosa <avelardelarosa@gmail.com>",
|
|
6
|
+
"private": false,
|
|
7
|
+
"license": "UNLICENSED",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"registry": "https://registry.npmjs.org/"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "nest build",
|
|
13
|
+
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
14
|
+
"start": "nest start",
|
|
15
|
+
"start:dev": "nest start --watch",
|
|
16
|
+
"start:debug": "nest start --debug --watch",
|
|
17
|
+
"start:prod": "node dist/main",
|
|
18
|
+
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
|
19
|
+
"test": "jest",
|
|
20
|
+
"test:watch": "jest --watch",
|
|
21
|
+
"test:cov": "jest --coverage",
|
|
22
|
+
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
|
23
|
+
"test:e2e": "jest --config ./test/jest-e2e.json"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@nestjs/common": "^11.0.1",
|
|
27
|
+
"@nestjs/core": "^11.0.1",
|
|
28
|
+
"@nestjs/platform-express": "^11.0.1",
|
|
29
|
+
"@nestjs/typeorm": "^11.0.0",
|
|
30
|
+
"class-transformer": "^0.5.1",
|
|
31
|
+
"class-validator": "^0.14.2",
|
|
32
|
+
"mysql2": "^3.14.2",
|
|
33
|
+
"reflect-metadata": "^0.2.2",
|
|
34
|
+
"rxjs": "^7.8.1",
|
|
35
|
+
"typeorm": "^0.3.25"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@eslint/eslintrc": "^3.2.0",
|
|
39
|
+
"@eslint/js": "^9.18.0",
|
|
40
|
+
"@nestjs/cli": "^11.0.0",
|
|
41
|
+
"@nestjs/schematics": "^11.0.0",
|
|
42
|
+
"@nestjs/testing": "^11.0.1",
|
|
43
|
+
"@swc/cli": "^0.6.0",
|
|
44
|
+
"@swc/core": "^1.10.7",
|
|
45
|
+
"@types/express": "^5.0.0",
|
|
46
|
+
"@types/jest": "^29.5.14",
|
|
47
|
+
"@types/node": "^22.10.7",
|
|
48
|
+
"@types/supertest": "^6.0.2",
|
|
49
|
+
"eslint": "^9.18.0",
|
|
50
|
+
"eslint-config-prettier": "^10.0.1",
|
|
51
|
+
"eslint-plugin-prettier": "^5.2.2",
|
|
52
|
+
"globals": "^16.0.0",
|
|
53
|
+
"jest": "^29.7.0",
|
|
54
|
+
"prettier": "^3.4.2",
|
|
55
|
+
"source-map-support": "^0.5.21",
|
|
56
|
+
"supertest": "^7.0.0",
|
|
57
|
+
"ts-jest": "^29.2.5",
|
|
58
|
+
"ts-loader": "^9.5.2",
|
|
59
|
+
"ts-node": "^10.9.2",
|
|
60
|
+
"tsconfig-paths": "^4.2.0",
|
|
61
|
+
"typescript": "^5.7.3",
|
|
62
|
+
"typescript-eslint": "^8.20.0"
|
|
63
|
+
},
|
|
64
|
+
"jest": {
|
|
65
|
+
"moduleFileExtensions": [
|
|
66
|
+
"js",
|
|
67
|
+
"json",
|
|
68
|
+
"ts"
|
|
69
|
+
],
|
|
70
|
+
"rootDir": "src",
|
|
71
|
+
"testRegex": ".*\\.spec\\.ts$",
|
|
72
|
+
"transform": {
|
|
73
|
+
"^.+\\.(t|j)s$": "ts-jest"
|
|
74
|
+
},
|
|
75
|
+
"collectCoverageFrom": [
|
|
76
|
+
"**/*.(t|j)s"
|
|
77
|
+
],
|
|
78
|
+
"coverageDirectory": "../coverage",
|
|
79
|
+
"testEnvironment": "node"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export class Pagination<T> {
|
|
2
|
+
pageNumber: number;
|
|
3
|
+
pageSize: number;
|
|
4
|
+
body: T[];
|
|
5
|
+
totalElements: number;
|
|
6
|
+
totalPages: number;
|
|
7
|
+
lastRow: boolean;
|
|
8
|
+
|
|
9
|
+
constructor(init?: Partial<Pagination<T>>) {
|
|
10
|
+
Object.assign(this, init);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class ApiResponse<T> {
|
|
15
|
+
successful: boolean;
|
|
16
|
+
code: string;
|
|
17
|
+
message: string;
|
|
18
|
+
data: T;
|
|
19
|
+
|
|
20
|
+
constructor(init?: Partial<ApiResponse<T>>) {
|
|
21
|
+
Object.assign(this, init);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
success(message: string, data: T) {
|
|
25
|
+
this.successful = true;
|
|
26
|
+
this.message = message;
|
|
27
|
+
this.data = data;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
error(code: string, message: string) {
|
|
31
|
+
this.successful = false;
|
|
32
|
+
this.code = code;
|
|
33
|
+
this.message = message;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
msg(message: string) {
|
|
37
|
+
this.successful = true;
|
|
38
|
+
this.message = message;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Test, TestingModule } from '@nestjs/testing';
|
|
2
|
+
import { AppController } from './app.controller';
|
|
3
|
+
import { AppService } from './app.service';
|
|
4
|
+
|
|
5
|
+
describe('AppController', () => {
|
|
6
|
+
let appController: AppController;
|
|
7
|
+
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
const app: TestingModule = await Test.createTestingModule({
|
|
10
|
+
controllers: [AppController],
|
|
11
|
+
providers: [AppService],
|
|
12
|
+
}).compile();
|
|
13
|
+
|
|
14
|
+
appController = app.get<AppController>(AppController);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('root', () => {
|
|
18
|
+
it('should return "Hello World!"', () => {
|
|
19
|
+
expect(appController.getHello()).toBe('Hello World!');
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Controller, Get } from '@nestjs/common';
|
|
2
|
+
import { AppService } from './app.service';
|
|
3
|
+
|
|
4
|
+
@Controller()
|
|
5
|
+
export class AppController {
|
|
6
|
+
constructor(private readonly appService: AppService) {}
|
|
7
|
+
|
|
8
|
+
@Get()
|
|
9
|
+
getHello(): string {
|
|
10
|
+
return this.appService.getHello();
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Column, Entity } from 'typeorm';
|
|
2
|
+
import { IsDate } from 'class-validator';
|
|
3
|
+
import { Type } from 'class-transformer';
|
|
4
|
+
|
|
5
|
+
@Entity()
|
|
6
|
+
export class Auditory {
|
|
7
|
+
@Column({ nullable: false })
|
|
8
|
+
createUser: string;
|
|
9
|
+
@Column({ type: 'timestamp', nullable: false })
|
|
10
|
+
@IsDate()
|
|
11
|
+
@Type(() => Date)
|
|
12
|
+
createDate: Date;
|
|
13
|
+
@Column({ nullable: false })
|
|
14
|
+
updateUser: string;
|
|
15
|
+
@Column({ type: 'timestamp', nullable: false })
|
|
16
|
+
@IsDate()
|
|
17
|
+
@Type(() => Date)
|
|
18
|
+
updateDate: string;
|
|
19
|
+
@Column({ nullable: false })
|
|
20
|
+
deleteUser: string;
|
|
21
|
+
@Column({ type: 'timestamp', nullable: false })
|
|
22
|
+
@IsDate()
|
|
23
|
+
@Type(() => Date)
|
|
24
|
+
deleteDate: string;
|
|
25
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ApiResponse, Pagination } from '../api/response/ApiResponse';
|
|
2
|
+
|
|
3
|
+
export interface IGenericCrud<T> {
|
|
4
|
+
pagination(): Promise<ApiResponse<Pagination<T>>>;
|
|
5
|
+
|
|
6
|
+
create(t: T): Promise<ApiResponse<T>>;
|
|
7
|
+
|
|
8
|
+
update(t: T): Promise<ApiResponse<T>>;
|
|
9
|
+
|
|
10
|
+
delete(id: string): Promise<ApiResponse<T>>;
|
|
11
|
+
}
|
package/src/main.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export class Validation<T> {
|
|
2
|
+
isNull(obj: T) {
|
|
3
|
+
return obj === null;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
isUndefined(obj: T) {
|
|
7
|
+
return obj === undefined;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
isEmpty(obj: T) {
|
|
11
|
+
return obj === '' || obj === null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
sString(obj: unknown): boolean {
|
|
15
|
+
return typeof obj === 'string';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
isNumber(obj: unknown): boolean {
|
|
19
|
+
return typeof obj === 'number' && !isNaN(obj);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
isBoolean(obj: unknown): boolean {
|
|
23
|
+
return typeof obj === 'boolean';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
isPositiveNumber(obj: T) {
|
|
27
|
+
return this.isNumber(obj) && (obj as number) > 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
isNegativeNumber(obj: T) {
|
|
31
|
+
return this.isNumber(obj) && (obj as number) < 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
isDate(obj: unknown): boolean {
|
|
35
|
+
return obj instanceof Date && !isNaN(obj.getTime());
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
isFutureDate(obj: unknown): boolean {
|
|
39
|
+
return this.isDate(obj) && (obj as Date).getTime() > Date.now();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
isPastDate(obj: unknown): boolean {
|
|
43
|
+
return this.isDate(obj) && (obj as Date).getTime() < Date.now();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
isInArray(value: unknown, array: unknown[]): boolean {
|
|
47
|
+
return array.includes(value);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
hasMinLength(obj: T, length: number): boolean {
|
|
51
|
+
if (typeof obj === 'string' || Array.isArray(obj)) {
|
|
52
|
+
return (obj as any).length >= length;
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
hasMaxLength(obj: T, length: number): boolean {
|
|
58
|
+
if (typeof obj === 'string' || Array.isArray(obj)) {
|
|
59
|
+
return (obj as any).length <= length;
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Test, TestingModule } from '@nestjs/testing';
|
|
2
|
+
import { INestApplication } from '@nestjs/common';
|
|
3
|
+
import * as request from 'supertest';
|
|
4
|
+
import { App } from 'supertest/types';
|
|
5
|
+
import { AppModule } from './../src/app.module';
|
|
6
|
+
|
|
7
|
+
describe('AppController (e2e)', () => {
|
|
8
|
+
let app: INestApplication<App>;
|
|
9
|
+
|
|
10
|
+
beforeEach(async () => {
|
|
11
|
+
const moduleFixture: TestingModule = await Test.createTestingModule({
|
|
12
|
+
imports: [AppModule],
|
|
13
|
+
}).compile();
|
|
14
|
+
|
|
15
|
+
app = moduleFixture.createNestApplication();
|
|
16
|
+
await app.init();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('/ (GET)', () => {
|
|
20
|
+
return request(app.getHttpServer())
|
|
21
|
+
.get('/')
|
|
22
|
+
.expect(200)
|
|
23
|
+
.expect('Hello World!');
|
|
24
|
+
});
|
|
25
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "commonjs",
|
|
4
|
+
"declaration": true,
|
|
5
|
+
"removeComments": true,
|
|
6
|
+
"emitDecoratorMetadata": true,
|
|
7
|
+
"experimentalDecorators": true,
|
|
8
|
+
"allowSyntheticDefaultImports": true,
|
|
9
|
+
"target": "ES2023",
|
|
10
|
+
"sourceMap": true,
|
|
11
|
+
"outDir": "./dist",
|
|
12
|
+
"baseUrl": "./",
|
|
13
|
+
"incremental": true,
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"strictNullChecks": true,
|
|
16
|
+
"forceConsistentCasingInFileNames": true,
|
|
17
|
+
"noImplicitAny": false,
|
|
18
|
+
"strictBindCallApply": false,
|
|
19
|
+
"noFallthroughCasesInSwitch": false
|
|
20
|
+
}
|
|
21
|
+
}
|