Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions docs/utils/index.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
# Funções utilitárias

Este módulo fornece funções para formatar diversos tipos de dados.

## Formatadores

### pluralize()

Funções para aplicação de plurais em palavras ou lista de palavras.
Expand All @@ -12,6 +8,12 @@ Funções para aplicação de plurais em palavras ou lista de palavras.

### commaline()

Funções para formatar listas de strings com vírgulas e conjunção "e".
Função para formatar listas de strings com vírgulas e conjunção "e".

- [Documentação](./commaline.md)

### sanitizeForm()

Função para sanitizar dados de formulário e aplicar transformações antes de enviá-los ao backend.

- [Documentação](./sanitizeForm.md)
196 changes: 196 additions & 0 deletions docs/utils/sanitizeForm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
# Sanitize Form

Utilitário para sanitizar dados de formulário antes de enviá-los ao backend.

## Instalação e Importação

```typescript
import { sanitizeForm } from '@sysvale/foundry';
```

## Função

### `sanitizeForm()`

Sanitiza dados de formulário

- Extrai IDs de objetos do tipo `{ id: string | number, value: string }`
- Mantém valores primitivos inalterados
- Processa recursivamente campos aninhados
- Aplica transformações em campos específicos por meio de `sanitizers`

#### Sintaxe

```typescript
sanitizeForm(
values: Record<string, FormValue>,
sanitizableFields?: SanitizableField[]
): Record<string, FormValue>
```

#### Parâmetros

- **`values`** (`Record<string, FormValue>`): Dados do formulário a serem sanitizados
- **`sanitizableFields`** (`SanitizableField[]`, opcional): Array de campos com sanitizadores personalizados

#### Tipos

```typescript
type FormValue =
| string
| number
| boolean
| null
| undefined
| FormObject
| FormValue[];

type FormObject = {
id?: string | number;
[key: string]: FormValue;
};

interface SanitizableField {
field: string;
sanitizer: (value: any) => FormValue;
}
```

#### Retorno

`Record<string, FormValue>` - Dados sanitizados conforme as regras aplicadas

#### Regras de Sanitização

1. **Valores primitivos**: Mantidos inalterados (string, number, boolean, null, undefined)
2. **Arrays de primitivos**: Preservados sem modificação
3. **Objetos com `id`**: Substituídos pelo valor da propriedade `id`
4. **Objetos sem `id`**: Processados recursivamente campo por campo
5. **Arrays com objetos**: Cada item é sanitizado recursivamente
6. **Sanitizadores personalizados**: Aplicados a campos específicos quando configurados
7. **Estruturas aninhadas**: Processamento recursivo em todos os níveis

## Exemplos

**Extração de IDs:**

```typescript
// Objeto com ID é substituído pelo ID
sanitizeForm({
category: { id: 'cat-123', name: 'Categoria A' },
});
// → { category: 'cat-123' }

// Array de objetos com IDs
sanitizeForm({
users: [
{ id: 1, name: 'João' },
{ id: 2, name: 'Maria' },
{ id: 3, name: 'Pedro' },
],
});
// → { users: [1, 2, 3] }
```

<br >

**Processamento recursivo:**

```typescript
// Objetos sem ID são processados recursivamente
sanitizeForm({
config: {
theme: 'dark',
notifications: {
email: true,
push: false,
},
},
});
// → { config: { theme: 'dark', notifications: { email: true, push: false } } }

// Combinação de extração de ID e processamento recursivo
sanitizeForm({
user: { id: 1, name: 'João' },
preferences: {
theme: 'dark',
language: { id: 'pt-BR', name: 'Português' },
},
});
// → { user: 1, preferences: { theme: 'dark', language: 'pt-BR' } }
```

<br >

**Estruturas complexas:**

```typescript
// Arrays aninhados com objetos
sanitizeForm({
categories: [
{
id: 1,
items: [
{ id: 10, name: 'Item A' },
{ id: 11, name: 'Item B' },
],
},
{
id: 2,
items: [{ id: 20, name: 'Item C' }],
},
],
});
// → { categories: [1, 2] }

// Objetos profundamente aninhados
sanitizeForm({
company: {
id: 100,
departments: [
{
id: 200,
employees: [
{ id: 300, name: 'João' },
{ id: 301, name: 'Maria' },
],
},
],
},
});
// → { company: 100 }
```

<br >

**Sanitizadores personalizados:**

```typescript
// Aplicação de sanitizadores customizados
const sanitizers = [
{
field: 'name',
sanitizer: value => value.toUpperCase(),
},
{
field: 'phone',
sanitizer: value => value.replace(/\D/g, ''),
},
];

sanitizeForm(
{
name: 'joão',
phone: '(11) 99999-9999',
age: 25,
},
sanitizers
);
// → { name: 'JOÃO', phone: '11999999999', age: 25 }
```

## Limitações

