diff --git a/AGENTS.md b/AGENTS.md index c221edf..a5aa66c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -40,7 +40,7 @@ src/ ├── constantes.ts # Constantes globais (enums, valores fixos) ├── situacoes.ts # Status/situações dos processos ├── tipagemRotas.ts # Tipagem forte de rotas da API -├── tipoFiltro.26.ts # Sistema de filtros tipados (operadores PG) +├── filtroDelta.ts # Sistema de filtros tipados (operadores PG) ├── uuid.ts # Geração e validação de UUIDs ├── dayjs26.ts # Wrapper do dayjs com locale e plugins ├── extensoes.ts # Extensões de tipos nativos diff --git a/README.md b/README.md index 2c5cc88..be02418 100755 --- a/README.md +++ b/README.md @@ -118,9 +118,9 @@ pnpm add --save-dev --save-exact @biomejs/biome@2.4.0 --- -## ✅ Sistema de Filtros (tipoFiltro26) +## ✅ Sistema de Filtros (filtroDelta) -O sistema `tipoFiltro26` foi projetado para gerar automaticamente a tipagem de filtros compatíveis com operadores padrão do PostgreSQL, a partir de um tipo base `T`. +O sistema `filtroDelta` foi projetado para gerar automaticamente a tipagem de filtros compatíveis com operadores padrão do PostgreSQL, a partir de um tipo base `T`. **Principais características:** - Tipagem forte e segura (TypeScript) @@ -178,7 +178,7 @@ O sistema `tipoFiltro26` foi projetado para gerar automaticamente a tipagem de f } ``` -### Operadores Suportados (`operadores26`) +### Operadores Suportados (`operadoresDelta`) - **Number**: `=`, `!=`, `>`, `>=`, `<`, `<=`, `in` - **String**: `=`, `!=`, `like`, `in` @@ -187,10 +187,10 @@ O sistema `tipoFiltro26` foi projetado para gerar automaticamente a tipagem de f ### Validação em Tempo de Execução (Zod) ```typescript -import { zFiltro26 } from "p-comuns" +import { zFiltroDelta } from "p-comuns" // Valida a estrutura (não checa existência de colunas no DB) -zFiltro26.parse(objetoFiltro) +zFiltroDelta.parse(objetoFiltro) ``` --- diff --git a/dist-back/filtroDelta.js b/dist-back/filtroDelta.js new file mode 100644 index 0000000..7628013 --- /dev/null +++ b/dist-back/filtroDelta.js @@ -0,0 +1,109 @@ +"use strict"; +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var filtroDelta_exports = {}; +__export(filtroDelta_exports, { + zColunaFiltroDelta: () => zColunaFiltroDelta, + zCondicaoFiltroDelta: () => zCondicaoFiltroDelta, + zFiltroDelta: () => zFiltroDelta, + zOperadorFiltroDelta: () => zOperadorFiltroDelta +}); +module.exports = __toCommonJS(filtroDelta_exports); +var import_zod = __toESM(require("zod")); +const zOperadorFiltroDelta = import_zod.default.enum([">", "<", ">=", "<=", "=", "!=", "in", "like"]); +const regexIdCondicaoFiltroDelta = /^\{[\w:]+\}$/; +const regexColunaFiltroDelta = /^\w+(\.\w+)*$/; +const zColunaFiltroDelta = import_zod.default.string().regex(regexColunaFiltroDelta, "Coluna inv\xE1lida").describe("nome da coluna ou caminho aninhado do jsonb"); +const zCondicaoFiltroDelta = import_zod.default.object({ + /** + * Identificador único da condição. + * + * Exemplo: + * {1} + */ + id: import_zod.default.string().describe("id da condi\xE7\xE3o do filtro").regex(regexIdCondicaoFiltroDelta, "O id deve seguir o formato {identificador}"), + /** + * Nome da coluna ou caminho jsonb. + */ + coluna: zColunaFiltroDelta, + /** + * Operador da comparação. + */ + operador: zOperadorFiltroDelta, + /** + * Valor utilizado na comparação. + */ + valor: import_zod.default.any().describe("valor de compara\xE7\xE3o") +}); +const formulaFiltroDeltaValida = (formula) => { + const tokensPermitidos = formula.match(/\{[\w:]+\}|\bNAO\b|\bE\b|\bOU\b|\(|\)/g) || []; + const formulaReconstruida = tokensPermitidos.join(""); + const formulaOriginalSemEspacos = formula.replace(/\s+/g, ""); + const formulaReconstruidaSemEspacos = formulaReconstruida.replace(/\s+/g, ""); + if (formulaOriginalSemEspacos !== formulaReconstruidaSemEspacos) { + return false; + } + const expressaoLogica = formula.replace(/\{[\w:]+\}/g, "true").replace(/\bNAO\b/g, "!").replace(/\bE\b/g, "&&").replace(/\bOU\b/g, "||"); + try { + new Function(`return (${expressaoLogica})`)(); + return true; + } catch { + return false; + } +}; +const zFiltroDelta = import_zod.default.object({ + /** + * Lista de condições disponíveis. + */ + condicoes: import_zod.default.array(zCondicaoFiltroDelta), + /** + * Fórmula lógica que combina as condições. + */ + formula: import_zod.default.string().refine(formulaFiltroDeltaValida, { + message: "F\xF3rmula inv\xE1lida. Use apenas refer\xEAncias de condi\xE7\xF5es {id} ou {id:sufixo}, operadores E/OU/NAO e par\xEAnteses." + }) +}).superRefine((value, ctx) => { + const idsCondicoes = new Set(value.condicoes.map((condicao) => condicao.id)); + const referenciasFormula = value.formula.match(/\{[\w:]+\}/g) || []; + for (const referencia of referenciasFormula) { + if (!idsCondicoes.has(referencia)) { + ctx.addIssue({ + code: "custom", + path: ["formula"], + message: `A refer\xEAncia ${referencia} n\xE3o existe em condicoes.` + }); + } + } +}); +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + zColunaFiltroDelta, + zCondicaoFiltroDelta, + zFiltroDelta, + zOperadorFiltroDelta +}); diff --git a/dist-back/index.js b/dist-back/index.js index f6204a6..0ee57a4 100644 --- a/dist-back/index.js +++ b/dist-back/index.js @@ -20,10 +20,10 @@ __reExport(index_exports, require("./auditoria"), module.exports); __reExport(index_exports, require("./cacheMemoria"), module.exports); __reExport(index_exports, require("./constantes"), module.exports); __reExport(index_exports, require("./consulta"), module.exports); -__reExport(index_exports, require("./dayjs26"), module.exports); __reExport(index_exports, require("./ecosistema"), module.exports); __reExport(index_exports, require("./extensoes"), module.exports); __reExport(index_exports, require("./extensoes"), module.exports); +__reExport(index_exports, require("./filtroDelta"), module.exports); __reExport(index_exports, require("./local"), module.exports); __reExport(index_exports, require("./postgres"), module.exports); __reExport(index_exports, require("./produtos"), module.exports); @@ -32,7 +32,6 @@ __reExport(index_exports, require("./testes-de-variaveis"), module.exports); __reExport(index_exports, require("./texto_busca"), module.exports); __reExport(index_exports, require("./tipagemRotas"), module.exports); __reExport(index_exports, require("./tipagemRotas"), module.exports); -__reExport(index_exports, require("./tipoFiltro.26"), module.exports); __reExport(index_exports, require("./unidades_medida"), module.exports); __reExport(index_exports, require("./uuid"), module.exports); __reExport(index_exports, require("./variaveisComuns"), module.exports); @@ -43,10 +42,10 @@ __reExport(index_exports, require("./variaveisComuns"), module.exports); ...require("./cacheMemoria"), ...require("./constantes"), ...require("./consulta"), - ...require("./dayjs26"), ...require("./ecosistema"), ...require("./extensoes"), ...require("./extensoes"), + ...require("./filtroDelta"), ...require("./local"), ...require("./postgres"), ...require("./produtos"), @@ -55,7 +54,6 @@ __reExport(index_exports, require("./variaveisComuns"), module.exports); ...require("./texto_busca"), ...require("./tipagemRotas"), ...require("./tipagemRotas"), - ...require("./tipoFiltro.26"), ...require("./unidades_medida"), ...require("./uuid"), ...require("./variaveisComuns") diff --git a/dist-back/tipoFiltro.26.js b/dist-back/tipoFiltro.26.js deleted file mode 100644 index fe14814..0000000 --- a/dist-back/tipoFiltro.26.js +++ /dev/null @@ -1,72 +0,0 @@ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var tipoFiltro_26_exports = {}; -__export(tipoFiltro_26_exports, { - agrupadores26: () => agrupadores26, - criarFiltro26: () => criarFiltro26, - operadores26: () => operadores26, - zFiltro26: () => zFiltro26 -}); -module.exports = __toCommonJS(tipoFiltro_26_exports); -var import_zod = require("zod"); -var operadores26 = /* @__PURE__ */ ((operadores262) => { - operadores262["="] = "="; - operadores262["!="] = "!="; - operadores262[">"] = ">"; - operadores262[">="] = ">="; - operadores262["<"] = "<"; - operadores262["<="] = "<="; - operadores262["like"] = "like"; - operadores262["in"] = "in"; - return operadores262; -})(operadores26 || {}); -var agrupadores26 = /* @__PURE__ */ ((agrupadores262) => { - agrupadores262["E"] = "E"; - agrupadores262["OU"] = "OU"; - return agrupadores262; -})(agrupadores26 || {}); -const zOperadores = import_zod.z.nativeEnum(operadores26); -const zValor = import_zod.z.any(); -const zCondicao = import_zod.z.record(zOperadores, zValor); -const zFiltro26 = import_zod.z.lazy( - () => import_zod.z.object({ - E: import_zod.z.array(zFiltro26).optional(), - OU: import_zod.z.array(zFiltro26).optional() - }).catchall(import_zod.z.union([zCondicao, zFiltro26])) -); -const criarFiltro26 = (filtro) => filtro; -const _filtro = criarFiltro26({ - idade: { [">=" /* >= */]: 18 }, - ["OU" /* OU */]: [ - { nome: { ["like" /* like */]: "%pa%" } }, - { - ["E" /* E */]: [ - { carro: { ano: { ["=" /* = */]: 2020 } } }, - { carro: { modelo: { ["in" /* in */]: ["Civic", "Corolla"] } } } - ] - } - ] -}); -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - agrupadores26, - criarFiltro26, - operadores26, - zFiltro26 -}); diff --git a/dist-front/index.d.mts b/dist-front/index.d.mts index e7b3026..29477e5 100644 --- a/dist-front/index.d.mts +++ b/dist-front/index.d.mts @@ -1,14 +1,4 @@ -import z, { z as z$1 } from 'zod'; -import _dayjs from 'dayjs'; -export { Dayjs, ManipulateType } from 'dayjs'; -import _duration from 'dayjs/plugin/duration'; -import _isSameOrAfter from 'dayjs/plugin/isSameOrAfter'; -import _isSameOrBefore from 'dayjs/plugin/isSameOrBefore'; -import _minMax from 'dayjs/plugin/minMax'; -import _relativeTime from 'dayjs/plugin/relativeTime'; -import _timezone from 'dayjs/plugin/timezone'; -import _utc from 'dayjs/plugin/utc'; -import _weekOfYear from 'dayjs/plugin/weekOfYear'; +import z from 'zod'; import { v4 } from 'uuid'; declare const aleatorio: (tamanho?: number) => string; @@ -124,70 +114,6 @@ declare const zFiltro: z.ZodObject<{ ou: z.ZodOptional; }, z.core.$strip>; -/** - * Utilitário de configuração do Dayjs focado em compatibilidade com SSR. - * - * PROBLEMA: - * A importação direta do `dayjs` e seus plugins frequentemente causa conflitos em ambientes - * de Renderização do Lado do Servidor (SSR), como Nuxt ou Next.js, devido a discrepâncias - * na resolução de módulos (ESM vs CJS) e instabilidades de importação. - * - * SOLUÇÃO: - * Este módulo utiliza o padrão de Injeção de Dependência. Ele expõe apenas tipagens e - * uma função de configuração (`defineDayjsBr`). A responsabilidade de importar as - * bibliotecas "vivas" é delegada à aplicação consumidora (o cliente da função). - * - * Isso permite que o bundler da aplicação principal (Vite, Webpack, etc.) gerencie as - * instâncias, garantindo consistência e evitando erros de "module not found" ou - * instâncias duplicadas/não inicializadas adequadamente. - */ - -/** - * Inicializa e configura o Dayjs com o locale 'pt-br' e plugins essenciais. - * - * MODO DE USO: - * Importe os pacotes reais na sua aplicação e passe-os para esta função. - * - * @example - * ```ts - * // Em seu arquivo de configuração (ex: plugins/dayjs.ts): - * import dayjs from "dayjs" - * import duration from "dayjs/plugin/duration" - * import isSameOrAfter from "dayjs/plugin/isSameOrAfter" - * import isSameOrBefore from "dayjs/plugin/isSameOrBefore" - * import minMax from "dayjs/plugin/minMax" - * import relativeTime from "dayjs/plugin/relativeTime" - * import timezone from "dayjs/plugin/timezone" - * import utc from "dayjs/plugin/utc" - * import weekOfYear from "dayjs/plugin/weekOfYear" - * import { defineDayjsBr } from "p-comuns" - * import "dayjs/locale/pt-br" // Importante: importar o locale! - - * export const dayjsbr = defineDayjsBr({ - * dayjs, - * duration, - * isSameOrAfter, - * isSameOrBefore, - * minMax, - * relativeTime, - * timezone, - * utc, - * weekOfYear, - * }) - * ``` - */ -declare const defineDayjsBr: ({ dayjs, duration, isSameOrAfter, isSameOrBefore, minMax, relativeTime, timezone, utc, weekOfYear, }: { - dayjs: typeof _dayjs; - duration: typeof _duration; - isSameOrAfter: typeof _isSameOrAfter; - isSameOrBefore: typeof _isSameOrBefore; - minMax: typeof _minMax; - relativeTime: typeof _relativeTime; - timezone: typeof _timezone; - utc: typeof _utc; - weekOfYear: typeof _weekOfYear; -}) => typeof _dayjs; - declare const link_paiol = "https://paiol.idz.one"; type tiposArquivo = "imagem" | "documento" | "vídeo" | "outros"; @@ -203,6 +129,67 @@ declare const extensoes: { */ declare const tipoArquivo: (nomeArquivo: string | null | undefined) => tiposArquivo; +/** + * Operadores permitidos para comparação. + */ +declare const zOperadorFiltroDelta: z.ZodEnum<{ + "=": "="; + "!=": "!="; + ">": ">"; + ">=": ">="; + "<": "<"; + "<=": "<="; + like: "like"; + in: "in"; +}>; +/** + * Coluna simples ou caminho aninhado de jsonb. + */ +declare const zColunaFiltroDelta: z.ZodString; +/** + * Estrutura individual de uma condição do filtro. + */ +declare const zCondicaoFiltroDelta: z.ZodObject<{ + id: z.ZodString; + coluna: z.ZodString; + operador: z.ZodEnum<{ + "=": "="; + "!=": "!="; + ">": ">"; + ">=": ">="; + "<": "<"; + "<=": "<="; + like: "like"; + in: "in"; + }>; + valor: z.ZodAny; +}, z.core.$strip>; +/** + * Estrutura principal do filtro delta. + */ +declare const zFiltroDelta: z.ZodObject<{ + condicoes: z.ZodArray": ">"; + ">=": ">="; + "<": "<"; + "<=": "<="; + like: "like"; + in: "in"; + }>; + valor: z.ZodAny; + }, z.core.$strip>>; + formula: z.ZodString; +}, z.core.$strip>; +type tipoOperadorFiltroDelta = z.infer; +type tipoColunaFiltroDelta = z.infer; +type tipoCondicaoFiltroDelta = z.infer; +type tipoFiltroDelta = z.infer; + /** * LocalStorage Tipado * Lê ou grava um valor no localStorage, mantendo o tipo genérico . @@ -347,151 +334,6 @@ declare class TipagemRotas; } -/** - * ============================================================================= - * tipoFiltro26 - * ============================================================================= - * - * OBJETIVO - * ----------------------------------------------------------------------------- - * Gerar automaticamente a tipagem de filtros compatíveis com operadores - * padrão do PostgreSQL, a partir de um tipo base T. - * - * Este tipo foi projetado para: - * - Construção de filtros dinâmicos - * - Geração posterior de WHERE (Knex / SQL) - * - Uso seguro por IA (evita filtros inválidos em nível de tipo) - * - * - * FORMATO DO FILTRO - * ----------------------------------------------------------------------------- - * 1) Campos simples: - * - * { - * idade: { ">=": 18 } - * } - * - * 2) Campos aninhados: - * - * { - * carro: { - * ano: { "=": 2020 } - * } - * } - * - * 3) Operador E (AND): - * - * { - * E: [ - * { idade: { ">=": 18 } }, - * { nome: { like: "%pa%" } } - * ] - * } - * - * 4) Operador OU (OR): - * - * { - * OU: [ - * { idade: { "<": 18 } }, - * { idade: { ">=": 60 } } - * ] - * } - * - * 5) Combinação complexa: - * - * { - * idade: { ">=": 18 }, - * OU: [ - * { nome: { like: "%pa%" } }, - * { - * E: [ - * { carro: { ano: { "=": 2020 } } }, - * { carro: { modelo: { in: ["Civic"] } } } - * ] - * } - * ] - * } - * - * - * REGRAS IMPORTANTES (PARA IA) - * ----------------------------------------------------------------------------- - * - Apenas campos existentes em T podem ser usados. - * - Operadores são restritos por tipo do campo. - * - Objetos são tratados recursivamente. - * - Arrays NÃO são tratados como objeto recursivo. - * - Funções NÃO são consideradas campos filtráveis. - * - * - * OPERADORES SUPORTADOS - * ----------------------------------------------------------------------------- - * number: - * =, !=, >, >=, <, <=, in - * - * string: - * =, !=, like, in - * - * boolean: - * =, !=, in - * - * Não há suporte automático a: - * - null - * - date - * - jsonb - * - arrays - * - * Essas extensões devem ser adicionadas explicitamente. - * - * ============================================================================= - */ -declare enum operadores26 { - "=" = "=", - "!=" = "!=", - ">" = ">", - ">=" = ">=", - "<" = "<", - "<=" = "<=", - like = "like", - in = "in" -} -declare enum agrupadores26 { - E = "E", - OU = "OU" -} -type PgOpsNumber = { - [K in Extract" | ">=" | "<" | "<=">]?: number; -} & { - [K in Extract]?: number[]; -}; -type PgOpsString = { - [K in Extract]?: string; -} & { - [K in Extract]?: string[]; -}; -type PgOpsBoolean = { - [K in Extract]?: boolean[]; -}; -type PgOpsFor = V extends number ? PgOpsNumber : V extends string ? PgOpsString : V extends boolean ? PgOpsBoolean : never; -type IsPlainObject = T extends object ? T extends Function ? false : T extends readonly any[] ? false : true : false; -type FiltroCampos = { - [K in keyof T]?: IsPlainObject extends true ? tipoFiltro26 : PgOpsFor; -}; -type tipoFiltro26 = FiltroCampos & { - /** - * E => AND lógico - * Todos os filtros dentro do array devem ser verdadeiros. - */ - E?: tipoFiltro26[]; - /** - * OU => OR lógico - * Pelo menos um filtro dentro do array deve ser verdadeiro. - */ - OU?: tipoFiltro26[]; -}; -declare const zFiltro26: z$1.ZodType; -declare const criarFiltro26: (filtro: tipoFiltro26) => tipoFiltro26; - /** * Essa variável se conecta a tabela_lidades * @@ -560,4 +402,4 @@ declare const nomeVariavel: (v: { [key: string]: any; }) => string; -export { Produtos, TipagemRotas, type TipoPayloadAuditoria, agrupadores26, aleatorio, cacheM, cacheMFixo, cacheMemoria, camposComuns, criarFiltro26, defineDayjsBr, erUuid, esperar, extensoes, type interfaceConsulta, link_paiol, localValor, nomeVariavel, objetoPg, operadores, operadores26, paraObjetoRegistroPg, pgObjeto, siglas_unidades_medida, texto_busca, tipoArquivo, type tipoFiltro, type tipoFiltro26, tipoUsuarioResiduos, tiposSituacoesElicencie, tx, umaFuncao, umaVariavel, unidades_medida, uuid, uuidV3, uuidV4, uuid_null, validarUuid, verCacheM, zFiltro, zFiltro26, zOperadores }; +export { Produtos, TipagemRotas, type TipoPayloadAuditoria, aleatorio, cacheM, cacheMFixo, cacheMemoria, camposComuns, erUuid, esperar, extensoes, type interfaceConsulta, link_paiol, localValor, nomeVariavel, objetoPg, operadores, paraObjetoRegistroPg, pgObjeto, siglas_unidades_medida, texto_busca, tipoArquivo, type tipoColunaFiltroDelta, type tipoCondicaoFiltroDelta, type tipoFiltro, type tipoFiltroDelta, type tipoOperadorFiltroDelta, tipoUsuarioResiduos, tiposSituacoesElicencie, tx, umaFuncao, umaVariavel, unidades_medida, uuid, uuidV3, uuidV4, uuid_null, validarUuid, verCacheM, zColunaFiltroDelta, zCondicaoFiltroDelta, zFiltro, zFiltroDelta, zOperadorFiltroDelta, zOperadores }; diff --git a/dist-front/index.mjs b/dist-front/index.mjs index e227f36..30d296e 100644 --- a/dist-front/index.mjs +++ b/dist-front/index.mjs @@ -1 +1 @@ -var u="ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""),V=o=>`eli-${Array.from({length:o||8}).map(()=>u[(999*Math.random()|0)%u.length]).join("")}`;var s={};globalThis.cacheMemoria_cache=s;var g=(o,r,a)=>{let n=typeof o=="string"?o:typeof o=="number"?String(o):encodeURIComponent(JSON.stringify(o)),t=a&&new Date().getTime()+a*1e3;r!==void 0&&(s[n]={valor:r,validade:t});let i=s[n];if(!(i?.validade&&i.validades,G=g,$=o=>r=>g(o,r);var R="00000000-0000-0000-0000-000000000000",v=(m=>(m.codigo="codigo",m.excluido="excluido",m.data_hora_criacao="data_hora_criacao",m.data_hora_atualizacao="data_hora_atualizacao",m.codigo_usuario_criacao="codigo_usuario_criacao",m.codigo_usuario_atualizacao="codigo_usuario_atualizacao",m.versao="versao",m))(v||{}),b=(r=>(r.token="token",r))(b||{}),h=(a=>(a.Usuario="usuario",a.Fornecedor="fornecedor",a))(h||{});import l from"zod";var O=(n=>(n["="]="=",n["!="]="!=",n[">"]=">",n[">="]=">=",n["<"]="<",n["<="]="<=",n.like="like",n.in="in",n.isNull="isNull",n))(O||{}),T=l.enum(["=","!=",">",">=","<","<=","like","in","isNull"]),Z=l.object({coluna:l.string(),valor:l.any(),operador:T,ou:l.boolean().optional()});var W=({dayjs:o,duration:r,isSameOrAfter:a,isSameOrBefore:n,minMax:t,relativeTime:i,timezone:d,utc:m,weekOfYear:y})=>(o.extend(m),o.extend(d),o.extend(y),o.extend(n),o.extend(a),o.extend(t),o.extend(i),o.extend(r),o.locale("pt-br"),o);var S="https://paiol.idz.one";var z=[{ext:"gif",tipo:"imagem",mime:"image/gif"},{ext:"jpg",tipo:"imagem",mime:"image/jpeg"},{ext:"jpeg",tipo:"imagem",mime:"image/jpeg"},{ext:"png",tipo:"imagem",mime:"image/png"},{ext:"bmp",tipo:"imagem",mime:"image/bmp"},{ext:"webp",tipo:"imagem",mime:"image/webp"},{ext:"tiff",tipo:"imagem",mime:"image/tiff"},{ext:"svg",tipo:"imagem",mime:"image/svg+xml"},{ext:"ico",tipo:"imagem",mime:"image/x-icon"},{ext:"pdf",tipo:"documento",mime:"application/pdf"},{ext:"doc",tipo:"documento",mime:"application/msword"},{ext:"docx",tipo:"documento",mime:"application/vnd.openxmlformats-officedocument.wordprocessingml.document"},{ext:"xls",tipo:"documento",mime:"application/vnd.ms-excel"},{ext:"xlsx",tipo:"documento",mime:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},{ext:"ppt",tipo:"documento",mime:"application/vnd.ms-powerpoint"},{ext:"pptx",tipo:"documento",mime:"application/vnd.openxmlformats-officedocument.presentationml.presentation"},{ext:"txt",tipo:"documento",mime:"text/plain"},{ext:"odt",tipo:"documento",mime:"application/vnd.oasis.opendocument.text"},{ext:"ods",tipo:"documento",mime:"application/vnd.oasis.opendocument.spreadsheet"},{ext:"rtf",tipo:"documento",mime:"application/rtf"},{ext:"csv",tipo:"documento",mime:"text/csv"},{ext:"mp4",tipo:"v\xEDdeo",mime:"video/mp4"},{ext:"avi",tipo:"v\xEDdeo",mime:"video/x-msvideo"},{ext:"mkv",tipo:"v\xEDdeo",mime:"video/x-matroska"},{ext:"mov",tipo:"v\xEDdeo",mime:"video/quicktime"},{ext:"wmv",tipo:"v\xEDdeo",mime:"video/x-ms-wmv"},{ext:"flv",tipo:"v\xEDdeo",mime:"video/x-flv"},{ext:"webm",tipo:"v\xEDdeo",mime:"video/webm"},{ext:"3gp",tipo:"v\xEDdeo",mime:"video/3gpp"},{ext:"mpeg",tipo:"v\xEDdeo",mime:"video/mpeg"}],ao=o=>{let r=String(o||"").toLocaleLowerCase().split(".").pop();return z.find(n=>n.ext===r)?.tipo||"outros"};var to=(o,r)=>{let a="localStorage"in globalThis?globalThis.localStorage:void 0;if(typeof a>"u")return null;let n=typeof o=="string"?o:encodeURIComponent(JSON.stringify(o));try{r!==void 0&&a.setItem(n,JSON.stringify(r));let t=a.getItem(n);if(t===null)return null;try{return JSON.parse(t)}catch{return t}}catch{return null}};var x=o=>{try{return Object.fromEntries(Object.entries(o).map(([r,a])=>[r,a===void 0||a==null||typeof a=="string"||typeof a=="number"||typeof a=="boolean"?a:JSON.stringify(a,null,2)]))}catch(r){throw new Error(`Erro na fun\xE7\xE3o paraObjetoRegistroPg: ${r.message} ${r.stack}`)}},io=x,mo=x;var w=(o=>(o["e-licencie"]="e-licencie",o["gov.e-licencie"]="gov.e-licencie",o))(w||{});var j=(e=>(e.modelo="000_modelo",e.vencida="100_vencida",e.expirado="200_expirado",e.alerta="300_alerta",e.protocoladafora="350_protocoladafora",e.protocolada="400_protocolada",e.protocoladaApenas="430_protocolada",e.protocolada_alteracao="450_protocolada",e.prazo="500_prazo",e.emitida="515_emitida",e.valida="518_valida",e.novo="520_novo",e.recebido="521_recebido",e.em_andamento="530_em_andamento",e.aguardando="530_aguardando",e.aguardandoresposta="540_aguardandoresposta",e.suspensaotemporaria="540_suspensaotemporaria",e.cancelada="550_cancelada",e.execucao="560_execucao",e.pendente="570_pendente",e.executadafora="600_executadafora",e.executada="700_executada",e.naoexecutada="701_naoexecutada",e.concluida="730_concluida",e.respondido_negado="740_respondido_negado",e.respondido_aceito="741_respondido_aceito",e.atendidoparcial="742_atendidoparcial",e.naoatendido="743_naoatendido",e.atendido="744_atendido",e.renovada="760_renovada",e.finalizada="800_finalizada",e.emitirnota="101_emitirnota",e.faturaatrasada="301_faturaatrasada",e.pagarfatura="302_pagarfatura",e.aguardandoconfirmacao="531_aguardandoconfirmacao",e.agendado="701_agendado",e.faturapaga="801_faturapaga",e.excluida="999_excluida",e.requerida="401_requerida",e.vigente="516_vigente",e.emrenovacao="402_emrenovacao",e.arquivada="801_arquivada",e.aguardando_sincronizacao="999_aguardando_sincronizacao",e.nao_conforme="710_nao_conforme",e.conforme="720_conforme",e.nao_aplicavel="730_nao_aplicavel",e.parcial="715_parcial",e))(j||{});var fo=()=>"Ol\xE1 Mundo! (fun\xE7\xE3o)";var go="Ol\xE1 Mundo! (vari\xE1vel)";var vo=(...o)=>o.map(r=>r==null?"":String(r).normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/\s+/g," ").toLowerCase()).join(" ");var c=class{constructor({caminho:r,acaoIr:a,rotulo:n}){this._partesCaminho=[];this._acaoIr=a,this._partesCaminho=(Array.isArray(r)?r:[r]).filter(Boolean).map(t=>String(t)).flatMap(t=>t.split("/")).filter(Boolean),this.rotulo=n}get caminho(){return`/${this._partesCaminho.join("/")}`}set caminho(r){this._partesCaminho=r.split("/").filter(a=>a)}endereco(r,a){let n=typeof globalThis<"u"&&globalThis.window||void 0,t=new URL(n?n.location.href:"http://localhost");t.pathname=this.caminho,t.search="";let i=Object.entries(r);for(let[d,m]of i)t.searchParams.set(String(d),JSON.stringify(m));return t.hash="",a&&(t.hash=`#${t.search}`,t.search=""),t.href}ir(r){if(this._acaoIr)this._acaoIr(this.endereco({...r}));else{let a=typeof globalThis<"u"&&globalThis.window||void 0;a&&(a.location.href=this.endereco({...r}))}}parametros(r){let a=r?new URL(r):new URL(typeof globalThis<"u"&&globalThis.window?globalThis.window.location.href:"http://localhost"),n=a.searchParams,t=Object.fromEntries(n.entries()),i=a.hash;if(i){let d=Object.fromEntries(new URLSearchParams(i.slice(1)).entries());t={...t,...d}}for(let d in t)try{t[d]=JSON.parse(t[d])}catch{console.log(`[${d}|${t[d]}] n\xE3o \xE9 um json v\xE1lido.`)}return t}};import{z as p}from"zod";var _=(a=>(a["="]="=",a["!="]="!=",a[">"]=">",a[">="]=">=",a["<"]="<",a["<="]="<=",a.like="like",a.in="in",a))(_||{}),k=(a=>(a.E="E",a.OU="OU",a))(k||{}),N=p.nativeEnum(_),F=p.any(),P=p.record(N,F),f=p.lazy(()=>p.object({E:p.array(f).optional(),OU:p.array(f).optional()}).catchall(p.union([P,f]))),M=o=>o,To=M({idade:{">=":18},OU:[{nome:{like:"%pa%"}},{E:[{carro:{ano:{"=":2020}}},{carro:{modelo:{in:["Civic","Corolla"]}}}]}]});var K=(i=>(i.UN="UN",i.KG="KG",i.TON="TON",i.g="g",i["M\xB3"]="M\xB3",i.Lt="Lt",i))(K||{}),wo=[{sigla_unidade:"KG",nome:"Quilograma",sigla_normalizada:"KG",normalizar:o=>o,tipo:"massa"},{sigla_unidade:"g",nome:"Grama",sigla_normalizada:"KG",normalizar:o=>o/1e3,tipo:"massa"},{sigla_unidade:"TON",nome:"Tonelada",sigla_normalizada:"KG",normalizar:o=>o*1e3,tipo:"massa"},{sigla_unidade:"Lt",nome:"Litro",sigla_normalizada:"Lt",normalizar:o=>o,tipo:"volume"},{sigla_unidade:"M\xB3",nome:"Metro C\xFAbico",sigla_normalizada:"Lt",normalizar:o=>o*1e3,tipo:"volume"},{sigla_unidade:"UN",nome:"Unidade",sigla_normalizada:"UN",normalizar:o=>o,tipo:"unidade"}];import{NIL as U,v3 as L,v4 as A}from"uuid";var q=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,No=o=>q.test(String(o||"")),C=(o,r)=>L(typeof o=="string"?o:typeof o=="number"?String(o):JSON.stringify(o),r?C(r):U),I=A,Fo=I;var Mo=o=>new Promise(r=>setTimeout(()=>r(!0),o)),Ko=o=>Object.keys(o).join("/");export{w as Produtos,c as TipagemRotas,k as agrupadores26,V as aleatorio,g as cacheM,$ as cacheMFixo,G as cacheMemoria,v as camposComuns,M as criarFiltro26,W as defineDayjsBr,q as erUuid,Mo as esperar,z as extensoes,S as link_paiol,to as localValor,Ko as nomeVariavel,mo as objetoPg,O as operadores,_ as operadores26,x as paraObjetoRegistroPg,io as pgObjeto,K as siglas_unidades_medida,vo as texto_busca,ao as tipoArquivo,h as tipoUsuarioResiduos,j as tiposSituacoesElicencie,b as tx,fo as umaFuncao,go as umaVariavel,wo as unidades_medida,Fo as uuid,C as uuidV3,I as uuidV4,R as uuid_null,No as validarUuid,J as verCacheM,Z as zFiltro,f as zFiltro26,T as zOperadores}; +var f="ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""),I=o=>`eli-${Array.from({length:o||8}).map(()=>f[(999*Math.random()|0)%f.length]).join("")}`;var s={};globalThis.cacheMemoria_cache=s;var u=(o,a,r)=>{let n=typeof o=="string"?o:typeof o=="number"?String(o):encodeURIComponent(JSON.stringify(o)),t=r&&new Date().getTime()+r*1e3;a!==void 0&&(s[n]={valor:a,validade:t});let i=s[n];if(!(i?.validade&&i.validades,J=u,R=o=>a=>u(o,a);var K="00000000-0000-0000-0000-000000000000",x=(m=>(m.codigo="codigo",m.excluido="excluido",m.data_hora_criacao="data_hora_criacao",m.data_hora_atualizacao="data_hora_atualizacao",m.codigo_usuario_criacao="codigo_usuario_criacao",m.codigo_usuario_atualizacao="codigo_usuario_atualizacao",m.versao="versao",m))(x||{}),_=(a=>(a.token="token",a))(_||{}),b=(r=>(r.Usuario="usuario",r.Fornecedor="fornecedor",r))(b||{});import p from"zod";var h=(n=>(n["="]="=",n["!="]="!=",n[">"]=">",n[">="]=">=",n["<"]="<",n["<="]="<=",n.like="like",n.in="in",n.isNull="isNull",n))(h||{}),v=p.enum(["=","!=",">",">=","<","<=","like","in","isNull"]),Q=p.object({coluna:p.string(),valor:p.any(),operador:v,ou:p.boolean().optional()});var W="https://paiol.idz.one";var y=[{ext:"gif",tipo:"imagem",mime:"image/gif"},{ext:"jpg",tipo:"imagem",mime:"image/jpeg"},{ext:"jpeg",tipo:"imagem",mime:"image/jpeg"},{ext:"png",tipo:"imagem",mime:"image/png"},{ext:"bmp",tipo:"imagem",mime:"image/bmp"},{ext:"webp",tipo:"imagem",mime:"image/webp"},{ext:"tiff",tipo:"imagem",mime:"image/tiff"},{ext:"svg",tipo:"imagem",mime:"image/svg+xml"},{ext:"ico",tipo:"imagem",mime:"image/x-icon"},{ext:"pdf",tipo:"documento",mime:"application/pdf"},{ext:"doc",tipo:"documento",mime:"application/msword"},{ext:"docx",tipo:"documento",mime:"application/vnd.openxmlformats-officedocument.wordprocessingml.document"},{ext:"xls",tipo:"documento",mime:"application/vnd.ms-excel"},{ext:"xlsx",tipo:"documento",mime:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},{ext:"ppt",tipo:"documento",mime:"application/vnd.ms-powerpoint"},{ext:"pptx",tipo:"documento",mime:"application/vnd.openxmlformats-officedocument.presentationml.presentation"},{ext:"txt",tipo:"documento",mime:"text/plain"},{ext:"odt",tipo:"documento",mime:"application/vnd.oasis.opendocument.text"},{ext:"ods",tipo:"documento",mime:"application/vnd.oasis.opendocument.spreadsheet"},{ext:"rtf",tipo:"documento",mime:"application/rtf"},{ext:"csv",tipo:"documento",mime:"text/csv"},{ext:"mp4",tipo:"v\xEDdeo",mime:"video/mp4"},{ext:"avi",tipo:"v\xEDdeo",mime:"video/x-msvideo"},{ext:"mkv",tipo:"v\xEDdeo",mime:"video/x-matroska"},{ext:"mov",tipo:"v\xEDdeo",mime:"video/quicktime"},{ext:"wmv",tipo:"v\xEDdeo",mime:"video/x-ms-wmv"},{ext:"flv",tipo:"v\xEDdeo",mime:"video/x-flv"},{ext:"webm",tipo:"v\xEDdeo",mime:"video/webm"},{ext:"3gp",tipo:"v\xEDdeo",mime:"video/3gpp"},{ext:"mpeg",tipo:"v\xEDdeo",mime:"video/mpeg"}],S=o=>{let a=String(o||"").toLocaleLowerCase().split(".").pop();return y.find(n=>n.ext===a)?.tipo||"outros"};import l from"zod";var z=l.enum([">","<",">=","<=","=","!=","in","like"]),w=/^\{[\w:]+\}$/,O=/^\w+(\.\w+)*$/,T=l.string().regex(O,"Coluna inv\xE1lida").describe("nome da coluna ou caminho aninhado do jsonb"),j=l.object({id:l.string().describe("id da condi\xE7\xE3o do filtro").regex(w,"O id deve seguir o formato {identificador}"),coluna:T,operador:z,valor:l.any().describe("valor de compara\xE7\xE3o")}),F=o=>{let r=(o.match(/\{[\w:]+\}|\bNAO\b|\bE\b|\bOU\b|\(|\)/g)||[]).join(""),n=o.replace(/\s+/g,""),t=r.replace(/\s+/g,"");if(n!==t)return!1;let i=o.replace(/\{[\w:]+\}/g,"true").replace(/\bNAO\b/g,"!").replace(/\bE\b/g,"&&").replace(/\bOU\b/g,"||");try{return new Function(`return (${i})`)(),!0}catch{return!1}},eo=l.object({condicoes:l.array(j),formula:l.string().refine(F,{message:"F\xF3rmula inv\xE1lida. Use apenas refer\xEAncias de condi\xE7\xF5es {id} ou {id:sufixo}, operadores E/OU/NAO e par\xEAnteses."})}).superRefine((o,a)=>{let r=new Set(o.condicoes.map(t=>t.id)),n=o.formula.match(/\{[\w:]+\}/g)||[];for(let t of n)r.has(t)||a.addIssue({code:"custom",path:["formula"],message:`A refer\xEAncia ${t} n\xE3o existe em condicoes.`})});var ro=(o,a)=>{let r="localStorage"in globalThis?globalThis.localStorage:void 0;if(typeof r>"u")return null;let n=typeof o=="string"?o:encodeURIComponent(JSON.stringify(o));try{a!==void 0&&r.setItem(n,JSON.stringify(a));let t=r.getItem(n);if(t===null)return null;try{return JSON.parse(t)}catch{return t}}catch{return null}};var g=o=>{try{return Object.fromEntries(Object.entries(o).map(([a,r])=>[a,r===void 0||r==null||typeof r=="string"||typeof r=="number"||typeof r=="boolean"?r:JSON.stringify(r,null,2)]))}catch(a){throw new Error(`Erro na fun\xE7\xE3o paraObjetoRegistroPg: ${a.message} ${a.stack}`)}},no=g,io=g;var N=(o=>(o["e-licencie"]="e-licencie",o["gov.e-licencie"]="gov.e-licencie",o))(N||{});var k=(e=>(e.modelo="000_modelo",e.vencida="100_vencida",e.expirado="200_expirado",e.alerta="300_alerta",e.protocoladafora="350_protocoladafora",e.protocolada="400_protocolada",e.protocoladaApenas="430_protocolada",e.protocolada_alteracao="450_protocolada",e.prazo="500_prazo",e.emitida="515_emitida",e.valida="518_valida",e.novo="520_novo",e.recebido="521_recebido",e.em_andamento="530_em_andamento",e.aguardando="530_aguardando",e.aguardandoresposta="540_aguardandoresposta",e.suspensaotemporaria="540_suspensaotemporaria",e.cancelada="550_cancelada",e.execucao="560_execucao",e.pendente="570_pendente",e.executadafora="600_executadafora",e.executada="700_executada",e.naoexecutada="701_naoexecutada",e.concluida="730_concluida",e.respondido_negado="740_respondido_negado",e.respondido_aceito="741_respondido_aceito",e.atendidoparcial="742_atendidoparcial",e.naoatendido="743_naoatendido",e.atendido="744_atendido",e.renovada="760_renovada",e.finalizada="800_finalizada",e.emitirnota="101_emitirnota",e.faturaatrasada="301_faturaatrasada",e.pagarfatura="302_pagarfatura",e.aguardandoconfirmacao="531_aguardandoconfirmacao",e.agendado="701_agendado",e.faturapaga="801_faturapaga",e.excluida="999_excluida",e.requerida="401_requerida",e.vigente="516_vigente",e.emrenovacao="402_emrenovacao",e.arquivada="801_arquivada",e.aguardando_sincronizacao="999_aguardando_sincronizacao",e.nao_conforme="710_nao_conforme",e.conforme="720_conforme",e.nao_aplicavel="730_nao_aplicavel",e.parcial="715_parcial",e))(k||{});var so=()=>"Ol\xE1 Mundo! (fun\xE7\xE3o)";var uo="Ol\xE1 Mundo! (vari\xE1vel)";var bo=(...o)=>o.map(a=>a==null?"":String(a).normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/\s+/g," ").toLowerCase()).join(" ");var c=class{constructor({caminho:a,acaoIr:r,rotulo:n}){this._partesCaminho=[];this._acaoIr=r,this._partesCaminho=(Array.isArray(a)?a:[a]).filter(Boolean).map(t=>String(t)).flatMap(t=>t.split("/")).filter(Boolean),this.rotulo=n}get caminho(){return`/${this._partesCaminho.join("/")}`}set caminho(a){this._partesCaminho=a.split("/").filter(r=>r)}endereco(a,r){let n=typeof globalThis<"u"&&globalThis.window||void 0,t=new URL(n?n.location.href:"http://localhost");t.pathname=this.caminho,t.search="";let i=Object.entries(a);for(let[d,m]of i)t.searchParams.set(String(d),JSON.stringify(m));return t.hash="",r&&(t.hash=`#${t.search}`,t.search=""),t.href}ir(a){if(this._acaoIr)this._acaoIr(this.endereco({...a}));else{let r=typeof globalThis<"u"&&globalThis.window||void 0;r&&(r.location.href=this.endereco({...a}))}}parametros(a){let r=a?new URL(a):new URL(typeof globalThis<"u"&&globalThis.window?globalThis.window.location.href:"http://localhost"),n=r.searchParams,t=Object.fromEntries(n.entries()),i=r.hash;if(i){let d=Object.fromEntries(new URLSearchParams(i.slice(1)).entries());t={...t,...d}}for(let d in t)try{t[d]=JSON.parse(t[d])}catch{console.log(`[${d}|${t[d]}] n\xE3o \xE9 um json v\xE1lido.`)}return t}};var D=(i=>(i.UN="UN",i.KG="KG",i.TON="TON",i.g="g",i["M\xB3"]="M\xB3",i.Lt="Lt",i))(D||{}),yo=[{sigla_unidade:"KG",nome:"Quilograma",sigla_normalizada:"KG",normalizar:o=>o,tipo:"massa"},{sigla_unidade:"g",nome:"Grama",sigla_normalizada:"KG",normalizar:o=>o/1e3,tipo:"massa"},{sigla_unidade:"TON",nome:"Tonelada",sigla_normalizada:"KG",normalizar:o=>o*1e3,tipo:"massa"},{sigla_unidade:"Lt",nome:"Litro",sigla_normalizada:"Lt",normalizar:o=>o,tipo:"volume"},{sigla_unidade:"M\xB3",nome:"Metro C\xFAbico",sigla_normalizada:"Lt",normalizar:o=>o*1e3,tipo:"volume"},{sigla_unidade:"UN",nome:"Unidade",sigla_normalizada:"UN",normalizar:o=>o,tipo:"unidade"}];import{NIL as C,v3 as U,v4 as L}from"uuid";var A=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,Oo=o=>A.test(String(o||"")),M=(o,a)=>U(typeof o=="string"?o:typeof o=="number"?String(o):JSON.stringify(o),a?M(a):C),q=L,To=q;var Fo=o=>new Promise(a=>setTimeout(()=>a(!0),o)),No=o=>Object.keys(o).join("/");export{N as Produtos,c as TipagemRotas,I as aleatorio,u as cacheM,R as cacheMFixo,J as cacheMemoria,x as camposComuns,A as erUuid,Fo as esperar,y as extensoes,W as link_paiol,ro as localValor,No as nomeVariavel,io as objetoPg,h as operadores,g as paraObjetoRegistroPg,no as pgObjeto,D as siglas_unidades_medida,bo as texto_busca,S as tipoArquivo,b as tipoUsuarioResiduos,k as tiposSituacoesElicencie,_ as tx,so as umaFuncao,uo as umaVariavel,yo as unidades_medida,To as uuid,M as uuidV3,q as uuidV4,K as uuid_null,Oo as validarUuid,P as verCacheM,T as zColunaFiltroDelta,j as zCondicaoFiltroDelta,Q as zFiltro,eo as zFiltroDelta,z as zOperadorFiltroDelta,v as zOperadores}; diff --git a/package.json b/package.json index da10e21..a4e57ac 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "p-comuns", - "version": "0.336.0", + "version": "0.339.0", "description": "", "main": "./dist-front/index.mjs", "module": "./dist-front/index.mjs", @@ -29,7 +29,7 @@ "dependencies": {}, "devDependencies": { "uuid": "^11.1.0", - "zod": "4.3.6", + "zod": "4.4.3", "dayjs": "^1.11.18", "@biomejs/biome": "2.4.12", "@types/node": "^22", @@ -41,6 +41,6 @@ "peerDependencies": { "dayjs": "^1.11.18", "uuid": "^11.1.0", - "zod": "4.3.6" + "zod": "4.4.3" } } diff --git a/pacote.tgz b/pacote.tgz index 226d8e9..e3b9867 100644 Binary files a/pacote.tgz and b/pacote.tgz differ diff --git a/src/filtroDelta.ts b/src/filtroDelta.ts new file mode 100644 index 0000000..1023c8d --- /dev/null +++ b/src/filtroDelta.ts @@ -0,0 +1,162 @@ +import z from "zod" + +/** + * Operadores permitidos para comparação. + */ +export const zOperadorFiltroDelta = z.enum([">", "<", ">=", "<=", "=", "!=", "in", "like"]) + +/** + * Valida o identificador da condição. + * + * Formato esperado: + * {identificador} ou {identificador:sufixo} + */ +const regexIdCondicaoFiltroDelta = /^\{[\w:]+\}$/ + +/** + * Valida nomes de colunas e caminhos jsonb. + */ +const regexColunaFiltroDelta = /^\w+(\.\w+)*$/ + +/** + * Coluna simples ou caminho aninhado de jsonb. + */ +export const zColunaFiltroDelta = z + .string() + .regex(regexColunaFiltroDelta, "Coluna inválida") + .describe("nome da coluna ou caminho aninhado do jsonb") + +/** + * Estrutura individual de uma condição do filtro. + */ +export const zCondicaoFiltroDelta = z.object({ + /** + * Identificador único da condição. + * + * Exemplo: + * {1} + */ + id: z + .string() + .describe("id da condição do filtro") + .regex(regexIdCondicaoFiltroDelta, "O id deve seguir o formato {identificador}"), + + /** + * Nome da coluna ou caminho jsonb. + */ + coluna: zColunaFiltroDelta, + + /** + * Operador da comparação. + */ + operador: zOperadorFiltroDelta, + + /** + * Valor utilizado na comparação. + */ + valor: z.any().describe("valor de comparação"), +}) + +/** + * Verifica se a fórmula possui uma estrutura lógica válida. + */ +const formulaFiltroDeltaValida = (formula: string) => { + /** + * Extrai apenas os tokens permitidos: + * - referências de condição: {id} ou {id:sufixo} + * - operadores lógicos: E, OU + * - negação: NAO(...) + * - parênteses + */ + const tokensPermitidos = formula.match(/\{[\w:]+\}|\bNAO\b|\bE\b|\bOU\b|\(|\)/g) || [] + + /** + * Reconstrói a fórmula usando apenas os tokens válidos. + */ + const formulaReconstruida = tokensPermitidos.join("") + + /** + * Remove espaços para comparar o texto original com o texto reconstruído. + */ + const formulaOriginalSemEspacos = formula.replace(/\s+/g, "") + const formulaReconstruidaSemEspacos = formulaReconstruida.replace(/\s+/g, "") + + /** + * Se forem diferentes, há conteúdo não permitido na fórmula. + */ + if (formulaOriginalSemEspacos !== formulaReconstruidaSemEspacos) { + return false + } + + /** + * Converte a fórmula para uma expressão JavaScript equivalente. + * + * NAO(x) → !x + * E → && + * OU → || + */ + const expressaoLogica = formula + .replace(/\{[\w:]+\}/g, "true") + .replace(/\bNAO\b/g, "!") + .replace(/\bE\b/g, "&&") + .replace(/\bOU\b/g, "||") + + try { + /** + * Valida a ordem dos operadores, parênteses e estrutura lógica geral. + */ + new Function(`return (${expressaoLogica})`)() + + return true + } catch { + return false + } +} + +/** + * Estrutura principal do filtro delta. + */ +export const zFiltroDelta = z + .object({ + /** + * Lista de condições disponíveis. + */ + condicoes: z.array(zCondicaoFiltroDelta), + + /** + * Fórmula lógica que combina as condições. + */ + formula: z.string().refine(formulaFiltroDeltaValida, { + message: + "Fórmula inválida. Use apenas referências de condições {id} ou {id:sufixo}, operadores E/OU/NAO e parênteses.", + }), + }) + .superRefine((value, ctx) => { + /** + * IDs das condições cadastradas. + */ + const idsCondicoes = new Set(value.condicoes.map((condicao) => condicao.id)) + + /** + * Referências usadas dentro da fórmula. + */ + const referenciasFormula = value.formula.match(/\{[\w:]+\}/g) || [] + + /** + * Verifica se toda referência da fórmula existe em condicoes. + */ + for (const referencia of referenciasFormula) { + if (!idsCondicoes.has(referencia)) { + ctx.addIssue({ + code: "custom", + path: ["formula"], + message: `A referência ${referencia} não existe em condicoes.`, + }) + } + } + }) + +export type tipoOperadorFiltroDelta = z.infer +export type tipoColunaFiltroDelta = z.infer +export type tipoCondicaoFiltroDelta = z.infer +export type tipoFiltroDelta = z.infer diff --git a/src/index.ts b/src/index.ts index 33d0c9c..f55b655 100755 --- a/src/index.ts +++ b/src/index.ts @@ -3,10 +3,10 @@ export * from "./auditoria" export * from "./cacheMemoria" export * from "./constantes" export * from "./consulta" -export * from "./dayjs26" export * from "./ecosistema" export * from "./extensoes" export * from "./extensoes" +export * from "./filtroDelta" export * from "./local" export * from "./postgres" export * from "./produtos" @@ -15,7 +15,7 @@ export * from "./testes-de-variaveis" export * from "./texto_busca" export * from "./tipagemRotas" export * from "./tipagemRotas" -export * from "./tipoFiltro.26" + export * from "./unidades_medida" export * from "./uuid" export * from "./variaveisComuns" diff --git a/src/tipoFiltro.26.ts b/src/tipoFiltro.26.ts deleted file mode 100644 index 839f59a..0000000 --- a/src/tipoFiltro.26.ts +++ /dev/null @@ -1,233 +0,0 @@ -import { z } from "zod" - -/** - * ============================================================================= - * tipoFiltro26 - * ============================================================================= - * - * OBJETIVO - * ----------------------------------------------------------------------------- - * Gerar automaticamente a tipagem de filtros compatíveis com operadores - * padrão do PostgreSQL, a partir de um tipo base T. - * - * Este tipo foi projetado para: - * - Construção de filtros dinâmicos - * - Geração posterior de WHERE (Knex / SQL) - * - Uso seguro por IA (evita filtros inválidos em nível de tipo) - * - * - * FORMATO DO FILTRO - * ----------------------------------------------------------------------------- - * 1) Campos simples: - * - * { - * idade: { ">=": 18 } - * } - * - * 2) Campos aninhados: - * - * { - * carro: { - * ano: { "=": 2020 } - * } - * } - * - * 3) Operador E (AND): - * - * { - * E: [ - * { idade: { ">=": 18 } }, - * { nome: { like: "%pa%" } } - * ] - * } - * - * 4) Operador OU (OR): - * - * { - * OU: [ - * { idade: { "<": 18 } }, - * { idade: { ">=": 60 } } - * ] - * } - * - * 5) Combinação complexa: - * - * { - * idade: { ">=": 18 }, - * OU: [ - * { nome: { like: "%pa%" } }, - * { - * E: [ - * { carro: { ano: { "=": 2020 } } }, - * { carro: { modelo: { in: ["Civic"] } } } - * ] - * } - * ] - * } - * - * - * REGRAS IMPORTANTES (PARA IA) - * ----------------------------------------------------------------------------- - * - Apenas campos existentes em T podem ser usados. - * - Operadores são restritos por tipo do campo. - * - Objetos são tratados recursivamente. - * - Arrays NÃO são tratados como objeto recursivo. - * - Funções NÃO são consideradas campos filtráveis. - * - * - * OPERADORES SUPORTADOS - * ----------------------------------------------------------------------------- - * number: - * =, !=, >, >=, <, <=, in - * - * string: - * =, !=, like, in - * - * boolean: - * =, !=, in - * - * Não há suporte automático a: - * - null - * - date - * - jsonb - * - arrays - * - * Essas extensões devem ser adicionadas explicitamente. - * - * ============================================================================= - */ - -/* ============================================================================= - OPERADORES POSTGRESQL POR TIPO - ============================================================================= */ - -export enum operadores26 { - "=" = "=", - "!=" = "!=", - ">" = ">", - ">=" = ">=", - "<" = "<", - "<=" = "<=", - like = "like", - in = "in", -} - -export enum agrupadores26 { - E = "E", - OU = "OU", -} - -type PgOpsNumber = { - [K in Extract" | ">=" | "<" | "<=">]?: number -} & { - [K in Extract]?: number[] -} - -type PgOpsString = { - [K in Extract]?: string -} & { - [K in Extract]?: string[] -} - -type PgOpsBoolean = { - [K in Extract]?: boolean[] -} - -/* ============================================================================= - SELEÇÃO AUTOMÁTICA DE OPERADORES BASEADA NO TIPO DO CAMPO -============================================================================= */ - -type PgOpsFor = V extends number - ? PgOpsNumber - : V extends string - ? PgOpsString - : V extends boolean - ? PgOpsBoolean - : never - -/* ============================================================================= - UTILITÁRIO: DETECTAR OBJETO PLANO -============================================================================= */ - -type IsPlainObject = T extends object - ? T extends Function - ? false - : T extends readonly any[] - ? false - : true - : false - -/* ============================================================================= - FILTRO RECURSIVO POR CAMPOS -============================================================================= */ - -type FiltroCampos = { - [K in keyof T]?: IsPlainObject extends true ? tipoFiltro26 : PgOpsFor -} - -/* ============================================================================= - TIPO PRINCIPAL EXPORTADO -============================================================================= */ - -export type tipoFiltro26 = FiltroCampos & { - /** - * E => AND lógico - * Todos os filtros dentro do array devem ser verdadeiros. - */ - E?: tipoFiltro26[] - - /** - * OU => OR lógico - * Pelo menos um filtro dentro do array deve ser verdadeiro. - */ - OU?: tipoFiltro26[] -} - -/* ============================================================================= - VALIDAÇÃO ESTRUTURAL (ZOD) -============================================================================= */ - -const zOperadores = z.nativeEnum(operadores26) -const zValor = z.any() -const zCondicao = z.record(zOperadores, zValor) - -export const zFiltro26: z.ZodType = z.lazy(() => - z - .object({ - E: z.array(zFiltro26).optional(), - OU: z.array(zFiltro26).optional(), - }) - .catchall(z.union([zCondicao, zFiltro26])), -) - -/* ============================================================================= - EXEMPLO DE USO -============================================================================= */ - -type Pessoa = { - codigo: string - nome: string - idade: number - carro: { - modelo: string - ano: number - } -} - -export const criarFiltro26 = (filtro: tipoFiltro26) => filtro - -const _filtro = criarFiltro26({ - idade: { [operadores26[">="]]: 18 }, - - [agrupadores26.OU]: [ - { nome: { [operadores26.like]: "%pa%" } }, - { - [agrupadores26.E]: [ - { carro: { ano: { [operadores26["="]]: 2020 } } }, - { carro: { modelo: { [operadores26.in]: ["Civic", "Corolla"] } } }, - ], - }, - ], -})