# Especificación del Formato de Texto USEE (FTU)

## Formato de Intercambio de Datos del Protocolo

**Versión 1.0**

---

## Propósito

El Formato de Texto USEE (FTU) es el lenguaje común de todas las piezas USEE. Define cómo se estructuran los datos de entrada y salida para garantizar que cualquier pieza pueda comunicarse con cualquier otra, independientemente del lenguaje de programación o plataforma.

### Principios de Diseño

El formato fue diseñado siguiendo los principios USEE:

| Principio | Cómo se aplica al formato |
|-----------|---------------------------|
| **Útil** | Expresa cualquier dato que una pieza necesite comunicar |
| **Simple** | Parseable con código básico en cualquier lenguaje |
| **Esencial** | Solo las características necesarias, nada superfluo |
| **Estable** | Basado en texto plano, funcionará en 50 años |

### Objetivos

1. Un programador debe poder escribir un parser completo en menos de 2 horas
2. Una persona no técnica debe poder leer y entender los datos
3. No debe requerir librerías externas para procesarse
4. Debe ser editable con cualquier editor de texto

---

## Especificación Formal

### 1. Codificación

- **Codificación de caracteres**: UTF-8
- **Fin de línea**: LF (`\n`) o CRLF (`\r\n`), ambos aceptados
- **Indentación**: 2 espacios (cuando aplica)

### 2. Estructura de Línea

Un documento FTU es una secuencia de líneas. Cada línea es uno de:

| Tipo | Identificación | Ejemplo |
|------|----------------|---------|
| Par clave-valor | Contiene `:` | `nombre: Juan` |
| Comentario | Inicia con `#` | `# Esto es un comentario` |
| Separador | Exactamente `---` | `---` |
| Continuación | Inicia con 2 espacios | `  línea continuada` |
| Vacía | Sin contenido | `` |

### 3. Pares Clave-Valor

#### Sintaxis

```
clave: valor
```

#### Reglas de Claves

| Regla | Válido | Inválido |
|-------|--------|----------|
| Solo minúsculas | `nombre` | `Nombre`, `NOMBRE` |
| Letras, números, guión bajo | `fecha_nacimiento`, `direccion2` | `fecha-nacimiento` |
| Debe iniciar con letra | `usuario1` | `1usuario` |
| Sin espacios | `nombre_completo` | `nombre completo` |
| Sin caracteres especiales | `direccion` | `dirección`, `año` |
| Longitud máxima: 64 caracteres | `campo_corto` | `campo_extremadamente_largo_que_supera_el_limite_establecido_de_caracteres` |

#### Expresión Regular para Claves

```
^[a-z][a-z0-9_]{0,63}$
```

#### Reglas de Valores

- Todo lo que aparece después de `:` y el espacio opcional es el valor
- Los espacios al inicio y final del valor se eliminan (trim)
- Un valor puede estar vacío
- Un valor puede contener cualquier carácter UTF-8, incluyendo `:`

#### Ejemplos

```
# Valor simple
nombre: Juan Pérez

# Valor con dos puntos (el primero separa, los demás son parte del valor)
horario: 10:30:00

# Valor con espacios (se preservan los internos)
direccion: Avenida Reforma 222, Piso 5

# Valor vacío (válido)
comentario:

# Espacios alrededor de : se ignoran (todos equivalentes)
edad: 30
edad:30
edad :30
edad : 30
```

---

### 4. Tipos de Valores

FTU no tiene tipos estrictos. Todo valor es texto. Sin embargo, define convenciones para interpretar valores comunes:

#### 4.1 Texto

Cualquier secuencia de caracteres.

```
mensaje: Hola, este es un texto libre con acentos: é, ñ, ü
```

#### 4.2 Números

Secuencia de dígitos, opcionalmente con signo y punto decimal.

```
edad: 30
temperatura: -5.5
precio: 1234.56
```

**Reglas:**
- Separador decimal: punto `.`
- Sin separador de miles
- Signo negativo: guión `-` al inicio

#### 4.3 Booleanos

Dos valores posibles: `si` o `no`

```
activo: si
eliminado: no
```

**Nota:** No se aceptan variantes como `true`, `false`, `1`, `0`, `sí` (con acento).

#### 4.4 Fechas y Tiempos

Formato ISO 8601 simplificado.

```
# Solo fecha
fecha_nacimiento: 2025-01-15

# Fecha y hora (UTC implícito)
creado: 2025-01-15T10:30:00

# Fecha y hora con zona horaria
modificado: 2025-01-15T10:30:00-06:00
```

**Formatos aceptados:**
- `YYYY-MM-DD` - Solo fecha
- `YYYY-MM-DDTHH:MM:SS` - Fecha y hora
- `YYYY-MM-DDTHH:MM:SSZ` - Fecha y hora UTC
- `YYYY-MM-DDTHH:MM:SS±HH:MM` - Fecha y hora con zona