- A função assume que objetos com propriedade `id` devem ser convertidos para seu ID
- Arrays são sempre processados recursivamente, não há opção para preservar objetos em arrays
- A propriedade `id` sempre tem prioridade sobre processamento recursivo do objeto
1 change: 1 addition & 0 deletions eslint.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ module.exports = [
'src/**/*.{ts,tsx}',
'lib/**/*.{ts,tsx}',
'components/**/*.{ts,tsx}',
'tests/**/*.{ts,tsx}',
],
languageOptions: {
ecmaVersion: 'latest',
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sysvale/foundry",
"version": "1.2.0",
"version": "1.3.0",
"description": "A forge for composables, helpers, and front-end utilities.",
"type": "module",
"main": "./dist/foundry.cjs.js",
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './utils/pluralize';
export * from './utils/commaline';
export * from './utils/sanitizeForm';
export { maskCpf, removeCpfMask } from './formatters/cpf';
export { maskPhone, removePhoneMask } from './formatters/phone';
8 changes: 8 additions & 0 deletions src/utils/commaline.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
export function commaline(str: string, index: number, length: number): string;
export function commaline(arr: string[]): string;

/**
* Função para formatar listas de strings com vírgulas e conjunção "e".
*
* @param strOrArray - String ou array de strings
* @param index - Índice (obrigatório se strOrArray for string)
* @param length - Tamanho total (obrigatório se strOrArray for string)
* @returns String formatada
*/
export function commaline(
strOrArray: string | string[],
index?: number,
Expand Down
43 changes: 43 additions & 0 deletions src/utils/pluralize.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/**
* Mapeamento de palavras com plurais irregulares em português.
*/
const irregulars: Record<string, string> = {
pão: 'pães',
mão: 'mãos',
Expand All @@ -11,6 +14,22 @@ const irregulars: Record<string, string> = {
nível: 'níveis',
};

/**
* Pluraliza uma palavra em português seguindo as regras gramaticais.
*
* @param count - Quantidade (0-1 = singular, >=2 = plural). Se string, trata como palavra. Null/undefined = 2.
* @param word - Palavra a ser pluralizada
* @param customPlural - Plural personalizado (opcional)
* @param customIrregulars - Plurais irregulares personalizados (opcional)
* @returns Palavra pluralizada conforme a quantidade
*
* @example
* pluralize(1, 'carro'); // → 'carro'
* pluralize(2, 'carro'); // → 'carros'
* pluralize(2, 'pão'); // → 'pães' (irregular)
* pluralize(2, 'livro', 'livrinhos'); // → 'livrinhos'
* pluralize('casa'); // → 'casas'
*/
export function pluralize(
count: number | string | null = null,
word: string,
Expand Down Expand Up @@ -69,13 +88,37 @@ export function pluralize(
return word;
}

/**
* Retorna a palavra pluralizada precedida pela quantidade.
*
* @param args - Mesmos parâmetros da função `pluralize`
* @returns Quantidade + palavra pluralizada
*
* @example
* pluralizeWithCount(1, 'carro'); // → '1 carro'
* pluralizeWithCount(3, 'avião'); // → '3 aviões'
*/
export function pluralizeWithCount(
...args: Parameters<typeof pluralize>
): string {
const [count] = args;
return `${count} ${pluralize(...args)}`;
}

/**
* Pluraliza múltiplas palavras simultaneamente.
*
* @param count - Quantidade para determinar pluralização
* @param words - Array de palavras
* @param customPlural - Array de plurais personalizados ou string única (opcional)
* @param customIrregulars - Plurais irregulares personalizados (opcional)
* @returns Palavras pluralizadas separadas por espaço
*
* @example
* pluralizeWords(1, ['avião', 'antigo']); // → 'avião antigo'
* pluralizeWords(2, ['avião', 'antigo']); // → 'aviões antigos'
* pluralizeWords(2, ['o', 'avião'], ['os', 'aviõezinhos']); // → 'os aviõezinhos'
*/
export function pluralizeWords(
count: number | string | null,
words: string[],
Expand Down
66 changes: 66 additions & 0 deletions src/utils/sanitizeForm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
type FormValue =
| string
| number
| boolean
| null
| undefined
| FormObject
| FormValue[];

type FormObject = {
id?: string | number;
[key: string]: FormValue;
};

type SanitizerFunction<T = FormValue, R = FormValue> = (value: T) => R;

export interface SanitizableField {
field: string;
sanitizer: SanitizerFunction;
}

/**
* Sanitiza dados de formulário removendo campos desnecessários e aplicando transformações.
*
* @param { Object } values
* @param { Object[{ field: 'name', sanitizer: () => {} }] } sanitizableFields
* @returns { Object }
*/
export function sanitizeForm(
values: Record<string, FormValue>,
sanitizableFields?: SanitizableField[]
): Record<string, FormValue> {
const sanitizers = new Map<string, SanitizerFunction>(
(sanitizableFields ?? []).map(({ field, sanitizer }) => [field, sanitizer])
);

const sanitizeValue = (value: FormValue, key?: string): FormValue => {
if (value == null) return value;

if (Array.isArray(value)) {
return value.map(item => sanitizeValue(item));
}

if (typeof value === 'object' && value !== null) {
const obj = value as FormObject;
if (obj.id !== undefined) return obj.id;

return Object.fromEntries(
Object.entries(obj).map(([k, v]) => [k, sanitizeValue(v, k)])
);
}

if (key && sanitizers.has(key)) {
return sanitizers.get(key)!(value);
}

return value;
};

return Object.fromEntries(
Object.entries(values).map(([key, value]) => [
key,
sanitizeValue(value, key),
])
);
}
Loading