@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/interpolate-error-message.ts","../src/base-error.ts","../src/define-error-catalog.ts","../src/either.ts"],"sourcesContent":["import {\r\n createParamPlaceholder,\r\n type DefaultParamDelimiters,\r\n} from \"./functions/create-param-placeholder.js\";\r\nimport type { ErrorDescriptor } from \"./types/error-descriptor.js\";\r\nimport type { ErrorParamDelimiters } from \"./types/error-param-delimiters.js\";\r\nimport type {\r\n ErrorParamValue,\r\n ParamsFromMessage,\r\n} from \"./types/params-from-message.js\";\r\n\r\n/**\r\n * Deriva, em tempo de compilação a lista de argumentos extras exigida para\r\n * interpolar uma mensagem de erro.\r\n *\r\n * - Se a mensagem **não** tiver placeholders o resultado é uma tupla vazia\r\n * (`[]`), ou seja, nenhum argumento adicional deve ser passado.\r\n * - Se tiver placeholders o resultado é uma tupla com um único argumento\r\n * obrigatório, `params` do tipo {@link ParamsFromMessage}.\r\n *\r\n * É pensado para ser usado como tipo de parâmetro rest (`...args`) de modo\r\n * que o objeto de parâmetros seja exigido apenas quando necessário.\r\n *\r\n * @template Message - Mensagem a ser analisada.\r\n * @template Delimiters - Objeto com os delimitadores `open` e `close` do\r\n * placeholder. Por padrão, {@link DefaultParamDelimiters}.\r\n *\r\n * @example\r\n * ```ts\r\n * type A = ErrorMessageArgs<\"Usuário {id} não encontrado\">;\r\n * // [params: Readonly<{ id: ErrorParamValue }>]\r\n *\r\n * type B = ErrorMessageArgs<\"Token inválido\">;\r\n * // []\r\n *\r\n * type C = ErrorMessageArgs<\r\n * \"Rota [route] não encontrada\",\r\n * { readonly open: \"[\"; readonly close: \"]\" }\r\n * >;\r\n * // [params: Readonly<{ route: ErrorParamValue }>]\r\n * ```\r\n */\r\nexport type ErrorMessageArgs<\r\n Message extends string,\r\n Delimiters extends ErrorParamDelimiters = DefaultParamDelimiters,\r\n> = [ParamsFromMessage<Message, Delimiters>] extends [never]\r\n ? []\r\n : [params: ParamsFromMessage<Message, Delimiters>];\r\n\r\n/**\r\n * Interpola os parâmetros informados na mensagem de um descritor de erro\r\n * substituindo cada placeholder pelo valor correspondente.\r\n *\r\n * Os placeholders são localizados com {@link createParamPlaceholder} a partir\r\n * dos delimitadores informados. O nome de cada placeholder é aparado\r\n * (`{ id }` equivale a `{id}`) e o valor é convertido para texto com `String`.\r\n *\r\n * O placeholder é mantido exatamente como está na mensagem (sem substituição)\r\n * quando:\r\n * - o nome é vazio (ex.: `{}` ou `{ }`);\r\n * - o nome não existe como propriedade própria de `params`.\r\n *\r\n * O objeto de parâmetros é exigido ou omitido conforme a mensagem via\r\n * {@link ErrorMessageArgs}: mensagens sem placeholders não aceitam `params` e\r\n * mensagens com placeholders exigem todos eles.\r\n *\r\n * @template Descriptor - Tipo do descritor de erro cuja `message` define os\r\n * parâmetros exigidos.\r\n * @template Delimiters - Tipo dos delimitadores dos placeholders. Por padrão,\r\n * {@link DefaultParamDelimiters}.\r\n * @param descriptor - Descritor de erro cuja mensagem será interpolada.\r\n * @param delimiters - Delimitadores `open` e `close` dos placeholders.\r\n * @param args - Objeto `params` com os valores dos placeholders exigido\r\n * apenas se a mensagem tiver placeholders.\r\n * @returns A mensagem com os placeholders substituídos.\r\n * @throws {InvalidParamDelimitersError} Se `open` ou `close` for uma string\r\n * vazia (lançado por {@link createParamPlaceholder}).\r\n *\r\n * @example\r\n * ```ts\r\n * const keys = { open: \"{\", close: \"}\" } as const;\r\n *\r\n * const USER_NOT_FOUND = {\r\n * code: \"USER_NOT_FOUND\",\r\n * message: \"Usuário {id} não encontrado em {table}\",\r\n * } as const satisfies ErrorDescriptor;\r\n *\r\n * interpolateErrorMessage(USER_NOT_FOUND, keys, {\r\n * id: 42,\r\n * table: \"users\",\r\n * });\r\n * // \"Usuário 42 não encontrado em users\"\r\n *\r\n * const INVALID_TOKEN = {\r\n * code: \"INVALID_TOKEN\",\r\n * message: \"Token inválido\",\r\n * } as const satisfies ErrorDescriptor;\r\n *\r\n * interpolateErrorMessage(INVALID_TOKEN, keys);\r\n * // \"Token inválido\" (sem params)\r\n *\r\n * // Delimitadores personalizados\r\n * const ROUTE_NOT_FOUND = {\r\n * code: \"ROUTE_NOT_FOUND\",\r\n * message: \"Rota [route] não encontrada\",\r\n * } as const satisfies ErrorDescriptor;\r\n *\r\n * interpolateErrorMessage(\r\n * ROUTE_NOT_FOUND,\r\n * { open: \"[\", close: \"]\" } as const,\r\n * { route: \"/home\" },\r\n * );\r\n * // \"Rota /home não encontrada\"\r\n * ```\r\n */\r\nexport function interpolateErrorMessage<\r\n Descriptor extends ErrorDescriptor,\r\n Delimiters extends ErrorParamDelimiters = DefaultParamDelimiters,\r\n>(\r\n descriptor: Descriptor,\r\n delimiters: Delimiters,\r\n ...args: ErrorMessageArgs<Descriptor[\"message\"], Delimiters>\r\n) {\r\n const params = (args[0] ?? {}) as Record<string, ErrorParamValue>;\r\n const placeholder = createParamPlaceholder(delimiters);\r\n\r\n return descriptor.message.replace(placeholder, (match, rawKey: string) => {\r\n const key = rawKey.trim();\r\n\r\n if (key === \"\" || !Object.hasOwn(params, key)) {\r\n return match;\r\n }\r\n\r\n return String(params[key]);\r\n });\r\n}\r\n","import {\r\n DEFAULT_PARAM_DELIMITERS,\r\n type DefaultParamDelimiters,\r\n} from \"./functions/create-param-placeholder.js\";\r\nimport { BASE_ERROR_BRAND, isBaseError } from \"./functions/is-base-error.js\";\r\nimport { serializeBaseError } from \"./functions/serialize-base-error.js\";\r\nimport { serializeCauseError } from \"./functions/serialize-cause-error.js\";\r\nimport {\r\n type ErrorMessageArgs,\r\n interpolateErrorMessage,\r\n} from \"./interpolate-error-message.js\";\r\nimport type { CatalogCode } from \"./types/catalog-code.js\";\r\nimport type { CatalogDescriptor } from \"./types/catalog-descriptor.js\";\r\nimport type { ErrorCatalog } from \"./types/error-catalog.js\";\r\nimport type { ErrorParamDelimiters } from \"./types/error-param-delimiters.js\";\r\nimport type { ErrorParams } from \"./types/error-params.js\";\r\n\r\n/**\r\n * Opções aceitas pelo construtor de {@link BaseError}.\r\n *\r\n * Estende `ErrorOptions` (que fornece `cause`) e acrescenta:\r\n * - `delimiters`: delimitadores dos placeholders da mensagem sempre opcional;\r\n * - `params`: valores dos placeholders **exigido apenas** quando a mensagem\r\n * do código possui placeholders (ver {@link ErrorParams}). Se a mensagem não\r\n * tiver placeholders a propriedade `params` não existe no tipo.\r\n *\r\n * @template Catalog - Catálogo de erros ao qual o código pertence. Por padrão,\r\n * `ErrorCatalog`.\r\n * @template Code - Código do erro dentro do catálogo. Por padrão, todos os\r\n * códigos do catálogo.\r\n * @template Delimiters - Tipo dos delimitadores dos placeholders. Por padrão,\r\n * {@link DefaultParamDelimiters}.\r\n *\r\n * @example\r\n * ```ts\r\n * // Mensagem sem placeholders: apenas `cause` e `delimiters` são aceitos\r\n * type A = BaseErrorOptions<typeof ERROR_CODES, \"INVALID_TOKEN\">;\r\n * // ErrorOptions & { delimiters?: DefaultParamDelimiters }\r\n *\r\n * // Mensagem com placeholders: `params` é obrigatório\r\n * type B = BaseErrorOptions<typeof ERROR_CODES, \"USER_NOT_FOUND\">;\r\n * // ErrorOptions & { params: Readonly<{ id: ErrorParamValue }>; delimiters?: ... }\r\n * ```\r\n */\r\nexport type BaseErrorOptions<\r\n Catalog extends ErrorCatalog = ErrorCatalog,\r\n Code extends CatalogCode<Catalog> = CatalogCode<Catalog>,\r\n Delimiters extends ErrorParamDelimiters = DefaultParamDelimiters,\r\n> = [ErrorParams<Catalog, Code, Delimiters>] extends [never]\r\n ? ErrorOptions & {\r\n delimiters?: Delimiters;\r\n }\r\n : ErrorOptions & {\r\n params: ErrorParams<Catalog, Code, Delimiters>;\r\n delimiters?: Delimiters;\r\n };\r\n\r\n/**\r\n * Deriva em tempo de compilação a lista de argumentos de opções do\r\n * construtor de {@link BaseError}.\r\n *\r\n * - Se a mensagem **não** tiver placeholders `options` é opcional.\r\n * - Se tiver placeholders `options` é obrigatório (pois deve conter `params`).\r\n *\r\n * É pensado para ser usado como tipo de parâmetro rest (`...args`).\r\n *\r\n * @template Catalog - Catálogo de erros ao qual o código pertence. Por padrão,\r\n * `ErrorCatalog`.\r\n * @template Code - Código do erro dentro do catálogo. Por padrão, todos os\r\n * códigos do catálogo.\r\n * @template Delimiters - Tipo dos delimitadores dos placeholders. Por padrão,\r\n * {@link DefaultParamDelimiters}.\r\n *\r\n * @example\r\n * ```ts\r\n * type A = BaseErrorOptionsArgs<typeof ERROR_CODES, \"INVALID_TOKEN\">;\r\n * // [options?: BaseErrorOptions<...>]\r\n *\r\n * type B = BaseErrorOptionsArgs<typeof ERROR_CODES, \"USER_NOT_FOUND\">;\r\n * // [options: BaseErrorOptions<...>]\r\n * ```\r\n */\r\nexport type BaseErrorOptionsArgs<\r\n Catalog extends ErrorCatalog = ErrorCatalog,\r\n Code extends CatalogCode<Catalog> = CatalogCode<Catalog>,\r\n Delimiters extends ErrorParamDelimiters = DefaultParamDelimiters,\r\n> = [ErrorParams<Catalog, Code, Delimiters>] extends [never]\r\n ? [options?: BaseErrorOptions<Catalog, Code, Delimiters>]\r\n : [options: BaseErrorOptions<Catalog, Code, Delimiters>];\r\n\r\n/**\r\n * Classe base abstrata para erros tipados a partir de um catálogo de erros.\r\n *\r\n * Cada erro é criado a partir de um descritor do catálogo (código e mensagem).\r\n * A mensagem é interpolada com os `params` informados e o tipo dos `params` é\r\n * derivado dos placeholders da mensagem, de modo que o compilador exige\r\n * exatamente os parâmetros necessários.\r\n *\r\n * O construtor é `protected`: a classe não pode ser instanciada diretamente e\r\n * deve ser estendida por classes que escolhem o descritor e repassam as\r\n * opções.\r\n *\r\n * Além de `message`, `cause`, `stack` e `name` herdados de `Error`, a\r\n * instância expõe:\r\n * - `code`: o código do erro, com tipo literal;\r\n * - `params`: os parâmetros usados na interpolação (ou `undefined`);\r\n * - {@link BaseError.serialize} e {@link BaseError.toJSON} para serialização;\r\n * - uma marca interna ({@link BASE_ERROR_BRAND}) que permite reconhecer o\r\n * erro com {@link isBaseError} mesmo com múltiplas cópias do pacote.\r\n *\r\n * O `name` do erro é o nome da classe concreta (`new.target.name`) e o\r\n * protótipo é ajustado explicitamente para que `instanceof` funcione em\r\n * subclasses mesmo em alvos de compilação antigos.\r\n *\r\n * @template Catalog - Catálogo de erros ao qual o código pertence. Por padrão,\r\n * `ErrorCatalog`.\r\n * @template Code - Código do erro dentro do catálogo. Por padrão, todos os\r\n * códigos do catálogo.\r\n * @template Delimiters - Tipo dos delimitadores dos placeholders. Por padrão,\r\n * {@link DefaultParamDelimiters}.\r\n *\r\n * @example\r\n * ```ts\r\n * const TEST_ERROR_CODES = defineErrorCatalog({\r\n * USER_NOT_FOUND: \"Usuário {id} não encontrado\",\r\n * INVALID_TOKEN: \"Token inválido\",\r\n * });\r\n *\r\n * type TestErrorCodes = typeof TEST_ERROR_CODES;\r\n *\r\n * class UserNotFoundError extends BaseError<TestErrorCodes, \"USER_NOT_FOUND\"> {\r\n * public constructor(id: number, options?: ErrorOptions) {\r\n * super(TEST_ERROR_CODES.USER_NOT_FOUND, { params: { id }, ...options });\r\n * }\r\n * }\r\n *\r\n * class InvalidTokenError extends BaseError<TestErrorCodes, \"INVALID_TOKEN\"> {\r\n * public constructor(options?: ErrorOptions) {\r\n * super(TEST_ERROR_CODES.INVALID_TOKEN, options);\r\n * }\r\n * }\r\n *\r\n * const erro = new UserNotFoundError(42);\r\n * erro.message; // \"Usuário 42 não encontrado\"\r\n * erro.code; // \"USER_NOT_FOUND\"\r\n * erro.params; // { id: 42 }\r\n * erro.name; // \"UserNotFoundError\"\r\n *\r\n * BaseError.is(erro); // true\r\n * JSON.stringify(erro); // usa toJSON(), sem stack trace\r\n * erro.serialize(true); // inclui o stack trace\r\n * ```\r\n */\r\nexport abstract class BaseError<\r\n Catalog extends ErrorCatalog = ErrorCatalog,\r\n Code extends CatalogCode<Catalog> = CatalogCode<Catalog>,\r\n Delimiters extends ErrorParamDelimiters = DefaultParamDelimiters,\r\n> extends Error {\r\n /** Código do erro conforme o catálogo (ex.: `\"USER_NOT_FOUND\"`). */\r\n public readonly code: Code;\r\n /**\r\n * Parâmetros usados para interpolar a mensagem. É `undefined` quando a\r\n * mensagem não possui placeholders (ou quando nenhum `params` foi informado).\r\n */\r\n public readonly params?: ErrorParams<Catalog, Code, Delimiters>;\r\n\r\n /**\r\n * Cria um erro a partir de um descritor do catálogo.\r\n *\r\n * A mensagem do descritor é interpolada com `options.params` usando os\r\n * delimitadores de `options.delimiters` (por padrão,\r\n * {@link DEFAULT_PARAM_DELIMITERS}). Os delimitadores são usados apenas na\r\n * interpolação e não são armazenados na instância. O objeto `options`\r\n * também é repassado ao construtor de `Error`, que utiliza `cause`.\r\n *\r\n * É `protected` então só pode ser chamado por subclasses.\r\n *\r\n * @param descriptor - Descritor do erro no catálogo com `code` e `message`.\r\n * @param args - Opções do erro ({@link BaseErrorOptions}). São obrigatórias\r\n * se a mensagem tiver placeholders (por conter `params`) e opcionais caso\r\n * contrário.\r\n * @throws {InvalidParamDelimitersError} Se algum dos delimitadores for uma\r\n * string vazia (lançado durante a interpolação).\r\n */\r\n protected constructor(\r\n descriptor: CatalogDescriptor<Catalog, Code>,\r\n ...args: BaseErrorOptionsArgs<Catalog, Code, Delimiters>\r\n ) {\r\n const options = args[0];\r\n const delimiters = (options?.delimiters ??\r\n DEFAULT_PARAM_DELIMITERS) as Delimiters;\r\n const params = options && \"params\" in options ? options.params : undefined;\r\n const interpolationArgs = (\r\n params === undefined ? [] : [params]\r\n ) as ErrorMessageArgs<\r\n CatalogDescriptor<Catalog, Code>[\"message\"],\r\n Delimiters\r\n >;\r\n\r\n super(\r\n interpolateErrorMessage(descriptor, delimiters, ...interpolationArgs),\r\n options,\r\n );\r\n\r\n this.name = new.target.name;\r\n this.code = descriptor.code;\r\n this.params = params;\r\n\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n\r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, new.target);\r\n }\r\n }\r\n\r\n /**\r\n * Marca interna que identifica a instância como um `BaseError`.\r\n *\r\n * Sempre retorna `true` e é lida por {@link isBaseError}. Por ser um\r\n * getter definido no protótipo, não é uma propriedade própria da instância\r\n * e portanto, não aparece em serializações nem em `Object.keys`.\r\n */\r\n public get [BASE_ERROR_BRAND]() {\r\n return true;\r\n }\r\n\r\n /**\r\n * Serializa o erro para um objeto simples apropriado para `JSON.stringify`,\r\n * logs ou transmissão. Veja {@link serializeBaseError} para os detalhes do\r\n * formato retornado.\r\n *\r\n * @param includeStack - Se `true` inclui o stack trace no resultado (e na\r\n * serialização de causas e parâmetros). Por padrão, `false`.\r\n * @returns Representação serializável do erro.\r\n */\r\n public serialize(includeStack = false) {\r\n return serializeBaseError(this as Readonly<BaseError>, includeStack);\r\n }\r\n\r\n /**\r\n * Chamado automaticamente por `JSON.stringify`. Equivale a\r\n * {@link BaseError.serialize} sem stack trace.\r\n *\r\n * @returns Representação serializável do erro sem stack trace.\r\n */\r\n public toJSON() {\r\n return this.serialize();\r\n }\r\n\r\n /**\r\n * Verifica se um valor é uma instância de `BaseError` (type guard).\r\n *\r\n * Atalho para {@link isBaseError}: usa a marca interna em vez de\r\n * `instanceof` funcionando mesmo com múltiplas cópias do pacote.\r\n *\r\n * @param error - Valor a ser verificado.\r\n * @returns `true` se `error` for um `BaseError`; caso contrário, `false`.\r\n */\r\n public static is(error: unknown): error is BaseError {\r\n return isBaseError(error);\r\n }\r\n\r\n /**\r\n * Serializa de forma segura qualquer valor usado como causa de um erro.\r\n *\r\n * Atalho para {@link serializeCauseError}: trata erros, datas, arrays,\r\n * objetos, funções, `bigint`, `symbol` e referências circulares.\r\n *\r\n * @param cause - Valor a ser serializado.\r\n * @param includeStack - Se `true` inclui o stack trace ao serializar\r\n * erros. Por padrão, `false`.\r\n * @returns Representação serializável do valor.\r\n */\r\n public static serializeCauseError(cause: unknown, includeStack = false) {\r\n return serializeCauseError(cause, includeStack);\r\n }\r\n}\r\n","import { InvalidErrorCode } from \"./errors/invalid-error-code.js\";\r\nimport type { ErrorCatalog } from \"./types/error-catalog.js\";\r\nimport type { ErrorDescriptor } from \"./types/error-descriptor.js\";\r\nimport type { ValidateErrorDefinitions } from \"./types/validate-error-definitions.js\";\r\nimport { isUpperSnakeCase } from \"./upper-snake-case.js\";\r\n\r\n/**\r\n * Cria um catálogo de erros imutável a partir de um objeto que associa cada\r\n * código de erro à sua mensagem.\r\n *\r\n * Para cada entrada de `definitions` gera um {@link ErrorDescriptor} com\r\n * `code` e `message` congelado com `Object.freeze`. O próprio catálogo\r\n * retornado também é congelado, de modo que nem o catálogo nem seus\r\n * descritores podem ser alterados depois de criados.\r\n *\r\n * A validação ocorre em duas camadas:\r\n * - em tempo de compilação via {@link ValidateErrorDefinitions}: códigos fora\r\n * de UPPER_SNAKE_CASE geram um erro de tipo com uma mensagem explicativa;\r\n * - em tempo de execução via {@link isUpperSnakeCase}: códigos inválidos\r\n * lançam {@link InvalidErrorCode}, o que protege contra definições que\r\n * escapem da checagem de tipos (ex.: objetos tipados como `any` ou\r\n * `Record<string, string>`).\r\n *\r\n * O parâmetro de tipo `T` é declarado como `const`, o que preserva os tipos\r\n * literais dos códigos e das mensagens sem a necessidade de `as const` na\r\n * chamada.\r\n *\r\n * @template Codes - Objeto que mapeia códigos de erro para suas mensagens.\r\n * @param definitions - Definições do catálogo: chaves são os códigos em\r\n * UPPER_SNAKE_CASE.\r\n * @returns Catálogo de erros somente leitura com um descritor para cada\r\n * código informado.\r\n * @throws {InvalidErrorCode} Se algum código não estiver em UPPER_SNAKE_CASE.\r\n *\r\n * @example\r\n * ```ts\r\n * const TEST_ERROR_CODES = defineErrorCatalog({\r\n * USER_NOT_FOUND: \"Usuário {id} não encontrado\",\r\n * INVALID_TOKEN: \"Token inválido\",\r\n * });\r\n *\r\n * TEST_ERROR_CODES.USER_NOT_FOUND.code; // \"USER_NOT_FOUND\"\r\n * TEST_ERROR_CODES.USER_NOT_FOUND.message; // \"Usuário {id} não encontrado\"\r\n *\r\n * // Erro de compilação (e de execução): código fora de UPPER_SNAKE_CASE\r\n * defineErrorCatalog({\r\n * userNotFound: \"Usuário não encontrado\",\r\n * });\r\n * // Lança InvalidErrorCode\r\n * ```\r\n */\r\nexport function defineErrorCatalog<const Codes extends Record<string, string>>(\r\n definitions: ValidateErrorDefinitions<Codes>,\r\n): ErrorCatalog<Codes> {\r\n const catalog: Record<string, ErrorDescriptor> = {};\r\n\r\n for (const [code, message] of Object.entries(\r\n definitions as Record<string, string>,\r\n )) {\r\n if (!isUpperSnakeCase(code)) {\r\n throw new InvalidErrorCode(code);\r\n }\r\n\r\n catalog[code] = Object.freeze({ code, message });\r\n }\r\n\r\n return Object.freeze(catalog) as ErrorCatalog<Codes>;\r\n}\r\n","import { EitherUnwrapError } from \"./errors/either-unwrap-error.js\";\r\n\r\n/**\r\n * Representa o resultado de uma operação que pode ter sucesso (`Ok`) ou\r\n * falhar (`Err`), tornando o erro parte explícita do tipo de retorno em vez\r\n * de depender de exceções.\r\n *\r\n * Um `Either<O, E>` é sempre uma instância de {@link Ok} que carrega um\r\n * valor de sucesso do tipo `O`, ou de {@link Err} que carrega um valor de\r\n * erro do tipo `E`. Use {@link ok} e {@link err} para criá-los.\r\n *\r\n * Os métodos {@link Either.map}, {@link Either.mapErr}, {@link Either.flatMap}\r\n * e {@link Either.orElse} retornam um novo `Either` e não alteram o original.\r\n * Para tratar os dois casos use {@link Either.match}, ou os type guards\r\n * {@link Either.isOk} e {@link Either.isErr}.\r\n *\r\n * @template O - Tipo do valor de sucesso.\r\n * @template E - Tipo do valor de erro.\r\n *\r\n * @example\r\n * ```ts\r\n * function toDivide(a: number, b: number): Either<number, string> {\r\n * return b === 0 ? err(\"Divisão por zero\") : ok(a / b);\r\n * }\r\n *\r\n * const message = toDivide(10, 2)\r\n * .map((resultado) => resultado * 3)\r\n * .match({\r\n * onOk: (valor) => `Resultado: ${valor}`,\r\n * onErr: (erro) => `Falha: ${erro}`,\r\n * });\r\n * // \"Resultado: 15\"\r\n * ```\r\n */\r\nexport abstract class Either<O, E> {\r\n /** Discriminante da variante: `\"Ok\"` para sucesso e `\"Err\"` para erro. */\r\n public abstract readonly tag: \"Ok\" | \"Err\";\r\n\r\n /**\r\n * Retorna o valor de sucesso.\r\n *\r\n * @returns O valor contido em `Ok`.\r\n * @throws {EitherUnwrapError} Se for um `Err`. A `cause` do erro é o valor\r\n * de erro contido.\r\n */\r\n public abstract unwrap(): O;\r\n\r\n /**\r\n * Retorna o valor de erro.\r\n *\r\n * @returns O valor contido em `Err`.\r\n * @throws {EitherUnwrapError} Se for um `Ok`. A `cause` do erro é o valor\r\n * de sucesso contido.\r\n */\r\n public abstract unwrapErr(): E;\r\n\r\n /**\r\n * Verifica se é um `Ok` funcionando como type guard.\r\n *\r\n * @returns `true` se for `Ok` (restringindo o tipo para {@link Ok});\r\n * caso contrário, `false`.\r\n */\r\n public abstract isOk(): this is Ok<O, E>;\r\n\r\n /**\r\n * Verifica se é um `Err` funcionando como type guard.\r\n *\r\n * @returns `true` se for `Err` (restringindo o tipo para {@link Err});\r\n * caso contrário, `false`.\r\n */\r\n public abstract isErr(): this is Err<O, E>;\r\n\r\n /**\r\n * Transforma o valor de sucesso mantendo o erro intacto.\r\n *\r\n * Se for `Ok` aplica `fn` ao valor e retorna um novo `Ok` com o resultado.\r\n * Se for `Err` `fn` não é chamada e um novo `Err` com o mesmo erro é\r\n * retornado. Exceções lançadas por `fn` não são capturadas.\r\n *\r\n * @template O2 - Tipo do novo valor de sucesso.\r\n * @param fn - Função que converte o valor de sucesso.\r\n * @returns Um `Either` com o valor transformado ou o erro original.\r\n *\r\n * @example\r\n * ```ts\r\n * ok<number, string>(2).map((n) => n * 2).unwrap(); // 4\r\n * err<number, string>(\"falhou\").map((n) => n * 2).unwrapErr(); // \"falhou\"\r\n * ```\r\n */\r\n public map<O2>(fn: (value: O) => O2): Either<O2, E> {\r\n if (this.isOk()) {\r\n return ok(fn(this.unwrap()));\r\n }\r\n\r\n return err(this.unwrapErr());\r\n }\r\n\r\n /**\r\n * Transforma o valor de erro mantendo o sucesso intacto.\r\n *\r\n * Se for `Err` aplica `fn` ao erro e retorna um novo `Err` com o resultado.\r\n * Se for `Ok` `fn` não é chamada e um novo `Ok` com o mesmo valor é\r\n * retornado. Exceções lançadas por `fn` não são capturadas.\r\n *\r\n * @template E2 - Tipo do novo valor de erro.\r\n * @param fn - Função que converte o valor de erro.\r\n * @returns Um `Either` com o erro transformado ou o valor original.\r\n *\r\n * @example\r\n * ```ts\r\n * err<number, string>(\"falhou\").mapErr((e) => e.length).unwrapErr(); // 7\r\n * ok<number, string>(1).mapErr((e) => e.length).unwrap(); // 1\r\n * ```\r\n */\r\n public mapErr<E2>(fn: (value: E) => E2): Either<O, E2> {\r\n if (this.isErr()) {\r\n return err(fn(this.unwrapErr()));\r\n }\r\n\r\n return ok(this.unwrap());\r\n }\r\n\r\n /**\r\n * Encadeia uma operação que também retorna um `Either` usada quando o\r\n * próximo passo também pode falhar.\r\n *\r\n * Se for `Ok`, retorna diretamente o `Either` produzido por `fn` (sem\r\n * aninhamento). Se for `Err` `fn` não é chamada e o erro é propagado.\r\n * O tipo de erro resultante é a união `E | E2`. Exceções lançadas por `fn`\r\n * não são capturadas.\r\n *\r\n * @template O2 - Tipo do valor de sucesso retornado por `fn`.\r\n * @template E2 - Tipo do valor de erro retornado por `fn`.\r\n * @param fn - Função que recebe o valor de sucesso e retorna um `Either`.\r\n * @returns O `Either` retornado por `fn`, ou o erro original.\r\n *\r\n * @example\r\n * ```ts\r\n * const forNumber = (s: string): Either<number, string> => {\r\n * const n = Number(s);\r\n * return Number.isNaN(n) ? err(\"Não é número\") : ok(n);\r\n * };\r\n *\r\n * ok<string, string>(\"42\").flatMap(forNumber).unwrap(); // 42\r\n * ok<string, string>(\"abc\").flatMap(forNumber).unwrapErr(); // \"Não é número\"\r\n * ```\r\n */\r\n public flatMap<O2, E2>(fn: (value: O) => Either<O2, E2>): Either<O2, E | E2> {\r\n if (this.isOk()) {\r\n return fn(this.unwrap());\r\n }\r\n\r\n return err(this.unwrapErr());\r\n }\r\n\r\n /**\r\n * Tenta se recuperar de um erro encadeando uma operação alternativa que\r\n * também retorna um `Either`. É o oposto de {@link Either.flatMap}.\r\n *\r\n * Se for `Err` retorna diretamente o `Either` produzido por `fn`. Se for\r\n * `Ok` `fn` não é chamada e o valor é mantido. O tipo de sucesso\r\n * resultante é a união `O | O2`. Exceções lançadas por `fn` não são\r\n * capturadas.\r\n *\r\n * @template O2 - Tipo do valor de sucesso retornado por `fn`.\r\n * @template E2 - Tipo do valor de erro retornado por `fn`.\r\n * @param fn - Função que recebe o valor de erro e retorna um `Either`.\r\n * @returns O `Either` retornado por `fn`, ou o valor de sucesso original.\r\n *\r\n * @example\r\n * ```ts\r\n * err<number, string>(\"falhou\").orElse(() => ok(0)).unwrap(); // 0\r\n * ok<number, string>(5).orElse(() => ok(0)).unwrap(); // 5\r\n * ```\r\n */\r\n public orElse<O2, E2>(fn: (value: E) => Either<O2, E2>): Either<O | O2, E2> {\r\n if (this.isErr()) {\r\n return fn(this.unwrapErr());\r\n }\r\n\r\n return ok(this.unwrap());\r\n }\r\n\r\n /**\r\n * Trata os dois casos e produz um único valor chamando o handler da\r\n * variante correspondente.\r\n *\r\n * @template R - Tipo do valor retornado pelos handlers.\r\n * @param handlers - Objeto com `onOk` chamado com o valor de sucesso e\r\n * `onErr` chamado com o valor de erro.\r\n * @returns O resultado do handler chamado.\r\n *\r\n * @example\r\n * ```ts\r\n * const texto = resultado.match({\r\n * onOk: (valor) => `Sucesso: ${valor}`,\r\n * onErr: (erro) => `Erro: ${erro}`,\r\n * });\r\n * ```\r\n */\r\n public match<R>(\r\n handlers: Readonly<{ onOk(value: O): R; onErr(value: E): R }>,\r\n ): R {\r\n if (this.isOk()) {\r\n return handlers.onOk(this.unwrap());\r\n }\r\n\r\n return handlers.onErr(this.unwrapErr());\r\n }\r\n}\r\n\r\n/**\r\n * Variante de sucesso de {@link Either} que carrega um valor do tipo `O`.\r\n *\r\n * O construtor é `protected`; para criar uma instância use {@link Ok.create}\r\n * ou a função {@link ok}.\r\n *\r\n * @template O - Tipo do valor de sucesso. Por padrão, `never`.\r\n * @template E - Tipo do valor de erro usado apenas para compatibilidade com\r\n * {@link Either}. Por padrão, `never`.\r\n */\r\nexport class Ok<O = never, E = never> extends Either<O, E> {\r\n /** Discriminante da variante sempre `\"Ok\"`. */\r\n public readonly tag = \"Ok\" as const;\r\n /** Valor de sucesso armazenado. */\r\n private readonly value: O;\r\n\r\n /**\r\n * @param value - Valor de sucesso a ser armazenado.\r\n */\r\n protected constructor(value: O) {\r\n super();\r\n\r\n this.value = value;\r\n }\r\n\r\n /**\r\n * Retorna o valor de sucesso armazenado.\r\n *\r\n * @returns O valor contido.\r\n */\r\n public unwrap(): O {\r\n return this.value;\r\n }\r\n\r\n /**\r\n * Sempre lança um erro pois um `Ok` não possui valor de erro.\r\n *\r\n * @throws {EitherUnwrapError} Sempre. A `cause` é o valor de sucesso contido.\r\n */\r\n public unwrapErr(): E {\r\n throw new EitherUnwrapError(\"Chamado unwrapErr() em Ok.\", {\r\n cause: this.value,\r\n });\r\n }\r\n\r\n /** @returns Sempre `true`. */\r\n public isOk(): this is Ok<O, E> {\r\n return true;\r\n }\r\n\r\n /** @returns Sempre `false`. */\r\n public isErr(): this is Err<O, E> {\r\n return false;\r\n }\r\n\r\n /**\r\n * Cria um `Ok` com o valor informado.\r\n *\r\n * @template O - Tipo do valor de sucesso. Por padrão, `never`.\r\n * @template E - Tipo do valor de erro. Por padrão, `never`.\r\n * @param value - Valor de sucesso.\r\n * @returns Uma nova instância de `Ok`.\r\n */\r\n public static create<O = never, E = never>(value: O): Ok<O, E> {\r\n return new Ok(value);\r\n }\r\n}\r\n\r\n/**\r\n * Variante de erro de {@link Either} que carrega um valor do tipo `E`.\r\n *\r\n * O construtor é `protected`; para criar uma instância use {@link Err.create}\r\n * ou a função {@link err}.\r\n *\r\n * @template O - Tipo do valor de sucesso usado apenas para compatibilidade\r\n * com {@link Either}. Por padrão, `never`.\r\n * @template E - Tipo do valor de erro. Por padrão, `never`.\r\n */\r\nexport class Err<O = never, E = never> extends Either<O, E> {\r\n /** Discriminante da variante sempre `\"Err\"`. */\r\n public readonly tag = \"Err\" as const;\r\n /** Valor de erro armazenado. */\r\n private readonly value: E;\r\n\r\n /**\r\n * @param value - Valor de erro a ser armazenado.\r\n */\r\n protected constructor(value: E) {\r\n super();\r\n\r\n this.value = value;\r\n }\r\n\r\n /**\r\n * Sempre lança um erro pois um `Err` não possui valor de sucesso.\r\n *\r\n * @throws {EitherUnwrapError} Sempre. A `cause` é o valor de erro contido.\r\n */\r\n public unwrap(): O {\r\n throw new EitherUnwrapError(\"Chamado unwrap() em Err.\", {\r\n cause: this.value,\r\n });\r\n }\r\n\r\n /**\r\n * Retorna o valor de erro armazenado.\r\n *\r\n * @returns O valor contido.\r\n */\r\n public unwrapErr(): E {\r\n return this.value;\r\n }\r\n\r\n /** @returns Sempre `false`. */\r\n public isOk(): this is Ok<O, E> {\r\n return false;\r\n }\r\n\r\n /** @returns Sempre `true`. */\r\n public isErr(): this is Err<O, E> {\r\n return true;\r\n }\r\n\r\n /**\r\n * Cria um `Err` com o valor informado.\r\n *\r\n * @template O - Tipo do valor de sucesso. Por padrão, `never`.\r\n * @template E - Tipo do valor de erro. Por padrão, `never`.\r\n * @param value - Valor de erro.\r\n * @returns Uma nova instância de `Err`.\r\n */\r\n public static create<O = never, E = never>(value: E): Err<O, E> {\r\n return new Err(value);\r\n }\r\n}\r\n\r\n/**\r\n * Cria um {@link Either} de sucesso (`Ok`) com o valor informado.\r\n *\r\n * O retorno é tipado como `Either<O, E>` e não como `Ok` para que possa ser\r\n * usado onde se espera qualquer variante. Como `E` não pode ser inferido a\r\n * partir do argumento, informe-o explicitamente quando necessário.\r\n *\r\n * @template O - Tipo do valor de sucesso. Por padrão, `never`.\r\n * @template E - Tipo do valor de erro. Por padrão, `never`.\r\n * @param value - Valor de sucesso.\r\n * @returns Um `Either` que é um `Ok` contendo `value`.\r\n *\r\n * @example\r\n * ```ts\r\n * const result = ok<number, string>(42);\r\n * result.isOk(); // true\r\n * result.unwrap(); // 42\r\n * ```\r\n */\r\nexport function ok<O = never, E = never>(value: O): Either<O, E> {\r\n return Ok.create(value);\r\n}\r\n\r\n/**\r\n * Cria um {@link Either} de erro (`Err`) com o valor informado.\r\n *\r\n * O retorno é tipado como `Either<O, E>` e não como `Err` para que possa ser\r\n * usado onde se espera qualquer variante. Como `O` não pode ser inferido a\r\n * partir do argumento, informe-o explicitamente quando necessário.\r\n *\r\n * @template O - Tipo do valor de sucesso. Por padrão, `never`.\r\n * @template E - Tipo do valor de erro. Por padrão, `never`.\r\n * @param value - Valor de erro.\r\n * @returns Um `Either` que é um `Err` contendo `value`.\r\n *\r\n * @example\r\n * ```ts\r\n * const result = err<number, string>(\"Algo deu errado\");\r\n * result.isErr(); // true\r\n * result.unwrapErr(); // \"Algo deu errado\"\r\n * ```\r\n */\r\nexport function err<O = never, E = never>(value: E): Either<O, E> {\r\n return Err.create(value);\r\n}\r\n"],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//#region src/errors/invalid-param-delimiters-error.ts
|
|
2
|
+
/**
|
|
3
|
+
* Erro lançado quando os delimitadores de placeholders são inválidos, ou
|
|
4
|
+
* seja, quando `open` ou `close` é uma string vazia.
|
|
5
|
+
*
|
|
6
|
+
* Estende `TypeError` pois indica um valor de formato inadequado. É lançado
|
|
7
|
+
* em tempo de execução por `createParamPlaceholder` e por consequência, por
|
|
8
|
+
* quem o utiliza como `interpolateErrorMessage` e o construtor de
|
|
9
|
+
* `BaseError`.
|
|
10
|
+
*
|
|
11
|
+
* O `name` do erro é o nome da classe concreta (`new.target.name`) e o
|
|
12
|
+
* protótipo é ajustado explicitamente para que `instanceof` funcione mesmo em
|
|
13
|
+
* subclasses e em alvos de compilação antigos.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* try {
|
|
18
|
+
* createParamPlaceholder({ open: "", close: "}" });
|
|
19
|
+
* } catch (error) {
|
|
20
|
+
* if (error instanceof InvalidParamDelimitersError) {
|
|
21
|
+
* error.message; // "Os delimitadores open e close não podem ser vazios."
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
var InvalidParamDelimitersError = class extends TypeError {
|
|
27
|
+
/**
|
|
28
|
+
* Cria o erro de delimitadores inválidos.
|
|
29
|
+
*
|
|
30
|
+
* @param message - Mensagem do erro. Por padrão, "Os delimitadores open e
|
|
31
|
+
* close não podem ser vazios.".
|
|
32
|
+
* @param options - Opções padrão de `Error` como `cause`.
|
|
33
|
+
*/
|
|
34
|
+
constructor(message = "Os delimitadores open e close não podem ser vazios.", options) {
|
|
35
|
+
super(message, options);
|
|
36
|
+
this.name = new.target.name;
|
|
37
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
38
|
+
if (Error.captureStackTrace) Error.captureStackTrace(this, new.target);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
//#endregion
|
|
42
|
+
export { InvalidParamDelimitersError as t };
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=invalid-param-delimiters-error-BFxlVXp3.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invalid-param-delimiters-error-BFxlVXp3.mjs","names":[],"sources":["../src/errors/invalid-param-delimiters-error.ts"],"sourcesContent":["/**\r\n * Erro lançado quando os delimitadores de placeholders são inválidos, ou\r\n * seja, quando `open` ou `close` é uma string vazia.\r\n *\r\n * Estende `TypeError` pois indica um valor de formato inadequado. É lançado\r\n * em tempo de execução por `createParamPlaceholder` e por consequência, por\r\n * quem o utiliza como `interpolateErrorMessage` e o construtor de\r\n * `BaseError`.\r\n *\r\n * O `name` do erro é o nome da classe concreta (`new.target.name`) e o\r\n * protótipo é ajustado explicitamente para que `instanceof` funcione mesmo em\r\n * subclasses e em alvos de compilação antigos.\r\n *\r\n * @example\r\n * ```ts\r\n * try {\r\n * createParamPlaceholder({ open: \"\", close: \"}\" });\r\n * } catch (error) {\r\n * if (error instanceof InvalidParamDelimitersError) {\r\n * error.message; // \"Os delimitadores open e close não podem ser vazios.\"\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport class InvalidParamDelimitersError extends TypeError {\r\n /**\r\n * Cria o erro de delimitadores inválidos.\r\n *\r\n * @param message - Mensagem do erro. Por padrão, \"Os delimitadores open e\r\n * close não podem ser vazios.\".\r\n * @param options - Opções padrão de `Error` como `cause`.\r\n */\r\n public constructor(\r\n message = \"Os delimitadores open e close não podem ser vazios.\",\r\n options?: ErrorOptions,\r\n ) {\r\n super(message, options);\r\n\r\n this.name = new.target.name;\r\n\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n\r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, new.target);\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAwBA,IAAa,8BAAb,cAAiD,UAAU;;;;;;;;CAQzD,YACE,UAAU,uDACV,SACA;EACA,MAAM,SAAS,OAAO;EAEtB,KAAK,OAAO,WAAW;EAEvB,OAAO,eAAe,MAAM,WAAW,SAAS;EAEhD,IAAI,MAAM,mBACR,MAAM,kBAAkB,MAAM,UAAU;CAE5C;AACF"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
//#region src/errors/invalid-param-delimiters-error.ts
|
|
2
|
+
/**
|
|
3
|
+
* Erro lançado quando os delimitadores de placeholders são inválidos, ou
|
|
4
|
+
* seja, quando `open` ou `close` é uma string vazia.
|
|
5
|
+
*
|
|
6
|
+
* Estende `TypeError` pois indica um valor de formato inadequado. É lançado
|
|
7
|
+
* em tempo de execução por `createParamPlaceholder` e por consequência, por
|
|
8
|
+
* quem o utiliza como `interpolateErrorMessage` e o construtor de
|
|
9
|
+
* `BaseError`.
|
|
10
|
+
*
|
|
11
|
+
* O `name` do erro é o nome da classe concreta (`new.target.name`) e o
|
|
12
|
+
* protótipo é ajustado explicitamente para que `instanceof` funcione mesmo em
|
|
13
|
+
* subclasses e em alvos de compilação antigos.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* try {
|
|
18
|
+
* createParamPlaceholder({ open: "", close: "}" });
|
|
19
|
+
* } catch (error) {
|
|
20
|
+
* if (error instanceof InvalidParamDelimitersError) {
|
|
21
|
+
* error.message; // "Os delimitadores open e close não podem ser vazios."
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
var InvalidParamDelimitersError = class extends TypeError {
|
|
27
|
+
/**
|
|
28
|
+
* Cria o erro de delimitadores inválidos.
|
|
29
|
+
*
|
|
30
|
+
* @param message - Mensagem do erro. Por padrão, "Os delimitadores open e
|
|
31
|
+
* close não podem ser vazios.".
|
|
32
|
+
* @param options - Opções padrão de `Error` como `cause`.
|
|
33
|
+
*/
|
|
34
|
+
constructor(message = "Os delimitadores open e close não podem ser vazios.", options) {
|
|
35
|
+
super(message, options);
|
|
36
|
+
this.name = new.target.name;
|
|
37
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
38
|
+
if (Error.captureStackTrace) Error.captureStackTrace(this, new.target);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
//#endregion
|
|
42
|
+
Object.defineProperty(exports, "InvalidParamDelimitersError", {
|
|
43
|
+
enumerable: true,
|
|
44
|
+
get: function() {
|
|
45
|
+
return InvalidParamDelimitersError;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
//# sourceMappingURL=invalid-param-delimiters-error-C6UxV7cK.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invalid-param-delimiters-error-C6UxV7cK.cjs","names":[],"sources":["../src/errors/invalid-param-delimiters-error.ts"],"sourcesContent":["/**\r\n * Erro lançado quando os delimitadores de placeholders são inválidos, ou\r\n * seja, quando `open` ou `close` é uma string vazia.\r\n *\r\n * Estende `TypeError` pois indica um valor de formato inadequado. É lançado\r\n * em tempo de execução por `createParamPlaceholder` e por consequência, por\r\n * quem o utiliza como `interpolateErrorMessage` e o construtor de\r\n * `BaseError`.\r\n *\r\n * O `name` do erro é o nome da classe concreta (`new.target.name`) e o\r\n * protótipo é ajustado explicitamente para que `instanceof` funcione mesmo em\r\n * subclasses e em alvos de compilação antigos.\r\n *\r\n * @example\r\n * ```ts\r\n * try {\r\n * createParamPlaceholder({ open: \"\", close: \"}\" });\r\n * } catch (error) {\r\n * if (error instanceof InvalidParamDelimitersError) {\r\n * error.message; // \"Os delimitadores open e close não podem ser vazios.\"\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport class InvalidParamDelimitersError extends TypeError {\r\n /**\r\n * Cria o erro de delimitadores inválidos.\r\n *\r\n * @param message - Mensagem do erro. Por padrão, \"Os delimitadores open e\r\n * close não podem ser vazios.\".\r\n * @param options - Opções padrão de `Error` como `cause`.\r\n */\r\n public constructor(\r\n message = \"Os delimitadores open e close não podem ser vazios.\",\r\n options?: ErrorOptions,\r\n ) {\r\n super(message, options);\r\n\r\n this.name = new.target.name;\r\n\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n\r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, new.target);\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAwBA,IAAa,8BAAb,cAAiD,UAAU;;;;;;;;CAQzD,YACE,UAAU,uDACV,SACA;EACA,MAAM,SAAS,OAAO;EAEtB,KAAK,OAAO,WAAW;EAEvB,OAAO,eAAe,MAAM,WAAW,SAAS;EAEhD,IAAI,MAAM,mBACR,MAAM,kBAAkB,MAAM,UAAU;CAE5C;AACF"}
|
|
File without changes
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { a as Trim, c as CatalogCode, i as ExtractPlaceholders, l as ErrorCatalog, m as ErrorParamDelimiters, n as ErrorParamValue, o as Whitespace, r as ParamsFromMessage, s as CatalogDescriptor, t as ErrorParams, u as ErrorDescriptor } from "../error-params-CR2parjT.cjs";
|
|
2
|
+
//#region src/types/validate-error-definitions.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Letras maiúsculas do alfabeto latino (`A` a `Z`), sem acentos.
|
|
5
|
+
*
|
|
6
|
+
* Usado para validar em tempo de compilação códigos em UPPER_SNAKE_CASE.
|
|
7
|
+
*/
|
|
8
|
+
export type UpperLetter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z";
|
|
9
|
+
/**
|
|
10
|
+
* Dígitos decimais (`0` a `9`), representados como string literals.
|
|
11
|
+
*/
|
|
12
|
+
export type Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
|
|
13
|
+
/**
|
|
14
|
+
* Caractere alfanumérico permitido em um segmento de código: uma letra
|
|
15
|
+
* maiúscula ({@link UpperLetter}) ou um dígito ({@link Digit}).
|
|
16
|
+
*/
|
|
17
|
+
export type AlphaNumeric = UpperLetter | Digit;
|
|
18
|
+
/**
|
|
19
|
+
* Verifica se `T` é um segmento válido: não vazio e composto apenas por
|
|
20
|
+
* caracteres alfanuméricos ({@link AlphaNumeric}), podendo continuar com
|
|
21
|
+
* novos segmentos separados por `_`.
|
|
22
|
+
*
|
|
23
|
+
* Exige que o primeiro caractere seja alfanumérico e delega o restante a
|
|
24
|
+
* {@link Tail}. É um tipo auxiliar de {@link IsUpperSnakeCase}, definido em
|
|
25
|
+
* recursão mútua com `Tail`.
|
|
26
|
+
*
|
|
27
|
+
* @template T - String literal a ser verificada.
|
|
28
|
+
* @returns `true` se for válido; caso contrário, `false`.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* type A = Segment<"ABC">; // true
|
|
33
|
+
* type B = Segment<"A_B">; // true
|
|
34
|
+
* type C = Segment<"_A">; // false (começa com "_")
|
|
35
|
+
* type D = Segment<"">; // false (segmento vazio)
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export type Segment<T extends string> = T extends `${AlphaNumeric}${infer Rest}` ? Tail<Rest> : false;
|
|
39
|
+
/**
|
|
40
|
+
* Verifica o restante de um código depois de seu primeiro caractere válido.
|
|
41
|
+
*
|
|
42
|
+
* Percorre a string caractere por caractere:
|
|
43
|
+
* - string vazia: o código é válido (`true`);
|
|
44
|
+
* - `_`: deve ser seguido por um novo segmento válido (via {@link Segment}),
|
|
45
|
+
* o que impede `_` duplicado ou no final;
|
|
46
|
+
* - caractere alfanumérico: continua a verificação;
|
|
47
|
+
* - qualquer outro caractere: o código é inválido (`false`).
|
|
48
|
+
*
|
|
49
|
+
* É um tipo auxiliar de {@link IsUpperSnakeCase}, definido em recursão mútua
|
|
50
|
+
* com {@link Segment}.
|
|
51
|
+
*
|
|
52
|
+
* @template T - Restante da string literal a ser verificado.
|
|
53
|
+
* @returns `true` se for válido; caso contrário, `false`.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* type A = Tail<"">; // true
|
|
58
|
+
* type B = Tail<"BC_D">; // true
|
|
59
|
+
* type C = Tail<"B__C">; // false (underscores consecutivos)
|
|
60
|
+
* type D = Tail<"B_">; // false (termina com "_")
|
|
61
|
+
* type E = Tail<"b">; // false (letra minúscula)
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export type Tail<T extends string> = T extends "" ? true : T extends `_${infer Rest}` ? Segment<Rest> : T extends `${AlphaNumeric}${infer Rest}` ? Tail<Rest> : false;
|
|
65
|
+
/**
|
|
66
|
+
* Verifica em tempo de compilação, se uma string literal está em
|
|
67
|
+
* UPPER_SNAKE_CASE.
|
|
68
|
+
*
|
|
69
|
+
* Regras:
|
|
70
|
+
* - deve começar com uma letra maiúscula (não pode começar com dígito);
|
|
71
|
+
* - pode conter letras maiúsculas, dígitos e `_`;
|
|
72
|
+
* - `_` só pode aparecer entre dois caracteres alfanuméricos, ou seja, não pode
|
|
73
|
+
* estar no início nem no fim e não pode ser repetido em sequência.
|
|
74
|
+
*
|
|
75
|
+
* Se `T` for o tipo genérico `string` (não literal), não é possível validar e
|
|
76
|
+
* o resultado é `false`.
|
|
77
|
+
*
|
|
78
|
+
* @template T - String literal a ser verificada.
|
|
79
|
+
* @returns `true` se estiver em UPPER_SNAKE_CASE; caso contrário, `false`.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* type A = IsUpperSnakeCase<"USER_NOT_FOUND">; // true
|
|
84
|
+
* type B = IsUpperSnakeCase<"ERROR_404">; // true
|
|
85
|
+
* type C = IsUpperSnakeCase<"userNotFound">; // false
|
|
86
|
+
* type D = IsUpperSnakeCase<"_USER">; // false
|
|
87
|
+
* type E = IsUpperSnakeCase<"USER_">; // false
|
|
88
|
+
* type F = IsUpperSnakeCase<"USER__NOT">; // false
|
|
89
|
+
* type G = IsUpperSnakeCase<"1ERROR">; // false
|
|
90
|
+
* type H = IsUpperSnakeCase<string>; // false
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export type IsUpperSnakeCase<T extends string> = string extends T ? false : T extends `${UpperLetter}${infer Rest}` ? Tail<Rest> : false;
|
|
94
|
+
/**
|
|
95
|
+
* Mensagem de erro em nível de tipos, exibida quando um código de erro não
|
|
96
|
+
* segue o formato UPPER_SNAKE_CASE.
|
|
97
|
+
*
|
|
98
|
+
* Por ser um tipo literal, ela aparece diretamente na mensagem de erro do
|
|
99
|
+
* compilador, indicando qual código é inválido.
|
|
100
|
+
*
|
|
101
|
+
* @template Code - Código de erro inválido a ser incluído na mensagem.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```ts
|
|
105
|
+
* type A = InvalidCodeMessage<"userNotFound">;
|
|
106
|
+
* // `Código de erro inválido "userNotFound". Os códigos de erro devem usar UPPER_SNAKE_CASE.`
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export type InvalidCodeMessage<Code extends string> = `Código de erro inválido "${Code}". Os códigos de erro devem usar UPPER_SNAKE_CASE.`;
|
|
110
|
+
/**
|
|
111
|
+
* Valida em tempo de compilação, as chaves de um objeto de definições de
|
|
112
|
+
* erros, exigindo que cada código esteja em UPPER_SNAKE_CASE.
|
|
113
|
+
*
|
|
114
|
+
* Para cada chave `K` de `T`:
|
|
115
|
+
* - se for válida (ver {@link IsUpperSnakeCase}), mantém o tipo da mensagem
|
|
116
|
+
* original, `T[K]`;
|
|
117
|
+
* - se for inválida, o tipo do valor passa a ser {@link InvalidCodeMessage},
|
|
118
|
+
* o que gera um erro de compilação com a explicação do problema;
|
|
119
|
+
* - chaves que não sejam `string` (ex.: `number` ou `symbol`) resultam em
|
|
120
|
+
* `never`.
|
|
121
|
+
*
|
|
122
|
+
* Costuma ser combinado com o próprio tipo das definições (`T &
|
|
123
|
+
* ValidateErrorDefinitions<T>`) em funções que criam catálogos de erros.
|
|
124
|
+
*
|
|
125
|
+
* @template T - Objeto que mapeia códigos de erro para suas mensagens. Por
|
|
126
|
+
* padrão, `Record<string, string>`.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```ts
|
|
130
|
+
* type A = ValidateErrorDefinitions<{
|
|
131
|
+
* USER_NOT_FOUND: "Usuário não encontrado";
|
|
132
|
+
* invalidCode: "Código fora do padrão";
|
|
133
|
+
* }>;
|
|
134
|
+
* // {
|
|
135
|
+
* // USER_NOT_FOUND: "Usuário não encontrado";
|
|
136
|
+
* // invalidCode: `Código de erro inválido "invalidCode". Os códigos de erro devem usar UPPER_SNAKE_CASE.`;
|
|
137
|
+
* // }
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
export type ValidateErrorDefinitions<T extends Record<string, string> = Record<string, string>> = { [K in keyof T]: K extends string ? IsUpperSnakeCase<K> extends true ? T[K] : InvalidCodeMessage<K> : never; };
|
|
141
|
+
//#endregion
|
|
142
|
+
export { CatalogCode, CatalogDescriptor, ErrorCatalog, ErrorDescriptor, ErrorParamDelimiters, ErrorParamValue, ErrorParams, ExtractPlaceholders, ParamsFromMessage, Trim, Whitespace };
|
|
143
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { a as Trim, c as CatalogCode, i as ExtractPlaceholders, l as ErrorCatalog, m as ErrorParamDelimiters, n as ErrorParamValue, o as Whitespace, r as ParamsFromMessage, s as CatalogDescriptor, t as ErrorParams, u as ErrorDescriptor } from "../error-params-CR2parjT.mjs";
|
|
2
|
+
//#region src/types/validate-error-definitions.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Letras maiúsculas do alfabeto latino (`A` a `Z`), sem acentos.
|
|
5
|
+
*
|
|
6
|
+
* Usado para validar em tempo de compilação códigos em UPPER_SNAKE_CASE.
|
|
7
|
+
*/
|
|
8
|
+
export type UpperLetter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z";
|
|
9
|
+
/**
|
|
10
|
+
* Dígitos decimais (`0` a `9`), representados como string literals.
|
|
11
|
+
*/
|
|
12
|
+
export type Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
|
|
13
|
+
/**
|
|
14
|
+
* Caractere alfanumérico permitido em um segmento de código: uma letra
|
|
15
|
+
* maiúscula ({@link UpperLetter}) ou um dígito ({@link Digit}).
|
|
16
|
+
*/
|
|
17
|
+
export type AlphaNumeric = UpperLetter | Digit;
|
|
18
|
+
/**
|
|
19
|
+
* Verifica se `T` é um segmento válido: não vazio e composto apenas por
|
|
20
|
+
* caracteres alfanuméricos ({@link AlphaNumeric}), podendo continuar com
|
|
21
|
+
* novos segmentos separados por `_`.
|
|
22
|
+
*
|
|
23
|
+
* Exige que o primeiro caractere seja alfanumérico e delega o restante a
|
|
24
|
+
* {@link Tail}. É um tipo auxiliar de {@link IsUpperSnakeCase}, definido em
|
|
25
|
+
* recursão mútua com `Tail`.
|
|
26
|
+
*
|
|
27
|
+
* @template T - String literal a ser verificada.
|
|
28
|
+
* @returns `true` se for válido; caso contrário, `false`.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* type A = Segment<"ABC">; // true
|
|
33
|
+
* type B = Segment<"A_B">; // true
|
|
34
|
+
* type C = Segment<"_A">; // false (começa com "_")
|
|
35
|
+
* type D = Segment<"">; // false (segmento vazio)
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export type Segment<T extends string> = T extends `${AlphaNumeric}${infer Rest}` ? Tail<Rest> : false;
|
|
39
|
+
/**
|
|
40
|
+
* Verifica o restante de um código depois de seu primeiro caractere válido.
|
|
41
|
+
*
|
|
42
|
+
* Percorre a string caractere por caractere:
|
|
43
|
+
* - string vazia: o código é válido (`true`);
|
|
44
|
+
* - `_`: deve ser seguido por um novo segmento válido (via {@link Segment}),
|
|
45
|
+
* o que impede `_` duplicado ou no final;
|
|
46
|
+
* - caractere alfanumérico: continua a verificação;
|
|
47
|
+
* - qualquer outro caractere: o código é inválido (`false`).
|
|
48
|
+
*
|
|
49
|
+
* É um tipo auxiliar de {@link IsUpperSnakeCase}, definido em recursão mútua
|
|
50
|
+
* com {@link Segment}.
|
|
51
|
+
*
|
|
52
|
+
* @template T - Restante da string literal a ser verificado.
|
|
53
|
+
* @returns `true` se for válido; caso contrário, `false`.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* type A = Tail<"">; // true
|
|
58
|
+
* type B = Tail<"BC_D">; // true
|
|
59
|
+
* type C = Tail<"B__C">; // false (underscores consecutivos)
|
|
60
|
+
* type D = Tail<"B_">; // false (termina com "_")
|
|
61
|
+
* type E = Tail<"b">; // false (letra minúscula)
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export type Tail<T extends string> = T extends "" ? true : T extends `_${infer Rest}` ? Segment<Rest> : T extends `${AlphaNumeric}${infer Rest}` ? Tail<Rest> : false;
|
|
65
|
+
/**
|
|
66
|
+
* Verifica em tempo de compilação, se uma string literal está em
|
|
67
|
+
* UPPER_SNAKE_CASE.
|
|
68
|
+
*
|
|
69
|
+
* Regras:
|
|
70
|
+
* - deve começar com uma letra maiúscula (não pode começar com dígito);
|
|
71
|
+
* - pode conter letras maiúsculas, dígitos e `_`;
|
|
72
|
+
* - `_` só pode aparecer entre dois caracteres alfanuméricos, ou seja, não pode
|
|
73
|
+
* estar no início nem no fim e não pode ser repetido em sequência.
|
|
74
|
+
*
|
|
75
|
+
* Se `T` for o tipo genérico `string` (não literal), não é possível validar e
|
|
76
|
+
* o resultado é `false`.
|
|
77
|
+
*
|
|
78
|
+
* @template T - String literal a ser verificada.
|
|
79
|
+
* @returns `true` se estiver em UPPER_SNAKE_CASE; caso contrário, `false`.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* type A = IsUpperSnakeCase<"USER_NOT_FOUND">; // true
|
|
84
|
+
* type B = IsUpperSnakeCase<"ERROR_404">; // true
|
|
85
|
+
* type C = IsUpperSnakeCase<"userNotFound">; // false
|
|
86
|
+
* type D = IsUpperSnakeCase<"_USER">; // false
|
|
87
|
+
* type E = IsUpperSnakeCase<"USER_">; // false
|
|
88
|
+
* type F = IsUpperSnakeCase<"USER__NOT">; // false
|
|
89
|
+
* type G = IsUpperSnakeCase<"1ERROR">; // false
|
|
90
|
+
* type H = IsUpperSnakeCase<string>; // false
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export type IsUpperSnakeCase<T extends string> = string extends T ? false : T extends `${UpperLetter}${infer Rest}` ? Tail<Rest> : false;
|
|
94
|
+
/**
|
|
95
|
+
* Mensagem de erro em nível de tipos, exibida quando um código de erro não
|
|
96
|
+
* segue o formato UPPER_SNAKE_CASE.
|
|
97
|
+
*
|
|
98
|
+
* Por ser um tipo literal, ela aparece diretamente na mensagem de erro do
|
|
99
|
+
* compilador, indicando qual código é inválido.
|
|
100
|
+
*
|
|
101
|
+
* @template Code - Código de erro inválido a ser incluído na mensagem.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```ts
|
|
105
|
+
* type A = InvalidCodeMessage<"userNotFound">;
|
|
106
|
+
* // `Código de erro inválido "userNotFound". Os códigos de erro devem usar UPPER_SNAKE_CASE.`
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export type InvalidCodeMessage<Code extends string> = `Código de erro inválido "${Code}". Os códigos de erro devem usar UPPER_SNAKE_CASE.`;
|
|
110
|
+
/**
|
|
111
|
+
* Valida em tempo de compilação, as chaves de um objeto de definições de
|
|
112
|
+
* erros, exigindo que cada código esteja em UPPER_SNAKE_CASE.
|
|
113
|
+
*
|
|
114
|
+
* Para cada chave `K` de `T`:
|
|
115
|
+
* - se for válida (ver {@link IsUpperSnakeCase}), mantém o tipo da mensagem
|
|
116
|
+
* original, `T[K]`;
|
|
117
|
+
* - se for inválida, o tipo do valor passa a ser {@link InvalidCodeMessage},
|
|
118
|
+
* o que gera um erro de compilação com a explicação do problema;
|
|
119
|
+
* - chaves que não sejam `string` (ex.: `number` ou `symbol`) resultam em
|
|
120
|
+
* `never`.
|
|
121
|
+
*
|
|
122
|
+
* Costuma ser combinado com o próprio tipo das definições (`T &
|
|
123
|
+
* ValidateErrorDefinitions<T>`) em funções que criam catálogos de erros.
|
|
124
|
+
*
|
|
125
|
+
* @template T - Objeto que mapeia códigos de erro para suas mensagens. Por
|
|
126
|
+
* padrão, `Record<string, string>`.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```ts
|
|
130
|
+
* type A = ValidateErrorDefinitions<{
|
|
131
|
+
* USER_NOT_FOUND: "Usuário não encontrado";
|
|
132
|
+
* invalidCode: "Código fora do padrão";
|
|
133
|
+
* }>;
|
|
134
|
+
* // {
|
|
135
|
+
* // USER_NOT_FOUND: "Usuário não encontrado";
|
|
136
|
+
* // invalidCode: `Código de erro inválido "invalidCode". Os códigos de erro devem usar UPPER_SNAKE_CASE.`;
|
|
137
|
+
* // }
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
export type ValidateErrorDefinitions<T extends Record<string, string> = Record<string, string>> = { [K in keyof T]: K extends string ? IsUpperSnakeCase<K> extends true ? T[K] : InvalidCodeMessage<K> : never; };
|
|
141
|
+
//#endregion
|
|
142
|
+
export { CatalogCode, CatalogDescriptor, ErrorCatalog, ErrorDescriptor, ErrorParamDelimiters, ErrorParamValue, ErrorParams, ExtractPlaceholders, ParamsFromMessage, Trim, Whitespace };
|
|
143
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,120 @@
|
|
|
1
1
|
{
|
|
2
|
+
"author": {
|
|
3
|
+
"email": "email@pedrohb.dev",
|
|
4
|
+
"name": "Pedro Henrique Bergamo",
|
|
5
|
+
"url": "https://github.com/DevPedroHB"
|
|
6
|
+
},
|
|
7
|
+
"bugs": {
|
|
8
|
+
"email": "email@pedrohb.dev",
|
|
9
|
+
"url": "https://github.com/DevPedroHB/pedrohb/issues"
|
|
10
|
+
},
|
|
11
|
+
"description": "Um sistema de erros tipado para aplicações TypeScript.",
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"@biomejs/biome": "^2.5.15",
|
|
14
|
+
"@pedrohb/ts-config": "1.0.0",
|
|
15
|
+
"@pedrohb/tsdown-config": "1.0.0",
|
|
16
|
+
"@pedrohb/vitest-config": "1.0.0",
|
|
17
|
+
"@types/node": "^26.6.4",
|
|
18
|
+
"@vitest/coverage-v8": "^5.0.3",
|
|
19
|
+
"@vitest/ui": "^5.0.3",
|
|
20
|
+
"tsdown": "^0.23.0",
|
|
21
|
+
"tsx": "^4.23.1",
|
|
22
|
+
"typescript": "^7.0.2",
|
|
23
|
+
"vitest": "^5.0.3"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=26"
|
|
27
|
+
},
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"import": {
|
|
31
|
+
"default": "./dist/index.mjs",
|
|
32
|
+
"types": "./dist/index.d.mts"
|
|
33
|
+
},
|
|
34
|
+
"require": {
|
|
35
|
+
"default": "./dist/index.cjs",
|
|
36
|
+
"types": "./dist/index.d.cts"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"./errors": {
|
|
40
|
+
"import": {
|
|
41
|
+
"default": "./dist/errors/index.mjs",
|
|
42
|
+
"types": "./dist/errors/index.d.mts"
|
|
43
|
+
},
|
|
44
|
+
"require": {
|
|
45
|
+
"default": "./dist/errors/index.cjs",
|
|
46
|
+
"types": "./dist/errors/index.d.cts"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"./functions": {
|
|
50
|
+
"import": {
|
|
51
|
+
"default": "./dist/functions/index.mjs",
|
|
52
|
+
"types": "./dist/functions/index.d.mts"
|
|
53
|
+
},
|
|
54
|
+
"require": {
|
|
55
|
+
"default": "./dist/functions/index.cjs",
|
|
56
|
+
"types": "./dist/functions/index.d.cts"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"./types": {
|
|
60
|
+
"import": {
|
|
61
|
+
"default": "./dist/types/index.mjs",
|
|
62
|
+
"types": "./dist/types/index.d.mts"
|
|
63
|
+
},
|
|
64
|
+
"require": {
|
|
65
|
+
"default": "./dist/types/index.cjs",
|
|
66
|
+
"types": "./dist/types/index.d.cts"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"files": [
|
|
71
|
+
"dist"
|
|
72
|
+
],
|
|
73
|
+
"funding": "https://github.com/sponsors/DevPedroHB",
|
|
74
|
+
"homepage": "https://github.com/DevPedroHB/pedrohb/tree/main/packages/errors",
|
|
75
|
+
"imports": {
|
|
76
|
+
"#/*": [
|
|
77
|
+
"./src/*"
|
|
78
|
+
],
|
|
79
|
+
"#test/*": [
|
|
80
|
+
"./test/*"
|
|
81
|
+
]
|
|
82
|
+
},
|
|
83
|
+
"keywords": [
|
|
84
|
+
"errors",
|
|
85
|
+
"error-handling",
|
|
86
|
+
"error-catalog",
|
|
87
|
+
"typed-errors",
|
|
88
|
+
"type-safe",
|
|
89
|
+
"either",
|
|
90
|
+
"result",
|
|
91
|
+
"functional-programming",
|
|
92
|
+
"serialization",
|
|
93
|
+
"typescript"
|
|
94
|
+
],
|
|
95
|
+
"license": "MIT",
|
|
96
|
+
"main": "./dist/index.cjs",
|
|
97
|
+
"module": "./dist/index.mjs",
|
|
2
98
|
"name": "@pedrohb/errors",
|
|
3
|
-
"
|
|
4
|
-
|
|
5
|
-
|
|
99
|
+
"publishConfig": {
|
|
100
|
+
"access": "public",
|
|
101
|
+
"provenance": true
|
|
102
|
+
},
|
|
103
|
+
"repository": {
|
|
104
|
+
"type": "git",
|
|
105
|
+
"url": "git+https://github.com/DevPedroHB/pedrohb.git"
|
|
106
|
+
},
|
|
107
|
+
"sideEffects": false,
|
|
108
|
+
"type": "module",
|
|
109
|
+
"types": "./dist/index.d.mts",
|
|
110
|
+
"version": "1.0.0",
|
|
111
|
+
"scripts": {
|
|
112
|
+
"build": "tsdown",
|
|
113
|
+
"check": "biome check --write",
|
|
114
|
+
"format": "biome format --write",
|
|
115
|
+
"lint": "biome lint --write",
|
|
116
|
+
"test": "vitest run",
|
|
117
|
+
"test:watch": "vitest --ui",
|
|
118
|
+
"typecheck": "tsc --noEmit"
|
|
119
|
+
}
|
|
6
120
|
}
|