#### 4.5 Listas

Valores múltiples separados por coma y espacio.

```
etiquetas: rojo, verde, azul
numeros: 1, 2, 3, 4, 5
```

**Reglas:**
- Separador: `, ` (coma seguida de espacio)
- Los elementos se procesan con trim
- Lista vacía: valor vacío o clave ausente

**Ejemplos:**

```
# Lista de tres elementos
colores: rojo, verde, azul

# Lista de un elemento
colores: rojo

# Lista vacía
colores:
```

#### 4.6 Valor Nulo

La ausencia de valor o la clave ausente representa nulo.

```
# Valor explícitamente vacío (nulo)
segundo_nombre:

# Equivalente: no incluir la clave
```

---

### 5. Comentarios

#### Sintaxis

```
# Esto es un comentario
```

#### Reglas

- Una línea es comentario si su primer carácter no-espacio es `#`
- Los comentarios se ignoran completamente al parsear
- No existen comentarios al final de línea

```
# Esto es un comentario válido
nombre: Juan  # Esto NO es comentario, es parte del valor

  # Esto también es comentario (espacios antes de #)
```

#### Uso Recomendado

```
# === Sección de Usuario ===
nombre: Juan
edad: 30

# Datos de contacto
correo: juan@ejemplo.com
telefono: 555-1234
```

---

### 6. Separador de Registros

#### Sintaxis

```
---
```

#### Propósito

Permite incluir múltiples registros independientes en un solo documento.

#### Reglas

- Exactamente tres guiones en una línea sola
- Sin espacios antes ni después
- Cada sección entre separadores es un registro independiente

#### Ejemplo

```
nombre: Juan
edad: 30
---
nombre: María
edad: 25
---
nombre: Pedro
edad: 40
```

Esto representa tres registros, cada uno con `nombre` y `edad`.

#### Casos Especiales

```
# Separador al inicio (primer registro vacío, se ignora)
---
nombre: Juan

# Separador al final (último registro vacío, se ignora)
nombre: Juan
---

# Separadores consecutivos (registros vacíos en medio, se ignoran)
nombre: Juan
---
---
nombre: María
```

---

### 7. Valores Multilínea

#### Sintaxis

```
clave: |
  Primera línea del valor
  Segunda línea del valor
  Tercera línea del valor
```

#### Reglas

- El carácter `|` solo (pipe) indica valor multilínea
- Las líneas siguientes deben estar indentadas con exactamente 2 espacios
- El valor termina cuando aparece una línea sin indentar o con menos de 2 espacios
- Los saltos de línea se preservan
- La indentación de 2 espacios se elimina del valor final

#### Ejemplo

```
descripcion: |
  Este es un texto largo que
  ocupa varias líneas.
  
  Incluso puede tener líneas vacías
  en medio del contenido.
siguiente_campo: valor normal
```

**Valor resultante de `descripcion`:**
```
Este es un texto largo que
ocupa varias líneas.

Incluso puede tener líneas vacías
en medio del contenido.
```

#### Espacios en Blanco

```
poema: |
  Dos caminos se bifurcaban
    en un bosque amarillo,
  y apenado por no poder
    tomar los dos...
```

Los espacios adicionales (más allá de los 2 de indentación) se preservan.

---

### 8. Datos Anidados

#### Sintaxis

```
padre.hijo: valor
padre.hijo.nieto: otro valor
```

#### Propósito

Representar estructuras jerárquicas sin usar llaves ni corchetes.

#### Reglas

- El punto `.` indica jerarquía
- Cada segmento sigue las reglas de nombres de claves
- No hay límite de profundidad (aunque se recomienda máximo 4 niveles)

#### Ejemplo

```
usuario.nombre: Juan Pérez
usuario.edad: 30
usuario.direccion.calle: Reforma 222
usuario.direccion.ciudad: Ciudad de México
usuario.direccion.pais: México
usuario.roles: admin, editor
```

**Estructura lógica equivalente:**
```
usuario
├── nombre: Juan Pérez
├── edad: 30
├── direccion
│   ├── calle: Reforma 222
│   ├── ciudad: Ciudad de México
│   └── pais: México
└── roles: [admin, editor]
```

#### Combinación con Listas

Para listas de objetos, usar separador de registros o índices numéricos:

**Opción A: Separador de registros**
```
# Lista de usuarios
nombre: Juan
rol: admin
---
nombre: María
rol: editor
---
nombre: Pedro
rol: lector
```

**Opción B: Índices numéricos**
```
usuarios.0.nombre: Juan
usuarios.0.rol: admin
usuarios.1.nombre: María
usuarios.1.rol: editor
usuarios.2.nombre: Pedro
usuarios.2.rol: lector
```

