Cayaqui.Helpers
0.4.21
dotnet add package Cayaqui.Helpers --version 0.4.21
NuGet\Install-Package Cayaqui.Helpers -Version 0.4.21
<PackageReference Include="Cayaqui.Helpers" Version="0.4.21" />
<PackageVersion Include="Cayaqui.Helpers" Version="0.4.21" />
<PackageReference Include="Cayaqui.Helpers" />
paket add Cayaqui.Helpers --version 0.4.21
#r "nuget: Cayaqui.Helpers, 0.4.21"
#:package Cayaqui.Helpers@0.4.21
#addin nuget:?package=Cayaqui.Helpers&version=0.4.21
#tool nuget:?package=Cayaqui.Helpers&version=0.4.21
Cayaqui.Helpers
Utilities zero-dependency para .NET 10 usadas transversalmente en los módulos Cayaqui.
Contenido
| Archivo | Tipos / métodos |
|---|---|
Guard.cs |
Guard.Against.* — Null, NullOrWhiteSpace, EmptyGuid, Negative, NegativeOrZero, OutOfRange, NullOrEmpty, ExceedsMaxLength, BelowMinLength, NotDefault, MatchesPattern, Email, FutureDate, PastDate, InvalidOperation |
Result.cs |
Result<T> / Result con Success/Failure, Map, Match |
PaginatedList.cs |
Metadata de paginación (TotalCount, PageNumber, HasNext, FirstItemIndex, …) |
DateRange.cs |
Record struct inclusiva con Contains, Overlaps, IntersectWith, EnumerateDays, DurationDays |
Money.cs |
Record struct con Amount + ISO 4217 Currency; arithmetic con validación de moneda, compact string (10.4M / 1.2K) |
IClock.cs |
Abstracción IClock + SystemClock + FakeClock (testeo determinista) |
JsonDefaults.cs |
JsonSerializerOptions preconfigurado (camelCase, enums string, ignore null, tolerant reader) |
Extensions/StringExtensions.cs |
Truncate, ToDisplayLabel, ToTitleCase, FormatCode, IsValidEmail, RemoveAccents, Slugify, NormalizeWhitespace, MaskLast, MaskEmail, ToSnakeCase, ToKebabCase |
Extensions/DateTimeExtensions.cs |
ToShortDisplay, WeekNumber (ISO 8601), WorkingDaysUntil, StartOfMonth/EndOfMonth, ToRelativeTime, IsWeekend/IsWeekday, Quarter, FiscalYear, NextBusinessDay, AddBusinessDays, ToUtc(tz)/ToLocal(tz) |
Extensions/DecimalExtensions.cs |
EVM: CpiOf, SpiOf, PfOf, CvOf, SvOf, EacByCpi, EtcOf, VacOf, TcpiBac, TcpiEac, ScheduleAtCompletion, VacPercent; formatting: ToPercentString, ToCurrencyString, ToIndexString, ToAccountingString; utils: Clamp, RoundToCents, WithinTolerance; status: CpiStatus, SpiStatus, PfStatus, ToStatusColor (enum EvmStatus) |
Extensions/EnumExtensions.cs |
GetDescription ([Description]), GetDisplayName ([Display]), TryParseEnum, GetValues |
Extensions/CollectionExtensions.cs |
IsNullOrEmpty, WithIndex, Batch, AddIfNotNull, IndexOf(predicate), ToOrdinalDictionary |
Distribución propietaria — requiere contrato comercial con Cayaqui. Ver
LICENSE.txt.
Instalación
dotnet add package Cayaqui.Helpers
Ejemplos rápidos
Guard clauses
using Cayaqui.Helpers;
public void CreateProject(string code, decimal budget, string email)
{
Guard.Against.NullOrWhiteSpace(code, nameof(code));
Guard.Against.BelowMinLength(code, 3, nameof(code));
Guard.Against.MatchesPattern(code, @"^[A-Z]{2,3}-\d{3,5}$", nameof(code));
Guard.Against.NegativeOrZero(budget, nameof(budget));
Guard.Against.Email(email, nameof(email));
}
Result pattern
using Cayaqui.Helpers;
public Result<Project> FindProject(Guid id) =>
_repo.Get(id) is { } p
? Result<Project>.Success(p)
: Result<Project>.Failure("PROJECT_NOT_FOUND", $"Project {id} does not exist.");
EVM
using Cayaqui.Helpers.Extensions;
decimal ev = 80_000, ac = 95_000, pv = 100_000, bac = 500_000, eac = 625_000;
decimal? cpi = ev.CpiOf(ac); // 0.8421
decimal? spi = ev.SpiOf(pv); // 0.80
decimal eac2 = bac.EacByCpi(cpi); // 593_750
decimal? tcpi = bac.TcpiEac(eac, ev, ac); // future efficiency needed vs EAC
decimal sac = 12m.ScheduleAtCompletion(spi); // PD 12m, SPI 0.8 → 15m
EvmStatus status = cpi.CpiStatus(); // Critical (< 0.85)
string display = cpi.ToIndexString(); // "0.84" (InvariantCulture default)
Money
using Cayaqui.Helpers;
var budget = new Money(500_000m, "USD");
var actual = new Money(435_000m, "USD");
var variance = budget - actual; // USD 65,000.00
var withVat = budget * 1.19m; // USD 595,000.00
budget.ToCompactString(); // "USD 500.0K"
budget.ToString(); // "USD 500,000.00"
// Currency mismatch → InvalidOperationException al operar
// var mixed = budget + new Money(100m, "EUR"); // throws
DateRange
using Cayaqui.Helpers;
var projectWindow = new DateRange(new DateTime(2025, 1, 1), new DateTime(2025, 12, 31));
projectWindow.Contains(DateTime.Today); // true si dentro
projectWindow.DurationDays; // 365
var phase = new DateRange(new DateTime(2025, 3, 1), new DateTime(2025, 6, 30));
projectWindow.Overlaps(phase); // true
projectWindow.IntersectWith(phase); // [2025-03-01, 2025-06-30]
IClock (testeo determinista)
public class ExpiryService(IClock clock)
{
public bool IsExpired(DateTime expiresAt) => clock.UtcNow > expiresAt;
}
// Producción
builder.Services.AddSingleton<IClock>(SystemClock.Instance);
// Tests
var fake = new FakeClock(new DateTime(2025, 6, 15, 10, 0, 0, DateTimeKind.Utc));
var service = new ExpiryService(fake);
fake.Advance(TimeSpan.FromHours(2)); // avanza el reloj sin tocar DateTime.UtcNow
JSON defaults
using Cayaqui.Helpers;
using System.Text.Json;
var json = JsonSerializer.Serialize(dto, JsonDefaults.Web);
// camelCase ✓ · enums como strings ✓ · null ignored ✓ · tolerant reader ✓
Strings y dates
using Cayaqui.Helpers.Extensions;
"Control Account 01 — Diseño Eléctrico".Slugify(); // "control-account-01-diseno-electrico"
"alejandro@cayaqui.com".MaskEmail(); // "a********@cayaqui.com"
"acción".RemoveAccents(); // "accion"
" hello\t\nworld ".NormalizeWhitespace(); // "hello world"
new DateTime(2025, 6, 15).Quarter(); // 2
new DateTime(2025, 8, 1).FiscalYear(fiscalStartMonth: 7); // 2026 (FY empieza en julio)
new DateTime(2025, 6, 6).NextBusinessDay(); // viernes → lunes
new DateTime(2025, 6, 2).AddBusinessDays(5); // suma 5 días hábiles
Requisitos
- .NET 10.0 o superior
- Sin dependencias externas — pure C# / BCL only.
Formato y cultura
Los formatters (ToShortDisplay, ToIndexString, ToCurrencyString, ToPercentString, ToAccountingString) usan InvariantCulture por default para salidas deterministas (APIs, reports, logs). Para UI localizada pasar CultureInfo explícita:
var es = new CultureInfo("es-CL");
value.ToPercentString(decimals: 2, culture: es); // "75,60%"
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.4.21 | 177 | 6/23/2026 |
| 0.4.20 | 128 | 6/23/2026 |
| 0.4.15 | 143 | 6/22/2026 |
| 0.4.14 | 130 | 6/22/2026 |
| 0.4.13 | 139 | 6/22/2026 |
| 0.4.10 | 139 | 6/20/2026 |
| 0.4.5 | 127 | 6/20/2026 |
| 0.4.3 | 129 | 6/20/2026 |
| 0.4.2 | 127 | 6/20/2026 |
| 0.4.1 | 131 | 6/20/2026 |
| 0.3.9 | 129 | 6/19/2026 |
| 0.3.8 | 118 | 6/18/2026 |
| 0.3.7 | 142 | 6/18/2026 |
| 0.3.6 | 130 | 6/18/2026 |
| 0.3.5 | 114 | 6/18/2026 |
| 0.3.4 | 144 | 6/17/2026 |
| 0.1.2 | 143 | 6/16/2026 |
| 0.1.1 | 144 | 6/16/2026 |
| 0.1.0 | 139 | 6/15/2026 |
Initial release. Guard, Result, PaginatedList, DateRange, Money, IClock (+FakeClock), JsonDefaults, Enum/Collection/String/DateTime/Decimal extensions with EVM indicators per ANSI-EIA-748.