@attrx/role-morphic 0.1.0 → 0.2.1
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.
- package/README.md +151 -84
- package/dist/cast.d.mts +678 -0
- package/dist/cast.d.ts +678 -0
- package/dist/cast.js +3569 -0
- package/dist/cast.js.map +1 -0
- package/dist/cast.mjs +3536 -0
- package/dist/cast.mjs.map +1 -0
- package/dist/constants-BZdBwuvJ.d.mts +168 -0
- package/dist/constants-BZdBwuvJ.d.ts +168 -0
- package/dist/convert.d.mts +1157 -0
- package/dist/convert.d.ts +1157 -0
- package/dist/convert.js +2244 -0
- package/dist/convert.js.map +1 -0
- package/dist/convert.mjs +2148 -0
- package/dist/convert.mjs.map +1 -0
- package/dist/format-Be15LzfS.d.ts +668 -0
- package/dist/format-o4Y3jPH-.d.mts +668 -0
- package/dist/format.d.mts +3 -0
- package/dist/format.d.ts +3 -0
- package/dist/format.js +2303 -0
- package/dist/format.js.map +1 -0
- package/dist/format.mjs +2286 -0
- package/dist/format.mjs.map +1 -0
- package/dist/index.d.mts +200 -601
- package/dist/index.d.ts +200 -601
- package/dist/index.js +5536 -2493
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5349 -2494
- package/dist/index.mjs.map +1 -1
- package/dist/types-mbeS1e-k.d.mts +312 -0
- package/dist/types-mbeS1e-k.d.ts +312 -0
- package/dist/validate.d.mts +884 -0
- package/dist/validate.d.ts +884 -0
- package/dist/validate.js +713 -0
- package/dist/validate.js.map +1 -0
- package/dist/validate.mjs +669 -0
- package/dist/validate.mjs.map +1 -0
- package/package.json +21 -1
package/dist/format.mjs
ADDED
|
@@ -0,0 +1,2286 @@
|
|
|
1
|
+
// src/roles/area/constants.ts
|
|
2
|
+
var AREA_UNITS = {
|
|
3
|
+
// SI Units (todos exatos)
|
|
4
|
+
square_kilometer: {
|
|
5
|
+
factor: 1e6,
|
|
6
|
+
symbol: "km\xB2",
|
|
7
|
+
singular: "square kilometer",
|
|
8
|
+
plural: "square kilometers"
|
|
9
|
+
},
|
|
10
|
+
hectare: {
|
|
11
|
+
factor: 1e4,
|
|
12
|
+
symbol: "ha",
|
|
13
|
+
singular: "hectare",
|
|
14
|
+
plural: "hectares"
|
|
15
|
+
},
|
|
16
|
+
are: {
|
|
17
|
+
factor: 100,
|
|
18
|
+
symbol: "a",
|
|
19
|
+
singular: "are",
|
|
20
|
+
plural: "ares"
|
|
21
|
+
},
|
|
22
|
+
square_meter: {
|
|
23
|
+
factor: 1,
|
|
24
|
+
symbol: "m\xB2",
|
|
25
|
+
singular: "square meter",
|
|
26
|
+
plural: "square meters"
|
|
27
|
+
},
|
|
28
|
+
square_decimeter: {
|
|
29
|
+
factor: 0.01,
|
|
30
|
+
symbol: "dm\xB2",
|
|
31
|
+
singular: "square decimeter",
|
|
32
|
+
plural: "square decimeters"
|
|
33
|
+
},
|
|
34
|
+
square_centimeter: {
|
|
35
|
+
factor: 1e-4,
|
|
36
|
+
symbol: "cm\xB2",
|
|
37
|
+
singular: "square centimeter",
|
|
38
|
+
plural: "square centimeters"
|
|
39
|
+
},
|
|
40
|
+
square_millimeter: {
|
|
41
|
+
factor: 1e-6,
|
|
42
|
+
symbol: "mm\xB2",
|
|
43
|
+
singular: "square millimeter",
|
|
44
|
+
plural: "square millimeters"
|
|
45
|
+
},
|
|
46
|
+
// Imperial/US (todos exatos, derivados de comprimento² desde 1959)
|
|
47
|
+
square_mile: {
|
|
48
|
+
factor: 2589988110336e-6,
|
|
49
|
+
symbol: "mi\xB2",
|
|
50
|
+
singular: "square mile",
|
|
51
|
+
plural: "square miles"
|
|
52
|
+
},
|
|
53
|
+
acre: {
|
|
54
|
+
factor: 4046.8564224,
|
|
55
|
+
symbol: "ac",
|
|
56
|
+
singular: "acre",
|
|
57
|
+
plural: "acres"
|
|
58
|
+
},
|
|
59
|
+
square_yard: {
|
|
60
|
+
factor: 0.83612736,
|
|
61
|
+
symbol: "yd\xB2",
|
|
62
|
+
singular: "square yard",
|
|
63
|
+
plural: "square yards"
|
|
64
|
+
},
|
|
65
|
+
square_foot: {
|
|
66
|
+
factor: 0.09290304,
|
|
67
|
+
symbol: "ft\xB2",
|
|
68
|
+
singular: "square foot",
|
|
69
|
+
plural: "square feet"
|
|
70
|
+
},
|
|
71
|
+
square_inch: {
|
|
72
|
+
factor: 64516e-8,
|
|
73
|
+
symbol: "in\xB2",
|
|
74
|
+
singular: "square inch",
|
|
75
|
+
plural: "square inches"
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
Object.fromEntries(
|
|
79
|
+
Object.entries(AREA_UNITS).map(([unit, config]) => [
|
|
80
|
+
unit,
|
|
81
|
+
config.factor ?? 1
|
|
82
|
+
])
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
// src/roles/area/format.ts
|
|
86
|
+
function formatArea(variant, value, options = {}) {
|
|
87
|
+
const { decimals = 2, verbose = false, locale, notation } = options;
|
|
88
|
+
const unit = AREA_UNITS[variant];
|
|
89
|
+
if (!unit) {
|
|
90
|
+
throw new Error(`Unknown area variant: ${variant}`);
|
|
91
|
+
}
|
|
92
|
+
let formattedValue;
|
|
93
|
+
if (locale) {
|
|
94
|
+
const formatOptions = {
|
|
95
|
+
minimumFractionDigits: 0,
|
|
96
|
+
maximumFractionDigits: decimals
|
|
97
|
+
};
|
|
98
|
+
if (notation) {
|
|
99
|
+
formatOptions.notation = notation;
|
|
100
|
+
}
|
|
101
|
+
formattedValue = value.toLocaleString(locale, formatOptions);
|
|
102
|
+
} else {
|
|
103
|
+
formattedValue = Number(value.toFixed(decimals)).toString();
|
|
104
|
+
}
|
|
105
|
+
const separator = unit.noSpace ? "" : " ";
|
|
106
|
+
if (verbose) {
|
|
107
|
+
const name = value === 1 ? unit.singular : unit.plural;
|
|
108
|
+
return `${formattedValue} ${name || unit.symbol}`;
|
|
109
|
+
}
|
|
110
|
+
return `${formattedValue}${separator}${unit.symbol}`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/roles/length/constants.ts
|
|
114
|
+
var LENGTH_UNITS = {
|
|
115
|
+
// SI Units (todos exatos)
|
|
116
|
+
kilometer: {
|
|
117
|
+
factor: 1e3,
|
|
118
|
+
symbol: "km",
|
|
119
|
+
singular: "kilometer",
|
|
120
|
+
plural: "kilometers"
|
|
121
|
+
},
|
|
122
|
+
hectometer: {
|
|
123
|
+
factor: 100,
|
|
124
|
+
symbol: "hm",
|
|
125
|
+
singular: "hectometer",
|
|
126
|
+
plural: "hectometers"
|
|
127
|
+
},
|
|
128
|
+
decameter: {
|
|
129
|
+
factor: 10,
|
|
130
|
+
symbol: "dam",
|
|
131
|
+
singular: "decameter",
|
|
132
|
+
plural: "decameters"
|
|
133
|
+
},
|
|
134
|
+
meter: {
|
|
135
|
+
factor: 1,
|
|
136
|
+
symbol: "m",
|
|
137
|
+
singular: "meter",
|
|
138
|
+
plural: "meters"
|
|
139
|
+
},
|
|
140
|
+
decimeter: {
|
|
141
|
+
factor: 0.1,
|
|
142
|
+
symbol: "dm",
|
|
143
|
+
singular: "decimeter",
|
|
144
|
+
plural: "decimeters"
|
|
145
|
+
},
|
|
146
|
+
centimeter: {
|
|
147
|
+
factor: 0.01,
|
|
148
|
+
symbol: "cm",
|
|
149
|
+
singular: "centimeter",
|
|
150
|
+
plural: "centimeters"
|
|
151
|
+
},
|
|
152
|
+
millimeter: {
|
|
153
|
+
factor: 1e-3,
|
|
154
|
+
symbol: "mm",
|
|
155
|
+
singular: "millimeter",
|
|
156
|
+
plural: "millimeters"
|
|
157
|
+
},
|
|
158
|
+
micrometer: {
|
|
159
|
+
factor: 1e-6,
|
|
160
|
+
symbol: "\u03BCm",
|
|
161
|
+
singular: "micrometer",
|
|
162
|
+
plural: "micrometers"
|
|
163
|
+
},
|
|
164
|
+
nanometer: {
|
|
165
|
+
factor: 1e-9,
|
|
166
|
+
symbol: "nm",
|
|
167
|
+
singular: "nanometer",
|
|
168
|
+
plural: "nanometers"
|
|
169
|
+
},
|
|
170
|
+
// Imperial/US (exatos desde 1959)
|
|
171
|
+
inch: {
|
|
172
|
+
factor: 0.0254,
|
|
173
|
+
symbol: "in",
|
|
174
|
+
singular: "inch",
|
|
175
|
+
plural: "inches"
|
|
176
|
+
},
|
|
177
|
+
foot: {
|
|
178
|
+
factor: 0.3048,
|
|
179
|
+
symbol: "ft",
|
|
180
|
+
singular: "foot",
|
|
181
|
+
plural: "feet"
|
|
182
|
+
},
|
|
183
|
+
yard: {
|
|
184
|
+
factor: 0.9144,
|
|
185
|
+
symbol: "yd",
|
|
186
|
+
singular: "yard",
|
|
187
|
+
plural: "yards"
|
|
188
|
+
},
|
|
189
|
+
mile: {
|
|
190
|
+
factor: 1609.344,
|
|
191
|
+
symbol: "mi",
|
|
192
|
+
singular: "mile",
|
|
193
|
+
plural: "miles"
|
|
194
|
+
},
|
|
195
|
+
// Nautical (exato por definição internacional)
|
|
196
|
+
nautical_mile: {
|
|
197
|
+
factor: 1852,
|
|
198
|
+
symbol: "nmi",
|
|
199
|
+
singular: "nautical mile",
|
|
200
|
+
plural: "nautical miles"
|
|
201
|
+
},
|
|
202
|
+
// Other (derivados, portanto exatos)
|
|
203
|
+
fathom: {
|
|
204
|
+
factor: 1.8288,
|
|
205
|
+
// 6 feet
|
|
206
|
+
symbol: "ftm",
|
|
207
|
+
singular: "fathom",
|
|
208
|
+
plural: "fathoms"
|
|
209
|
+
},
|
|
210
|
+
furlong: {
|
|
211
|
+
factor: 201.168,
|
|
212
|
+
// 660 feet = 1/8 mile
|
|
213
|
+
symbol: "fur",
|
|
214
|
+
singular: "furlong",
|
|
215
|
+
plural: "furlongs"
|
|
216
|
+
},
|
|
217
|
+
league: {
|
|
218
|
+
factor: 4828.032,
|
|
219
|
+
// 3 miles
|
|
220
|
+
symbol: "lea",
|
|
221
|
+
singular: "league",
|
|
222
|
+
plural: "leagues"
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
Object.fromEntries(
|
|
226
|
+
Object.entries(LENGTH_UNITS).map(([unit, config]) => [
|
|
227
|
+
unit,
|
|
228
|
+
config.factor ?? 1
|
|
229
|
+
])
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
// src/roles/length/format.ts
|
|
233
|
+
function formatLength(variant, value, options = {}) {
|
|
234
|
+
const { decimals = 2, verbose = false, locale, notation } = options;
|
|
235
|
+
const unit = LENGTH_UNITS[variant];
|
|
236
|
+
if (!unit) {
|
|
237
|
+
throw new Error(`Unknown length variant: ${variant}`);
|
|
238
|
+
}
|
|
239
|
+
let formattedValue;
|
|
240
|
+
if (locale) {
|
|
241
|
+
const formatOptions = {
|
|
242
|
+
minimumFractionDigits: 0,
|
|
243
|
+
maximumFractionDigits: decimals
|
|
244
|
+
};
|
|
245
|
+
if (notation) {
|
|
246
|
+
formatOptions.notation = notation;
|
|
247
|
+
}
|
|
248
|
+
formattedValue = value.toLocaleString(locale, formatOptions);
|
|
249
|
+
} else {
|
|
250
|
+
formattedValue = Number(value.toFixed(decimals)).toString();
|
|
251
|
+
}
|
|
252
|
+
const separator = unit.noSpace ? "" : " ";
|
|
253
|
+
if (verbose) {
|
|
254
|
+
const name = value === 1 ? unit.singular : unit.plural;
|
|
255
|
+
return `${formattedValue} ${name || unit.symbol}`;
|
|
256
|
+
}
|
|
257
|
+
return `${formattedValue}${separator}${unit.symbol}`;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// src/roles/mass/constants.ts
|
|
261
|
+
var MASS_UNITS = {
|
|
262
|
+
// ===========================================================================
|
|
263
|
+
// SI / Metric
|
|
264
|
+
// ===========================================================================
|
|
265
|
+
metric_ton: {
|
|
266
|
+
factor: 1e3,
|
|
267
|
+
symbol: "t",
|
|
268
|
+
singular: "metric ton",
|
|
269
|
+
plural: "metric tons"
|
|
270
|
+
},
|
|
271
|
+
kilogram: {
|
|
272
|
+
factor: 1,
|
|
273
|
+
symbol: "kg",
|
|
274
|
+
singular: "kilogram",
|
|
275
|
+
plural: "kilograms"
|
|
276
|
+
},
|
|
277
|
+
hectogram: {
|
|
278
|
+
factor: 0.1,
|
|
279
|
+
symbol: "hg",
|
|
280
|
+
singular: "hectogram",
|
|
281
|
+
plural: "hectograms"
|
|
282
|
+
},
|
|
283
|
+
decagram: {
|
|
284
|
+
factor: 0.01,
|
|
285
|
+
symbol: "dag",
|
|
286
|
+
singular: "decagram",
|
|
287
|
+
plural: "decagrams"
|
|
288
|
+
},
|
|
289
|
+
gram: {
|
|
290
|
+
factor: 1e-3,
|
|
291
|
+
symbol: "g",
|
|
292
|
+
singular: "gram",
|
|
293
|
+
plural: "grams"
|
|
294
|
+
},
|
|
295
|
+
decigram: {
|
|
296
|
+
factor: 1e-4,
|
|
297
|
+
symbol: "dg",
|
|
298
|
+
singular: "decigram",
|
|
299
|
+
plural: "decigrams"
|
|
300
|
+
},
|
|
301
|
+
centigram: {
|
|
302
|
+
factor: 1e-5,
|
|
303
|
+
symbol: "cg",
|
|
304
|
+
singular: "centigram",
|
|
305
|
+
plural: "centigrams"
|
|
306
|
+
},
|
|
307
|
+
milligram: {
|
|
308
|
+
factor: 1e-6,
|
|
309
|
+
symbol: "mg",
|
|
310
|
+
singular: "milligram",
|
|
311
|
+
plural: "milligrams"
|
|
312
|
+
},
|
|
313
|
+
microgram: {
|
|
314
|
+
factor: 1e-9,
|
|
315
|
+
symbol: "\u03BCg",
|
|
316
|
+
singular: "microgram",
|
|
317
|
+
plural: "micrograms"
|
|
318
|
+
},
|
|
319
|
+
// ===========================================================================
|
|
320
|
+
// Avoirdupois (US/UK) - Sistema padrão para peso comum
|
|
321
|
+
// ===========================================================================
|
|
322
|
+
long_ton: {
|
|
323
|
+
factor: 1016.0469088,
|
|
324
|
+
// 2240 lb (exato)
|
|
325
|
+
symbol: "long tn",
|
|
326
|
+
singular: "long ton",
|
|
327
|
+
plural: "long tons"
|
|
328
|
+
},
|
|
329
|
+
short_ton: {
|
|
330
|
+
factor: 907.18474,
|
|
331
|
+
// 2000 lb (exato)
|
|
332
|
+
symbol: "sh tn",
|
|
333
|
+
singular: "short ton",
|
|
334
|
+
plural: "short tons"
|
|
335
|
+
},
|
|
336
|
+
stone: {
|
|
337
|
+
factor: 6.35029318,
|
|
338
|
+
// 14 lb (exato)
|
|
339
|
+
symbol: "st",
|
|
340
|
+
singular: "stone",
|
|
341
|
+
plural: "stone"
|
|
342
|
+
// stone não muda no plural em inglês
|
|
343
|
+
},
|
|
344
|
+
pound: {
|
|
345
|
+
factor: 0.45359237,
|
|
346
|
+
// Exato desde 1959
|
|
347
|
+
symbol: "lb",
|
|
348
|
+
singular: "pound",
|
|
349
|
+
plural: "pounds"
|
|
350
|
+
},
|
|
351
|
+
ounce: {
|
|
352
|
+
factor: 0.028349523125,
|
|
353
|
+
// 1/16 lb (exato)
|
|
354
|
+
symbol: "oz",
|
|
355
|
+
singular: "ounce",
|
|
356
|
+
plural: "ounces"
|
|
357
|
+
},
|
|
358
|
+
dram: {
|
|
359
|
+
factor: 0.0017718451953125,
|
|
360
|
+
// 1/16 oz (exato)
|
|
361
|
+
symbol: "dr",
|
|
362
|
+
singular: "dram",
|
|
363
|
+
plural: "drams"
|
|
364
|
+
},
|
|
365
|
+
grain: {
|
|
366
|
+
factor: 6479891e-11,
|
|
367
|
+
// 1/7000 lb (exato)
|
|
368
|
+
symbol: "gr",
|
|
369
|
+
singular: "grain",
|
|
370
|
+
plural: "grains"
|
|
371
|
+
},
|
|
372
|
+
// ===========================================================================
|
|
373
|
+
// Troy (metais preciosos)
|
|
374
|
+
// ===========================================================================
|
|
375
|
+
troy_pound: {
|
|
376
|
+
factor: 0.3732417216,
|
|
377
|
+
// 12 troy oz (exato)
|
|
378
|
+
symbol: "lb t",
|
|
379
|
+
singular: "troy pound",
|
|
380
|
+
plural: "troy pounds"
|
|
381
|
+
},
|
|
382
|
+
troy_ounce: {
|
|
383
|
+
factor: 0.0311034768,
|
|
384
|
+
// 480 grains (exato)
|
|
385
|
+
symbol: "oz t",
|
|
386
|
+
singular: "troy ounce",
|
|
387
|
+
plural: "troy ounces"
|
|
388
|
+
},
|
|
389
|
+
pennyweight: {
|
|
390
|
+
factor: 0.00155517384,
|
|
391
|
+
// 1/20 troy oz (exato)
|
|
392
|
+
symbol: "dwt",
|
|
393
|
+
singular: "pennyweight",
|
|
394
|
+
plural: "pennyweights"
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
Object.fromEntries(
|
|
398
|
+
Object.entries(MASS_UNITS).map(([unit, config]) => [
|
|
399
|
+
unit,
|
|
400
|
+
config.factor ?? 1
|
|
401
|
+
])
|
|
402
|
+
);
|
|
403
|
+
|
|
404
|
+
// src/roles/mass/format.ts
|
|
405
|
+
function formatMass(variant, value, options = {}) {
|
|
406
|
+
const { decimals = 2, verbose = false, locale, notation } = options;
|
|
407
|
+
const unit = MASS_UNITS[variant];
|
|
408
|
+
if (!unit) {
|
|
409
|
+
throw new Error(`Unknown mass variant: ${variant}`);
|
|
410
|
+
}
|
|
411
|
+
let formattedValue;
|
|
412
|
+
if (locale) {
|
|
413
|
+
const formatOptions = {
|
|
414
|
+
minimumFractionDigits: 0,
|
|
415
|
+
maximumFractionDigits: decimals
|
|
416
|
+
};
|
|
417
|
+
if (notation) {
|
|
418
|
+
formatOptions.notation = notation;
|
|
419
|
+
}
|
|
420
|
+
formattedValue = value.toLocaleString(locale, formatOptions);
|
|
421
|
+
} else {
|
|
422
|
+
formattedValue = Number(value.toFixed(decimals)).toString();
|
|
423
|
+
}
|
|
424
|
+
const separator = unit.noSpace ? "" : " ";
|
|
425
|
+
if (verbose) {
|
|
426
|
+
const name = value === 1 ? unit.singular : unit.plural;
|
|
427
|
+
return `${formattedValue} ${name || unit.symbol}`;
|
|
428
|
+
}
|
|
429
|
+
return `${formattedValue}${separator}${unit.symbol}`;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// src/roles/temperature/constants.ts
|
|
433
|
+
var TEMPERATURE_UNITS = {
|
|
434
|
+
celsius: {
|
|
435
|
+
symbol: "\xB0C",
|
|
436
|
+
singular: "degree Celsius",
|
|
437
|
+
plural: "degrees Celsius",
|
|
438
|
+
toBase: (c) => c,
|
|
439
|
+
fromBase: (c) => c,
|
|
440
|
+
noSpace: true
|
|
441
|
+
// 25°C não 25 °C
|
|
442
|
+
},
|
|
443
|
+
fahrenheit: {
|
|
444
|
+
symbol: "\xB0F",
|
|
445
|
+
singular: "degree Fahrenheit",
|
|
446
|
+
plural: "degrees Fahrenheit",
|
|
447
|
+
toBase: (f) => (f - 32) * (5 / 9),
|
|
448
|
+
fromBase: (c) => c * (9 / 5) + 32,
|
|
449
|
+
noSpace: true
|
|
450
|
+
// 77°F não 77 °F
|
|
451
|
+
},
|
|
452
|
+
kelvin: {
|
|
453
|
+
symbol: "K",
|
|
454
|
+
singular: "kelvin",
|
|
455
|
+
plural: "kelvins",
|
|
456
|
+
toBase: (k) => k - 273.15,
|
|
457
|
+
fromBase: (c) => c + 273.15
|
|
458
|
+
// Kelvin usa espaço: "273 K" (convenção SI)
|
|
459
|
+
},
|
|
460
|
+
rankine: {
|
|
461
|
+
symbol: "\xB0R",
|
|
462
|
+
singular: "degree Rankine",
|
|
463
|
+
plural: "degrees Rankine",
|
|
464
|
+
toBase: (r) => (r - 491.67) * (5 / 9),
|
|
465
|
+
fromBase: (c) => (c + 273.15) * (9 / 5),
|
|
466
|
+
noSpace: true
|
|
467
|
+
// 500°R não 500 °R
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
// src/roles/temperature/format.ts
|
|
472
|
+
function formatTemperature(variant, value, options = {}) {
|
|
473
|
+
const { decimals = 2, verbose = false, locale, notation } = options;
|
|
474
|
+
const unit = TEMPERATURE_UNITS[variant];
|
|
475
|
+
if (!unit) {
|
|
476
|
+
throw new Error(`Unknown temperature variant: ${variant}`);
|
|
477
|
+
}
|
|
478
|
+
let formattedValue;
|
|
479
|
+
if (locale) {
|
|
480
|
+
const formatOptions = {
|
|
481
|
+
minimumFractionDigits: 0,
|
|
482
|
+
maximumFractionDigits: decimals
|
|
483
|
+
};
|
|
484
|
+
if (notation) {
|
|
485
|
+
formatOptions.notation = notation;
|
|
486
|
+
}
|
|
487
|
+
formattedValue = value.toLocaleString(locale, formatOptions);
|
|
488
|
+
} else {
|
|
489
|
+
formattedValue = Number(value.toFixed(decimals)).toString();
|
|
490
|
+
}
|
|
491
|
+
const separator = unit.noSpace ? "" : " ";
|
|
492
|
+
if (verbose) {
|
|
493
|
+
const name = value === 1 ? unit.singular : unit.plural;
|
|
494
|
+
return `${formattedValue} ${name || unit.symbol}`;
|
|
495
|
+
}
|
|
496
|
+
return `${formattedValue}${separator}${unit.symbol}`;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// src/roles/volume/constants.ts
|
|
500
|
+
var VOLUME_UNITS = {
|
|
501
|
+
// SI / Métrico
|
|
502
|
+
cubic_meter: {
|
|
503
|
+
factor: 1e3,
|
|
504
|
+
symbol: "m\xB3",
|
|
505
|
+
singular: "cubic meter",
|
|
506
|
+
plural: "cubic meters"
|
|
507
|
+
},
|
|
508
|
+
cubic_decimeter: {
|
|
509
|
+
factor: 1,
|
|
510
|
+
symbol: "dm\xB3",
|
|
511
|
+
singular: "cubic decimeter",
|
|
512
|
+
plural: "cubic decimeters"
|
|
513
|
+
},
|
|
514
|
+
cubic_centimeter: {
|
|
515
|
+
factor: 1e-3,
|
|
516
|
+
symbol: "cm\xB3",
|
|
517
|
+
singular: "cubic centimeter",
|
|
518
|
+
plural: "cubic centimeters"
|
|
519
|
+
},
|
|
520
|
+
cubic_millimeter: {
|
|
521
|
+
factor: 1e-6,
|
|
522
|
+
symbol: "mm\xB3",
|
|
523
|
+
singular: "cubic millimeter",
|
|
524
|
+
plural: "cubic millimeters"
|
|
525
|
+
},
|
|
526
|
+
hectoliter: {
|
|
527
|
+
factor: 100,
|
|
528
|
+
symbol: "hL",
|
|
529
|
+
singular: "hectoliter",
|
|
530
|
+
plural: "hectoliters"
|
|
531
|
+
},
|
|
532
|
+
decaliter: {
|
|
533
|
+
factor: 10,
|
|
534
|
+
symbol: "daL",
|
|
535
|
+
singular: "decaliter",
|
|
536
|
+
plural: "decaliters"
|
|
537
|
+
},
|
|
538
|
+
liter: {
|
|
539
|
+
factor: 1,
|
|
540
|
+
symbol: "L",
|
|
541
|
+
singular: "liter",
|
|
542
|
+
plural: "liters"
|
|
543
|
+
},
|
|
544
|
+
deciliter: {
|
|
545
|
+
factor: 0.1,
|
|
546
|
+
symbol: "dL",
|
|
547
|
+
singular: "deciliter",
|
|
548
|
+
plural: "deciliters"
|
|
549
|
+
},
|
|
550
|
+
centiliter: {
|
|
551
|
+
factor: 0.01,
|
|
552
|
+
symbol: "cL",
|
|
553
|
+
singular: "centiliter",
|
|
554
|
+
plural: "centiliters"
|
|
555
|
+
},
|
|
556
|
+
milliliter: {
|
|
557
|
+
factor: 1e-3,
|
|
558
|
+
symbol: "mL",
|
|
559
|
+
singular: "milliliter",
|
|
560
|
+
plural: "milliliters"
|
|
561
|
+
},
|
|
562
|
+
microliter: {
|
|
563
|
+
factor: 1e-6,
|
|
564
|
+
symbol: "\u03BCL",
|
|
565
|
+
singular: "microliter",
|
|
566
|
+
plural: "microliters"
|
|
567
|
+
},
|
|
568
|
+
// US Customary (baseado em 1 gallon = 231 in³ = 3.785411784 L)
|
|
569
|
+
gallon_us: {
|
|
570
|
+
factor: 3.785411784,
|
|
571
|
+
symbol: "gal",
|
|
572
|
+
singular: "gallon",
|
|
573
|
+
plural: "gallons"
|
|
574
|
+
},
|
|
575
|
+
quart_us: {
|
|
576
|
+
factor: 0.946352946,
|
|
577
|
+
// gallon/4
|
|
578
|
+
symbol: "qt",
|
|
579
|
+
singular: "quart",
|
|
580
|
+
plural: "quarts"
|
|
581
|
+
},
|
|
582
|
+
pint_us: {
|
|
583
|
+
factor: 0.473176473,
|
|
584
|
+
// gallon/8
|
|
585
|
+
symbol: "pt",
|
|
586
|
+
singular: "pint",
|
|
587
|
+
plural: "pints"
|
|
588
|
+
},
|
|
589
|
+
cup_us: {
|
|
590
|
+
factor: 0.2365882365,
|
|
591
|
+
// gallon/16
|
|
592
|
+
symbol: "cup",
|
|
593
|
+
singular: "cup",
|
|
594
|
+
plural: "cups"
|
|
595
|
+
},
|
|
596
|
+
fluid_ounce_us: {
|
|
597
|
+
factor: 0.0295735295625,
|
|
598
|
+
// gallon/128
|
|
599
|
+
symbol: "fl oz",
|
|
600
|
+
singular: "fluid ounce",
|
|
601
|
+
plural: "fluid ounces"
|
|
602
|
+
},
|
|
603
|
+
tablespoon_us: {
|
|
604
|
+
factor: 0.01478676478125,
|
|
605
|
+
// fl oz/2
|
|
606
|
+
symbol: "tbsp",
|
|
607
|
+
singular: "tablespoon",
|
|
608
|
+
plural: "tablespoons"
|
|
609
|
+
},
|
|
610
|
+
teaspoon_us: {
|
|
611
|
+
factor: 0.00492892159375,
|
|
612
|
+
// tbsp/3
|
|
613
|
+
symbol: "tsp",
|
|
614
|
+
singular: "teaspoon",
|
|
615
|
+
plural: "teaspoons"
|
|
616
|
+
},
|
|
617
|
+
// Imperial UK (1 gallon UK = 4.54609 L exato)
|
|
618
|
+
gallon_uk: {
|
|
619
|
+
factor: 4.54609,
|
|
620
|
+
symbol: "gal (UK)",
|
|
621
|
+
singular: "gallon (UK)",
|
|
622
|
+
plural: "gallons (UK)"
|
|
623
|
+
},
|
|
624
|
+
quart_uk: {
|
|
625
|
+
factor: 1.1365225,
|
|
626
|
+
// gallon/4
|
|
627
|
+
symbol: "qt (UK)",
|
|
628
|
+
singular: "quart (UK)",
|
|
629
|
+
plural: "quarts (UK)"
|
|
630
|
+
},
|
|
631
|
+
pint_uk: {
|
|
632
|
+
factor: 0.56826125,
|
|
633
|
+
// gallon/8
|
|
634
|
+
symbol: "pt (UK)",
|
|
635
|
+
singular: "pint (UK)",
|
|
636
|
+
plural: "pints (UK)"
|
|
637
|
+
},
|
|
638
|
+
fluid_ounce_uk: {
|
|
639
|
+
factor: 0.0284130625,
|
|
640
|
+
// gallon/160
|
|
641
|
+
symbol: "fl oz (UK)",
|
|
642
|
+
singular: "fluid ounce (UK)",
|
|
643
|
+
plural: "fluid ounces (UK)"
|
|
644
|
+
},
|
|
645
|
+
// Other
|
|
646
|
+
barrel_oil: {
|
|
647
|
+
factor: 158.987294928,
|
|
648
|
+
// 42 US gallons (petroleum)
|
|
649
|
+
symbol: "bbl",
|
|
650
|
+
singular: "barrel",
|
|
651
|
+
plural: "barrels"
|
|
652
|
+
},
|
|
653
|
+
cubic_inch: {
|
|
654
|
+
factor: 0.016387064,
|
|
655
|
+
// (0.0254)³ × 1000
|
|
656
|
+
symbol: "in\xB3",
|
|
657
|
+
singular: "cubic inch",
|
|
658
|
+
plural: "cubic inches"
|
|
659
|
+
},
|
|
660
|
+
cubic_foot: {
|
|
661
|
+
factor: 28.316846592,
|
|
662
|
+
// (0.3048)³ × 1000
|
|
663
|
+
symbol: "ft\xB3",
|
|
664
|
+
singular: "cubic foot",
|
|
665
|
+
plural: "cubic feet"
|
|
666
|
+
},
|
|
667
|
+
cubic_yard: {
|
|
668
|
+
factor: 764.554857984,
|
|
669
|
+
// (0.9144)³ × 1000
|
|
670
|
+
symbol: "yd\xB3",
|
|
671
|
+
singular: "cubic yard",
|
|
672
|
+
plural: "cubic yards"
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
Object.fromEntries(
|
|
676
|
+
Object.entries(VOLUME_UNITS).map(([unit, config]) => [
|
|
677
|
+
unit,
|
|
678
|
+
config.factor ?? 1
|
|
679
|
+
])
|
|
680
|
+
);
|
|
681
|
+
|
|
682
|
+
// src/roles/volume/format.ts
|
|
683
|
+
function formatVolume(variant, value, options = {}) {
|
|
684
|
+
const { decimals = 2, verbose = false, locale, notation } = options;
|
|
685
|
+
const unit = VOLUME_UNITS[variant];
|
|
686
|
+
if (!unit) {
|
|
687
|
+
throw new Error(`Unknown volume variant: ${variant}`);
|
|
688
|
+
}
|
|
689
|
+
let formattedValue;
|
|
690
|
+
if (locale) {
|
|
691
|
+
const formatOptions = {
|
|
692
|
+
minimumFractionDigits: 0,
|
|
693
|
+
maximumFractionDigits: decimals
|
|
694
|
+
};
|
|
695
|
+
if (notation) {
|
|
696
|
+
formatOptions.notation = notation;
|
|
697
|
+
}
|
|
698
|
+
formattedValue = value.toLocaleString(locale, formatOptions);
|
|
699
|
+
} else {
|
|
700
|
+
formattedValue = Number(value.toFixed(decimals)).toString();
|
|
701
|
+
}
|
|
702
|
+
const separator = unit.noSpace ? "" : " ";
|
|
703
|
+
if (verbose) {
|
|
704
|
+
const name = value === 1 ? unit.singular : unit.plural;
|
|
705
|
+
return `${formattedValue} ${name || unit.symbol}`;
|
|
706
|
+
}
|
|
707
|
+
return `${formattedValue}${separator}${unit.symbol}`;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// src/roles/speed/constants.ts
|
|
711
|
+
var SPEED_UNITS = {
|
|
712
|
+
// SI Units
|
|
713
|
+
meter_per_second: {
|
|
714
|
+
factor: 1,
|
|
715
|
+
symbol: "m/s",
|
|
716
|
+
singular: "meter per second",
|
|
717
|
+
plural: "meters per second"
|
|
718
|
+
},
|
|
719
|
+
kilometer_per_hour: {
|
|
720
|
+
factor: 1e3 / 3600,
|
|
721
|
+
// 0.277777...
|
|
722
|
+
symbol: "km/h",
|
|
723
|
+
singular: "kilometer per hour",
|
|
724
|
+
plural: "kilometers per hour"
|
|
725
|
+
},
|
|
726
|
+
// Imperial/US (exatos desde 1959)
|
|
727
|
+
mile_per_hour: {
|
|
728
|
+
factor: 0.44704,
|
|
729
|
+
// 1609.344 / 3600 (exato)
|
|
730
|
+
symbol: "mph",
|
|
731
|
+
singular: "mile per hour",
|
|
732
|
+
plural: "miles per hour"
|
|
733
|
+
},
|
|
734
|
+
foot_per_second: {
|
|
735
|
+
factor: 0.3048,
|
|
736
|
+
// exato
|
|
737
|
+
symbol: "ft/s",
|
|
738
|
+
singular: "foot per second",
|
|
739
|
+
plural: "feet per second"
|
|
740
|
+
},
|
|
741
|
+
// Nautical (exato)
|
|
742
|
+
knot: {
|
|
743
|
+
factor: 1852 / 3600,
|
|
744
|
+
// 0.514444...
|
|
745
|
+
symbol: "kn",
|
|
746
|
+
singular: "knot",
|
|
747
|
+
plural: "knots"
|
|
748
|
+
},
|
|
749
|
+
// Scientific
|
|
750
|
+
mach: {
|
|
751
|
+
factor: 340.29,
|
|
752
|
+
// velocidade do som ao nível do mar, 15°C (aproximado)
|
|
753
|
+
symbol: "Ma",
|
|
754
|
+
singular: "mach",
|
|
755
|
+
plural: "mach"
|
|
756
|
+
},
|
|
757
|
+
speed_of_light: {
|
|
758
|
+
factor: 299792458,
|
|
759
|
+
// exato por definição SI
|
|
760
|
+
symbol: "c",
|
|
761
|
+
singular: "speed of light",
|
|
762
|
+
plural: "speed of light"
|
|
763
|
+
}
|
|
764
|
+
};
|
|
765
|
+
Object.fromEntries(
|
|
766
|
+
Object.entries(SPEED_UNITS).map(([unit, config]) => [
|
|
767
|
+
unit,
|
|
768
|
+
config.factor ?? 1
|
|
769
|
+
])
|
|
770
|
+
);
|
|
771
|
+
|
|
772
|
+
// src/roles/speed/format.ts
|
|
773
|
+
function formatSpeed(variant, value, options = {}) {
|
|
774
|
+
const { decimals = 2, verbose = false, locale, notation } = options;
|
|
775
|
+
const unit = SPEED_UNITS[variant];
|
|
776
|
+
if (!unit) {
|
|
777
|
+
throw new Error(`Unknown speed variant: ${variant}`);
|
|
778
|
+
}
|
|
779
|
+
let formattedValue;
|
|
780
|
+
if (locale) {
|
|
781
|
+
const formatOptions = {
|
|
782
|
+
minimumFractionDigits: 0,
|
|
783
|
+
maximumFractionDigits: decimals
|
|
784
|
+
};
|
|
785
|
+
if (notation) {
|
|
786
|
+
formatOptions.notation = notation;
|
|
787
|
+
}
|
|
788
|
+
formattedValue = value.toLocaleString(locale, formatOptions);
|
|
789
|
+
} else {
|
|
790
|
+
formattedValue = Number(value.toFixed(decimals)).toString();
|
|
791
|
+
}
|
|
792
|
+
const separator = unit.noSpace ? "" : " ";
|
|
793
|
+
if (verbose) {
|
|
794
|
+
const name = value === 1 ? unit.singular : unit.plural;
|
|
795
|
+
return `${formattedValue} ${name || unit.symbol}`;
|
|
796
|
+
}
|
|
797
|
+
return `${formattedValue}${separator}${unit.symbol}`;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// src/roles/energy/constants.ts
|
|
801
|
+
var ENERGY_UNITS = {
|
|
802
|
+
// SI Units (todos exatos)
|
|
803
|
+
gigajoule: {
|
|
804
|
+
factor: 1e9,
|
|
805
|
+
symbol: "GJ",
|
|
806
|
+
singular: "gigajoule",
|
|
807
|
+
plural: "gigajoules"
|
|
808
|
+
},
|
|
809
|
+
megajoule: {
|
|
810
|
+
factor: 1e6,
|
|
811
|
+
symbol: "MJ",
|
|
812
|
+
singular: "megajoule",
|
|
813
|
+
plural: "megajoules"
|
|
814
|
+
},
|
|
815
|
+
kilojoule: {
|
|
816
|
+
factor: 1e3,
|
|
817
|
+
symbol: "kJ",
|
|
818
|
+
singular: "kilojoule",
|
|
819
|
+
plural: "kilojoules"
|
|
820
|
+
},
|
|
821
|
+
joule: {
|
|
822
|
+
factor: 1,
|
|
823
|
+
symbol: "J",
|
|
824
|
+
singular: "joule",
|
|
825
|
+
plural: "joules"
|
|
826
|
+
},
|
|
827
|
+
millijoule: {
|
|
828
|
+
factor: 1e-3,
|
|
829
|
+
symbol: "mJ",
|
|
830
|
+
singular: "millijoule",
|
|
831
|
+
plural: "millijoules"
|
|
832
|
+
},
|
|
833
|
+
// Calories (International Table - IT)
|
|
834
|
+
// 1 cal (IT) = 4.1868 J (exato por definição)
|
|
835
|
+
calorie: {
|
|
836
|
+
factor: 4.1868,
|
|
837
|
+
symbol: "cal",
|
|
838
|
+
singular: "calorie",
|
|
839
|
+
plural: "calories"
|
|
840
|
+
},
|
|
841
|
+
// 1 kcal = 1000 cal = 4186.8 J (= 1 "food Calorie")
|
|
842
|
+
kilocalorie: {
|
|
843
|
+
factor: 4186.8,
|
|
844
|
+
symbol: "kcal",
|
|
845
|
+
singular: "kilocalorie",
|
|
846
|
+
plural: "kilocalories"
|
|
847
|
+
},
|
|
848
|
+
// Watt-hour (exatos)
|
|
849
|
+
// 1 Wh = 1 W × 3600 s = 3600 J
|
|
850
|
+
watt_hour: {
|
|
851
|
+
factor: 3600,
|
|
852
|
+
symbol: "Wh",
|
|
853
|
+
singular: "watt-hour",
|
|
854
|
+
plural: "watt-hours"
|
|
855
|
+
},
|
|
856
|
+
kilowatt_hour: {
|
|
857
|
+
factor: 36e5,
|
|
858
|
+
symbol: "kWh",
|
|
859
|
+
singular: "kilowatt-hour",
|
|
860
|
+
plural: "kilowatt-hours"
|
|
861
|
+
},
|
|
862
|
+
megawatt_hour: {
|
|
863
|
+
factor: 36e8,
|
|
864
|
+
symbol: "MWh",
|
|
865
|
+
singular: "megawatt-hour",
|
|
866
|
+
plural: "megawatt-hours"
|
|
867
|
+
},
|
|
868
|
+
gigawatt_hour: {
|
|
869
|
+
factor: 36e11,
|
|
870
|
+
symbol: "GWh",
|
|
871
|
+
singular: "gigawatt-hour",
|
|
872
|
+
plural: "gigawatt-hours"
|
|
873
|
+
},
|
|
874
|
+
// BTU (International Table)
|
|
875
|
+
// 1 BTU (IT) = 1055.05585262 J (definição)
|
|
876
|
+
btu: {
|
|
877
|
+
factor: 1055.05585262,
|
|
878
|
+
symbol: "BTU",
|
|
879
|
+
singular: "BTU",
|
|
880
|
+
plural: "BTUs"
|
|
881
|
+
},
|
|
882
|
+
// 1 therm = 100,000 BTU (IT)
|
|
883
|
+
therm: {
|
|
884
|
+
factor: 105505585262e-3,
|
|
885
|
+
symbol: "thm",
|
|
886
|
+
singular: "therm",
|
|
887
|
+
plural: "therms"
|
|
888
|
+
},
|
|
889
|
+
// Scientific
|
|
890
|
+
// 1 eV = 1.602176634e-19 J (SI 2019, exato por definição)
|
|
891
|
+
electronvolt: {
|
|
892
|
+
factor: 1602176634e-28,
|
|
893
|
+
symbol: "eV",
|
|
894
|
+
singular: "electronvolt",
|
|
895
|
+
plural: "electronvolts"
|
|
896
|
+
},
|
|
897
|
+
kiloelectronvolt: {
|
|
898
|
+
factor: 1602176634e-25,
|
|
899
|
+
symbol: "keV",
|
|
900
|
+
singular: "kiloelectronvolt",
|
|
901
|
+
plural: "kiloelectronvolts"
|
|
902
|
+
},
|
|
903
|
+
megaelectronvolt: {
|
|
904
|
+
factor: 1602176634e-22,
|
|
905
|
+
symbol: "MeV",
|
|
906
|
+
singular: "megaelectronvolt",
|
|
907
|
+
plural: "megaelectronvolts"
|
|
908
|
+
},
|
|
909
|
+
// 1 erg = 1e-7 J (CGS, exato)
|
|
910
|
+
erg: {
|
|
911
|
+
factor: 1e-7,
|
|
912
|
+
symbol: "erg",
|
|
913
|
+
singular: "erg",
|
|
914
|
+
plural: "ergs"
|
|
915
|
+
},
|
|
916
|
+
// Mechanical
|
|
917
|
+
// 1 ft⋅lbf = 1.3558179483314004 J (derivado de foot e pound-force)
|
|
918
|
+
foot_pound: {
|
|
919
|
+
factor: 1.3558179483314003,
|
|
920
|
+
symbol: "ft\u22C5lbf",
|
|
921
|
+
singular: "foot-pound",
|
|
922
|
+
plural: "foot-pounds"
|
|
923
|
+
}
|
|
924
|
+
};
|
|
925
|
+
Object.fromEntries(
|
|
926
|
+
Object.entries(ENERGY_UNITS).map(([unit, config]) => [
|
|
927
|
+
unit,
|
|
928
|
+
config.factor ?? 1
|
|
929
|
+
])
|
|
930
|
+
);
|
|
931
|
+
|
|
932
|
+
// src/roles/energy/format.ts
|
|
933
|
+
function formatEnergy(variant, value, options = {}) {
|
|
934
|
+
const { decimals = 2, verbose = false, locale, notation } = options;
|
|
935
|
+
const unit = ENERGY_UNITS[variant];
|
|
936
|
+
if (!unit) {
|
|
937
|
+
throw new Error(`Unknown energy variant: ${variant}`);
|
|
938
|
+
}
|
|
939
|
+
let formattedValue;
|
|
940
|
+
if (locale) {
|
|
941
|
+
const formatOptions = {
|
|
942
|
+
minimumFractionDigits: 0,
|
|
943
|
+
maximumFractionDigits: decimals
|
|
944
|
+
};
|
|
945
|
+
if (notation) {
|
|
946
|
+
formatOptions.notation = notation;
|
|
947
|
+
}
|
|
948
|
+
formattedValue = value.toLocaleString(locale, formatOptions);
|
|
949
|
+
} else {
|
|
950
|
+
formattedValue = Number(value.toFixed(decimals)).toString();
|
|
951
|
+
}
|
|
952
|
+
const separator = unit.noSpace ? "" : " ";
|
|
953
|
+
if (verbose) {
|
|
954
|
+
const name = value === 1 ? unit.singular : unit.plural;
|
|
955
|
+
return `${formattedValue} ${name || unit.symbol}`;
|
|
956
|
+
}
|
|
957
|
+
return `${formattedValue}${separator}${unit.symbol}`;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
// src/roles/power/constants.ts
|
|
961
|
+
var POWER_UNITS = {
|
|
962
|
+
// SI Units (todos exatos)
|
|
963
|
+
gigawatt: {
|
|
964
|
+
factor: 1e9,
|
|
965
|
+
symbol: "GW",
|
|
966
|
+
singular: "gigawatt",
|
|
967
|
+
plural: "gigawatts"
|
|
968
|
+
},
|
|
969
|
+
megawatt: {
|
|
970
|
+
factor: 1e6,
|
|
971
|
+
symbol: "MW",
|
|
972
|
+
singular: "megawatt",
|
|
973
|
+
plural: "megawatts"
|
|
974
|
+
},
|
|
975
|
+
kilowatt: {
|
|
976
|
+
factor: 1e3,
|
|
977
|
+
symbol: "kW",
|
|
978
|
+
singular: "kilowatt",
|
|
979
|
+
plural: "kilowatts"
|
|
980
|
+
},
|
|
981
|
+
watt: {
|
|
982
|
+
factor: 1,
|
|
983
|
+
symbol: "W",
|
|
984
|
+
singular: "watt",
|
|
985
|
+
plural: "watts"
|
|
986
|
+
},
|
|
987
|
+
milliwatt: {
|
|
988
|
+
factor: 1e-3,
|
|
989
|
+
symbol: "mW",
|
|
990
|
+
singular: "milliwatt",
|
|
991
|
+
plural: "milliwatts"
|
|
992
|
+
},
|
|
993
|
+
microwatt: {
|
|
994
|
+
factor: 1e-6,
|
|
995
|
+
symbol: "\u03BCW",
|
|
996
|
+
singular: "microwatt",
|
|
997
|
+
plural: "microwatts"
|
|
998
|
+
},
|
|
999
|
+
// Horsepower variants
|
|
1000
|
+
// Mechanical (imperial): 550 ft⋅lbf/s
|
|
1001
|
+
// = 550 × 0.3048 m × 4.4482216152605 N / s = 745.69987158227 W
|
|
1002
|
+
horsepower_mechanical: {
|
|
1003
|
+
factor: 745.69987158227,
|
|
1004
|
+
symbol: "hp",
|
|
1005
|
+
singular: "horsepower",
|
|
1006
|
+
plural: "horsepower"
|
|
1007
|
+
},
|
|
1008
|
+
// Metric (PS, CV, pk): 75 kgf⋅m/s = 75 × 9.80665 W = 735.49875 W (exato)
|
|
1009
|
+
horsepower_metric: {
|
|
1010
|
+
factor: 735.49875,
|
|
1011
|
+
symbol: "PS",
|
|
1012
|
+
singular: "metric horsepower",
|
|
1013
|
+
plural: "metric horsepower"
|
|
1014
|
+
},
|
|
1015
|
+
// Electrical: 746 W (exato por definição)
|
|
1016
|
+
horsepower_electric: {
|
|
1017
|
+
factor: 746,
|
|
1018
|
+
symbol: "hp(E)",
|
|
1019
|
+
singular: "electric horsepower",
|
|
1020
|
+
plural: "electric horsepower"
|
|
1021
|
+
},
|
|
1022
|
+
// Boiler: 33,475 BTU/h = 9809.5 W
|
|
1023
|
+
horsepower_boiler: {
|
|
1024
|
+
factor: 9809.5,
|
|
1025
|
+
symbol: "hp(S)",
|
|
1026
|
+
singular: "boiler horsepower",
|
|
1027
|
+
plural: "boiler horsepower"
|
|
1028
|
+
},
|
|
1029
|
+
// BTU-based
|
|
1030
|
+
// 1 BTU/h = 1055.05585262 J / 3600 s = 0.29307107017222 W
|
|
1031
|
+
btu_per_hour: {
|
|
1032
|
+
factor: 0.29307107017222,
|
|
1033
|
+
symbol: "BTU/h",
|
|
1034
|
+
singular: "BTU per hour",
|
|
1035
|
+
plural: "BTUs per hour"
|
|
1036
|
+
},
|
|
1037
|
+
// 1 BTU/s = 1055.05585262 W
|
|
1038
|
+
btu_per_second: {
|
|
1039
|
+
factor: 1055.05585262,
|
|
1040
|
+
symbol: "BTU/s",
|
|
1041
|
+
singular: "BTU per second",
|
|
1042
|
+
plural: "BTUs per second"
|
|
1043
|
+
},
|
|
1044
|
+
// Other
|
|
1045
|
+
// 1 ton of refrigeration = 12000 BTU/h = 3516.8528420667 W
|
|
1046
|
+
ton_of_refrigeration: {
|
|
1047
|
+
factor: 3516.8528420667,
|
|
1048
|
+
symbol: "TR",
|
|
1049
|
+
singular: "ton of refrigeration",
|
|
1050
|
+
plural: "tons of refrigeration"
|
|
1051
|
+
},
|
|
1052
|
+
// 1 ft⋅lbf/s = 1.3558179483314004 W
|
|
1053
|
+
foot_pound_per_second: {
|
|
1054
|
+
factor: 1.3558179483314003,
|
|
1055
|
+
symbol: "ft\u22C5lbf/s",
|
|
1056
|
+
singular: "foot-pound per second",
|
|
1057
|
+
plural: "foot-pounds per second"
|
|
1058
|
+
},
|
|
1059
|
+
// 1 cal/s = 4.1868 W
|
|
1060
|
+
calorie_per_second: {
|
|
1061
|
+
factor: 4.1868,
|
|
1062
|
+
symbol: "cal/s",
|
|
1063
|
+
singular: "calorie per second",
|
|
1064
|
+
plural: "calories per second"
|
|
1065
|
+
},
|
|
1066
|
+
// 1 kcal/h = 4186.8 / 3600 = 1.163 W
|
|
1067
|
+
kilocalorie_per_hour: {
|
|
1068
|
+
factor: 1.163,
|
|
1069
|
+
symbol: "kcal/h",
|
|
1070
|
+
singular: "kilocalorie per hour",
|
|
1071
|
+
plural: "kilocalories per hour"
|
|
1072
|
+
}
|
|
1073
|
+
};
|
|
1074
|
+
Object.fromEntries(
|
|
1075
|
+
Object.entries(POWER_UNITS).map(([unit, config]) => [
|
|
1076
|
+
unit,
|
|
1077
|
+
config.factor ?? 1
|
|
1078
|
+
])
|
|
1079
|
+
);
|
|
1080
|
+
|
|
1081
|
+
// src/roles/power/format.ts
|
|
1082
|
+
function formatPower(variant, value, options = {}) {
|
|
1083
|
+
const config = POWER_UNITS[variant];
|
|
1084
|
+
if (!config) {
|
|
1085
|
+
throw new Error(`Unknown power unit: ${variant}`);
|
|
1086
|
+
}
|
|
1087
|
+
const { decimals, verbose = false, locale, notation = "standard" } = options;
|
|
1088
|
+
let formattedNumber;
|
|
1089
|
+
if (locale || notation !== "standard") {
|
|
1090
|
+
const intlOptions = { notation };
|
|
1091
|
+
if (decimals !== void 0) {
|
|
1092
|
+
intlOptions.minimumFractionDigits = decimals;
|
|
1093
|
+
intlOptions.maximumFractionDigits = decimals;
|
|
1094
|
+
}
|
|
1095
|
+
formattedNumber = new Intl.NumberFormat(locale, intlOptions).format(value);
|
|
1096
|
+
} else if (decimals !== void 0) {
|
|
1097
|
+
formattedNumber = value.toFixed(decimals);
|
|
1098
|
+
} else {
|
|
1099
|
+
formattedNumber = Number(value.toPrecision(12)).toString();
|
|
1100
|
+
}
|
|
1101
|
+
const unitLabel = verbose ? value === 1 ? config.singular : config.plural : config.symbol;
|
|
1102
|
+
return `${formattedNumber} ${unitLabel}`;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
// src/roles/pressure/constants.ts
|
|
1106
|
+
var PRESSURE_UNITS = {
|
|
1107
|
+
// SI Units (todos exatos)
|
|
1108
|
+
megapascal: {
|
|
1109
|
+
factor: 1e6,
|
|
1110
|
+
symbol: "MPa",
|
|
1111
|
+
singular: "megapascal",
|
|
1112
|
+
plural: "megapascals"
|
|
1113
|
+
},
|
|
1114
|
+
kilopascal: {
|
|
1115
|
+
factor: 1e3,
|
|
1116
|
+
symbol: "kPa",
|
|
1117
|
+
singular: "kilopascal",
|
|
1118
|
+
plural: "kilopascals"
|
|
1119
|
+
},
|
|
1120
|
+
hectopascal: {
|
|
1121
|
+
factor: 100,
|
|
1122
|
+
symbol: "hPa",
|
|
1123
|
+
singular: "hectopascal",
|
|
1124
|
+
plural: "hectopascals"
|
|
1125
|
+
},
|
|
1126
|
+
pascal: {
|
|
1127
|
+
factor: 1,
|
|
1128
|
+
symbol: "Pa",
|
|
1129
|
+
singular: "pascal",
|
|
1130
|
+
plural: "pascals"
|
|
1131
|
+
},
|
|
1132
|
+
// Bar (exatos por definição)
|
|
1133
|
+
bar: {
|
|
1134
|
+
factor: 1e5,
|
|
1135
|
+
symbol: "bar",
|
|
1136
|
+
singular: "bar",
|
|
1137
|
+
plural: "bar"
|
|
1138
|
+
},
|
|
1139
|
+
millibar: {
|
|
1140
|
+
factor: 100,
|
|
1141
|
+
// = 1 hPa
|
|
1142
|
+
symbol: "mbar",
|
|
1143
|
+
singular: "millibar",
|
|
1144
|
+
plural: "millibar"
|
|
1145
|
+
},
|
|
1146
|
+
// Atmosphere (exato, CGPM 1954)
|
|
1147
|
+
atmosphere: {
|
|
1148
|
+
factor: 101325,
|
|
1149
|
+
symbol: "atm",
|
|
1150
|
+
singular: "atmosphere",
|
|
1151
|
+
plural: "atmospheres"
|
|
1152
|
+
},
|
|
1153
|
+
// Mercury column
|
|
1154
|
+
torr: {
|
|
1155
|
+
factor: 101325 / 760,
|
|
1156
|
+
// ≈ 133.322368421
|
|
1157
|
+
symbol: "Torr",
|
|
1158
|
+
singular: "torr",
|
|
1159
|
+
plural: "torr"
|
|
1160
|
+
},
|
|
1161
|
+
mmhg: {
|
|
1162
|
+
factor: 133.322387415,
|
|
1163
|
+
// Convenção NIST
|
|
1164
|
+
symbol: "mmHg",
|
|
1165
|
+
singular: "millimeter of mercury",
|
|
1166
|
+
plural: "millimeters of mercury"
|
|
1167
|
+
},
|
|
1168
|
+
inhg: {
|
|
1169
|
+
factor: 3386.389,
|
|
1170
|
+
// Polegadas de mercúrio
|
|
1171
|
+
symbol: "inHg",
|
|
1172
|
+
singular: "inch of mercury",
|
|
1173
|
+
plural: "inches of mercury"
|
|
1174
|
+
},
|
|
1175
|
+
// Imperial (derivados de lb/in²)
|
|
1176
|
+
psi: {
|
|
1177
|
+
factor: 6894.757293168,
|
|
1178
|
+
// 1 lbf/in²
|
|
1179
|
+
symbol: "psi",
|
|
1180
|
+
singular: "pound per square inch",
|
|
1181
|
+
plural: "pounds per square inch"
|
|
1182
|
+
},
|
|
1183
|
+
ksi: {
|
|
1184
|
+
factor: 6894757293168e-6,
|
|
1185
|
+
// 1000 psi
|
|
1186
|
+
symbol: "ksi",
|
|
1187
|
+
singular: "kilopound per square inch",
|
|
1188
|
+
plural: "kilopounds per square inch"
|
|
1189
|
+
},
|
|
1190
|
+
// Water column
|
|
1191
|
+
cmh2o: {
|
|
1192
|
+
factor: 98.0665,
|
|
1193
|
+
// cm de água a 4°C
|
|
1194
|
+
symbol: "cmH\u2082O",
|
|
1195
|
+
singular: "centimeter of water",
|
|
1196
|
+
plural: "centimeters of water"
|
|
1197
|
+
},
|
|
1198
|
+
inh2o: {
|
|
1199
|
+
factor: 249.08891,
|
|
1200
|
+
// polegadas de água
|
|
1201
|
+
symbol: "inH\u2082O",
|
|
1202
|
+
singular: "inch of water",
|
|
1203
|
+
plural: "inches of water"
|
|
1204
|
+
}
|
|
1205
|
+
};
|
|
1206
|
+
Object.fromEntries(
|
|
1207
|
+
Object.entries(PRESSURE_UNITS).map(([unit, config]) => [
|
|
1208
|
+
unit,
|
|
1209
|
+
config.factor ?? 1
|
|
1210
|
+
])
|
|
1211
|
+
);
|
|
1212
|
+
|
|
1213
|
+
// src/roles/pressure/format.ts
|
|
1214
|
+
function formatPressure(variant, value, options = {}) {
|
|
1215
|
+
const config = PRESSURE_UNITS[variant];
|
|
1216
|
+
if (!config) {
|
|
1217
|
+
throw new Error(`Unknown pressure unit: ${variant}`);
|
|
1218
|
+
}
|
|
1219
|
+
const { decimals, verbose = false, locale, notation = "standard" } = options;
|
|
1220
|
+
let formattedNumber;
|
|
1221
|
+
if (locale || notation !== "standard") {
|
|
1222
|
+
const intlOptions = { notation };
|
|
1223
|
+
if (decimals !== void 0) {
|
|
1224
|
+
intlOptions.minimumFractionDigits = decimals;
|
|
1225
|
+
intlOptions.maximumFractionDigits = decimals;
|
|
1226
|
+
}
|
|
1227
|
+
formattedNumber = new Intl.NumberFormat(locale, intlOptions).format(value);
|
|
1228
|
+
} else if (decimals !== void 0) {
|
|
1229
|
+
formattedNumber = value.toFixed(decimals);
|
|
1230
|
+
} else {
|
|
1231
|
+
formattedNumber = Number(value.toPrecision(12)).toString();
|
|
1232
|
+
}
|
|
1233
|
+
const unitLabel = verbose ? value === 1 ? config.singular : config.plural : config.symbol;
|
|
1234
|
+
return `${formattedNumber} ${unitLabel}`;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
// src/roles/frequency/constants.ts
|
|
1238
|
+
var FREQUENCY_UNITS = {
|
|
1239
|
+
// SI Units (todos exatos)
|
|
1240
|
+
terahertz: {
|
|
1241
|
+
factor: 1e12,
|
|
1242
|
+
symbol: "THz",
|
|
1243
|
+
singular: "terahertz",
|
|
1244
|
+
plural: "terahertz"
|
|
1245
|
+
},
|
|
1246
|
+
gigahertz: {
|
|
1247
|
+
factor: 1e9,
|
|
1248
|
+
symbol: "GHz",
|
|
1249
|
+
singular: "gigahertz",
|
|
1250
|
+
plural: "gigahertz"
|
|
1251
|
+
},
|
|
1252
|
+
megahertz: {
|
|
1253
|
+
factor: 1e6,
|
|
1254
|
+
symbol: "MHz",
|
|
1255
|
+
singular: "megahertz",
|
|
1256
|
+
plural: "megahertz"
|
|
1257
|
+
},
|
|
1258
|
+
kilohertz: {
|
|
1259
|
+
factor: 1e3,
|
|
1260
|
+
symbol: "kHz",
|
|
1261
|
+
singular: "kilohertz",
|
|
1262
|
+
plural: "kilohertz"
|
|
1263
|
+
},
|
|
1264
|
+
hertz: {
|
|
1265
|
+
factor: 1,
|
|
1266
|
+
symbol: "Hz",
|
|
1267
|
+
singular: "hertz",
|
|
1268
|
+
plural: "hertz"
|
|
1269
|
+
},
|
|
1270
|
+
millihertz: {
|
|
1271
|
+
factor: 1e-3,
|
|
1272
|
+
symbol: "mHz",
|
|
1273
|
+
singular: "millihertz",
|
|
1274
|
+
plural: "millihertz"
|
|
1275
|
+
},
|
|
1276
|
+
microhertz: {
|
|
1277
|
+
factor: 1e-6,
|
|
1278
|
+
symbol: "\u03BCHz",
|
|
1279
|
+
singular: "microhertz",
|
|
1280
|
+
plural: "microhertz"
|
|
1281
|
+
},
|
|
1282
|
+
// Other units
|
|
1283
|
+
rpm: {
|
|
1284
|
+
factor: 1 / 60,
|
|
1285
|
+
// 1 RPM = 1/60 Hz
|
|
1286
|
+
symbol: "rpm",
|
|
1287
|
+
singular: "revolution per minute",
|
|
1288
|
+
plural: "revolutions per minute"
|
|
1289
|
+
},
|
|
1290
|
+
bpm: {
|
|
1291
|
+
factor: 1 / 60,
|
|
1292
|
+
// 1 BPM = 1/60 Hz
|
|
1293
|
+
symbol: "bpm",
|
|
1294
|
+
singular: "beat per minute",
|
|
1295
|
+
plural: "beats per minute"
|
|
1296
|
+
},
|
|
1297
|
+
radians_per_second: {
|
|
1298
|
+
factor: 1 / (2 * Math.PI),
|
|
1299
|
+
// 1 rad/s = 1/(2π) Hz ≈ 0.159154943
|
|
1300
|
+
symbol: "rad/s",
|
|
1301
|
+
singular: "radian per second",
|
|
1302
|
+
plural: "radians per second"
|
|
1303
|
+
},
|
|
1304
|
+
cycles_per_minute: {
|
|
1305
|
+
factor: 1 / 60,
|
|
1306
|
+
// same as RPM
|
|
1307
|
+
symbol: "cpm",
|
|
1308
|
+
singular: "cycle per minute",
|
|
1309
|
+
plural: "cycles per minute"
|
|
1310
|
+
}
|
|
1311
|
+
};
|
|
1312
|
+
Object.fromEntries(
|
|
1313
|
+
Object.entries(FREQUENCY_UNITS).map(([unit, config]) => [
|
|
1314
|
+
unit,
|
|
1315
|
+
config.factor ?? 1
|
|
1316
|
+
])
|
|
1317
|
+
);
|
|
1318
|
+
|
|
1319
|
+
// src/roles/frequency/format.ts
|
|
1320
|
+
function formatFrequency(variant, value, options = {}) {
|
|
1321
|
+
const config = FREQUENCY_UNITS[variant];
|
|
1322
|
+
if (!config) {
|
|
1323
|
+
throw new Error(`Unknown frequency unit: ${variant}`);
|
|
1324
|
+
}
|
|
1325
|
+
const { decimals, verbose = false, locale, notation = "standard" } = options;
|
|
1326
|
+
let formattedNumber;
|
|
1327
|
+
if (locale || notation !== "standard") {
|
|
1328
|
+
const intlOptions = { notation };
|
|
1329
|
+
if (decimals !== void 0) {
|
|
1330
|
+
intlOptions.minimumFractionDigits = decimals;
|
|
1331
|
+
intlOptions.maximumFractionDigits = decimals;
|
|
1332
|
+
}
|
|
1333
|
+
formattedNumber = new Intl.NumberFormat(locale, intlOptions).format(value);
|
|
1334
|
+
} else if (decimals !== void 0) {
|
|
1335
|
+
formattedNumber = value.toFixed(decimals);
|
|
1336
|
+
} else {
|
|
1337
|
+
formattedNumber = Number(value.toPrecision(12)).toString();
|
|
1338
|
+
}
|
|
1339
|
+
const unitLabel = verbose ? value === 1 ? config.singular : config.plural : config.symbol;
|
|
1340
|
+
return `${formattedNumber} ${unitLabel}`;
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
// src/roles/angle/constants.ts
|
|
1344
|
+
var DEGREES_PER_RADIAN = 180 / Math.PI;
|
|
1345
|
+
var DEGREES_PER_MILLIRADIAN = 180 / (1e3 * Math.PI);
|
|
1346
|
+
var ANGLE_UNITS = {
|
|
1347
|
+
// Volta completa
|
|
1348
|
+
turn: {
|
|
1349
|
+
factor: 360,
|
|
1350
|
+
symbol: "tr",
|
|
1351
|
+
singular: "turn",
|
|
1352
|
+
plural: "turns"
|
|
1353
|
+
},
|
|
1354
|
+
// Base
|
|
1355
|
+
degree: {
|
|
1356
|
+
factor: 1,
|
|
1357
|
+
symbol: "\xB0",
|
|
1358
|
+
singular: "degree",
|
|
1359
|
+
plural: "degrees",
|
|
1360
|
+
noSpace: true
|
|
1361
|
+
// 45° não 45 °
|
|
1362
|
+
},
|
|
1363
|
+
// Subdivisões do grau
|
|
1364
|
+
arcminute: {
|
|
1365
|
+
factor: 1 / 60,
|
|
1366
|
+
// 0.016666...
|
|
1367
|
+
symbol: "\u2032",
|
|
1368
|
+
singular: "arcminute",
|
|
1369
|
+
plural: "arcminutes",
|
|
1370
|
+
noSpace: true
|
|
1371
|
+
// 30′ não 30 ′
|
|
1372
|
+
},
|
|
1373
|
+
arcsecond: {
|
|
1374
|
+
factor: 1 / 3600,
|
|
1375
|
+
// 0.000277...
|
|
1376
|
+
symbol: "\u2033",
|
|
1377
|
+
singular: "arcsecond",
|
|
1378
|
+
plural: "arcseconds",
|
|
1379
|
+
noSpace: true
|
|
1380
|
+
// 45″ não 45 ″
|
|
1381
|
+
},
|
|
1382
|
+
milliarcsecond: {
|
|
1383
|
+
factor: 1 / 36e5,
|
|
1384
|
+
// 2.777...e-7
|
|
1385
|
+
symbol: "mas",
|
|
1386
|
+
singular: "milliarcsecond",
|
|
1387
|
+
plural: "milliarcseconds"
|
|
1388
|
+
},
|
|
1389
|
+
// Radianos (unidade SI)
|
|
1390
|
+
radian: {
|
|
1391
|
+
factor: DEGREES_PER_RADIAN,
|
|
1392
|
+
// 180/π ≈ 57.2958
|
|
1393
|
+
symbol: "rad",
|
|
1394
|
+
singular: "radian",
|
|
1395
|
+
plural: "radians"
|
|
1396
|
+
},
|
|
1397
|
+
milliradian: {
|
|
1398
|
+
factor: DEGREES_PER_MILLIRADIAN,
|
|
1399
|
+
// 180/(1000π) ≈ 0.0573
|
|
1400
|
+
symbol: "mrad",
|
|
1401
|
+
singular: "milliradian",
|
|
1402
|
+
plural: "milliradians"
|
|
1403
|
+
},
|
|
1404
|
+
// Gradiano (gon)
|
|
1405
|
+
gradian: {
|
|
1406
|
+
factor: 0.9,
|
|
1407
|
+
// 360/400
|
|
1408
|
+
symbol: "gon",
|
|
1409
|
+
singular: "gradian",
|
|
1410
|
+
plural: "gradians"
|
|
1411
|
+
}
|
|
1412
|
+
};
|
|
1413
|
+
Object.fromEntries(
|
|
1414
|
+
Object.entries(ANGLE_UNITS).map(([unit, config]) => [
|
|
1415
|
+
unit,
|
|
1416
|
+
config.factor ?? 1
|
|
1417
|
+
])
|
|
1418
|
+
);
|
|
1419
|
+
|
|
1420
|
+
// src/roles/angle/format.ts
|
|
1421
|
+
function formatAngle(variant, value, options = {}) {
|
|
1422
|
+
const config = ANGLE_UNITS[variant];
|
|
1423
|
+
if (!config) {
|
|
1424
|
+
throw new Error(`Unknown angle unit: ${variant}`);
|
|
1425
|
+
}
|
|
1426
|
+
const { decimals, verbose = false, locale, notation = "standard" } = options;
|
|
1427
|
+
let formattedNumber;
|
|
1428
|
+
if (locale || notation !== "standard") {
|
|
1429
|
+
const intlOptions = { notation };
|
|
1430
|
+
if (decimals !== void 0) {
|
|
1431
|
+
intlOptions.minimumFractionDigits = decimals;
|
|
1432
|
+
intlOptions.maximumFractionDigits = decimals;
|
|
1433
|
+
}
|
|
1434
|
+
formattedNumber = new Intl.NumberFormat(locale, intlOptions).format(value);
|
|
1435
|
+
} else if (decimals !== void 0) {
|
|
1436
|
+
formattedNumber = value.toFixed(decimals);
|
|
1437
|
+
} else {
|
|
1438
|
+
formattedNumber = Number(value.toPrecision(12)).toString();
|
|
1439
|
+
}
|
|
1440
|
+
const unitLabel = verbose ? value === 1 ? config.singular : config.plural : config.symbol;
|
|
1441
|
+
const separator = config.noSpace && !verbose ? "" : " ";
|
|
1442
|
+
return `${formattedNumber}${separator}${unitLabel}`;
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
// src/roles/time/constants.ts
|
|
1446
|
+
var TIME_UNITS = {
|
|
1447
|
+
// SI prefixes (exatos)
|
|
1448
|
+
nanosecond: {
|
|
1449
|
+
factor: 1e-9,
|
|
1450
|
+
symbol: "ns",
|
|
1451
|
+
singular: "nanosecond",
|
|
1452
|
+
plural: "nanoseconds"
|
|
1453
|
+
},
|
|
1454
|
+
microsecond: {
|
|
1455
|
+
factor: 1e-6,
|
|
1456
|
+
symbol: "\u03BCs",
|
|
1457
|
+
singular: "microsecond",
|
|
1458
|
+
plural: "microseconds"
|
|
1459
|
+
},
|
|
1460
|
+
millisecond: {
|
|
1461
|
+
factor: 1e-3,
|
|
1462
|
+
symbol: "ms",
|
|
1463
|
+
singular: "millisecond",
|
|
1464
|
+
plural: "milliseconds"
|
|
1465
|
+
},
|
|
1466
|
+
second: {
|
|
1467
|
+
factor: 1,
|
|
1468
|
+
symbol: "s",
|
|
1469
|
+
singular: "second",
|
|
1470
|
+
plural: "seconds"
|
|
1471
|
+
},
|
|
1472
|
+
// Common (exatos)
|
|
1473
|
+
minute: {
|
|
1474
|
+
factor: 60,
|
|
1475
|
+
symbol: "min",
|
|
1476
|
+
singular: "minute",
|
|
1477
|
+
plural: "minutes"
|
|
1478
|
+
},
|
|
1479
|
+
hour: {
|
|
1480
|
+
factor: 3600,
|
|
1481
|
+
symbol: "h",
|
|
1482
|
+
singular: "hour",
|
|
1483
|
+
plural: "hours"
|
|
1484
|
+
},
|
|
1485
|
+
day: {
|
|
1486
|
+
factor: 86400,
|
|
1487
|
+
symbol: "d",
|
|
1488
|
+
singular: "day",
|
|
1489
|
+
plural: "days"
|
|
1490
|
+
},
|
|
1491
|
+
week: {
|
|
1492
|
+
factor: 604800,
|
|
1493
|
+
symbol: "wk",
|
|
1494
|
+
singular: "week",
|
|
1495
|
+
plural: "weeks"
|
|
1496
|
+
},
|
|
1497
|
+
// Calendar (aproximados - baseados no ano Gregoriano)
|
|
1498
|
+
month: {
|
|
1499
|
+
factor: 2629746,
|
|
1500
|
+
// 31556952 / 12
|
|
1501
|
+
symbol: "mo",
|
|
1502
|
+
singular: "month",
|
|
1503
|
+
plural: "months"
|
|
1504
|
+
},
|
|
1505
|
+
year: {
|
|
1506
|
+
factor: 31556952,
|
|
1507
|
+
// 365.2425 * 86400
|
|
1508
|
+
symbol: "yr",
|
|
1509
|
+
singular: "year",
|
|
1510
|
+
plural: "years"
|
|
1511
|
+
},
|
|
1512
|
+
decade: {
|
|
1513
|
+
factor: 315569520,
|
|
1514
|
+
// 10 * year
|
|
1515
|
+
symbol: "dec",
|
|
1516
|
+
singular: "decade",
|
|
1517
|
+
plural: "decades"
|
|
1518
|
+
},
|
|
1519
|
+
century: {
|
|
1520
|
+
factor: 3155695200,
|
|
1521
|
+
// 100 * year
|
|
1522
|
+
symbol: "c",
|
|
1523
|
+
singular: "century",
|
|
1524
|
+
plural: "centuries"
|
|
1525
|
+
},
|
|
1526
|
+
millennium: {
|
|
1527
|
+
factor: 31556952e3,
|
|
1528
|
+
// 1000 * year
|
|
1529
|
+
symbol: "ky",
|
|
1530
|
+
singular: "millennium",
|
|
1531
|
+
plural: "millennia"
|
|
1532
|
+
}
|
|
1533
|
+
};
|
|
1534
|
+
Object.fromEntries(
|
|
1535
|
+
Object.entries(TIME_UNITS).map(([unit, config]) => [
|
|
1536
|
+
unit,
|
|
1537
|
+
config.factor ?? 1
|
|
1538
|
+
])
|
|
1539
|
+
);
|
|
1540
|
+
|
|
1541
|
+
// src/roles/time/format.ts
|
|
1542
|
+
function formatTime(variant, value, options = {}) {
|
|
1543
|
+
const config = TIME_UNITS[variant];
|
|
1544
|
+
if (!config) {
|
|
1545
|
+
throw new Error(`Unknown time unit: ${variant}`);
|
|
1546
|
+
}
|
|
1547
|
+
const { decimals, verbose = false, locale, notation = "standard" } = options;
|
|
1548
|
+
let formattedNumber;
|
|
1549
|
+
if (locale || notation !== "standard") {
|
|
1550
|
+
const intlOptions = { notation };
|
|
1551
|
+
if (decimals !== void 0) {
|
|
1552
|
+
intlOptions.minimumFractionDigits = decimals;
|
|
1553
|
+
intlOptions.maximumFractionDigits = decimals;
|
|
1554
|
+
}
|
|
1555
|
+
formattedNumber = new Intl.NumberFormat(locale, intlOptions).format(value);
|
|
1556
|
+
} else if (decimals !== void 0) {
|
|
1557
|
+
formattedNumber = value.toFixed(decimals);
|
|
1558
|
+
} else {
|
|
1559
|
+
formattedNumber = Number(value.toPrecision(12)).toString();
|
|
1560
|
+
}
|
|
1561
|
+
const unitLabel = verbose ? value === 1 ? config.singular : config.plural : config.symbol;
|
|
1562
|
+
return `${formattedNumber} ${unitLabel}`;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
// src/roles/digital/constants.ts
|
|
1566
|
+
var DIGITAL_UNITS = {
|
|
1567
|
+
// Fundamental
|
|
1568
|
+
bit: {
|
|
1569
|
+
factor: 0.125,
|
|
1570
|
+
// 1/8 byte
|
|
1571
|
+
symbol: "b",
|
|
1572
|
+
singular: "bit",
|
|
1573
|
+
plural: "bits"
|
|
1574
|
+
},
|
|
1575
|
+
byte: {
|
|
1576
|
+
factor: 1,
|
|
1577
|
+
symbol: "B",
|
|
1578
|
+
singular: "byte",
|
|
1579
|
+
plural: "bytes"
|
|
1580
|
+
},
|
|
1581
|
+
// IEC Binary (base 1024) - RAM, cache, file systems
|
|
1582
|
+
kibibyte: {
|
|
1583
|
+
factor: 1024,
|
|
1584
|
+
// 2^10
|
|
1585
|
+
symbol: "KiB",
|
|
1586
|
+
singular: "kibibyte",
|
|
1587
|
+
plural: "kibibytes"
|
|
1588
|
+
},
|
|
1589
|
+
mebibyte: {
|
|
1590
|
+
factor: 1048576,
|
|
1591
|
+
// 2^20
|
|
1592
|
+
symbol: "MiB",
|
|
1593
|
+
singular: "mebibyte",
|
|
1594
|
+
plural: "mebibytes"
|
|
1595
|
+
},
|
|
1596
|
+
gibibyte: {
|
|
1597
|
+
factor: 1073741824,
|
|
1598
|
+
// 2^30
|
|
1599
|
+
symbol: "GiB",
|
|
1600
|
+
singular: "gibibyte",
|
|
1601
|
+
plural: "gibibytes"
|
|
1602
|
+
},
|
|
1603
|
+
tebibyte: {
|
|
1604
|
+
factor: 1099511627776,
|
|
1605
|
+
// 2^40
|
|
1606
|
+
symbol: "TiB",
|
|
1607
|
+
singular: "tebibyte",
|
|
1608
|
+
plural: "tebibytes"
|
|
1609
|
+
},
|
|
1610
|
+
pebibyte: {
|
|
1611
|
+
factor: 1125899906842624,
|
|
1612
|
+
// 2^50
|
|
1613
|
+
symbol: "PiB",
|
|
1614
|
+
singular: "pebibyte",
|
|
1615
|
+
plural: "pebibytes"
|
|
1616
|
+
},
|
|
1617
|
+
exbibyte: {
|
|
1618
|
+
factor: 1152921504606847e3,
|
|
1619
|
+
// 2^60
|
|
1620
|
+
symbol: "EiB",
|
|
1621
|
+
singular: "exbibyte",
|
|
1622
|
+
plural: "exbibytes"
|
|
1623
|
+
},
|
|
1624
|
+
// SI Decimal (base 1000) - HD marketing, network speeds
|
|
1625
|
+
kilobyte: {
|
|
1626
|
+
factor: 1e3,
|
|
1627
|
+
// 10^3
|
|
1628
|
+
symbol: "kB",
|
|
1629
|
+
singular: "kilobyte",
|
|
1630
|
+
plural: "kilobytes"
|
|
1631
|
+
},
|
|
1632
|
+
megabyte: {
|
|
1633
|
+
factor: 1e6,
|
|
1634
|
+
// 10^6
|
|
1635
|
+
symbol: "MB",
|
|
1636
|
+
singular: "megabyte",
|
|
1637
|
+
plural: "megabytes"
|
|
1638
|
+
},
|
|
1639
|
+
gigabyte: {
|
|
1640
|
+
factor: 1e9,
|
|
1641
|
+
// 10^9
|
|
1642
|
+
symbol: "GB",
|
|
1643
|
+
singular: "gigabyte",
|
|
1644
|
+
plural: "gigabytes"
|
|
1645
|
+
},
|
|
1646
|
+
terabyte: {
|
|
1647
|
+
factor: 1e12,
|
|
1648
|
+
// 10^12
|
|
1649
|
+
symbol: "TB",
|
|
1650
|
+
singular: "terabyte",
|
|
1651
|
+
plural: "terabytes"
|
|
1652
|
+
},
|
|
1653
|
+
petabyte: {
|
|
1654
|
+
factor: 1e15,
|
|
1655
|
+
// 10^15
|
|
1656
|
+
symbol: "PB",
|
|
1657
|
+
singular: "petabyte",
|
|
1658
|
+
plural: "petabytes"
|
|
1659
|
+
},
|
|
1660
|
+
exabyte: {
|
|
1661
|
+
factor: 1e18,
|
|
1662
|
+
// 10^18
|
|
1663
|
+
symbol: "EB",
|
|
1664
|
+
singular: "exabyte",
|
|
1665
|
+
plural: "exabytes"
|
|
1666
|
+
}
|
|
1667
|
+
};
|
|
1668
|
+
Object.fromEntries(
|
|
1669
|
+
Object.entries(DIGITAL_UNITS).map(([unit, config]) => [
|
|
1670
|
+
unit,
|
|
1671
|
+
config.factor ?? 1
|
|
1672
|
+
])
|
|
1673
|
+
);
|
|
1674
|
+
|
|
1675
|
+
// src/roles/digital/format.ts
|
|
1676
|
+
function formatDigital(variant, value, options = {}) {
|
|
1677
|
+
const config = DIGITAL_UNITS[variant];
|
|
1678
|
+
if (!config) {
|
|
1679
|
+
throw new Error(`Unknown digital unit: ${variant}`);
|
|
1680
|
+
}
|
|
1681
|
+
const { decimals, verbose = false, locale, notation = "standard" } = options;
|
|
1682
|
+
let formattedNumber;
|
|
1683
|
+
if (locale || notation !== "standard") {
|
|
1684
|
+
const intlOptions = { notation };
|
|
1685
|
+
if (decimals !== void 0) {
|
|
1686
|
+
intlOptions.minimumFractionDigits = decimals;
|
|
1687
|
+
intlOptions.maximumFractionDigits = decimals;
|
|
1688
|
+
}
|
|
1689
|
+
formattedNumber = new Intl.NumberFormat(locale, intlOptions).format(value);
|
|
1690
|
+
} else if (decimals !== void 0) {
|
|
1691
|
+
formattedNumber = value.toFixed(decimals);
|
|
1692
|
+
} else {
|
|
1693
|
+
formattedNumber = Number(value.toPrecision(12)).toString();
|
|
1694
|
+
}
|
|
1695
|
+
const unitLabel = verbose ? value === 1 ? config.singular : config.plural : config.symbol;
|
|
1696
|
+
return `${formattedNumber} ${unitLabel}`;
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
// src/roles/color/types.ts
|
|
1700
|
+
function clamp(value, min, max) {
|
|
1701
|
+
return Math.min(Math.max(value, min), max);
|
|
1702
|
+
}
|
|
1703
|
+
function normalizeRgbChannel(value) {
|
|
1704
|
+
return clamp(Math.round(value), 0, 255);
|
|
1705
|
+
}
|
|
1706
|
+
function normalizeAlpha(value) {
|
|
1707
|
+
if (value === void 0) return 1;
|
|
1708
|
+
return clamp(value, 0, 1);
|
|
1709
|
+
}
|
|
1710
|
+
function rgbToHsl(r, g, b) {
|
|
1711
|
+
r /= 255;
|
|
1712
|
+
g /= 255;
|
|
1713
|
+
b /= 255;
|
|
1714
|
+
const max = Math.max(r, g, b);
|
|
1715
|
+
const min = Math.min(r, g, b);
|
|
1716
|
+
const l = (max + min) / 2;
|
|
1717
|
+
if (max === min) {
|
|
1718
|
+
return { h: 0, s: 0, l: l * 100 };
|
|
1719
|
+
}
|
|
1720
|
+
const d = max - min;
|
|
1721
|
+
const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
1722
|
+
let h;
|
|
1723
|
+
switch (max) {
|
|
1724
|
+
case r:
|
|
1725
|
+
h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
1726
|
+
break;
|
|
1727
|
+
case g:
|
|
1728
|
+
h = ((b - r) / d + 2) / 6;
|
|
1729
|
+
break;
|
|
1730
|
+
default:
|
|
1731
|
+
h = ((r - g) / d + 4) / 6;
|
|
1732
|
+
break;
|
|
1733
|
+
}
|
|
1734
|
+
return {
|
|
1735
|
+
h: Math.round(h * 360),
|
|
1736
|
+
s: Math.round(s * 100),
|
|
1737
|
+
l: Math.round(l * 100)
|
|
1738
|
+
};
|
|
1739
|
+
}
|
|
1740
|
+
function hslToRgb(h, s, l) {
|
|
1741
|
+
h /= 360;
|
|
1742
|
+
s /= 100;
|
|
1743
|
+
l /= 100;
|
|
1744
|
+
if (s === 0) {
|
|
1745
|
+
const gray = Math.round(l * 255);
|
|
1746
|
+
return { r: gray, g: gray, b: gray };
|
|
1747
|
+
}
|
|
1748
|
+
const hue2rgb = (p2, q2, t) => {
|
|
1749
|
+
if (t < 0) t += 1;
|
|
1750
|
+
if (t > 1) t -= 1;
|
|
1751
|
+
if (t < 1 / 6) return p2 + (q2 - p2) * 6 * t;
|
|
1752
|
+
if (t < 1 / 2) return q2;
|
|
1753
|
+
if (t < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - t) * 6;
|
|
1754
|
+
return p2;
|
|
1755
|
+
};
|
|
1756
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
1757
|
+
const p = 2 * l - q;
|
|
1758
|
+
return {
|
|
1759
|
+
r: Math.round(hue2rgb(p, q, h + 1 / 3) * 255),
|
|
1760
|
+
g: Math.round(hue2rgb(p, q, h) * 255),
|
|
1761
|
+
b: Math.round(hue2rgb(p, q, h - 1 / 3) * 255)
|
|
1762
|
+
};
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
// src/roles/color/convert.ts
|
|
1766
|
+
function hexToRgba(hex) {
|
|
1767
|
+
let h = hex.trim();
|
|
1768
|
+
if (h.startsWith("#")) h = h.slice(1);
|
|
1769
|
+
let r, g, b, a;
|
|
1770
|
+
if (h.length === 3) {
|
|
1771
|
+
r = parseInt(h[0] + h[0], 16);
|
|
1772
|
+
g = parseInt(h[1] + h[1], 16);
|
|
1773
|
+
b = parseInt(h[2] + h[2], 16);
|
|
1774
|
+
a = 1;
|
|
1775
|
+
} else if (h.length === 4) {
|
|
1776
|
+
r = parseInt(h[0] + h[0], 16);
|
|
1777
|
+
g = parseInt(h[1] + h[1], 16);
|
|
1778
|
+
b = parseInt(h[2] + h[2], 16);
|
|
1779
|
+
a = parseInt(h[3] + h[3], 16) / 255;
|
|
1780
|
+
} else if (h.length === 6) {
|
|
1781
|
+
r = parseInt(h.slice(0, 2), 16);
|
|
1782
|
+
g = parseInt(h.slice(2, 4), 16);
|
|
1783
|
+
b = parseInt(h.slice(4, 6), 16);
|
|
1784
|
+
a = 1;
|
|
1785
|
+
} else if (h.length === 8) {
|
|
1786
|
+
r = parseInt(h.slice(0, 2), 16);
|
|
1787
|
+
g = parseInt(h.slice(2, 4), 16);
|
|
1788
|
+
b = parseInt(h.slice(4, 6), 16);
|
|
1789
|
+
a = parseInt(h.slice(6, 8), 16) / 255;
|
|
1790
|
+
} else {
|
|
1791
|
+
throw new Error(`Invalid hex color: ${hex}`);
|
|
1792
|
+
}
|
|
1793
|
+
return { r, g, b, a };
|
|
1794
|
+
}
|
|
1795
|
+
function rgbObjectToRgba(rgb) {
|
|
1796
|
+
return {
|
|
1797
|
+
r: normalizeRgbChannel(rgb.r),
|
|
1798
|
+
g: normalizeRgbChannel(rgb.g),
|
|
1799
|
+
b: normalizeRgbChannel(rgb.b),
|
|
1800
|
+
a: normalizeAlpha(rgb.a)
|
|
1801
|
+
};
|
|
1802
|
+
}
|
|
1803
|
+
function rgbStringToRgba(rgb) {
|
|
1804
|
+
const match = rgb.match(/rgba?\s*\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)\s*(?:,\s*([\d.]+)\s*)?\)/i);
|
|
1805
|
+
if (!match) {
|
|
1806
|
+
throw new Error(`Invalid RGB string: ${rgb}`);
|
|
1807
|
+
}
|
|
1808
|
+
return {
|
|
1809
|
+
r: normalizeRgbChannel(parseFloat(match[1])),
|
|
1810
|
+
g: normalizeRgbChannel(parseFloat(match[2])),
|
|
1811
|
+
b: normalizeRgbChannel(parseFloat(match[3])),
|
|
1812
|
+
a: match[4] !== void 0 ? normalizeAlpha(parseFloat(match[4])) : 1
|
|
1813
|
+
};
|
|
1814
|
+
}
|
|
1815
|
+
function hslObjectToRgba(hsl) {
|
|
1816
|
+
const { r, g, b } = hslToRgb(hsl.h, hsl.s, hsl.l);
|
|
1817
|
+
return {
|
|
1818
|
+
r,
|
|
1819
|
+
g,
|
|
1820
|
+
b,
|
|
1821
|
+
a: normalizeAlpha(hsl.a)
|
|
1822
|
+
};
|
|
1823
|
+
}
|
|
1824
|
+
function hslStringToRgba(hsl) {
|
|
1825
|
+
const match = hsl.match(/hsla?\s*\(\s*([\d.]+)\s*,\s*([\d.]+)%?\s*,\s*([\d.]+)%?\s*(?:,\s*([\d.]+)\s*)?\)/i);
|
|
1826
|
+
if (!match) {
|
|
1827
|
+
throw new Error(`Invalid HSL string: ${hsl}`);
|
|
1828
|
+
}
|
|
1829
|
+
const h = parseFloat(match[1]);
|
|
1830
|
+
const s = parseFloat(match[2]);
|
|
1831
|
+
const l = parseFloat(match[3]);
|
|
1832
|
+
const a = match[4] !== void 0 ? parseFloat(match[4]) : 1;
|
|
1833
|
+
const { r, g, b } = hslToRgb(h, s, l);
|
|
1834
|
+
return { r, g, b, a: normalizeAlpha(a) };
|
|
1835
|
+
}
|
|
1836
|
+
function toBaseColor(variant, value) {
|
|
1837
|
+
switch (variant) {
|
|
1838
|
+
case "hex":
|
|
1839
|
+
return hexToRgba(value);
|
|
1840
|
+
case "rgb_object":
|
|
1841
|
+
return rgbObjectToRgba(value);
|
|
1842
|
+
case "rgb_string":
|
|
1843
|
+
return rgbStringToRgba(value);
|
|
1844
|
+
case "hsl_object":
|
|
1845
|
+
return hslObjectToRgba(value);
|
|
1846
|
+
case "hsl_string":
|
|
1847
|
+
return hslStringToRgba(value);
|
|
1848
|
+
default:
|
|
1849
|
+
throw new Error(`Unknown color variant: ${variant}`);
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
// src/roles/color/format.ts
|
|
1854
|
+
var DEFAULT_OPTIONS = {
|
|
1855
|
+
uppercase: false,
|
|
1856
|
+
includeAlpha: false,
|
|
1857
|
+
compact: false
|
|
1858
|
+
};
|
|
1859
|
+
function formatAsHex(rgba, options) {
|
|
1860
|
+
const r = rgba.r.toString(16).padStart(2, "0");
|
|
1861
|
+
const g = rgba.g.toString(16).padStart(2, "0");
|
|
1862
|
+
const b = rgba.b.toString(16).padStart(2, "0");
|
|
1863
|
+
let hex;
|
|
1864
|
+
if (options.includeAlpha || rgba.a < 1) {
|
|
1865
|
+
const a = Math.round(rgba.a * 255).toString(16).padStart(2, "0");
|
|
1866
|
+
hex = `#${r}${g}${b}${a}`;
|
|
1867
|
+
} else {
|
|
1868
|
+
hex = `#${r}${g}${b}`;
|
|
1869
|
+
}
|
|
1870
|
+
if (options.compact && !options.includeAlpha && rgba.a === 1) {
|
|
1871
|
+
if (r[0] === r[1] && g[0] === g[1] && b[0] === b[1]) {
|
|
1872
|
+
hex = `#${r[0]}${g[0]}${b[0]}`;
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
return options.uppercase ? hex.toUpperCase() : hex.toLowerCase();
|
|
1876
|
+
}
|
|
1877
|
+
function formatAsRgbString(rgba, options) {
|
|
1878
|
+
if (options.includeAlpha || rgba.a < 1) {
|
|
1879
|
+
if (options.compact) {
|
|
1880
|
+
return `rgba(${rgba.r},${rgba.g},${rgba.b},${rgba.a})`;
|
|
1881
|
+
}
|
|
1882
|
+
return `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})`;
|
|
1883
|
+
}
|
|
1884
|
+
if (options.compact) {
|
|
1885
|
+
return `rgb(${rgba.r},${rgba.g},${rgba.b})`;
|
|
1886
|
+
}
|
|
1887
|
+
return `rgb(${rgba.r}, ${rgba.g}, ${rgba.b})`;
|
|
1888
|
+
}
|
|
1889
|
+
function formatAsHslString(rgba, options) {
|
|
1890
|
+
const { h, s, l } = rgbToHsl(rgba.r, rgba.g, rgba.b);
|
|
1891
|
+
if (options.includeAlpha || rgba.a < 1) {
|
|
1892
|
+
if (options.compact) {
|
|
1893
|
+
return `hsla(${h},${s}%,${l}%,${rgba.a})`;
|
|
1894
|
+
}
|
|
1895
|
+
return `hsla(${h}, ${s}%, ${l}%, ${rgba.a})`;
|
|
1896
|
+
}
|
|
1897
|
+
if (options.compact) {
|
|
1898
|
+
return `hsl(${h},${s}%,${l}%)`;
|
|
1899
|
+
}
|
|
1900
|
+
return `hsl(${h}, ${s}%, ${l}%)`;
|
|
1901
|
+
}
|
|
1902
|
+
function formatAsRgbObject(rgba, options) {
|
|
1903
|
+
return formatAsRgbString(rgba, options);
|
|
1904
|
+
}
|
|
1905
|
+
function formatAsHslObject(rgba, options) {
|
|
1906
|
+
return formatAsHslString(rgba, options);
|
|
1907
|
+
}
|
|
1908
|
+
function formatColor(variant, value, options) {
|
|
1909
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
1910
|
+
let rgba;
|
|
1911
|
+
if (typeof value === "object" && value !== null && "r" in value && "g" in value && "b" in value) {
|
|
1912
|
+
const obj = value;
|
|
1913
|
+
rgba = {
|
|
1914
|
+
r: obj.r,
|
|
1915
|
+
g: obj.g,
|
|
1916
|
+
b: obj.b,
|
|
1917
|
+
a: obj.a ?? 1
|
|
1918
|
+
};
|
|
1919
|
+
} else if (typeof value === "object" && value !== null && "h" in value && "s" in value && "l" in value) {
|
|
1920
|
+
rgba = toBaseColor("hsl_object", value);
|
|
1921
|
+
} else if (typeof value === "string") {
|
|
1922
|
+
rgba = toBaseColor(detectStringVariant(value), value);
|
|
1923
|
+
} else {
|
|
1924
|
+
throw new Error(`Cannot format color: ${String(value)}`);
|
|
1925
|
+
}
|
|
1926
|
+
switch (variant) {
|
|
1927
|
+
case "hex":
|
|
1928
|
+
return formatAsHex(rgba, opts);
|
|
1929
|
+
case "rgb_string":
|
|
1930
|
+
return formatAsRgbString(rgba, opts);
|
|
1931
|
+
case "hsl_string":
|
|
1932
|
+
return formatAsHslString(rgba, opts);
|
|
1933
|
+
case "rgb_object":
|
|
1934
|
+
return formatAsRgbObject(rgba, opts);
|
|
1935
|
+
case "hsl_object":
|
|
1936
|
+
return formatAsHslObject(rgba, opts);
|
|
1937
|
+
default:
|
|
1938
|
+
throw new Error(`Unknown color variant: ${variant}`);
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
function detectStringVariant(value) {
|
|
1942
|
+
const trimmed = value.trim().toLowerCase();
|
|
1943
|
+
if (/^#?[0-9a-f]{3,8}$/i.test(trimmed)) {
|
|
1944
|
+
return "hex";
|
|
1945
|
+
}
|
|
1946
|
+
if (/^rgba?\s*\(/i.test(trimmed)) {
|
|
1947
|
+
return "rgb_string";
|
|
1948
|
+
}
|
|
1949
|
+
if (/^hsla?\s*\(/i.test(trimmed)) {
|
|
1950
|
+
return "hsl_string";
|
|
1951
|
+
}
|
|
1952
|
+
return "hex";
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
// src/roles/date/format.ts
|
|
1956
|
+
function formatIso(value, options) {
|
|
1957
|
+
const date = new Date(value);
|
|
1958
|
+
if (isNaN(date.getTime())) {
|
|
1959
|
+
return "Invalid Date";
|
|
1960
|
+
}
|
|
1961
|
+
if (!options || !options.dateStyle && !options.timeStyle && !options.dateOnly && !options.timeOnly) {
|
|
1962
|
+
return value;
|
|
1963
|
+
}
|
|
1964
|
+
return formatWithIntl(date, options);
|
|
1965
|
+
}
|
|
1966
|
+
function formatTimestamp(value, options) {
|
|
1967
|
+
const date = new Date(value);
|
|
1968
|
+
if (isNaN(date.getTime())) {
|
|
1969
|
+
return "Invalid Date";
|
|
1970
|
+
}
|
|
1971
|
+
if (!options || !options.dateStyle && !options.timeStyle && !options.dateOnly && !options.timeOnly) {
|
|
1972
|
+
return String(value);
|
|
1973
|
+
}
|
|
1974
|
+
return formatWithIntl(date, options);
|
|
1975
|
+
}
|
|
1976
|
+
function formatEpoch(value, options) {
|
|
1977
|
+
const date = new Date(value * 1e3);
|
|
1978
|
+
if (isNaN(date.getTime())) {
|
|
1979
|
+
return "Invalid Date";
|
|
1980
|
+
}
|
|
1981
|
+
if (!options || !options.dateStyle && !options.timeStyle && !options.dateOnly && !options.timeOnly) {
|
|
1982
|
+
return String(value);
|
|
1983
|
+
}
|
|
1984
|
+
return formatWithIntl(date, options);
|
|
1985
|
+
}
|
|
1986
|
+
function formatDate(variant, value, options) {
|
|
1987
|
+
switch (variant) {
|
|
1988
|
+
case "iso":
|
|
1989
|
+
return formatIso(value, options);
|
|
1990
|
+
case "timestamp":
|
|
1991
|
+
return formatTimestamp(value, options);
|
|
1992
|
+
case "epoch":
|
|
1993
|
+
return formatEpoch(value, options);
|
|
1994
|
+
default:
|
|
1995
|
+
return "Invalid Date";
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
function formatWithIntl(date, options) {
|
|
1999
|
+
const locale = options.locale || "en-US";
|
|
2000
|
+
const formatOptions = {};
|
|
2001
|
+
if (options.timeZone) {
|
|
2002
|
+
formatOptions.timeZone = options.timeZone;
|
|
2003
|
+
}
|
|
2004
|
+
if (options.dateOnly) {
|
|
2005
|
+
formatOptions.dateStyle = options.dateStyle || "medium";
|
|
2006
|
+
} else if (options.timeOnly) {
|
|
2007
|
+
formatOptions.timeStyle = options.timeStyle || "medium";
|
|
2008
|
+
} else {
|
|
2009
|
+
if (options.dateStyle) formatOptions.dateStyle = options.dateStyle;
|
|
2010
|
+
if (options.timeStyle) formatOptions.timeStyle = options.timeStyle;
|
|
2011
|
+
}
|
|
2012
|
+
return new Intl.DateTimeFormat(locale, formatOptions).format(date);
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
// src/roles/currency/constants.ts
|
|
2016
|
+
var CURRENCY_CONFIGS = {
|
|
2017
|
+
// ===========================================================================
|
|
2018
|
+
// Major Currencies
|
|
2019
|
+
// ===========================================================================
|
|
2020
|
+
USD: {
|
|
2021
|
+
code: "USD",
|
|
2022
|
+
symbol: "$",
|
|
2023
|
+
singular: "US dollar",
|
|
2024
|
+
plural: "US dollars",
|
|
2025
|
+
decimals: 2,
|
|
2026
|
+
symbolFirst: true,
|
|
2027
|
+
thousandsSeparator: ",",
|
|
2028
|
+
decimalSeparator: "."
|
|
2029
|
+
},
|
|
2030
|
+
EUR: {
|
|
2031
|
+
code: "EUR",
|
|
2032
|
+
symbol: "\u20AC",
|
|
2033
|
+
singular: "euro",
|
|
2034
|
+
plural: "euros",
|
|
2035
|
+
decimals: 2,
|
|
2036
|
+
symbolFirst: false,
|
|
2037
|
+
// 100 € (europeu) ou €100 (varia)
|
|
2038
|
+
thousandsSeparator: ".",
|
|
2039
|
+
decimalSeparator: ","
|
|
2040
|
+
},
|
|
2041
|
+
GBP: {
|
|
2042
|
+
code: "GBP",
|
|
2043
|
+
symbol: "\xA3",
|
|
2044
|
+
singular: "British pound",
|
|
2045
|
+
plural: "British pounds",
|
|
2046
|
+
decimals: 2,
|
|
2047
|
+
symbolFirst: true,
|
|
2048
|
+
thousandsSeparator: ",",
|
|
2049
|
+
decimalSeparator: "."
|
|
2050
|
+
},
|
|
2051
|
+
JPY: {
|
|
2052
|
+
code: "JPY",
|
|
2053
|
+
symbol: "\xA5",
|
|
2054
|
+
singular: "Japanese yen",
|
|
2055
|
+
plural: "Japanese yen",
|
|
2056
|
+
decimals: 0,
|
|
2057
|
+
// Yen não tem centavos
|
|
2058
|
+
symbolFirst: true,
|
|
2059
|
+
thousandsSeparator: ",",
|
|
2060
|
+
decimalSeparator: "."
|
|
2061
|
+
},
|
|
2062
|
+
CHF: {
|
|
2063
|
+
code: "CHF",
|
|
2064
|
+
symbol: "CHF",
|
|
2065
|
+
singular: "Swiss franc",
|
|
2066
|
+
plural: "Swiss francs",
|
|
2067
|
+
decimals: 2,
|
|
2068
|
+
symbolFirst: true,
|
|
2069
|
+
thousandsSeparator: "'",
|
|
2070
|
+
decimalSeparator: "."
|
|
2071
|
+
},
|
|
2072
|
+
CNY: {
|
|
2073
|
+
code: "CNY",
|
|
2074
|
+
symbol: "\xA5",
|
|
2075
|
+
singular: "Chinese yuan",
|
|
2076
|
+
plural: "Chinese yuan",
|
|
2077
|
+
decimals: 2,
|
|
2078
|
+
symbolFirst: true,
|
|
2079
|
+
thousandsSeparator: ",",
|
|
2080
|
+
decimalSeparator: "."
|
|
2081
|
+
},
|
|
2082
|
+
CAD: {
|
|
2083
|
+
code: "CAD",
|
|
2084
|
+
symbol: "C$",
|
|
2085
|
+
singular: "Canadian dollar",
|
|
2086
|
+
plural: "Canadian dollars",
|
|
2087
|
+
decimals: 2,
|
|
2088
|
+
symbolFirst: true,
|
|
2089
|
+
thousandsSeparator: ",",
|
|
2090
|
+
decimalSeparator: "."
|
|
2091
|
+
},
|
|
2092
|
+
AUD: {
|
|
2093
|
+
code: "AUD",
|
|
2094
|
+
symbol: "A$",
|
|
2095
|
+
singular: "Australian dollar",
|
|
2096
|
+
plural: "Australian dollars",
|
|
2097
|
+
decimals: 2,
|
|
2098
|
+
symbolFirst: true,
|
|
2099
|
+
thousandsSeparator: ",",
|
|
2100
|
+
decimalSeparator: "."
|
|
2101
|
+
},
|
|
2102
|
+
// ===========================================================================
|
|
2103
|
+
// Latin America
|
|
2104
|
+
// ===========================================================================
|
|
2105
|
+
BRL: {
|
|
2106
|
+
code: "BRL",
|
|
2107
|
+
symbol: "R$",
|
|
2108
|
+
singular: "Brazilian real",
|
|
2109
|
+
plural: "Brazilian reais",
|
|
2110
|
+
decimals: 2,
|
|
2111
|
+
symbolFirst: true,
|
|
2112
|
+
thousandsSeparator: ".",
|
|
2113
|
+
decimalSeparator: ","
|
|
2114
|
+
},
|
|
2115
|
+
MXN: {
|
|
2116
|
+
code: "MXN",
|
|
2117
|
+
symbol: "$",
|
|
2118
|
+
singular: "Mexican peso",
|
|
2119
|
+
plural: "Mexican pesos",
|
|
2120
|
+
decimals: 2,
|
|
2121
|
+
symbolFirst: true,
|
|
2122
|
+
thousandsSeparator: ",",
|
|
2123
|
+
decimalSeparator: "."
|
|
2124
|
+
},
|
|
2125
|
+
ARS: {
|
|
2126
|
+
code: "ARS",
|
|
2127
|
+
symbol: "$",
|
|
2128
|
+
singular: "Argentine peso",
|
|
2129
|
+
plural: "Argentine pesos",
|
|
2130
|
+
decimals: 2,
|
|
2131
|
+
symbolFirst: true,
|
|
2132
|
+
thousandsSeparator: ".",
|
|
2133
|
+
decimalSeparator: ","
|
|
2134
|
+
},
|
|
2135
|
+
CLP: {
|
|
2136
|
+
code: "CLP",
|
|
2137
|
+
symbol: "$",
|
|
2138
|
+
singular: "Chilean peso",
|
|
2139
|
+
plural: "Chilean pesos",
|
|
2140
|
+
decimals: 0,
|
|
2141
|
+
// Peso chileno não tem centavos
|
|
2142
|
+
symbolFirst: true,
|
|
2143
|
+
thousandsSeparator: ".",
|
|
2144
|
+
decimalSeparator: ","
|
|
2145
|
+
},
|
|
2146
|
+
COP: {
|
|
2147
|
+
code: "COP",
|
|
2148
|
+
symbol: "$",
|
|
2149
|
+
singular: "Colombian peso",
|
|
2150
|
+
plural: "Colombian pesos",
|
|
2151
|
+
decimals: 0,
|
|
2152
|
+
// Peso colombiano praticamente não usa centavos
|
|
2153
|
+
symbolFirst: true,
|
|
2154
|
+
thousandsSeparator: ".",
|
|
2155
|
+
decimalSeparator: ","
|
|
2156
|
+
},
|
|
2157
|
+
// ===========================================================================
|
|
2158
|
+
// Other Important
|
|
2159
|
+
// ===========================================================================
|
|
2160
|
+
INR: {
|
|
2161
|
+
code: "INR",
|
|
2162
|
+
symbol: "\u20B9",
|
|
2163
|
+
singular: "Indian rupee",
|
|
2164
|
+
plural: "Indian rupees",
|
|
2165
|
+
decimals: 2,
|
|
2166
|
+
symbolFirst: true,
|
|
2167
|
+
thousandsSeparator: ",",
|
|
2168
|
+
decimalSeparator: "."
|
|
2169
|
+
},
|
|
2170
|
+
KRW: {
|
|
2171
|
+
code: "KRW",
|
|
2172
|
+
symbol: "\u20A9",
|
|
2173
|
+
singular: "South Korean won",
|
|
2174
|
+
plural: "South Korean won",
|
|
2175
|
+
decimals: 0,
|
|
2176
|
+
// Won não tem centavos
|
|
2177
|
+
symbolFirst: true,
|
|
2178
|
+
thousandsSeparator: ",",
|
|
2179
|
+
decimalSeparator: "."
|
|
2180
|
+
},
|
|
2181
|
+
RUB: {
|
|
2182
|
+
code: "RUB",
|
|
2183
|
+
symbol: "\u20BD",
|
|
2184
|
+
singular: "Russian ruble",
|
|
2185
|
+
plural: "Russian rubles",
|
|
2186
|
+
decimals: 2,
|
|
2187
|
+
symbolFirst: false,
|
|
2188
|
+
thousandsSeparator: " ",
|
|
2189
|
+
decimalSeparator: ","
|
|
2190
|
+
},
|
|
2191
|
+
TRY: {
|
|
2192
|
+
code: "TRY",
|
|
2193
|
+
symbol: "\u20BA",
|
|
2194
|
+
singular: "Turkish lira",
|
|
2195
|
+
plural: "Turkish lira",
|
|
2196
|
+
decimals: 2,
|
|
2197
|
+
symbolFirst: true,
|
|
2198
|
+
thousandsSeparator: ".",
|
|
2199
|
+
decimalSeparator: ","
|
|
2200
|
+
},
|
|
2201
|
+
ZAR: {
|
|
2202
|
+
code: "ZAR",
|
|
2203
|
+
symbol: "R",
|
|
2204
|
+
singular: "South African rand",
|
|
2205
|
+
plural: "South African rand",
|
|
2206
|
+
decimals: 2,
|
|
2207
|
+
symbolFirst: true,
|
|
2208
|
+
thousandsSeparator: " ",
|
|
2209
|
+
decimalSeparator: ","
|
|
2210
|
+
}
|
|
2211
|
+
};
|
|
2212
|
+
|
|
2213
|
+
// src/roles/currency/format.ts
|
|
2214
|
+
function formatCurrency(value, options) {
|
|
2215
|
+
const config = CURRENCY_CONFIGS[options.currency];
|
|
2216
|
+
if (!config) {
|
|
2217
|
+
throw new Error(`Unknown currency code: ${options.currency}`);
|
|
2218
|
+
}
|
|
2219
|
+
if (options.locale) {
|
|
2220
|
+
return formatWithIntl2(value, options, config);
|
|
2221
|
+
}
|
|
2222
|
+
return formatManual(value, options, config);
|
|
2223
|
+
}
|
|
2224
|
+
function formatWithIntl2(value, options, config) {
|
|
2225
|
+
const decimals = options.decimals ?? config.decimals;
|
|
2226
|
+
const intlOptions = {
|
|
2227
|
+
style: options.hideSymbol ? "decimal" : "currency",
|
|
2228
|
+
currency: config.code,
|
|
2229
|
+
minimumFractionDigits: decimals,
|
|
2230
|
+
maximumFractionDigits: decimals
|
|
2231
|
+
};
|
|
2232
|
+
if (options.verbose) {
|
|
2233
|
+
intlOptions.currencyDisplay = "name";
|
|
2234
|
+
}
|
|
2235
|
+
let formatted = new Intl.NumberFormat(options.locale, intlOptions).format(
|
|
2236
|
+
value
|
|
2237
|
+
);
|
|
2238
|
+
if (options.showPositiveSign && value > 0) {
|
|
2239
|
+
formatted = "+" + formatted;
|
|
2240
|
+
}
|
|
2241
|
+
return formatted;
|
|
2242
|
+
}
|
|
2243
|
+
function formatManual(value, options, config) {
|
|
2244
|
+
const decimals = options.decimals ?? config.decimals;
|
|
2245
|
+
const isNegative = value < 0;
|
|
2246
|
+
const absValue = Math.abs(value);
|
|
2247
|
+
const formattedNumber = formatNumber(
|
|
2248
|
+
absValue,
|
|
2249
|
+
decimals,
|
|
2250
|
+
config.thousandsSeparator,
|
|
2251
|
+
config.decimalSeparator
|
|
2252
|
+
);
|
|
2253
|
+
let result = "";
|
|
2254
|
+
if (isNegative) {
|
|
2255
|
+
result += "-";
|
|
2256
|
+
} else if (options.showPositiveSign) {
|
|
2257
|
+
result += "+";
|
|
2258
|
+
}
|
|
2259
|
+
if (options.hideSymbol) {
|
|
2260
|
+
result += formattedNumber;
|
|
2261
|
+
} else if (options.verbose) {
|
|
2262
|
+
const name = absValue === 1 ? config.singular : config.plural;
|
|
2263
|
+
result += `${formattedNumber} ${name}`;
|
|
2264
|
+
} else {
|
|
2265
|
+
const symbolFirst = options.symbolFirst !== void 0 ? options.symbolFirst : config.symbolFirst;
|
|
2266
|
+
if (symbolFirst) {
|
|
2267
|
+
result += `${config.symbol}${formattedNumber}`;
|
|
2268
|
+
} else {
|
|
2269
|
+
result += `${formattedNumber} ${config.symbol}`;
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
return result;
|
|
2273
|
+
}
|
|
2274
|
+
function formatNumber(value, decimals, thousandsSeparator, decimalSeparator) {
|
|
2275
|
+
const fixed = value.toFixed(decimals);
|
|
2276
|
+
const [intPart, decPart] = fixed.split(".");
|
|
2277
|
+
const intFormatted = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsSeparator);
|
|
2278
|
+
if (decimals > 0 && decPart) {
|
|
2279
|
+
return `${intFormatted}${decimalSeparator}${decPart}`;
|
|
2280
|
+
}
|
|
2281
|
+
return intFormatted;
|
|
2282
|
+
}
|
|
2283
|
+
|
|
2284
|
+
export { formatAngle, formatArea, formatColor, formatCurrency, formatDate, formatDigital, formatEnergy, formatFrequency, formatLength, formatMass, formatPower, formatPressure, formatSpeed, formatTemperature, formatTime, formatVolume };
|
|
2285
|
+
//# sourceMappingURL=format.mjs.map
|
|
2286
|
+
//# sourceMappingURL=format.mjs.map
|