@wikytam/helpers 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,373 @@
1
+ //#region src/types.d.ts
2
+ /**
3
+ * Configuration for the Formatter class, mirroring yii\i18n\Formatter properties.
4
+ * All properties are optional - sensible defaults are applied when not provided.
5
+ */
6
+ interface FormatterOptions {
7
+ /** Locale used by the Intl API (default: "en-US") */
8
+ locale?: string;
9
+ /** Output time zone for date/time formatting (default: "UTC") */
10
+ timeZone?: string;
11
+ /** Time zone assumed for input values without explicit timezone (default: "UTC") */
12
+ defaultTimeZone?: string;
13
+ /** Default date format - ICU preset name or Intl options (default: "medium") */
14
+ dateFormat?: string | Intl.DateTimeFormatOptions;
15
+ /** Default time format (default: "medium") */
16
+ timeFormat?: string | Intl.DateTimeFormatOptions;
17
+ /** Default datetime format (default: "medium") */
18
+ datetimeFormat?: string | Intl.DateTimeFormatOptions;
19
+ /** [falsyLabel, truthyLabel] (default: ["No", "Yes"]) */
20
+ booleanFormat?: [string, string];
21
+ /** String displayed when value is null/undefined (default: "(not set)") */
22
+ nullDisplay?: string;
23
+ /** Default ISO 4217 currency code (default: "USD") */
24
+ currencyCode?: string;
25
+ /** Custom decimal separator (null = use locale default) */
26
+ decimalSeparator?: string | null;
27
+ /** Custom thousands separator (null = use locale default) */
28
+ thousandSeparator?: string | null;
29
+ /** Custom decimal separator for currency (null = use locale default) */
30
+ currencyDecimalSeparator?: string | null;
31
+ /** Base for file size calculation: 1024 (binary) or 1000 (decimal) */
32
+ sizeFormatBase?: 1024 | 1000;
33
+ /** System of measurement units: "metric" or "imperial" */
34
+ systemOfUnits?: "metric" | "imperial";
35
+ /** Default number of decimal digits (null = auto) */
36
+ defaultDecimalDigits?: number | null;
37
+ }
38
+ /** ICU-style date/time format width presets */
39
+ type DateFormatPreset = "short" | "medium" | "long" | "full";
40
+ /** Time units for Intl.RelativeTimeFormat */
41
+ type RelativeTimeUnit = "second" | "minute" | "hour" | "day" | "week" | "month" | "year";
42
+ /** System of measurement units */
43
+ type UnitSystem = "metric" | "imperial";
44
+ /** Measurement unit category */
45
+ type UnitType = "length" | "mass";
46
+ /** Format width for size/measurement output */
47
+ type FormatWidth = "long" | "short";
48
+ /** Configuration for a single measurement unit */
49
+ interface MeasureUnitConfig {
50
+ factor: number;
51
+ longLabel: string;
52
+ shortLabel: string;
53
+ }
54
+ /** Options for asEmail() */
55
+ interface EmailOptions {
56
+ /** Custom display text instead of the email address */
57
+ text?: string;
58
+ /** Email subject line */
59
+ subject?: string;
60
+ /** Email body content */
61
+ body?: string;
62
+ }
63
+ /** Options for asUrl() */
64
+ interface UrlOptions {
65
+ /** Target attribute for the link (default: "_blank") */
66
+ target?: string;
67
+ /** Custom display text instead of the URL */
68
+ text?: string;
69
+ /** Rel attribute for the link (e.g. "noopener noreferrer") */
70
+ rel?: string;
71
+ /** CSS class(es) for the link element */
72
+ class?: string;
73
+ }
74
+ /** Options for asImage() */
75
+ interface ImageOptions {
76
+ /** Alt text for the image */
77
+ alt?: string;
78
+ /** Image width (number for pixels, string for CSS value) */
79
+ width?: number | string;
80
+ /** Image height (number for pixels, string for CSS value) */
81
+ height?: number | string;
82
+ /** CSS class(es) for the image element */
83
+ class?: string;
84
+ /** Loading strategy: "lazy" defers offscreen images, "eager" loads immediately */
85
+ loading?: "lazy" | "eager";
86
+ }
87
+ /** Options for asParagraphs() */
88
+ interface ParagraphOptions {
89
+ /** HTML tag to wrap paragraphs (default: "p") */
90
+ tag?: string;
91
+ /** Whether to convert single newlines within paragraphs to `<br />` (default: false) */
92
+ lineBreaks?: boolean;
93
+ }
94
+ /** Allowlist-based HTML sanitizer config */
95
+ interface HtmlSanitizeConfig {
96
+ /** Allowed HTML tags (e.g. ["b", "i", "a", "p", "br"]) */
97
+ allowedTags?: string[];
98
+ /** Allowed attributes per tag (e.g. { a: ["href", "target"] }) */
99
+ allowedAttributes?: Record<string, string[]>;
100
+ }
101
+ /** Ordinal suffix map for a language: PluralRule category -> suffix */
102
+ type OrdinalSuffixMap = Record<string, string>;
103
+ /** Options for asNumberShort() */
104
+ interface NumberShortOptions {
105
+ /** Number of decimal places (default: 1) */
106
+ decimals?: number;
107
+ /** Fallback format when below smallest threshold: "currency" | "decimal" | "integer" (default: "currency") */
108
+ fallback?: "currency" | "decimal" | "integer";
109
+ /** Whether to add a space between number and suffix (default: false for backward compat) */
110
+ spaceBefore?: boolean;
111
+ }
112
+ /** Options for asGpsDistance() */
113
+ interface GpsDistanceOptions {
114
+ /** Output unit: "m" (meters), "km" (kilometers), "mi" (miles), "auto" (default: "auto") */
115
+ unit?: "m" | "km" | "mi" | "auto";
116
+ /** Number of decimal places (default: 1) */
117
+ decimals?: number;
118
+ /** Earth radius in meters (default: 6371000) */
119
+ earthRadius?: number;
120
+ }
121
+ /** Options for asMaskedValue() */
122
+ interface MaskOptions {
123
+ /** Number of visible characters at the start (default: 4) */
124
+ startVisible?: number;
125
+ /** Number of visible characters at the end (default: 3) */
126
+ endVisible?: number;
127
+ /** Character used for masking (default: "X") */
128
+ maskChar?: string;
129
+ /** Keep original character type (letters->letter mask, digits->digit mask). Currently uses maskChar for all. */
130
+ preserveFormat?: boolean;
131
+ }
132
+ //#endregion
133
+ //#region src/formatter.d.ts
134
+ /**
135
+ * TypeScript port of yii\i18n\Formatter.
136
+ *
137
+ * Uses only built-in Intl APIs - zero external dependencies.
138
+ * Supports: strings, HTML, numbers, currency, dates, times,
139
+ * file sizes, measurement units, and more.
140
+ */
141
+ export declare class Formatter {
142
+ locale: string;
143
+ timeZone: string;
144
+ defaultTimeZone: string;
145
+ dateFormat: string | Intl.DateTimeFormatOptions;
146
+ timeFormat: string | Intl.DateTimeFormatOptions;
147
+ datetimeFormat: string | Intl.DateTimeFormatOptions;
148
+ booleanFormat: [string, string];
149
+ nullDisplay: string;
150
+ currencyCode: string;
151
+ decimalSeparator: string | null;
152
+ thousandSeparator: string | null;
153
+ currencyDecimalSeparator: string | null;
154
+ sizeFormatBase: 1024 | 1000;
155
+ systemOfUnits: UnitSystem;
156
+ defaultDecimalDigits: number | null;
157
+ constructor(options?: FormatterOptions);
158
+ /**
159
+ * Format a value by type name, like Yii2's `$formatter->format($value, 'date')`.
160
+ * Supports both string and tuple `[formatName, ...params]` signatures.
161
+ */
162
+ format(value: unknown, type: string | [string, ...unknown[]]): string;
163
+ /** Returns the value as-is without any formatting. */
164
+ asRaw(value: unknown): string;
165
+ /** Formats the value as HTML-encoded plain text. */
166
+ asText(value: unknown): string;
167
+ /**
168
+ * Formats the value as HTML-encoded text with newlines converted to `<br />`.
169
+ * Handles all line-ending variants: `\r\n` (Windows), `\r` (old Mac), `\n` (Unix).
170
+ * Consecutive newlines produce multiple `<br />` tags.
171
+ */
172
+ asNtext(value: unknown): string;
173
+ /**
174
+ * Formats the value as HTML-encoded text paragraphs (split by double newlines).
175
+ * Supports configurable wrapper tag and inline line-break conversion.
176
+ */
177
+ asParagraphs(value: unknown, options?: ParagraphOptions): string;
178
+ /**
179
+ * Returns the value as HTML text.
180
+ * When a sanitize config is provided, only allowed tags and attributes are kept.
181
+ * Without config, the value is returned as-is (caller is responsible for safety).
182
+ */
183
+ asHtml(value: unknown, sanitize?: HtmlSanitizeConfig): string;
184
+ /**
185
+ * Allowlist-based HTML sanitizer. Strips tags and attributes not in the config.
186
+ * Handles self-closing tags, nested tags, and attribute filtering.
187
+ */
188
+ private static sanitizeHtml;
189
+ /**
190
+ * Formats the value as a mailto link.
191
+ * Supports custom display text, subject, and body parameters.
192
+ * Validates email format - returns escaped plain text for invalid emails.
193
+ */
194
+ asEmail(value: unknown, options?: EmailOptions): string;
195
+ /** Basic email format validation (covers most common patterns). */
196
+ private static isValidEmail;
197
+ /**
198
+ * Formats the value as a hyperlink.
199
+ * Detects http, https, ftp, ftps, and mailto schemes.
200
+ * Prepends `http://` when no recognized scheme is present.
201
+ */
202
+ asUrl(value: unknown, options?: UrlOptions): string;
203
+ /**
204
+ * Formats the value as an image tag.
205
+ * Supports width, height, CSS class, and loading strategy attributes.
206
+ */
207
+ asImage(value: unknown, options?: ImageOptions): string;
208
+ /** Formats the value as a boolean using the configured booleanFormat labels. */
209
+ asBoolean(value: unknown): string;
210
+ /** Formats the value as an integer by removing decimal digits without rounding. */
211
+ asInteger(value: unknown): string;
212
+ /** Formats the value as a decimal number. */
213
+ asDecimal(value: unknown, decimals?: number): string;
214
+ /** Formats the value as a percent number with "%" sign. */
215
+ asPercent(value: unknown, decimals?: number): string;
216
+ /** Formats the value as a currency number using ISO 4217 codes. */
217
+ asCurrency(value: unknown, currency?: string): string;
218
+ /** Formats the value as a scientific number (e-notation). */
219
+ asScientific(value: unknown, decimals?: number): string;
220
+ /**
221
+ * Formats the value as a number spellout (e.g. 42 -> "forty-two").
222
+ * Supports multiple locales via the locales/ registry.
223
+ */
224
+ asSpellout(value: unknown): string;
225
+ /**
226
+ * Formats the value as an ordinal number (e.g. 1 -> "1st", 2 -> "2nd").
227
+ * Supports multiple locales via built-in suffix maps and custom overrides
228
+ * through `Formatter.registerOrdinalSuffixes()`.
229
+ */
230
+ asOrdinal(value: unknown): string;
231
+ /** Built-in ordinal suffix registry. Extensible at runtime. */
232
+ private static ordinalSuffixes;
233
+ /**
234
+ * Register ordinal suffixes for a language at runtime.
235
+ * Keys are Intl.PluralRules ordinal categories: "one", "two", "few", "other".
236
+ */
237
+ static registerOrdinalSuffixes(lang: string, suffixes: OrdinalSuffixMap): void;
238
+ /** Formats the value as a date. */
239
+ asDate(value: unknown, format?: string | Intl.DateTimeFormatOptions): string;
240
+ /** Formats the value as a time. */
241
+ asTime(value: unknown, format?: string | Intl.DateTimeFormatOptions): string;
242
+ /** Formats the value as a datetime. */
243
+ asDatetime(value: unknown, format?: string | Intl.DateTimeFormatOptions): string;
244
+ /** Returns the value as a UNIX timestamp (seconds since epoch). */
245
+ asTimestamp(value: unknown): string;
246
+ /**
247
+ * Formats the value as the time interval between a date and now in human readable form.
248
+ * Uses Intl.RelativeTimeFormat (built-in in Node.js / browsers).
249
+ */
250
+ asRelativeTime(value: unknown, referenceTime?: unknown): string;
251
+ /**
252
+ * Represents the value as duration in human readable format.
253
+ * Example: 5400 -> "1 hour, 30 minutes"
254
+ */
255
+ asDuration(value: unknown, implode?: string): string;
256
+ /** Formats the value in bytes as a size in human readable form (e.g. "12 kilobytes"). */
257
+ asSize(value: unknown, decimals?: number): string;
258
+ /** Formats the value in bytes as a size in human readable form (e.g. "12 kB"). */
259
+ asShortSize(value: unknown, decimals?: number): string;
260
+ /** Formats the value as a length in human readable form (e.g. "12 meters"). */
261
+ asLength(value: unknown, decimals?: number): string;
262
+ /** Formats the value as a length in human readable form (e.g. "12 m"). */
263
+ asShortLength(value: unknown, decimals?: number): string;
264
+ /** Formats the value as a weight in human readable form (e.g. "12 kilograms"). */
265
+ asWeight(value: unknown, decimals?: number): string;
266
+ /** Formats the value as a weight in human readable form (e.g. "12 kg"). */
267
+ asShortWeight(value: unknown, decimals?: number): string;
268
+ /**
269
+ * Abbreviate a large number with locale-aware suffixes.
270
+ * e.g. 1500000 -> "1.5 Million" (en) or "1,5 Trieu" (vi).
271
+ */
272
+ asNumberShort(value: unknown, options?: NumberShortOptions): string;
273
+ /**
274
+ * Format the GPS (great-circle) distance between two coordinates.
275
+ * Returns a human-readable string with unit suffix.
276
+ */
277
+ asGpsDistance(latFrom: number, lonFrom: number, latTo: number, lonTo: number, options?: GpsDistanceOptions): string;
278
+ /** Haversine formula: returns distance in meters between two GPS coordinates. */
279
+ private static gpsDistance;
280
+ /**
281
+ * Mask a string value, showing only the first and last N characters.
282
+ * Instance method with options support.
283
+ */
284
+ asMaskedValue(value: unknown, options?: MaskOptions): string;
285
+ /** Core masking logic used by asMaskedValue(). */
286
+ private static getMaskedValue;
287
+ /**
288
+ * Format bytes into the most appropriate size unit.
289
+ * Supports both base-1024 (binary) and base-1000 (decimal).
290
+ */
291
+ private formatBytes;
292
+ /**
293
+ * Format a measurement value (length or mass).
294
+ * Automatically selects the most appropriate unit based on value magnitude.
295
+ */
296
+ private formatMeasure;
297
+ /** Get measurement unit configs for the configured system (metric/imperial). */
298
+ private getMeasureUnits;
299
+ /** Format the numeric part of a result using locale-aware Intl. */
300
+ private formatNumberPart;
301
+ /** Create a locale-aware duration label using Intl unit formatting. */
302
+ private getDurationLabel;
303
+ /** English ordinal suffix fallback. */
304
+ private getOrdinalSuffixEn;
305
+ }
306
+ //#endregion
307
+ //#region src/global.d.ts
308
+ /** The global Formatter singleton. Ready to use after `configureFormatter()`. */
309
+ export declare const formatter: Formatter;
310
+ /**
311
+ * Configure the global formatter once (typically at app bootstrap).
312
+ * Replaces the internal instance - all existing `formatter` references
313
+ * automatically pick up the new config via the proxy.
314
+ */
315
+ export declare function configureFormatter(options: FormatterOptions): void;
316
+ //#endregion
317
+ //#region src/locales/types.d.ts
318
+ /**
319
+ * Interface for locale-specific spellout and number-short providers.
320
+ * Implement this to add a new language for asSpellout() and formatNumberShort().
321
+ */
322
+ interface LocaleSpellout {
323
+ /** Convert an integer to words (e.g. 42 -> "forty-two") */
324
+ integerToWords(n: number): string;
325
+ /** Convert a single digit to its word form (e.g. 5 -> "five") */
326
+ digitToWord(digit: string): string;
327
+ /** The word for "point" used between integer and decimal parts */
328
+ pointWord: string;
329
+ /** The word for "zero" */
330
+ zeroWord: string;
331
+ /** The prefix for negative numbers (e.g. "minus", "am") */
332
+ negativePrefix: string;
333
+ }
334
+ /**
335
+ * Short-number suffix configuration for a locale.
336
+ * Used by formatNumberShort() to abbreviate large numbers.
337
+ */
338
+ interface NumberShortConfig {
339
+ thresholds: Array<{
340
+ value: number;
341
+ suffix: string;
342
+ }>;
343
+ }
344
+ //#endregion
345
+ //#region src/locales/index.d.ts
346
+ /** Get the spellout provider for a locale, falling back to English. */
347
+ export declare function getSpellout(locale: string): LocaleSpellout;
348
+ /** Get the number-short config for a locale, falling back to English. */
349
+ export declare function getNumberShortConfig(locale: string): NumberShortConfig;
350
+ /** Register a custom spellout locale at runtime. */
351
+ export declare function registerSpellout(lang: string, impl: LocaleSpellout): void;
352
+ /** Register a custom number-short config at runtime. */
353
+ export declare function registerNumberShort(lang: string, config: NumberShortConfig): void;
354
+ //#endregion
355
+ //#region src/utils.d.ts
356
+ /**
357
+ * Escape the 5 HTML-special characters, equivalent to PHP's htmlspecialchars().
358
+ * No external dependency - pure string replacement.
359
+ */
360
+ export declare function escapeHtml(value: string): string;
361
+ /**
362
+ * Normalize an input value into a Date object.
363
+ * Accepts: Date, number (UNIX seconds or milliseconds), string (ISO 8601).
364
+ */
365
+ export declare function normalizeDate(value: unknown): Date;
366
+ /**
367
+ * Normalize an input value into a number.
368
+ * Accepts: number, numeric string (with optional comma grouping), boolean.
369
+ */
370
+ export declare function normalizeNumber(value: unknown): number;
371
+ //#endregion
372
+ export type { DateFormatPreset, EmailOptions, FormatWidth, FormatterOptions, GpsDistanceOptions, HtmlSanitizeConfig, ImageOptions, LocaleSpellout, MaskOptions, MeasureUnitConfig, NumberShortConfig, NumberShortOptions, OrdinalSuffixMap, ParagraphOptions, RelativeTimeUnit, UnitSystem, UnitType, UrlOptions };
373
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/formatter.ts","../src/global.ts","../src/locales/types.ts","../src/locales/index.ts","../src/utils.ts"],"mappings":";;;;;UAIiB;;EAEhB;;EAGA;;EAGA;;EAGA,sBAAsB,KAAK;;EAG3B,sBAAsB,KAAK;;EAG3B,0BAA0B,KAAK;;EAG/B;;EAGA;;EAGA;;EAGA;;EAGA;;EAGA;;EAGA;;EAGA;;EAGA;;;KAIW;;KAGA;;KAUA;;KAGA;;KAGA;;UAGK;EAChB;EACA;EACA;;;UAIgB;;EAEhB;;EAEA;;EAEA;;;UAIgB;;EAEhB;;EAEA;;EAEA;;EAEA;;;UAIgB;;EAEhB;;EAEA;;EAEA;;EAEA;;EAEA;;;UAIgB;;EAEhB;;EAEA;;;UAIgB;;EAEhB;;EAEA,oBAAoB;;;KAIT,mBAAmB;;UAGd;;EAEhB;;EAEA;;EAEA;;;UAIgB;;EAEhB;;EAEA;;EAEA;;;UAIgB;;EAEhB;;EAEA;;EAEA;;EAEA;;;;;;;;;;;qBCrIY;EACL;EACA;EACA;EACA,qBAAqB,KAAK;EAC1B,qBAAqB,KAAK;EAC1B,yBAAyB,KAAK;EAC9B;EACA;EACA;EACA;EACA;EACA;EACA;EACA,eAAe;EACf;EAEP,YAAY,UAAS;;;;;EAwBd,OAAO,gBAAgB;;EAsBvB,MAAM;;EAMN,OAAO;;;;;;EAUP,QAAQ;;;;;EAUR,aAAa,gBAAgB,UAAU;;;;;;EAyBvC,OAAO,gBAAgB,WAAW;;;;;iBAW1B;;;;;;EAuDR,QAAQ,gBAAgB,UAAU;;iBAmB1B;;;;;;EASR,MAAM,gBAAgB,UAAU;;;;;EAqBhC,QAAQ,gBAAgB,UAAU;;EAoBlC,UAAU;;EAQV,UAAU;;EAmBV,UAAU,gBAAgB;;EAmB1B,UAAU,gBAAgB;;EAoB1B,WAAW,gBAAgB;;EAmB3B,aAAa,gBAAgB;;;;;EAgB7B,WAAW;;;;;;EA6BX,UAAU;;iBAoBF;;;;;SAiBD,wBACb,cACA,UAAU;;EAQJ,OACN,gBACA,kBAAkB,KAAK;;EAiBjB,OACN,gBACA,kBAAkB,KAAK;;EAiBjB,WACN,gBACA,kBAAkB,KAAK;;EAiBjB,YAAY;;;;;EAUZ,eAAe,gBAAgB;;;;;EAwB/B,WAAW,gBAAgB;;EA+B3B,OAAO,gBAAgB;;EAKvB,YAAY,gBAAgB;;EAK5B,SAAS,gBAAgB;;EAKzB,cAAc,gBAAgB;;EAK9B,SAAS,gBAAgB;;EAKzB,cAAc,gBAAgB;;;;;EAU9B,cAAc,gBAAgB,UAAU;;;;;EAgCxC,cACN,iBACA,iBACA,eACA,eACA,UAAU;;iBAuCI;;;;;EA0BR,cAAc,gBAAgB,UAAU;;iBAYhC;;;;;UAwBP;;;;;UAwDA;;UA+BA;;UAgCA;;UAeA;;UAeA;;;;;qBCh3BI,WAAS;;;;;;wBAWN,mBAAmB,SAAS;;;;;;;UC5B3B;;EAEhB,eAAe;;EAGf,YAAY;;EAGZ;;EAGA;;EAGA;;;;;;UAOgB;EAChB,YAAY;IACX;IACA;;;;;;wBCJc,YAAY,iBAAiB;;wBAM7B,qBAAqB,iBAAiB;;wBAMtC,iBAAiB,cAAc,MAAM;;wBAKrC,oBACf,cACA,QAAQ;;;;;;;wBCrCO,WAAW;;;;;wBAaX,cAAc,iBAAiB;;;;;wBAuB/B,gBAAgB"}