Se recomienda Opción A para listas de registros completos y Opción B cuando los registros están mezclados con otros datos.

---

### 9. Líneas Vacías

- Las líneas vacías se ignoran al parsear
- Se pueden usar libremente para mejorar legibilidad
- No afectan la estructura del documento

```
nombre: Juan

edad: 30


ciudad: México
```

Es equivalente a:

```
nombre: Juan
edad: 30
ciudad: México
```

---

### 10. Orden de Claves

- El orden de las claves NO es significativo
- Los parsers pueden retornar claves en cualquier orden
- Si una clave aparece múltiples veces, el último valor prevalece

```
nombre: Juan
nombre: Pedro
```

El valor final de `nombre` es `Pedro`.

---

## Gramática Formal

### Notación EBNF

```ebnf
documento     = { linea } ;
linea         = ( par | comentario | separador | continuacion | vacia ) , fin_linea ;
par           = clave , ":" , [ espacio ] , valor ;
clave         = letra , { letra | digito | "_" } ;
valor         = valor_simple | valor_multilinea ;
valor_simple  = { caracter } ;
valor_multilinea = "|" , fin_linea , { linea_indentada } ;
linea_indentada = "  " , { caracter } , fin_linea ;
comentario    = { espacio } , "#" , { caracter } ;
separador     = "---" ;
continuacion  = "  " , { caracter } ;
vacia         = { espacio } ;
letra         = "a" | "b" | ... | "z" ;
digito        = "0" | "1" | ... | "9" ;
espacio       = " " | "\t" ;
fin_linea     = "\n" | "\r\n" ;
caracter      = (* cualquier carácter UTF-8 excepto fin_linea *) ;
```

---

## Algoritmo de Parsing

### Pseudocódigo

```
función parsear_ftu(texto):
    registros = []
    registro_actual = {}
    clave_multilinea = nulo
    valor_multilinea = []
    
    para cada linea en texto.dividir_lineas():
        linea_limpia = linea.sin_espacios_finales()
        
        # Finalizar valor multilínea si es necesario
        si clave_multilinea != nulo:
            si linea.inicia_con("  "):
                valor_multilinea.agregar(linea.substring(2))
                continuar
            sino:
                registro_actual[clave_multilinea] = valor_multilinea.unir("\n")
                clave_multilinea = nulo
                valor_multilinea = []
        
        # Línea vacía
        si linea_limpia == "":
            continuar
        
        # Comentario
        si linea_limpia.inicia_con("#"):
            continuar
        
        # Separador
        si linea_limpia == "---":
            si registro_actual no está vacío:
                registros.agregar(registro_actual)
                registro_actual = {}
            continuar
        
        # Par clave-valor
        si linea_limpia.contiene(":"):
            posicion = linea_limpia.indice_de(":")
            clave = linea_limpia.substring(0, posicion).trim()
            valor = linea_limpia.substring(posicion + 1).trim()
            
            si valor == "|":
                clave_multilinea = clave
                valor_multilinea = []
            sino:
                registro_actual[clave] = valor
            continuar
        
        # Línea inválida (ignorar o reportar error según implementación)
        reportar_advertencia("Línea no reconocida: " + linea)
    
    # Finalizar último valor multilínea
    si clave_multilinea != nulo:
        registro_actual[clave_multilinea] = valor_multilinea.unir("\n")
    
    # Agregar último registro
    si registro_actual no está vacío:
        registros.agregar(registro_actual)
    
    retornar registros
```

---

## Conversión a Otros Formatos

### FTU a JSON

#### Reglas de Conversión

| FTU | JSON |
|-----|------|
| `clave: valor` | `"clave": "valor"` |
| `clave: 123` | `"clave": 123` (si es numérico) |
| `clave: si` | `"clave": true` |
| `clave: no` | `"clave": false` |
| `clave: a, b, c` | `"clave": ["a", "b", "c"]` |
| `clave:` (vacío) | `"clave": null` |
| `padre.hijo: valor` | `"padre": {"hijo": "valor"}` |
| Separador `---` | Elementos de array |

#### Ejemplo

**FTU:**
```
nombre: Juan
edad: 30
activo: si
roles: admin, editor
direccion.ciudad: México
direccion.pais: MX
---
nombre: María
edad: 25
activo: no
roles: lector
direccion.ciudad: Bogotá
direccion.pais: CO
```

**JSON:**
```json
[
  {
    "nombre": "Juan",
    "edad": 30,
    "activo": true,
    "roles": ["admin", "editor"],
    "direccion": {
      "ciudad": "México",
      "pais": "MX"
    }
  },
  {
    "nombre": "María",
    "edad": 25,
    "activo": false,
    "roles": ["lector"],
    "direccion": {
      "ciudad": "Bogotá",
      "pais": "CO"
    }
  }
]
```

