@pedrohb/errors 0.0.0-stage → 1.0.0
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/LICENSE +21 -0
- package/README.md +52 -3
- package/dist/error-params-CR2parjT.d.cts +387 -0
- package/dist/error-params-CR2parjT.d.mts +387 -0
- package/dist/errors/index.cjs +6 -0
- package/dist/errors/index.d.cts +115 -0
- package/dist/errors/index.d.mts +115 -0
- package/dist/errors/index.mjs +3 -0
- package/dist/errors-DrDL51y9.mjs +149 -0
- package/dist/errors-DrDL51y9.mjs.map +1 -0
- package/dist/errors-TgPe2YUV.cjs +178 -0
- package/dist/errors-TgPe2YUV.cjs.map +1 -0
- package/dist/functions/index.cjs +408 -0
- package/dist/functions/index.cjs.map +1 -0
- package/dist/functions/index.d.cts +3 -0
- package/dist/functions/index.d.mts +3 -0
- package/dist/functions/index.mjs +399 -0
- package/dist/functions/index.mjs.map +1 -0
- package/dist/index-B4tdSdCF.d.mts +544 -0
- package/dist/index-BzFCOXvr.d.cts +544 -0
- package/dist/index.cjs +637 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +510 -0
- package/dist/index.d.mts +510 -0
- package/dist/index.mjs +614 -0
- package/dist/index.mjs.map +1 -0
- package/dist/invalid-param-delimiters-error-BFxlVXp3.mjs +44 -0
- package/dist/invalid-param-delimiters-error-BFxlVXp3.mjs.map +1 -0
- package/dist/invalid-param-delimiters-error-C6UxV7cK.cjs +49 -0
- package/dist/invalid-param-delimiters-error-C6UxV7cK.cjs.map +1 -0
- package/dist/types/index.cjs +0 -0
- package/dist/types/index.d.cts +143 -0
- package/dist/types/index.d.mts +143 -0
- package/dist/types/index.mjs +1 -0
- package/package.json +117 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pedro Henrique Bergamo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,52 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# @pedrohb/errors
|
|
2
|
+
|
|
3
|
+
Um sistema de erros tipado para aplicações TypeScript. Defina catálogos imutáveis de códigos, associe mensagens parametrizadas a erros e serialize causas com segurança.
|
|
4
|
+
|
|
5
|
+
## Instalação
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
pnpm add @pedrohb/errors
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Catálogo e erros tipados
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { BaseError, defineErrorCatalog } from "@pedrohb/errors";
|
|
15
|
+
|
|
16
|
+
const errors = defineErrorCatalog({
|
|
17
|
+
USER_NOT_FOUND: "Usuário {userId} não encontrado.",
|
|
18
|
+
INVALID_CREDENTIALS: "Credenciais inválidas.",
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
class UserNotFoundError extends BaseError<typeof errors, "USER_NOT_FOUND"> {
|
|
22
|
+
public constructor(userId: string, options?: ErrorOptions) {
|
|
23
|
+
super(errors.USER_NOT_FOUND, {
|
|
24
|
+
...options,
|
|
25
|
+
params: { userId },
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const error = new UserNotFoundError("user-123");
|
|
31
|
+
console.log(error.code, error.message);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Os códigos devem estar em `UPPER_SNAKE_CASE`. Os placeholders entre chaves são inferidos pelo TypeScript e usados para tipar os parâmetros da mensagem.
|
|
35
|
+
|
|
36
|
+
## Serialização
|
|
37
|
+
|
|
38
|
+
`BaseError` preserva `code`, `message` e parâmetros. `serialize()` retorna uma representação apropriada para logs e transporte; a pilha é omitida por padrão e pode ser incluída chamando `serialize(true)`. Causas nativas, erros da biblioteca, datas, valores não serializáveis por JSON e referências circulares são tratadas pela serialização.
|
|
39
|
+
|
|
40
|
+
## Resultado `Either`
|
|
41
|
+
|
|
42
|
+
O pacote também exporta `Either`, `Ok`, `Err`, `ok` e `err` para representar resultados de sucesso ou falha sem lançar exceções. Os métodos `map`, `mapErr`, `flatMap`, `orElse` e `match` permitem compor e consumir esses resultados.
|
|
43
|
+
|
|
44
|
+
## Imports por subpath
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { InvalidErrorCode } from "@pedrohb/errors/errors";
|
|
48
|
+
import { serializeBaseError } from "@pedrohb/errors/functions";
|
|
49
|
+
import type { ErrorCatalog } from "@pedrohb/errors/types";
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
O pacote fornece formatos ESM e CommonJS, com declarações TypeScript correspondentes.
|
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
//#region src/types/error-param-delimiters.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Delimitadores de abertura e fechamento usados para identificar os
|
|
4
|
+
* placeholders em uma mensagem de erro (ex.: `{id}`). Também pode
|
|
5
|
+
* ser usado para tipar, em runtime, o objeto de delimitadores.
|
|
6
|
+
*
|
|
7
|
+
* Os parâmetros de tipo têm `string` como padrão, de modo que
|
|
8
|
+
* `ErrorParamDelimiters` sem argumentos serve como restrição genérica
|
|
9
|
+
* (`extends ErrorParamDelimiters`) aceitando quaisquer delimitadores. Para o
|
|
10
|
+
* par padrão `{` e `}`, informe os literais explicitamente.
|
|
11
|
+
*
|
|
12
|
+
* @template Open - Tipo literal do delimitador de abertura. Por padrão, `string`.
|
|
13
|
+
* @template Close - Tipo literal do delimitador de fechamento. Por padrão, `string`.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const keys = { open: "{", close: "}" } as const satisfies ErrorParamDelimiters;
|
|
18
|
+
*
|
|
19
|
+
* const brackets: ErrorParamDelimiters<"[", "]"> = {
|
|
20
|
+
* open: "[",
|
|
21
|
+
* close: "]",
|
|
22
|
+
* };
|
|
23
|
+
* // Mensagem correspondente: "Usuário [id] não encontrado"
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
type ErrorParamDelimiters<Open extends string = string, Close extends string = string> = Readonly<{
|
|
27
|
+
/** Delimitador que marca o início de um placeholder (ex.: `"{"`). */
|
|
28
|
+
open: Open;
|
|
29
|
+
/** Delimitador que marca o fim de um placeholder (ex.: `"}"`). */
|
|
30
|
+
close: Close;
|
|
31
|
+
}>;
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/functions/create-param-placeholder.d.ts
|
|
34
|
+
/**
|
|
35
|
+
* Delimitadores padrão dos placeholders em mensagens de erro: `{` para abrir
|
|
36
|
+
* e `}` para fechar (ex.: `{id}`).
|
|
37
|
+
*
|
|
38
|
+
* Declarado com `as const`, então mantém os tipos literais `"{"` e `"}"`,
|
|
39
|
+
* o que permite derivar {@link DefaultParamDelimiters} a partir dele.
|
|
40
|
+
*/
|
|
41
|
+
declare const DEFAULT_PARAM_DELIMITERS: {
|
|
42
|
+
readonly open: "{";
|
|
43
|
+
readonly close: "}";
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Tipo dos delimitadores padrão equivalente a
|
|
47
|
+
* `{ readonly open: "{"; readonly close: "}" }`.
|
|
48
|
+
*
|
|
49
|
+
* É usado como valor padrão de `Delimiters` em tipos como `ErrorParams`.
|
|
50
|
+
*/
|
|
51
|
+
type DefaultParamDelimiters = typeof DEFAULT_PARAM_DELIMITERS;
|
|
52
|
+
/**
|
|
53
|
+
* Cria uma expressão regular global que localiza os placeholders de uma
|
|
54
|
+
* mensagem de erro com base nos delimitadores informados.
|
|
55
|
+
*
|
|
56
|
+
* Os delimitadores são escapados com {@link escapeRegExp}, então símbolos como
|
|
57
|
+
* `[`, `(` ou `$` são tratados como texto literal. Delimitadores com mais de
|
|
58
|
+
* um caractere (ex.: `{{` e `}}`) também são aceitos.
|
|
59
|
+
*
|
|
60
|
+
* Em cada correspondência o grupo de captura `1` contém o texto entre os
|
|
61
|
+
* delimitadores, exatamente como aparece na mensagem (sem aparar espaços).
|
|
62
|
+
* O conteúdo pode ocupar várias linhas, mas não pode conter os delimitadores
|
|
63
|
+
* de abertura ou de fechamento. Em casos como `{{id}}` a correspondência
|
|
64
|
+
* recai sobre o par mais interno (`{id}`). Placeholders vazios (ex.: `{}`)
|
|
65
|
+
* também correspondem com o grupo `1` igual a `""`.
|
|
66
|
+
*
|
|
67
|
+
* Cada chamada devolve uma nova instância de `RegExp`. Como ela usa a flag
|
|
68
|
+
* `g` que mantém estado em `lastIndex`, isso evita que usos diferentes
|
|
69
|
+
* compartilhem o mesmo estado.
|
|
70
|
+
*
|
|
71
|
+
* @param delimiters - Delimitadores `open` e `close` do placeholder. Por
|
|
72
|
+
* padrão, {@link DEFAULT_PARAM_DELIMITERS} (`{` e `}`).
|
|
73
|
+
* @returns Expressão regular global que corresponde a cada placeholder.
|
|
74
|
+
* @throws {InvalidParamDelimitersError} Se `open` ou `close` for uma string
|
|
75
|
+
* vazia.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* const regex = createParamPlaceholder();
|
|
80
|
+
*
|
|
81
|
+
* for (const match of "Usuário {id} não encontrado em {table}".matchAll(regex)) {
|
|
82
|
+
* console.log(match[1]);
|
|
83
|
+
* }
|
|
84
|
+
* // "id"
|
|
85
|
+
* // "table"
|
|
86
|
+
*
|
|
87
|
+
* "Olá, {nome}!".replace(regex, (_, param) => `<${param}>`);
|
|
88
|
+
* // "Olá, <nome>!"
|
|
89
|
+
*
|
|
90
|
+
* // Delimitadores personalizados
|
|
91
|
+
* const brackets = createParamPlaceholder({ open: "[", close: "]" });
|
|
92
|
+
* "Rota [route] não encontrada".match(brackets); // ["[route]"]
|
|
93
|
+
*
|
|
94
|
+
* // Delimitadores vazios não são permitidos
|
|
95
|
+
* createParamPlaceholder({ open: "", close: "}" });
|
|
96
|
+
* // Lança InvalidParamDelimitersError
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
declare function createParamPlaceholder(delimiters?: ErrorParamDelimiters): RegExp;
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/types/error-descriptor.d.ts
|
|
102
|
+
/**
|
|
103
|
+
* Descreve um erro do catálogo: um código identificador e a mensagem associada.
|
|
104
|
+
*
|
|
105
|
+
* A mensagem pode conter placeholders (ex.: `"Usuário {id} não encontrado"`),
|
|
106
|
+
* que são preenchidos com os parâmetros informados na criação do erro.
|
|
107
|
+
*
|
|
108
|
+
* @template Code - Tipo literal do código do erro. Por padrão, `string`.
|
|
109
|
+
* @template Message - Tipo literal da mensagem do erro. Por padrão, `string`.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```ts
|
|
113
|
+
* const USER_NOT_FOUND = {
|
|
114
|
+
* code: "USER_NOT_FOUND",
|
|
115
|
+
* message: "Usuário {id} não encontrado",
|
|
116
|
+
* } as const satisfies ErrorDescriptor;
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
interface ErrorDescriptor<Code extends string = string, Message extends string = string> {
|
|
120
|
+
/** Código único que identifica o erro (ex.: `"USER_NOT_FOUND"`). */
|
|
121
|
+
readonly code: Code;
|
|
122
|
+
/** Mensagem do erro, podendo conter placeholders como `{id}`. */
|
|
123
|
+
readonly message: Message;
|
|
124
|
+
}
|
|
125
|
+
//#endregion
|
|
126
|
+
//#region src/types/error-catalog.d.ts
|
|
127
|
+
/**
|
|
128
|
+
* Catálogo de erros somente leitura, derivado de um objeto que associa cada
|
|
129
|
+
* código de erro à sua mensagem.
|
|
130
|
+
*
|
|
131
|
+
* Para cada entrada de `Definitions`, a chave vira o `code` e o valor vira a
|
|
132
|
+
* `message` de um {@link ErrorDescriptor}, preservando os tipos literais de
|
|
133
|
+
* ambos. Assim, `TEST_ERROR_CODES.USER_NOT_FOUND.code` tem o tipo `"USER_NOT_FOUND"`
|
|
134
|
+
* e `TEST_ERROR_CODES.USER_NOT_FOUND.message` tem o tipo literal da mensagem definida.
|
|
135
|
+
*
|
|
136
|
+
* Apenas chaves do tipo `string` são consideradas.
|
|
137
|
+
*
|
|
138
|
+
* @template Definitions - Objeto que mapeia códigos de erro para suas
|
|
139
|
+
* mensagens. Por padrão, `Record<string, string>`.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* type TEST_ERROR_CODES = ErrorCatalog<{
|
|
144
|
+
* USER_NOT_FOUND: "Usuário {id} não encontrado";
|
|
145
|
+
* INVALID_TOKEN: "Token inválido";
|
|
146
|
+
* }>;
|
|
147
|
+
* // {
|
|
148
|
+
* // readonly USER_NOT_FOUND: ErrorDescriptor<"USER_NOT_FOUND", "Usuário {id} não encontrado">;
|
|
149
|
+
* // readonly INVALID_TOKEN: ErrorDescriptor<"INVALID_TOKEN", "Token inválido">;
|
|
150
|
+
* // }
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
type ErrorCatalog<Definitions extends Record<string, string> = Record<string, string>> = Readonly<{ [Code in keyof Definitions & string]: ErrorDescriptor<Code, Definitions[Code]>; }>;
|
|
154
|
+
//#endregion
|
|
155
|
+
//#region src/types/catalog-code.d.ts
|
|
156
|
+
/**
|
|
157
|
+
* Extrai a união de todos os códigos de erro presentes em um catálogo.
|
|
158
|
+
*
|
|
159
|
+
* Percorre cada {@link ErrorDescriptor} do catálogo e coleta o tipo literal de
|
|
160
|
+
* sua propriedade `code`. Útil para tipar parâmetros que aceitam apenas
|
|
161
|
+
* códigos válidos de um catálogo específico.
|
|
162
|
+
*
|
|
163
|
+
* @template Catalog - Catálogo de erros a ser analisado. Por padrão,
|
|
164
|
+
* `ErrorCatalog`, caso em que o resultado é `string`.
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```ts
|
|
168
|
+
* type TEST_ERROR_CODES = ErrorCatalog<{
|
|
169
|
+
* USER_NOT_FOUND: "Usuário {id} não encontrado";
|
|
170
|
+
* INVALID_TOKEN: "Token inválido";
|
|
171
|
+
* }>;
|
|
172
|
+
*
|
|
173
|
+
* type TestErrorCatalogCode = CatalogCode<TEST_ERROR_CODES>;
|
|
174
|
+
* // "USER_NOT_FOUND" | "INVALID_TOKEN"
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
type CatalogCode<Catalog extends ErrorCatalog = ErrorCatalog> = Catalog[keyof Catalog]["code"];
|
|
178
|
+
//#endregion
|
|
179
|
+
//#region src/types/catalog-descriptor.d.ts
|
|
180
|
+
/**
|
|
181
|
+
* Obtém o descritor de erro correspondente a um código específico de um
|
|
182
|
+
* catálogo.
|
|
183
|
+
*
|
|
184
|
+
* Busca em `Catalog` a entrada cujo `code` é `Code` e retorna o respectivo
|
|
185
|
+
* `ErrorDescriptor`, com `code` e `message` em seus tipos literais. Se `Code`
|
|
186
|
+
* for uma união de códigos, o resultado é a união dos descritores
|
|
187
|
+
* correspondentes. Se `Code` não for informado, o resultado é a união de todos
|
|
188
|
+
* os descritores do catálogo.
|
|
189
|
+
*
|
|
190
|
+
* @template Catalog - Catálogo de erros a ser consultado. Por padrão,
|
|
191
|
+
* `ErrorCatalog`.
|
|
192
|
+
* @template Code - Código (ou união de códigos) a ser buscado, restrito aos
|
|
193
|
+
* códigos existentes no catálogo (ver {@link CatalogCode}). Por padrão, todos
|
|
194
|
+
* os códigos do catálogo.
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```ts
|
|
198
|
+
* type TEST_ERROR_CODES = ErrorCatalog<{
|
|
199
|
+
* USER_NOT_FOUND: "Usuário {id} não encontrado";
|
|
200
|
+
* INVALID_TOKEN: "Token inválido";
|
|
201
|
+
* }>;
|
|
202
|
+
*
|
|
203
|
+
* type A = CatalogDescriptor<TEST_ERROR_CODES, "USER_NOT_FOUND">;
|
|
204
|
+
* // ErrorDescriptor<"USER_NOT_FOUND", "Usuário {id} não encontrado">
|
|
205
|
+
*
|
|
206
|
+
* type B = CatalogDescriptor<TEST_ERROR_CODES, "USER_NOT_FOUND" | "INVALID_TOKEN">;
|
|
207
|
+
* // ErrorDescriptor<"USER_NOT_FOUND", ...> | ErrorDescriptor<"INVALID_TOKEN", ...>
|
|
208
|
+
*
|
|
209
|
+
* type C = CatalogDescriptor<TEST_ERROR_CODES>;
|
|
210
|
+
* // união de todos os descritores do catálogo
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
type CatalogDescriptor<Catalog extends ErrorCatalog = ErrorCatalog, Code extends CatalogCode<Catalog> = CatalogCode<Catalog>> = Extract<Catalog[Code], {
|
|
214
|
+
code: Code;
|
|
215
|
+
}>;
|
|
216
|
+
//#endregion
|
|
217
|
+
//#region src/types/extract-placeholders.d.ts
|
|
218
|
+
/**
|
|
219
|
+
* Caracteres de espaço em branco reconhecidos pelos tipos utilitários deste módulo.
|
|
220
|
+
*
|
|
221
|
+
* Inclui espaço, tabulação, quebra de linha (`\n`) e retorno de carro (`\r`).
|
|
222
|
+
*/
|
|
223
|
+
type Whitespace = " " | "\t" | "\n" | "\r";
|
|
224
|
+
/**
|
|
225
|
+
* Remove, em tempo de compilação, todos os espaços em branco no início e no fim
|
|
226
|
+
* de uma string literal. É o equivalente em nível de tipos a `String.prototype.trim()`.
|
|
227
|
+
*
|
|
228
|
+
* O tipo é recursivo: remove um caractere de espaço por vez do início e
|
|
229
|
+
* quando não há mais nenhum, do fim até restar apenas o conteúdo "limpo".
|
|
230
|
+
*
|
|
231
|
+
* @template T - Tipo string literal a ser aparado. Por padrão, `string`.
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```ts
|
|
235
|
+
* type A = Trim<" olá ">; // "olá"
|
|
236
|
+
* type B = Trim<"\n\tabc\r">; // "abc"
|
|
237
|
+
* type C = Trim<"sem-espaço">; // "sem-espaço"
|
|
238
|
+
* type D = Trim<string>; // string
|
|
239
|
+
* ```
|
|
240
|
+
*/
|
|
241
|
+
type Trim<T extends string = string> = T extends `${Whitespace}${infer Rest}` ? Trim<Rest> : T extends `${infer Rest}${Whitespace}` ? Trim<Rest> : T;
|
|
242
|
+
/**
|
|
243
|
+
* Extrai, em tempo de compilação, os nomes dos placeholders presentes em uma
|
|
244
|
+
* string de mensagem, retornando-os como uma união de string literals.
|
|
245
|
+
*
|
|
246
|
+
* Os delimitadores de abertura e fechamento são informados por meio de um
|
|
247
|
+
* objeto {@link ErrorParamDelimiters}. O conteúdo de cada placeholder é
|
|
248
|
+
* aparado com {@link Trim} e placeholders vazios (ex.: `{}` ou `{ }`) são
|
|
249
|
+
* ignorados.
|
|
250
|
+
*
|
|
251
|
+
* Se `Message` for o tipo genérico `string` (ou seja, não for um literal),
|
|
252
|
+
* não é possível inferir os placeholders e o resultado é `string`. Se a
|
|
253
|
+
* mensagem não contiver nenhum placeholder, o resultado é `never`.
|
|
254
|
+
*
|
|
255
|
+
*
|
|
256
|
+
* @template Message - Mensagem a ser analisada. Por padrão, `string`.
|
|
257
|
+
* @template Delimiters - Objeto com os delimitadores `open` e `close` do
|
|
258
|
+
* placeholder. Por padrão, {@link DefaultParamDelimiters}.
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* ```ts
|
|
262
|
+
* type Keys = { readonly open: "{"; readonly close: "}" };
|
|
263
|
+
*
|
|
264
|
+
* type A = ExtractPlaceholders<"Olá, {nome}! Você tem {qtd} mensagens.", Keys>;
|
|
265
|
+
* // "nome" | "qtd"
|
|
266
|
+
*
|
|
267
|
+
* type B = ExtractPlaceholders<"Valor: { valor }", Keys>;
|
|
268
|
+
* // "valor" (espaços internos são removidos)
|
|
269
|
+
*
|
|
270
|
+
* type C = ExtractPlaceholders<"Sem placeholders", Keys>;
|
|
271
|
+
* // never
|
|
272
|
+
*
|
|
273
|
+
* type D = ExtractPlaceholders<"Olá, {}!", Keys>;
|
|
274
|
+
* // never (placeholder vazio é ignorado)
|
|
275
|
+
*
|
|
276
|
+
* type E = ExtractPlaceholders<
|
|
277
|
+
* "Olá, [nome]!",
|
|
278
|
+
* { readonly open: "["; readonly close: "]" }
|
|
279
|
+
* >;
|
|
280
|
+
* // "nome" (delimitadores personalizados)
|
|
281
|
+
*
|
|
282
|
+
* type F = ExtractPlaceholders<string, Keys>;
|
|
283
|
+
* // string (mensagem não literal)
|
|
284
|
+
* ```
|
|
285
|
+
*/
|
|
286
|
+
type ExtractPlaceholders<Message extends string = string, Delimiters extends ErrorParamDelimiters = DefaultParamDelimiters> = string extends Message ? string : Message extends `${string}${Delimiters["open"]}${infer Param}${Delimiters["close"]}${infer Rest}` ? Trim<Param> extends "" ? ExtractPlaceholders<Rest, Delimiters> : Trim<Param> | ExtractPlaceholders<Rest, Delimiters> : never;
|
|
287
|
+
//#endregion
|
|
288
|
+
//#region src/types/params-from-message.d.ts
|
|
289
|
+
/**
|
|
290
|
+
* Valores aceitos como parâmetros para preencher os placeholders de uma
|
|
291
|
+
* mensagem de erro.
|
|
292
|
+
*
|
|
293
|
+
* Restringe-se a tipos primitivos simples e serializáveis, o que evita
|
|
294
|
+
* objetos arbitrários e referências circulares nos parâmetros do erro.
|
|
295
|
+
*/
|
|
296
|
+
type ErrorParamValue = string | number | boolean | bigint | null;
|
|
297
|
+
/**
|
|
298
|
+
* Deriva em tempo de compilação, o tipo do objeto de parâmetros exigido por
|
|
299
|
+
* uma mensagem com base nos placeholders presentes nela.
|
|
300
|
+
*
|
|
301
|
+
* Cada placeholder encontrado (via {@link ExtractPlaceholders}) vira uma
|
|
302
|
+
* propriedade obrigatória e somente leitura do tipo {@link ErrorParamValue}.
|
|
303
|
+
* Os delimitadores dos placeholders são informados por meio de um objeto
|
|
304
|
+
* {@link ErrorParamDelimiters}.
|
|
305
|
+
*
|
|
306
|
+
* - Se a mensagem **não** tiver placeholders o resultado é `never`, indicando
|
|
307
|
+
* que nenhum parâmetro deve ser informado.
|
|
308
|
+
* - Se `Message` for o tipo genérico `string` (não literal), não é possível
|
|
309
|
+
* inferir os placeholders e o resultado é um objeto com chaves `string`
|
|
310
|
+
* arbitrárias, ou seja, `Readonly<Record<string, ErrorParamValue>>`.
|
|
311
|
+
*
|
|
312
|
+
* @template Message - Mensagem a ser analisada. Por padrão, `string`.
|
|
313
|
+
* @template Delimiters - Objeto com os delimitadores `open` e `close` do
|
|
314
|
+
* placeholder. Por padrão, {@link DefaultParamDelimiters}.
|
|
315
|
+
*
|
|
316
|
+
* @example
|
|
317
|
+
* ```ts
|
|
318
|
+
* type Keys = { readonly open: "{"; readonly close: "}" };
|
|
319
|
+
*
|
|
320
|
+
* type A = ParamsFromMessage<"Usuário {id} não encontrado em {table}", Keys>;
|
|
321
|
+
* // Readonly<{ id: ErrorParamValue; table: ErrorParamValue }>
|
|
322
|
+
*
|
|
323
|
+
* type B = ParamsFromMessage<"Algo deu errado", Keys>;
|
|
324
|
+
* // never (sem placeholders, sem parâmetros)
|
|
325
|
+
*
|
|
326
|
+
* type C = ParamsFromMessage<
|
|
327
|
+
* "Falha em [resource]",
|
|
328
|
+
* { readonly open: "["; readonly close: "]" }
|
|
329
|
+
* >;
|
|
330
|
+
* // Readonly<{ resource: ErrorParamValue }>
|
|
331
|
+
*
|
|
332
|
+
* type D = ParamsFromMessage<string, Keys>;
|
|
333
|
+
* // Readonly<Record<string, ErrorParamValue>>
|
|
334
|
+
* ```
|
|
335
|
+
*/
|
|
336
|
+
type ParamsFromMessage<Message extends string = string, Delimiters extends ErrorParamDelimiters = DefaultParamDelimiters> = [ExtractPlaceholders<Message, Delimiters>] extends [never] ? never : Readonly<{ [K in ExtractPlaceholders<Message, Delimiters>]: ErrorParamValue; }>;
|
|
337
|
+
//#endregion
|
|
338
|
+
//#region src/types/error-params.d.ts
|
|
339
|
+
/**
|
|
340
|
+
* Deriva em tempo de compilação, o tipo do objeto de parâmetros exigido para
|
|
341
|
+
* criar o erro de um código específico de um catálogo.
|
|
342
|
+
*
|
|
343
|
+
* Localiza o descritor do código em `Catalog` (via {@link CatalogDescriptor}),
|
|
344
|
+
* lê sua `message` e converte os placeholders encontrados em propriedades
|
|
345
|
+
* obrigatórias (via {@link ParamsFromMessage}). Os delimitadores dos
|
|
346
|
+
* placeholders são informados por meio de um objeto
|
|
347
|
+
* {@link ErrorParamDelimiters}.
|
|
348
|
+
*
|
|
349
|
+
* - Se a mensagem do código **não** tiver placeholders, o resultado é `never`,
|
|
350
|
+
* indicando que nenhum parâmetro deve ser informado.
|
|
351
|
+
* - Se `Code` for uma união de códigos, o resultado exige os placeholders de
|
|
352
|
+
* todas as mensagens correspondentes, e não apenas os de uma delas.
|
|
353
|
+
*
|
|
354
|
+
* @template Catalog - Catálogo de erros a ser consultado. Por padrão,
|
|
355
|
+
* `ErrorCatalog`.
|
|
356
|
+
* @template Code - Código (ou união de códigos) do erro, restrito aos códigos
|
|
357
|
+
* existentes no catálogo (ver {@link CatalogCode}). Por padrão, todos os
|
|
358
|
+
* códigos do catálogo.
|
|
359
|
+
* @template Delimiters - Objeto com os delimitadores `open` e `close` do
|
|
360
|
+
* placeholder. Por padrão, {@link DefaultParamDelimiters}.
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* ```ts
|
|
364
|
+
* type TEST_ERROR_CODES = ErrorCatalog<{
|
|
365
|
+
* USER_NOT_FOUND: "Usuário {id} não encontrado em {tabela}";
|
|
366
|
+
* INVALID_TOKEN: "Token inválido";
|
|
367
|
+
* ROUTE_NOT_FOUND: "Rota [rota] não encontrada";
|
|
368
|
+
* }>;
|
|
369
|
+
*
|
|
370
|
+
* type A = ErrorParams<TEST_ERROR_CODES, "USER_NOT_FOUND">;
|
|
371
|
+
* // Readonly<{ id: ErrorParamValue; tabela: ErrorParamValue }>
|
|
372
|
+
*
|
|
373
|
+
* type B = ErrorParams<TEST_ERROR_CODES, "INVALID_TOKEN">;
|
|
374
|
+
* // never (sem placeholders, sem parâmetros)
|
|
375
|
+
*
|
|
376
|
+
* type C = ErrorParams<
|
|
377
|
+
* TEST_ERROR_CODES,
|
|
378
|
+
* "ROUTE_NOT_FOUND",
|
|
379
|
+
* { readonly open: "["; readonly close: "]" }
|
|
380
|
+
* >;
|
|
381
|
+
* // Readonly<{ rota: ErrorParamValue }> (delimitadores personalizados)
|
|
382
|
+
* ```
|
|
383
|
+
*/
|
|
384
|
+
type ErrorParams<Catalog extends ErrorCatalog = ErrorCatalog, Code extends CatalogCode<Catalog> = CatalogCode<Catalog>, Delimiters extends ErrorParamDelimiters = DefaultParamDelimiters> = ParamsFromMessage<CatalogDescriptor<Catalog, Code>["message"], Delimiters>;
|
|
385
|
+
//#endregion
|
|
386
|
+
export { Trim as a, CatalogCode as c, DEFAULT_PARAM_DELIMITERS as d, DefaultParamDelimiters as f, ExtractPlaceholders as i, ErrorCatalog as l, ErrorParamDelimiters as m, ErrorParamValue as n, Whitespace as o, createParamPlaceholder as p, ParamsFromMessage as r, CatalogDescriptor as s, ErrorParams as t, ErrorDescriptor as u };
|
|
387
|
+
//# sourceMappingURL=error-params-CR2parjT.d.cts.map
|