Cayaqui.Helpers
0.3.9
dotnet add package Cayaqui.Helpers --version 0.3.9
NuGet\Install-Package Cayaqui.Helpers -Version 0.3.9
<PackageReference Include="Cayaqui.Helpers" Version="0.3.9" />
<PackageVersion Include="Cayaqui.Helpers" Version="0.3.9" />
<PackageReference Include="Cayaqui.Helpers" />
paket add Cayaqui.Helpers --version 0.3.9
#r "nuget: Cayaqui.Helpers, 0.3.9"
#:package Cayaqui.Helpers@0.3.9
#addin nuget:?package=Cayaqui.Helpers&version=0.3.9
#tool nuget:?package=Cayaqui.Helpers&version=0.3.9
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.
Initial release. Guard, Result, PaginatedList, DateRange, Money, IClock (+FakeClock), JsonDefaults, Enum/Collection/String/DateTime/Decimal extensions with EVM indicators per ANSI-EIA-748.