### JSON a FTU

El proceso inverso sigue las mismas reglas.

**Reglas especiales:**
- Arrays de primitivos → lista separada por comas
- Arrays de objetos → registros separados por `---`
- Objetos anidados → notación de punto
- `null` → valor vacío
- `true` → `si`
- `false` → `no`

---

## Manejo de Errores

### Errores Recuperables

El parser debe continuar procesando ante estos errores:

| Error | Comportamiento |
|-------|---------------|
| Línea sin `:` | Ignorar línea, emitir advertencia |
| Clave duplicada | Usar último valor |
| Clave con formato inválido | Intentar normalizar o ignorar |
| Registro vacío | Ignorar |

### Errores Fatales

El parser debe detenerse ante estos errores:

| Error | Razón |
|-------|-------|
| Codificación no UTF-8 | Imposible interpretar contenido |
| Archivo binario | No es texto |

---

## Extensiones Reservadas

Las siguientes características están reservadas para futuras versiones del formato. Los parsers actuales deben ignorarlas si las encuentran:

| Sintaxis | Propósito Reservado |
|----------|---------------------|
| `@directiva` | Directivas de procesamiento |
| `<<clave` | Referencias a otros valores |
| `!tipo` | Anotaciones de tipo explícitas |
| `[indice]` | Acceso a arrays (alternativo a `.N`) |

---

## Ejemplos Completos

### Entrada de Pieza Login

```
# Solicitud de autenticación
# Generado: 2025-01-15T10:30:00Z

usuario: maria@ejemplo.com
clave: contraseña_segura_123
recordar: si

# Opciones adicionales
origen: web
ip_cliente: 192.168.1.100
```

### Salida Exitosa de Pieza Login

```
estado: ok
sesion_id: ses_7f8a9b2c3d4e5f6g
expira: 2025-01-16T10:30:00Z

usuario.id: usr_001
usuario.nombre: María García
usuario.correo: maria@ejemplo.com
usuario.roles: admin, editor

metadata.tiempo_respuesta_ms: 45
metadata.servidor: auth-01
```

### Salida de Error

```
estado: error
codigo: credenciales_invalidas
mensaje: El correo o la contraseña son incorrectos
detalle: No se encontró coincidencia en la base de datos
sugerencia: Verifique que el correo esté escrito correctamente

metadata.intentos_restantes: 2
metadata.bloqueado_hasta:
```

### Lista de Resultados

```
# Resultados de búsqueda de usuarios
# Total: 3 registros

nombre: Juan Pérez
correo: juan@ejemplo.com
rol: admin
activo: si
---
nombre: María García
correo: maria@ejemplo.com
rol: editor
activo: si
---
nombre: Pedro López
correo: pedro@ejemplo.com
rol: lector
activo: no
```

### Configuración de Pieza

```
# Configuración para pieza de correo
# Archivo: correo.config.usee

servidor.host: smtp.ejemplo.com
servidor.puerto: 587
servidor.seguro: si

credenciales.usuario: sistema@ejemplo.com
credenciales.clave: clave_smtp_segura

opciones.reintentos: 3
opciones.timeout_segundos: 30
opciones.registro_envios: si

plantilla.saludo: |
  Estimado/a {nombre},
  
  Gracias por contactarnos.
plantilla.despedida: |
  Atentamente,
  El equipo de soporte
```

---

## Implementaciones de Referencia

Para facilitar la adopción, se proporcionarán parsers de referencia en:

- Python
- JavaScript
- Go
- Rust
- C

Estos parsers estarán disponibles como piezas USEE:

```
usee-ftu-python
usee-ftu-javascript
usee-ftu-go
usee-ftu-rust
usee-ftu-c
```

---

## Resumen de Sintaxis

| Elemento | Sintaxis | Ejemplo |
|----------|----------|---------|
| Par clave-valor | `clave: valor` | `nombre: Juan` |
| Comentario | `# texto` | `# Esto es un comentario` |
| Lista | `clave: a, b, c` | `roles: admin, editor` |
| Booleano | `si` / `no` | `activo: si` |
| Fecha | `YYYY-MM-DD` | `fecha: 2025-01-15` |
| Fecha-hora | ISO 8601 | `creado: 2025-01-15T10:30:00Z` |
| Separador | `---` | `---` |
| Multilínea | `clave: \|` + indentado | Ver sección 7 |
| Anidado | `padre.hijo: valor` | `usuario.nombre: Juan` |
| Vacío/Nulo | `clave:` | `comentario:` |

---

**FTU**: Texto que humanos y máquinas entienden por igual.
