Criteria -> quickSearch
This commit is contained in:
parent
2043bbb78b
commit
19fb7c04e2
@ -1 +1 @@
|
||||
|
||||
export * from "./sequelize-func";
|
||||
|
||||
18
modules/core/src/api/helpers/sequelize-func.ts
Normal file
18
modules/core/src/api/helpers/sequelize-func.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { FindOptions } from "sequelize";
|
||||
|
||||
// orderItem puede ser: ['campo', 'ASC'|'DESC']
|
||||
// o [Sequelize.literal('score'), 'DESC']
|
||||
// o [[{ model: X, as: 'alias' }, 'campo', 'ASC']] etc.
|
||||
type OrderItem = any;
|
||||
|
||||
export function prependOrder(options: FindOptions, orderItem: OrderItem) {
|
||||
if (!options.order) {
|
||||
options.order = [orderItem];
|
||||
return;
|
||||
}
|
||||
// Si viene como algo no-array (poco común), lo envolvemos
|
||||
if (!Array.isArray(options.order)) {
|
||||
options.order = [options.order as any];
|
||||
}
|
||||
(options.order as OrderItem[]).unshift(orderItem);
|
||||
}
|
||||
@ -24,7 +24,12 @@ import {
|
||||
isDuplicateEntityError,
|
||||
isEntityNotFoundError,
|
||||
} from "../../domain";
|
||||
import { isInfrastructureRepositoryError, isInfrastructureUnavailableError } from "../errors";
|
||||
import {
|
||||
InfrastructureRepositoryError,
|
||||
InfrastructureUnavailableError,
|
||||
isInfrastructureRepositoryError,
|
||||
isInfrastructureUnavailableError,
|
||||
} from "../errors";
|
||||
import {
|
||||
ApiError,
|
||||
ConflictApiError,
|
||||
@ -146,14 +151,22 @@ const defaultRules: ReadonlyArray<ErrorToApiRule> = [
|
||||
{
|
||||
priority: 60,
|
||||
matches: (e) => isInfrastructureUnavailableError(e),
|
||||
build: () => new UnavailableApiError("Service temporarily unavailable."),
|
||||
build: (e) =>
|
||||
new UnavailableApiError(
|
||||
(e as InfrastructureUnavailableError).message,
|
||||
"Service temporarily unavailable."
|
||||
),
|
||||
},
|
||||
|
||||
// 6) Infra no transitoria (errores de repositorio inesperados)
|
||||
{
|
||||
priority: 50,
|
||||
matches: (e) => isInfrastructureRepositoryError(e),
|
||||
build: () => new InternalApiError("Unexpected repository error."),
|
||||
build: (e) =>
|
||||
new InternalApiError(
|
||||
(e as InfrastructureRepositoryError).message,
|
||||
"Unexpected repository error"
|
||||
),
|
||||
},
|
||||
|
||||
// 7) Autenticación/autorización por nombre (si no tienes clases dedicadas)
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { ApiError } from "./api-error";
|
||||
|
||||
export class InternalApiError extends ApiError {
|
||||
constructor(detail: string) {
|
||||
constructor(detail: string, title?: string) {
|
||||
super({
|
||||
status: 500,
|
||||
title: "Internal Server Error",
|
||||
title: title ?? "Internal Server Error",
|
||||
detail,
|
||||
type: "https://httpstatuses.com/500",
|
||||
});
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { ApiError } from "./api-error";
|
||||
|
||||
export class UnavailableApiError extends ApiError {
|
||||
constructor(detail: string) {
|
||||
constructor(detail: string, title?: string) {
|
||||
super({
|
||||
status: 503,
|
||||
title: "Service Unavailable",
|
||||
title: title ?? "Service Unavailable",
|
||||
detail,
|
||||
type: "https://httpstatuses.com/503",
|
||||
});
|
||||
|
||||
@ -17,6 +17,8 @@ import { InfrastructureUnavailableError } from "../errors/infrastructure-unavail
|
||||
* 👉 Este traductor pertenece a la infraestructura (persistencia)
|
||||
*/
|
||||
export function translateSequelizeError(err: unknown): Error {
|
||||
console.log(err);
|
||||
|
||||
// 1) Duplicados (índices únicos)
|
||||
if (err instanceof UniqueConstraintError) {
|
||||
// Tomamos el primer detalle (puede haber varios)
|
||||
|
||||
@ -12,6 +12,8 @@ export const FilterPrimitiveSchema = z.object({
|
||||
});
|
||||
|
||||
export const CriteriaSchema = z.object({
|
||||
q: z.string().optional(),
|
||||
|
||||
filters: z.array(FilterPrimitiveSchema).optional(),
|
||||
|
||||
// Preferimos omitido; si viene, no puede ser cadena vacía
|
||||
|
||||
@ -43,6 +43,7 @@ export class CustomerInvoiceModel extends Model<
|
||||
declare currency_code: CreationOptional<string>;
|
||||
|
||||
declare reference: CreationOptional<string | null>;
|
||||
declare description: CreationOptional<string | null>;
|
||||
|
||||
declare notes: CreationOptional<string | null>;
|
||||
|
||||
@ -192,6 +193,12 @@ export default (database: Sequelize) => {
|
||||
defaultValue: null,
|
||||
},
|
||||
|
||||
description: {
|
||||
type: new DataTypes.STRING(),
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
},
|
||||
|
||||
notes: {
|
||||
type: new DataTypes.TEXT(),
|
||||
allowNull: true,
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { CriteriaDTO } from "@erp/core";
|
||||
import { Presenter } from "@erp/core/api";
|
||||
import { CustomerListDTO } from "@erp/customer-invoices/api/infrastructure";
|
||||
import { Criteria } from "@repo/rdx-criteria/server";
|
||||
@ -68,7 +69,7 @@ export class ListCustomersPresenter extends Presenter {
|
||||
items: items,
|
||||
metadata: {
|
||||
entity: "customers",
|
||||
criteria: criteria.toJSON(),
|
||||
criteria: criteria.toJSON() as CriteriaDTO,
|
||||
//links: {
|
||||
// self: `/api/customer-invoices?page=${criteria.pageNumber}&per_page=${criteria.pageSize}`,
|
||||
// first: `/api/customer-invoices?page=1&per_page=${criteria.pageSize}`,
|
||||
|
||||
@ -14,8 +14,8 @@ export class ListCustomersController extends ExpressController {
|
||||
return this.criteria;
|
||||
}
|
||||
|
||||
const { filters, pageSize, pageNumber } = this.criteria.toPrimitives();
|
||||
return Criteria.fromPrimitives(filters, "name", "ASC", pageSize, pageNumber);
|
||||
const { q: quicksearch, filters, pageSize, pageNumber } = this.criteria.toPrimitives();
|
||||
return Criteria.fromPrimitives(filters, "name", "ASC", pageSize, pageNumber, quicksearch);
|
||||
}
|
||||
|
||||
protected async executeImpl() {
|
||||
|
||||
@ -233,6 +233,11 @@ export default (database: Sequelize) => {
|
||||
indexes: [
|
||||
{ name: "company_idx", fields: ["company_id"], unique: false },
|
||||
{ name: "idx_company_idx", fields: ["id", "company_id"], unique: true },
|
||||
{
|
||||
name: "ft_customer",
|
||||
type: "FULLTEXT",
|
||||
fields: ["name", "trade_name", "reference", "tin", "email_primary", "mobile_primary"],
|
||||
},
|
||||
],
|
||||
|
||||
whereMergeStrategy: "and", // <- cómo tratar el merge de un scope
|
||||
|
||||
@ -121,7 +121,17 @@ export class CustomerRepository
|
||||
});
|
||||
|
||||
const converter = new CriteriaToSequelizeConverter();
|
||||
const query = converter.convert(criteria, { name: "name" });
|
||||
const query = converter.convert(criteria, {
|
||||
searchableFields: [
|
||||
"name",
|
||||
"trade_name",
|
||||
"reference",
|
||||
"tin",
|
||||
"email_primary",
|
||||
"mobile_primary",
|
||||
],
|
||||
database: this._database,
|
||||
});
|
||||
|
||||
query.where = {
|
||||
...query.where,
|
||||
|
||||
@ -1,11 +1,7 @@
|
||||
{
|
||||
"name": "uecko-erp-2025",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
"modules/*",
|
||||
"packages/*"
|
||||
],
|
||||
"workspaces": ["apps/*", "modules/*", "packages/*"],
|
||||
"scripts": {
|
||||
"build": "turbo build",
|
||||
"dev": "turbo dev",
|
||||
@ -21,9 +17,12 @@
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "1.9.4",
|
||||
"@repo/typescript-config": "workspace:*",
|
||||
"@types/jest": "^29.5.14",
|
||||
"change-case": "^5.4.4",
|
||||
"inquirer": "^12.5.2",
|
||||
"jest": "^29.7.0",
|
||||
"plop": "^4.0.4",
|
||||
"ts-jest": "^29.2.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"turbo": "^2.5.1",
|
||||
"typescript": "5.8.3"
|
||||
|
||||
@ -11,10 +11,12 @@ The criteria converter expect an url with the following format:
|
||||
* `pageNumber`: The page number.
|
||||
|
||||
### Valid operators
|
||||
* `=`: Equal
|
||||
* `!=`: Not equal
|
||||
* `>`: Greater than
|
||||
* `<`: Less than
|
||||
* `EQUALS`: Equal
|
||||
* `NOT_EQUALS`: Not equal
|
||||
* `GREATER_THAN`: Greater than
|
||||
* `GREATER_THAN_OR_EQUAL`: Greater than or equal
|
||||
* `LOWER_THAN`: Less than
|
||||
* `LOWER_THAN_OR_EQUAL`: Less than or equal
|
||||
* `CONTAINS`: Contains. It will translate to `like` in SQL.
|
||||
* `NOT_CONTAINS`: Not contains. It will translate to `not like` in SQL.
|
||||
|
||||
|
||||
@ -5,17 +5,20 @@ export class Criteria extends BaseCriteria {
|
||||
/**
|
||||
* Creates a new Criteria instance.
|
||||
*
|
||||
* @param quickSearch - 'Quicksearch' field.
|
||||
* @param filters - The filters to apply.
|
||||
* @param order - The order to apply.
|
||||
* @param pageSize - The size of the page.
|
||||
* @param pageNumber - The number of the page.
|
||||
*
|
||||
*/
|
||||
|
||||
constructor(
|
||||
protected constructor(
|
||||
public readonly filters: Filters,
|
||||
public readonly order: Order,
|
||||
public readonly pageSize: number,
|
||||
public readonly pageNumber: number
|
||||
public readonly pageNumber: number,
|
||||
public readonly quickSearch?: string //Texto libre para búsqueda rápida
|
||||
) {
|
||||
super(filters, order, pageSize, pageNumber);
|
||||
}
|
||||
@ -25,18 +28,21 @@ export class Criteria extends BaseCriteria {
|
||||
orderBy: string | null,
|
||||
orderType: string | null,
|
||||
pageSize: number | null,
|
||||
pageNumber: number | null
|
||||
pageNumber: number | null,
|
||||
quickSearch?: string | null
|
||||
): Criteria {
|
||||
return new Criteria(
|
||||
Filters.fromPrimitives(filters),
|
||||
Order.fromPrimitives(orderBy, orderType),
|
||||
pageSize ?? INITIAL_PAGE_SIZE,
|
||||
pageNumber ?? INITIAL_PAGE_INDEX
|
||||
pageNumber ?? INITIAL_PAGE_INDEX,
|
||||
quickSearch ?? undefined
|
||||
);
|
||||
}
|
||||
|
||||
toPrimitives() {
|
||||
return {
|
||||
q: this.quickSearch ?? "",
|
||||
filters: this.filters.toPrimitives(),
|
||||
orderBy: this.order.orderBy.value,
|
||||
orderType: this.order.orderType.value,
|
||||
|
||||
@ -26,23 +26,25 @@ export class CriteriaFromUrlConverter {
|
||||
defaults: defaultsType;
|
||||
}
|
||||
): Criteria {
|
||||
const { searchParams } = url;
|
||||
const { searchParams: urlParams } = url;
|
||||
const defaults = {
|
||||
order: options?.defaults?.order ?? defaultOptions.order,
|
||||
pageSize: options?.defaults?.pageSize ?? defaultOptions.pageSize,
|
||||
pageNumber: options?.defaults?.pageNumber ?? defaultOptions.pageNumber,
|
||||
};
|
||||
|
||||
const filters = this.parseFilters(searchParams);
|
||||
const quickSearch = urlParams.get("q");
|
||||
|
||||
const orderBy = searchParams.get("orderBy");
|
||||
const filters = this.parseFilters(urlParams);
|
||||
|
||||
const order = searchParams.has("order") ? String(searchParams.get("order")) : defaults.order;
|
||||
const orderBy = urlParams.get("orderBy");
|
||||
|
||||
const pageSize = this.parseInteger(searchParams.get("pageSize"), defaults.pageSize);
|
||||
const pageNumber = this.parseInteger(searchParams.get("pageNumber"), defaults.pageNumber);
|
||||
const order = urlParams.has("order") ? String(urlParams.get("order")) : defaults.order;
|
||||
|
||||
return Criteria.fromPrimitives(filters, orderBy, order, pageSize, pageNumber);
|
||||
const pageSize = this.parseInteger(urlParams.get("pageSize"), defaults.pageSize);
|
||||
const pageNumber = this.parseInteger(urlParams.get("pageNumber"), defaults.pageNumber);
|
||||
|
||||
return Criteria.fromPrimitives(filters, orderBy, order, pageSize, pageNumber, quickSearch);
|
||||
}
|
||||
|
||||
public toFiltersPrimitives(url: URL): FiltersPrimitives[] {
|
||||
|
||||
@ -1,32 +1,115 @@
|
||||
import { Filter } from "@codelytv/criteria";
|
||||
import { FindOptions, Op, OrderItem, WhereOptions } from "sequelize";
|
||||
import { FindOptions, Op, OrderItem, Sequelize, WhereOptions } from "sequelize";
|
||||
import { Criteria } from "./critera";
|
||||
import { type ConvertParams, type CriteriaMappings, ICriteriaToOrmConverter } from "./types";
|
||||
import { appendOrder, prependOrder } from "./utils";
|
||||
|
||||
type CriteriaMappings = { [key: string]: string };
|
||||
|
||||
export class CriteriaToSequelizeConverter {
|
||||
export class CriteriaToSequelizeConverter implements ICriteriaToOrmConverter {
|
||||
//convert(fieldsToSelect: string[], criteria: Criteria, mappings: Mappings = {}): FindOptions {
|
||||
convert(criteria: Criteria, mappings: CriteriaMappings = {}): FindOptions {
|
||||
convert(criteria: Criteria, params: ConvertParams = {}): FindOptions {
|
||||
const options: FindOptions = {};
|
||||
const { mappings = {} } = params;
|
||||
|
||||
// Selección de campos
|
||||
/*if (fieldsToSelect.length > 0) {
|
||||
options.attributes = fieldsToSelect;
|
||||
}*/
|
||||
|
||||
// Filtros
|
||||
this.applyFilters(options, criteria, mappings);
|
||||
this.applyQuickSearch(options, criteria, params);
|
||||
this.applyOrder(options, criteria, mappings);
|
||||
this.applyPagination(options, criteria);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
public applyFilters(options: FindOptions, criteria: Criteria, mappings: CriteriaMappings) {
|
||||
const filterConditions: WhereOptions = {};
|
||||
if (criteria.hasFilters()) {
|
||||
options.where = this.buildWhere(criteria.filters.value, mappings);
|
||||
criteria.filters.value.forEach((filter) => {
|
||||
const field = mappings[filter.field.value] || filter.field.value;
|
||||
const operator = this.mapOperator(filter.operator.value);
|
||||
const value = filter.value.value;
|
||||
|
||||
if (!filterConditions[field]) {
|
||||
filterConditions[field] = {};
|
||||
}
|
||||
|
||||
filterConditions[field][operator] = this.transformValue(operator, value);
|
||||
});
|
||||
|
||||
if (options.where) {
|
||||
options.where = { [Op.and]: [options.where, { [Op.or]: filterConditions }] };
|
||||
} else {
|
||||
options.where = { [Op.or]: filterConditions };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public applyQuickSearch(options: FindOptions, criteria: Criteria, params: ConvertParams): void {
|
||||
const {
|
||||
mappings = {},
|
||||
searchableFields = [],
|
||||
database,
|
||||
} = params as ConvertParams & {
|
||||
database: Sequelize;
|
||||
};
|
||||
|
||||
const term = typeof criteria.quickSearch === "string" ? criteria.quickSearch.trim() : "";
|
||||
|
||||
// Si no hay término de búsqueda o no hay campos configurados, no hacemos nada
|
||||
if (term === "" || searchableFields.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Orden
|
||||
// Construimos query de boolean mode con prefijo
|
||||
const booleanTerm = term
|
||||
.split(/\s+/)
|
||||
.map((w) => `+${w}*`)
|
||||
.join(" ");
|
||||
|
||||
// Campos reales (con mappings aplicados)
|
||||
const mappedFields = searchableFields.map((field) => mappings[field] || field);
|
||||
|
||||
const matchExpr = `MATCH(${mappedFields.join(", ")}) AGAINST (${database.escape(
|
||||
booleanTerm
|
||||
)} IN BOOLEAN MODE)`;
|
||||
|
||||
const matchLiteral = Sequelize.literal(matchExpr);
|
||||
|
||||
// Añadimos score a los attributes (sin machacar si ya existen)
|
||||
if (!options.attributes) {
|
||||
options.attributes = { include: [] };
|
||||
}
|
||||
|
||||
if (Array.isArray(options.attributes)) {
|
||||
options.attributes.push([matchLiteral, "score"]);
|
||||
} else {
|
||||
options.attributes.include = options.attributes.include || [];
|
||||
options.attributes.include.push([matchLiteral, "score"]);
|
||||
}
|
||||
|
||||
// WHERE score > 0
|
||||
const scoreCondition = Sequelize.where(matchLiteral, { [Op.gt]: 0 });
|
||||
if (options.where) {
|
||||
options.where = { [Op.and]: [options.where, { [Op.or]: scoreCondition }] };
|
||||
} else {
|
||||
options.where = { [Op.and]: scoreCondition };
|
||||
}
|
||||
|
||||
// Ordenar por relevancia (score)
|
||||
prependOrder(options, [Sequelize.literal("score"), "DESC"]);
|
||||
}
|
||||
|
||||
public applyOrder(options: FindOptions, criteria: Criteria, mappings: CriteriaMappings): void {
|
||||
if (criteria.hasOrder()) {
|
||||
const field = mappings[criteria.order.orderBy.value] || criteria.order.orderBy.value;
|
||||
const direction = criteria.order.orderType.value.toUpperCase();
|
||||
options.order = [[field, direction]] as OrderItem[];
|
||||
}
|
||||
|
||||
// Paginación
|
||||
appendOrder(options, [[field, direction]] as OrderItem[]);
|
||||
}
|
||||
}
|
||||
|
||||
public applyPagination(options: FindOptions, criteria: Criteria): void {
|
||||
if (criteria.pageSize !== null) {
|
||||
options.limit = criteria.pageSize;
|
||||
}
|
||||
@ -34,26 +117,6 @@ export class CriteriaToSequelizeConverter {
|
||||
if (criteria.pageSize !== null && criteria.pageNumber !== null) {
|
||||
options.offset = criteria.pageSize * criteria.pageNumber;
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
private buildWhere(filters: Filter[], mappings: CriteriaMappings): WhereOptions {
|
||||
const where: WhereOptions = {};
|
||||
|
||||
filters.forEach((filter) => {
|
||||
const field = mappings[filter.field.value] || filter.field.value;
|
||||
const operator = this.mapOperator(filter.operator.value);
|
||||
const value = filter.value.value;
|
||||
|
||||
if (!where[field]) {
|
||||
where[field] = {};
|
||||
}
|
||||
|
||||
where[field][operator] = this.transformValue(operator, value);
|
||||
});
|
||||
|
||||
return where;
|
||||
}
|
||||
|
||||
private mapOperator(operator: string): symbol {
|
||||
|
||||
16
packages/rdx-criteria/src/types.d.ts
vendored
Normal file
16
packages/rdx-criteria/src/types.d.ts
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
import { FindOptions } from "sequelize";
|
||||
import { Criteria } from "./critera";
|
||||
|
||||
export type CriteriaMappings = { [key: string]: string };
|
||||
export type ConvertParams = { mappings?: CriteriaMappings; searchableFields?: string[] } & Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
|
||||
export interface ICriteriaToOrmConverter {
|
||||
convert(criteria: Criteria, params: ConvertParams): FindOptions;
|
||||
applyFilters(options: FindOptions, criteria: Criteria, mappings: CriteriaMappings): void;
|
||||
applyQuickSearch(options: FindOptions, criteria: Criteria, params: ConvertParams): void;
|
||||
applyOrder(options: FindOptions, criteria: Criteria, mappings: CriteriaMappings): void;
|
||||
applyPagination(options: FindOptions, criteria: Criteria): void;
|
||||
}
|
||||
29
packages/rdx-criteria/src/utils.ts
Normal file
29
packages/rdx-criteria/src/utils.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { FindOptions } from "sequelize";
|
||||
|
||||
// orderItem puede ser: ['campo', 'ASC'|'DESC']
|
||||
// o [Sequelize.literal('score'), 'DESC']
|
||||
// o [[{ model: X, as: 'alias' }, 'campo', 'ASC']] etc.
|
||||
type OrderItem = any;
|
||||
|
||||
export function prependOrder(options: FindOptions, orderItem: OrderItem) {
|
||||
if (!options.order) {
|
||||
options.order = [orderItem];
|
||||
return;
|
||||
}
|
||||
// Si viene como algo no-array (poco común), lo envolvemos
|
||||
if (!Array.isArray(options.order)) {
|
||||
options.order = [options.order as any];
|
||||
}
|
||||
(options.order as OrderItem[]).unshift(orderItem);
|
||||
}
|
||||
|
||||
export function appendOrder(options: FindOptions, orderItem: OrderItem) {
|
||||
if (!options.order) {
|
||||
options.order = [orderItem];
|
||||
return;
|
||||
}
|
||||
if (!Array.isArray(options.order)) {
|
||||
options.order = [options.order as any];
|
||||
}
|
||||
(options.order as OrderItem[]).push(orderItem);
|
||||
}
|
||||
188
pnpm-lock.yaml
188
pnpm-lock.yaml
@ -14,15 +14,24 @@ importers:
|
||||
'@repo/typescript-config':
|
||||
specifier: workspace:*
|
||||
version: link:packages/typescript-config
|
||||
'@types/jest':
|
||||
specifier: ^29.5.14
|
||||
version: 29.5.14
|
||||
change-case:
|
||||
specifier: ^5.4.4
|
||||
version: 5.4.4
|
||||
inquirer:
|
||||
specifier: ^12.5.2
|
||||
version: 12.6.3(@types/node@24.0.3)
|
||||
jest:
|
||||
specifier: ^29.7.0
|
||||
version: 29.7.0(@types/node@24.0.3)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.0.3)(typescript@5.8.3))
|
||||
plop:
|
||||
specifier: ^4.0.4
|
||||
version: 4.0.4(@types/node@24.0.3)
|
||||
ts-jest:
|
||||
specifier: ^29.2.5
|
||||
version: 29.4.0(@babel/core@7.27.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.4))(jest-util@29.7.0)(jest@29.7.0(@types/node@24.0.3)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.0.3)(typescript@5.8.3)))(typescript@5.8.3)
|
||||
ts-node:
|
||||
specifier: ^10.9.2
|
||||
version: 10.9.2(@types/node@24.0.3)(typescript@5.8.3)
|
||||
@ -1154,10 +1163,6 @@ packages:
|
||||
resolution: {integrity: sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/generator@7.27.3':
|
||||
resolution: {integrity: sha512-xnlJYj5zepml8NXtjkG0WquFUv8RskFqyFcVgTBp5k+NaA/8uw/K+OSVf8AMGw5e9HKP2ETd5xpK5MLZQD6b4Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/generator@7.27.5':
|
||||
resolution: {integrity: sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@ -7085,14 +7090,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/generator@7.27.3':
|
||||
dependencies:
|
||||
'@babel/parser': 7.27.5
|
||||
'@babel/types': 7.27.3
|
||||
'@jridgewell/gen-mapping': 0.3.8
|
||||
'@jridgewell/trace-mapping': 0.3.25
|
||||
jsesc: 3.1.0
|
||||
|
||||
'@babel/generator@7.27.5':
|
||||
dependencies:
|
||||
'@babel/parser': 7.27.5
|
||||
@ -7760,6 +7757,41 @@ snapshots:
|
||||
- supports-color
|
||||
- ts-node
|
||||
|
||||
'@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.0.3)(typescript@5.8.3))':
|
||||
dependencies:
|
||||
'@jest/console': 29.7.0
|
||||
'@jest/reporters': 29.7.0
|
||||
'@jest/test-result': 29.7.0
|
||||
'@jest/transform': 29.7.0
|
||||
'@jest/types': 29.6.3
|
||||
'@types/node': 22.15.32
|
||||
ansi-escapes: 4.3.2
|
||||
chalk: 4.1.2
|
||||
ci-info: 3.9.0
|
||||
exit: 0.1.2
|
||||
graceful-fs: 4.2.11
|
||||
jest-changed-files: 29.7.0
|
||||
jest-config: 29.7.0(@types/node@22.15.32)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.0.3)(typescript@5.8.3))
|
||||
jest-haste-map: 29.7.0
|
||||
jest-message-util: 29.7.0
|
||||
jest-regex-util: 29.6.3
|
||||
jest-resolve: 29.7.0
|
||||
jest-resolve-dependencies: 29.7.0
|
||||
jest-runner: 29.7.0
|
||||
jest-runtime: 29.7.0
|
||||
jest-snapshot: 29.7.0
|
||||
jest-util: 29.7.0
|
||||
jest-validate: 29.7.0
|
||||
jest-watcher: 29.7.0
|
||||
micromatch: 4.0.8
|
||||
pretty-format: 29.7.0
|
||||
slash: 3.0.0
|
||||
strip-ansi: 6.0.1
|
||||
transitivePeerDependencies:
|
||||
- babel-plugin-macros
|
||||
- supports-color
|
||||
- ts-node
|
||||
|
||||
'@jest/environment@29.7.0':
|
||||
dependencies:
|
||||
'@jest/fake-timers': 29.7.0
|
||||
@ -9874,6 +9906,21 @@ snapshots:
|
||||
- supports-color
|
||||
- ts-node
|
||||
|
||||
create-jest@29.7.0(@types/node@24.0.3)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.0.3)(typescript@5.8.3)):
|
||||
dependencies:
|
||||
'@jest/types': 29.6.3
|
||||
chalk: 4.1.2
|
||||
exit: 0.1.2
|
||||
graceful-fs: 4.2.11
|
||||
jest-config: 29.7.0(@types/node@24.0.3)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.0.3)(typescript@5.8.3))
|
||||
jest-util: 29.7.0
|
||||
prompts: 2.4.2
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- babel-plugin-macros
|
||||
- supports-color
|
||||
- ts-node
|
||||
|
||||
create-require@1.1.1: {}
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
@ -10976,6 +11023,25 @@ snapshots:
|
||||
- supports-color
|
||||
- ts-node
|
||||
|
||||
jest-cli@29.7.0(@types/node@24.0.3)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.0.3)(typescript@5.8.3)):
|
||||
dependencies:
|
||||
'@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.0.3)(typescript@5.8.3))
|
||||
'@jest/test-result': 29.7.0
|
||||
'@jest/types': 29.6.3
|
||||
chalk: 4.1.2
|
||||
create-jest: 29.7.0(@types/node@24.0.3)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.0.3)(typescript@5.8.3))
|
||||
exit: 0.1.2
|
||||
import-local: 3.2.0
|
||||
jest-config: 29.7.0(@types/node@24.0.3)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.0.3)(typescript@5.8.3))
|
||||
jest-util: 29.7.0
|
||||
jest-validate: 29.7.0
|
||||
yargs: 17.7.2
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- babel-plugin-macros
|
||||
- supports-color
|
||||
- ts-node
|
||||
|
||||
jest-config@29.7.0(@types/node@22.15.32)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.15.32)(typescript@5.8.3)):
|
||||
dependencies:
|
||||
'@babel/core': 7.27.4
|
||||
@ -11007,6 +11073,68 @@ snapshots:
|
||||
- babel-plugin-macros
|
||||
- supports-color
|
||||
|
||||
jest-config@29.7.0(@types/node@22.15.32)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.0.3)(typescript@5.8.3)):
|
||||
dependencies:
|
||||
'@babel/core': 7.27.4
|
||||
'@jest/test-sequencer': 29.7.0
|
||||
'@jest/types': 29.6.3
|
||||
babel-jest: 29.7.0(@babel/core@7.27.4)
|
||||
chalk: 4.1.2
|
||||
ci-info: 3.9.0
|
||||
deepmerge: 4.3.1
|
||||
glob: 7.2.3
|
||||
graceful-fs: 4.2.11
|
||||
jest-circus: 29.7.0(babel-plugin-macros@3.1.0)
|
||||
jest-environment-node: 29.7.0
|
||||
jest-get-type: 29.6.3
|
||||
jest-regex-util: 29.6.3
|
||||
jest-resolve: 29.7.0
|
||||
jest-runner: 29.7.0
|
||||
jest-util: 29.7.0
|
||||
jest-validate: 29.7.0
|
||||
micromatch: 4.0.8
|
||||
parse-json: 5.2.0
|
||||
pretty-format: 29.7.0
|
||||
slash: 3.0.0
|
||||
strip-json-comments: 3.1.1
|
||||
optionalDependencies:
|
||||
'@types/node': 22.15.32
|
||||
ts-node: 10.9.2(@types/node@24.0.3)(typescript@5.8.3)
|
||||
transitivePeerDependencies:
|
||||
- babel-plugin-macros
|
||||
- supports-color
|
||||
|
||||
jest-config@29.7.0(@types/node@24.0.3)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.0.3)(typescript@5.8.3)):
|
||||
dependencies:
|
||||
'@babel/core': 7.27.4
|
||||
'@jest/test-sequencer': 29.7.0
|
||||
'@jest/types': 29.6.3
|
||||
babel-jest: 29.7.0(@babel/core@7.27.4)
|
||||
chalk: 4.1.2
|
||||
ci-info: 3.9.0
|
||||
deepmerge: 4.3.1
|
||||
glob: 7.2.3
|
||||
graceful-fs: 4.2.11
|
||||
jest-circus: 29.7.0(babel-plugin-macros@3.1.0)
|
||||
jest-environment-node: 29.7.0
|
||||
jest-get-type: 29.6.3
|
||||
jest-regex-util: 29.6.3
|
||||
jest-resolve: 29.7.0
|
||||
jest-runner: 29.7.0
|
||||
jest-util: 29.7.0
|
||||
jest-validate: 29.7.0
|
||||
micromatch: 4.0.8
|
||||
parse-json: 5.2.0
|
||||
pretty-format: 29.7.0
|
||||
slash: 3.0.0
|
||||
strip-json-comments: 3.1.1
|
||||
optionalDependencies:
|
||||
'@types/node': 24.0.3
|
||||
ts-node: 10.9.2(@types/node@24.0.3)(typescript@5.8.3)
|
||||
transitivePeerDependencies:
|
||||
- babel-plugin-macros
|
||||
- supports-color
|
||||
|
||||
jest-diff@29.7.0:
|
||||
dependencies:
|
||||
chalk: 4.1.2
|
||||
@ -11164,10 +11292,10 @@ snapshots:
|
||||
jest-snapshot@29.7.0:
|
||||
dependencies:
|
||||
'@babel/core': 7.27.4
|
||||
'@babel/generator': 7.27.3
|
||||
'@babel/generator': 7.27.5
|
||||
'@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.4)
|
||||
'@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.27.4)
|
||||
'@babel/types': 7.27.3
|
||||
'@babel/types': 7.27.6
|
||||
'@jest/expect-utils': 29.7.0
|
||||
'@jest/transform': 29.7.0
|
||||
'@jest/types': 29.6.3
|
||||
@ -11234,6 +11362,18 @@ snapshots:
|
||||
- supports-color
|
||||
- ts-node
|
||||
|
||||
jest@29.7.0(@types/node@24.0.3)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.0.3)(typescript@5.8.3)):
|
||||
dependencies:
|
||||
'@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.0.3)(typescript@5.8.3))
|
||||
'@jest/types': 29.6.3
|
||||
import-local: 3.2.0
|
||||
jest-cli: 29.7.0(@types/node@24.0.3)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.0.3)(typescript@5.8.3))
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- babel-plugin-macros
|
||||
- supports-color
|
||||
- ts-node
|
||||
|
||||
jiti@2.4.2: {}
|
||||
|
||||
joi@17.13.3:
|
||||
@ -12859,6 +12999,26 @@ snapshots:
|
||||
esbuild: 0.25.5
|
||||
jest-util: 29.7.0
|
||||
|
||||
ts-jest@29.4.0(@babel/core@7.27.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.4))(jest-util@29.7.0)(jest@29.7.0(@types/node@24.0.3)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.0.3)(typescript@5.8.3)))(typescript@5.8.3):
|
||||
dependencies:
|
||||
bs-logger: 0.2.6
|
||||
ejs: 3.1.10
|
||||
fast-json-stable-stringify: 2.1.0
|
||||
jest: 29.7.0(@types/node@24.0.3)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.0.3)(typescript@5.8.3))
|
||||
json5: 2.2.3
|
||||
lodash.memoize: 4.1.2
|
||||
make-error: 1.3.6
|
||||
semver: 7.7.2
|
||||
type-fest: 4.41.0
|
||||
typescript: 5.8.3
|
||||
yargs-parser: 21.1.1
|
||||
optionalDependencies:
|
||||
'@babel/core': 7.27.4
|
||||
'@jest/transform': 29.7.0
|
||||
'@jest/types': 29.6.3
|
||||
babel-jest: 29.7.0(@babel/core@7.27.4)
|
||||
jest-util: 29.7.0
|
||||
|
||||
ts-node@10.9.2(@types/node@22.15.32)(typescript@5.8.3):
|
||||
dependencies:
|
||||
'@cspotcode/source-map-support': 0.8.1
|
||||
|
||||
Loading…
Reference in New Issue
Block a user