Todos los cambios relevantes de la librería. El formato sigue Keep a Changelog.
Revisión de robustez y experiencia de desarrollo. No hay cambios que rompan código existente: todo lo anterior sigue compilando y comportándose igual, salvo donde el comportamiento anterior era un fallo (ver Corregido).
- Multi-target
net8.0/net9.0/net10.0. Antes el paquete sólo se podía instalar ennet10.0, lo que dejaba fuera a la mayoría de proyectos en producción (net8.0 es LTS). DocumentoEspanol, fachada estática para el caso más común:DocumentoEspanol.EsValido("12345678Z"). Sin instanciar nada, sin asignaciones y sin excepciones.AddValidacionDocumentosEspanoles(), extensión deIServiceCollectionque registraIValidadorDocumentos,ValidadorDocumentosUltraFastyProcesadorLotesUltraFastcomo singleton. UsaTryAdd, así que respeta una implementación propia ya registrada.- Streaming perezoso en ambos motores:
ValidarStream(IEnumerable<string?>)yValidarStreamAsync(IAsyncEnumerable<string?>). Memoria constante independientemente del tamaño del origen; losValidarLote*materializan el origen entero y no sirven para ficheros que no caben en RAM. - Atajos booleanos en el motor ultra:
EsDniValido,EsNieValido,EsNifValido,EsCifValido,EsDocumentoValido. ValidarLoteCompatAsyncy sobrecarga deValidarLotepara cualquierIEnumerable<string?>.UtilesValidacion.TryNormalizar(ReadOnlySpan<char>, Span<char>, out int): normalización contra un buffer del llamante, cero asignaciones.ResultadoValidacionUltra.MensajeyProcesadorLotesUltraFast.DescribirError(int): mensaje legible a partir del código de error, sin construir nada por documento.IReglaValidacion<T>.Cumple(T): comprobación booleana sin construir el mensaje de error. Implementación por defecto incluida, las reglas propias no necesitan cambios.ValidadorDocumentos.InstanciayProcesadorLotesUltraFast.Instanciapara uso sin contenedor de DI.CancellationTokenen los lotes del motor ultra (ValidarLote,ValidarLoteCompat).- SourceLink, símbolos (
.snupkg) y build determinista en el paquete: se puede depurar con F11 dentro de la librería. - Marcado como
IsAotCompatibleeIsTrimmable. - 71 tests nuevos de robustez y DX (737 en total), ejecutados en
net8.0ynet10.0.
- El motor ultra aceptaba CIFs con letra de entidad inexistente.
ValidadorDocumentosUltraFast.ValidarCif("I00000000")devolvía válido (tambiénO,T, y cualquier otra letra fuera deABCDEFGHJNPQRSUVW), mientras que la API clásica los rechazaba. La regla nunca comprobaba el primer carácter: el código de error 403 existía pero no se emitía nunca. Ambos motores dan ahora el mismo veredicto sobre cualquier entrada. - Los lotes asíncronos perdían el orden de entrada.
ValidarLote*Asyncacumulaba en unConcurrentBag, así queResultadosIndividuales[i]no correspondía al documentoiy el resultado no coincidía con el de la versión síncrona. Ahora se escribe en un array indexado por partición. ProcesarStreamAsyncdejaba colgado al consumidor. Si un worker fallaba o se cancelaba la operación, el canal de salida no se completaba nunca y elawait foreachdel consumidor esperaba de forma indefinida. Ahora se completa siempre (con la excepción, si la hubo) en unfinally.- La cancelación no cancelaba nada.
ValidarLoteAsyncsólo pasaba el token aTask.Run, lo que impide empezar pero no parar: un lote de millones de documentos seguía ocupando todos los núcleos hasta terminar. Ahora el token se comprueba durante el proceso, en ambos motores. - Fuga de memoria en el procesador de lotes. Dos
ConcurrentDictionaryestáticos cacheaban resultados sin límite ni expiración. Con documentos distintos —el caso real de un padrón o un censo— crecían sin tope: un millón de documentos únicos dejaba ~100 MB retenidos permanentemente, y las tandas sucesivas acababan enOutOfMemoryException. Se han eliminado; recalcular cuesta nanosegundos. Normalizarreservaba memoria proporcional a la entrada. Una entrada anómala de 40 MB reservaba unchar[]de 80 MB en el LOH. Ahora la memoria usada no depende del tamaño de la entrada.ErrorValidacion.CodigoErrorStringconstruía una excepción en cada lectura, sólo para leerle una propiedad (~136 bytes por lectura). Ahora resuelve con una tabla.Resumeny los porcentajes dependían de la cultura del proceso: el mismo lote daba66,67%en un servidores-ESy66.67%en unoen-US. Ahora se formatean conInvariantCulture.ValidadorEncadenado.AcumularErrores()mutaba la instancia, de modo que pedir la versión acumulada cambiaba el modo de evaluación para el resto de consumidores. Ahora devuelve un validador nuevo con su propia copia de reglas.- Códigos de error desconocidos se casteaban a un valor de enum inexistente.
Ahora se mapean a
ReglaValidacionFallida. - Ejemplos del README que no compilaban: espacio de nombres incorrecto
(
nif_dni_nie_cif_validation),ValidarDniSpantratado comoboolyValidarDocumento(Span)en lugar deValidarDocumentoSpan. El ejemplo deChannel<T>mostraba además un patrón que interbloquea con canales acotados.
- Los caminos booleanos ya no usan excepciones como control de flujo.
Dni.Intentar,Nie.Intentar,Nif.Intentar,Cif.Intentary todos losEsXValidovalidaban dentro de untry/catch: cada documento inválido lanzaba y capturaba una excepción completa (~1,3 KB y varios microsegundos). Ahora validan y sólo construyen si procede. - Las cadenas de reglas se construyen una sola vez. Antes cada validación
creaba 5 objetos regla + una lista + LINQ.
EsDniValidoha pasado de 379 ns y 856 B a ~35 ns y 0 B. - Las reglas del motor ultra ya no construyen texto en el camino de fallo. El detalle interpolado que generaban no lo leía nadie.
- Los métodos de validación aceptan
string?y los lotesIEnumerable<string?>?: la tolerancia anullya existía, ahora también la declara la firma. IntentarValidarXvalida una sola vez (antes ejecutaba la cadena de reglas y después repetía la validación completa al construir el objeto de valor).CrearValidador()sigue devolviendo una instancia nueva, extensible con.Agregar(...)sin afectar a la que usa la librería.- CI:
timeout-minutesen los jobs y en los tests (un test colgado ya no puede retener un runner durante horas), build con-warnaserror, tests contra los runtimes de los tres TFMs y ejecución también en pull requests. - Corregidas las 29 advertencias de compilación (documentación XML ausente o
con referencias
crefsin resolver). El build está limpio con-warnaserror.