unacy 0.6.0 → 0.8.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.
- package/README.md +193 -47
- package/dist/converters.d.ts +28 -4
- package/dist/converters.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/registry.d.ts +39 -41
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +58 -14
- package/dist/registry.js.map +1 -1
- package/dist/types.d.ts +159 -18
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/validation.d.ts +106 -0
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +317 -0
- package/dist/utils/validation.js.map +1 -1
- package/package.json +16 -8
- package/dist/__tests__/converters.test.d.ts +0 -2
- package/dist/__tests__/converters.test.d.ts.map +0 -1
- package/dist/__tests__/converters.test.js +0 -128
- package/dist/__tests__/converters.test.js.map +0 -1
- package/dist/__tests__/errors.test.d.ts +0 -2
- package/dist/__tests__/errors.test.d.ts.map +0 -1
- package/dist/__tests__/errors.test.js +0 -93
- package/dist/__tests__/errors.test.js.map +0 -1
- package/dist/__tests__/formatters.test.d.ts +0 -2
- package/dist/__tests__/formatters.test.d.ts.map +0 -1
- package/dist/__tests__/formatters.test.js +0 -244
- package/dist/__tests__/formatters.test.js.map +0 -1
- package/dist/__tests__/registry.test.d.ts +0 -2
- package/dist/__tests__/registry.test.d.ts.map +0 -1
- package/dist/__tests__/registry.test.js +0 -403
- package/dist/__tests__/registry.test.js.map +0 -1
- package/dist/__tests__/types.test.d.ts +0 -2
- package/dist/__tests__/types.test.d.ts.map +0 -1
- package/dist/__tests__/types.test.js +0 -115
- package/dist/__tests__/types.test.js.map +0 -1
package/README.md
CHANGED
|
@@ -11,6 +11,8 @@ Type-safe unit and format conversion library with automatic multi-hop compositio
|
|
|
11
11
|
- 🛡️ **Cycle detection** - Prevents infinite conversion loops
|
|
12
12
|
- 📦 **Tree-shakeable** - Only bundle converters you use
|
|
13
13
|
- ✨ **Fluent API** - Clean, readable conversion syntax
|
|
14
|
+
- 🎯 **Typed Metadata** - Native support for `number`, `string`, `boolean`, and `bigint` units
|
|
15
|
+
- 🧩 **Non-Primitive Types** - First-class support for enums, classes, records, and tuples
|
|
14
16
|
|
|
15
17
|
## Installation
|
|
16
18
|
|
|
@@ -21,15 +23,27 @@ pnpm add @unacy/core
|
|
|
21
23
|
## Quick Start
|
|
22
24
|
|
|
23
25
|
```typescript
|
|
24
|
-
import { createRegistry
|
|
26
|
+
import { createRegistry } from '@unacy/core';
|
|
27
|
+
import type { WithTypedUnits } from '@unacy/core';
|
|
25
28
|
|
|
26
|
-
// Define your
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
// Define metadata for your units (name + type)
|
|
30
|
+
const CelsiusMetadata = {
|
|
31
|
+
name: 'Celsius' as const,
|
|
32
|
+
type: 'number' as const
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const FahrenheitMetadata = {
|
|
36
|
+
name: 'Fahrenheit' as const,
|
|
37
|
+
type: 'number' as const
|
|
38
|
+
};
|
|
29
39
|
|
|
30
|
-
//
|
|
40
|
+
// Define your unit types with metadata
|
|
41
|
+
type Celsius = WithTypedUnits<typeof CelsiusMetadata>;
|
|
42
|
+
type Fahrenheit = WithTypedUnits<typeof FahrenheitMetadata>;
|
|
43
|
+
|
|
44
|
+
// Create a registry and register converters
|
|
31
45
|
const tempRegistry = createRegistry()
|
|
32
|
-
.register(
|
|
46
|
+
.register(CelsiusMetadata, FahrenheitMetadata, (c) => ((c * 9/5) + 32));
|
|
33
47
|
|
|
34
48
|
// Create branded values using callable accessors (NEW!)
|
|
35
49
|
const temp = tempRegistry.Celsius(25); // Returns Celsius type
|
|
@@ -44,9 +58,6 @@ const fahrenheit2 = tempRegistry.Celsius.to.Fahrenheit(tempRegistry.Celsius(30))
|
|
|
44
58
|
|
|
45
59
|
console.log(fahrenheit1); // 77
|
|
46
60
|
console.log(fahrenheit2); // 86
|
|
47
|
-
|
|
48
|
-
// Old way still works (manual casting)
|
|
49
|
-
const tempOld: Celsius = 25 as Celsius;
|
|
50
61
|
```
|
|
51
62
|
|
|
52
63
|
## Usage Examples
|
|
@@ -57,15 +68,12 @@ Unit accessors are now callable functions that create branded values:
|
|
|
57
68
|
|
|
58
69
|
```typescript
|
|
59
70
|
// Create branded values without manual type casting
|
|
60
|
-
const temp = registry.Celsius(25); // Returns
|
|
61
|
-
const distance = registry.meters(100); // Returns
|
|
71
|
+
const temp = registry.Celsius(25); // Returns WithTypedUnits<typeof CelsiusMetadata>
|
|
72
|
+
const distance = registry.meters(100); // Returns WithTypedUnits<typeof MetersMetadata>
|
|
62
73
|
|
|
63
74
|
// Fluent workflow
|
|
64
75
|
const fahrenheit = registry.Celsius.to.Fahrenheit(registry.Celsius(20));
|
|
65
76
|
|
|
66
|
-
// Compare with old way (still works)
|
|
67
|
-
const tempOld: Celsius = 25 as Celsius;
|
|
68
|
-
|
|
69
77
|
// Benefits:
|
|
70
78
|
// - Cleaner syntax
|
|
71
79
|
// - Less verbose than manual casting
|
|
@@ -73,11 +81,32 @@ const tempOld: Celsius = 25 as Celsius;
|
|
|
73
81
|
// - Works seamlessly with conversions
|
|
74
82
|
```
|
|
75
83
|
|
|
84
|
+
### Typed Metadata
|
|
85
|
+
|
|
86
|
+
Define metadata with minimal required fields (name + type):
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
const CelsiusMetadata = {
|
|
90
|
+
name: 'Celsius' as const,
|
|
91
|
+
type: 'number' as const
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const EtherMetadata = {
|
|
95
|
+
name: 'ether' as const,
|
|
96
|
+
type: 'bigint' as const
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const FlagMetadata = {
|
|
100
|
+
name: 'enabled' as const,
|
|
101
|
+
type: 'boolean' as const
|
|
102
|
+
};
|
|
103
|
+
```
|
|
104
|
+
|
|
76
105
|
### Basic Unit Conversions
|
|
77
106
|
|
|
78
107
|
```typescript
|
|
79
108
|
// Same registry as above
|
|
80
|
-
const distance
|
|
109
|
+
const distance = distanceRegistry.meters(10);
|
|
81
110
|
|
|
82
111
|
// Access units directly via property syntax
|
|
83
112
|
const feet = distanceRegistry.meters.to.feet(distance);
|
|
@@ -87,28 +116,38 @@ console.log(feet); // 32.8084
|
|
|
87
116
|
const feet2 = distanceRegistry.meters.to.feet(distanceRegistry.meters(10));
|
|
88
117
|
|
|
89
118
|
// Works in both directions
|
|
90
|
-
const meters = distanceRegistry.feet.to.meters(32.8084
|
|
119
|
+
const meters = distanceRegistry.feet.to.meters(distanceRegistry.feet(32.8084));
|
|
91
120
|
console.log(meters); // 10
|
|
92
121
|
```
|
|
93
122
|
|
|
94
123
|
### Bidirectional Converters
|
|
95
124
|
|
|
96
125
|
```typescript
|
|
97
|
-
import { createRegistry
|
|
126
|
+
import { createRegistry } from '@unacy/core';
|
|
127
|
+
import type { WithTypedUnits } from '@unacy/core';
|
|
98
128
|
|
|
99
|
-
|
|
100
|
-
|
|
129
|
+
const MetersMetadata = {
|
|
130
|
+
name: 'meters' as const,
|
|
131
|
+
type: 'number' as const
|
|
132
|
+
};
|
|
101
133
|
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
134
|
+
const KilometersMetadata = {
|
|
135
|
+
name: 'kilometers' as const,
|
|
136
|
+
type: 'number' as const
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
type Meters = WithTypedUnits<typeof MetersMetadata>;
|
|
140
|
+
type Kilometers = WithTypedUnits<typeof KilometersMetadata>;
|
|
141
|
+
|
|
142
|
+
const registry = createRegistry()
|
|
143
|
+
.register(MetersMetadata, KilometersMetadata, {
|
|
144
|
+
to: (m: number) => (m / 1000),
|
|
145
|
+
from: (km: number) => (km * 1000)
|
|
107
146
|
});
|
|
108
147
|
|
|
109
148
|
// Both directions work automatically
|
|
110
|
-
const km = registry.convert(5000
|
|
111
|
-
const m = registry.convert(5
|
|
149
|
+
const km = registry.convert(registry.meters(5000), 'meters').to('kilometers'); // 5
|
|
150
|
+
const m = registry.convert(registry.kilometers(5), 'kilometers').to('meters'); // 5000
|
|
112
151
|
```
|
|
113
152
|
|
|
114
153
|
### Multi-Hop Auto-Composition
|
|
@@ -116,24 +155,27 @@ const m = registry.convert(5 as Kilometers, 'kilometers').to('meters'); // 5000
|
|
|
116
155
|
The registry automatically composes converters via shortest path:
|
|
117
156
|
|
|
118
157
|
```typescript
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
158
|
+
const MetersMetadata = { name: 'meters' as const, type: 'number' as const };
|
|
159
|
+
const KilometersMetadata = { name: 'kilometers' as const, type: 'number' as const };
|
|
160
|
+
const MilesMetadata = { name: 'miles' as const, type: 'number' as const };
|
|
161
|
+
|
|
162
|
+
type Meters = WithTypedUnits<typeof MetersMetadata>;
|
|
163
|
+
type Kilometers = WithTypedUnits<typeof KilometersMetadata>;
|
|
164
|
+
type Miles = WithTypedUnits<typeof MilesMetadata>;
|
|
165
|
+
|
|
166
|
+
const registry = createRegistry()
|
|
167
|
+
.register(MetersMetadata, KilometersMetadata, {
|
|
168
|
+
to: (m: number) => (m / 1000),
|
|
169
|
+
from: (km: number) => (km * 1000)
|
|
127
170
|
})
|
|
128
|
-
.
|
|
129
|
-
to: (km) => (km * 0.621371)
|
|
130
|
-
from: (mi) => (mi / 0.621371)
|
|
171
|
+
.register(KilometersMetadata, MilesMetadata, {
|
|
172
|
+
to: (km: number) => (km * 0.621371),
|
|
173
|
+
from: (mi: number) => (mi / 0.621371)
|
|
131
174
|
});
|
|
132
175
|
|
|
133
176
|
// No direct meters→miles converter registered!
|
|
134
177
|
// Registry auto-composes: meters → kilometers → miles
|
|
135
|
-
const
|
|
136
|
-
const miles = registry.convert(meters, 'meters').to('miles');
|
|
178
|
+
const miles = registry.convert(registry.meters(5000), 'meters').to('miles');
|
|
137
179
|
console.log(miles); // 3.106855
|
|
138
180
|
```
|
|
139
181
|
|
|
@@ -165,18 +207,121 @@ const str = iso8601.format(now); // "2026-01-06T12:00:00.000Z"
|
|
|
165
207
|
const date = iso8601.parse('2026-01-06T12:00:00.000Z');
|
|
166
208
|
```
|
|
167
209
|
|
|
210
|
+
### Non-Primitive Types
|
|
211
|
+
|
|
212
|
+
Beyond primitives, the registry supports enums, classes, records, and tuples
|
|
213
|
+
as unit types. The `type` field in metadata IS the runtime value itself.
|
|
214
|
+
|
|
215
|
+
#### Enum Units
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
import { createRegistry } from '@unacy/core';
|
|
219
|
+
import type { WithTypedUnits, TypedMetadata } from '@unacy/core';
|
|
220
|
+
|
|
221
|
+
enum LogLevel { DEBUG = 0, INFO = 1, WARN = 2, ERROR = 3 }
|
|
222
|
+
|
|
223
|
+
const LogLevelMeta = { name: 'LogLevel', type: LogLevel } as const;
|
|
224
|
+
type LogLevelUnit = WithTypedUnits<typeof LogLevelMeta>;
|
|
225
|
+
|
|
226
|
+
const registry = createRegistry()
|
|
227
|
+
.register(LogLevelMeta, /* ... */);
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
#### Class Units
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
class Temperature {
|
|
234
|
+
constructor(public value: number, public scale: string) {}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const TempMeta = { name: 'Temperature', type: Temperature } as const;
|
|
238
|
+
type TempUnit = WithTypedUnits<typeof TempMeta>;
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
#### Record Units
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
const PointSchema = { x: 'number', y: 'number' } as const;
|
|
245
|
+
const PointMeta = { name: 'Point', type: PointSchema } as const;
|
|
246
|
+
type PointUnit = WithTypedUnits<typeof PointMeta>;
|
|
247
|
+
|
|
248
|
+
// Nested schemas
|
|
249
|
+
const LineMeta = {
|
|
250
|
+
name: 'Line',
|
|
251
|
+
type: { start: { x: 'number', y: 'number' }, end: { x: 'number', y: 'number' } }
|
|
252
|
+
} as const;
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
#### Tuple Units
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
const RGBSchema = ['number', 'number', 'number'] as const;
|
|
259
|
+
const RGBMeta = { name: 'RGB', type: RGBSchema } as const;
|
|
260
|
+
type RGBUnit = WithTypedUnits<typeof RGBMeta>;
|
|
261
|
+
|
|
262
|
+
// Optional and rest elements
|
|
263
|
+
const HeaderSchema = ['string', 'number?', '...string'] as const;
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
#### Runtime Type Guards
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
import {
|
|
270
|
+
isEnumMetadata, isClassMetadata,
|
|
271
|
+
isRecordMetadata, isTupleMetadata,
|
|
272
|
+
detectMetadataKind
|
|
273
|
+
} from '@unacy/core';
|
|
274
|
+
|
|
275
|
+
detectMetadataKind(LogLevelMeta); // 'enum'
|
|
276
|
+
detectMetadataKind(TempMeta); // 'class'
|
|
277
|
+
detectMetadataKind(PointMeta); // 'record'
|
|
278
|
+
detectMetadataKind(RGBMeta); // 'tuple'
|
|
279
|
+
|
|
280
|
+
if (isEnumMetadata(meta)) {
|
|
281
|
+
// meta.type is narrowed to EnumType
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
168
285
|
## API Reference
|
|
169
286
|
|
|
170
287
|
### Types
|
|
171
288
|
|
|
289
|
+
#### `WithTypedUnits<M extends TypedMetadata<T>>`
|
|
290
|
+
Brand a value with strongly-typed metadata for compile-time unit safety.
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
const CelsiusMetadata = { name: 'Celsius' as const, type: 'number' as const };
|
|
294
|
+
type Celsius = WithTypedUnits<typeof CelsiusMetadata>;
|
|
295
|
+
const temp: Celsius = tempRegistry.Celsius(25);
|
|
296
|
+
```
|
|
297
|
+
|
|
172
298
|
#### `WithUnits<T, U>`
|
|
173
|
-
Brand a value with a unit identifier for compile-time safety.
|
|
299
|
+
Legacy: Brand a value with a unit identifier for compile-time safety.
|
|
174
300
|
|
|
175
301
|
```typescript
|
|
176
302
|
type Celsius = WithUnits<number, 'Celsius'>;
|
|
177
303
|
const temp: Celsius = 25 as Celsius;
|
|
178
304
|
```
|
|
179
305
|
|
|
306
|
+
#### `TypedMetadata<T>`
|
|
307
|
+
Minimal metadata type with name and type information.
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
type NumericMetadata = TypedMetadata<number>;
|
|
311
|
+
// { name: string; type: 'number' }
|
|
312
|
+
|
|
313
|
+
type StringMetadata = TypedMetadata<string>;
|
|
314
|
+
// { name: string; type: 'string' }
|
|
315
|
+
|
|
316
|
+
// Non-primitive: type IS the value itself
|
|
317
|
+
type EnumMetadata = TypedMetadata<typeof LogLevel>;
|
|
318
|
+
// { name: string; type: typeof LogLevel }
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
#### `SupportedType`
|
|
322
|
+
Union of all types that can be used as a unit base:
|
|
323
|
+
`number | string | boolean | bigint | EnumType | ClassType | RecordSchema | TupleSchema`
|
|
324
|
+
|
|
180
325
|
#### `WithFormat<T, F>`
|
|
181
326
|
Brand a value with a format identifier for serialization safety.
|
|
182
327
|
|
|
@@ -198,8 +343,8 @@ Pair of converters for two-way transformations.
|
|
|
198
343
|
|
|
199
344
|
```typescript
|
|
200
345
|
const meterKm: BidirectionalConverter<Meters, Kilometers> = {
|
|
201
|
-
to: (m) => (m / 1000)
|
|
202
|
-
from: (km) => (km * 1000)
|
|
346
|
+
to: (m: number) => (m / 1000),
|
|
347
|
+
from: (km: number) => (km * 1000)
|
|
203
348
|
};
|
|
204
349
|
```
|
|
205
350
|
|
|
@@ -216,14 +361,14 @@ const registry = createRegistry<'A' | 'B' | 'C'>();
|
|
|
216
361
|
Register a unidirectional converter.
|
|
217
362
|
|
|
218
363
|
```typescript
|
|
219
|
-
registry.register(
|
|
364
|
+
registry.register(CelsiusMetadata, FahrenheitMetadata, celsiusToFahrenheit);
|
|
220
365
|
```
|
|
221
366
|
|
|
222
|
-
#### `
|
|
367
|
+
#### `register(from, to, converter)` (bidirectional)
|
|
223
368
|
Register both directions at once.
|
|
224
369
|
|
|
225
370
|
```typescript
|
|
226
|
-
registry.
|
|
371
|
+
registry.register(MetersMetadata, KilometersMetadata, meterKm);
|
|
227
372
|
```
|
|
228
373
|
|
|
229
374
|
#### `convert(value, fromUnit).to(toUnit)`
|
|
@@ -243,11 +388,12 @@ const result = registry.convert(value, 'Celsius').to('Fahrenheit');
|
|
|
243
388
|
|
|
244
389
|
## Best Practices
|
|
245
390
|
|
|
246
|
-
1. **Define
|
|
391
|
+
1. **Define metadata as const at module boundaries** for consistency
|
|
247
392
|
2. **Use bidirectional converters** when both directions are needed
|
|
248
393
|
3. **Document precision loss** in converters
|
|
249
394
|
4. **Cache registries** for performance
|
|
250
|
-
5. **
|
|
395
|
+
5. **Use `WithTypedUnits`** for brand-new code; leverage type inference
|
|
396
|
+
6. **Validate with Zod** in parsers
|
|
251
397
|
|
|
252
398
|
## Performance
|
|
253
399
|
|
package/dist/converters.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Type-safe converter function signatures
|
|
3
3
|
* @packageDocumentation
|
|
4
4
|
*/
|
|
5
|
-
import type { PrimitiveType, Relax as BaseRelax } from './types.js';
|
|
5
|
+
import type { PrimitiveType, Relax as BaseRelax, Unwrap } from './types.js';
|
|
6
6
|
/**
|
|
7
7
|
* Unidirectional converter from one unit to another.
|
|
8
8
|
*
|
|
@@ -25,7 +25,7 @@ import type { PrimitiveType, Relax as BaseRelax } from './types.js';
|
|
|
25
25
|
*/
|
|
26
26
|
export type Converter<TInput, TOutput> = (input: TInput) => TOutput;
|
|
27
27
|
export type RelaxConverter<ConverterType> = ConverterType extends Converter<infer A extends PrimitiveType, infer B extends PrimitiveType> ? (input: BaseRelax<A>) => BaseRelax<B> : (input: PrimitiveType) => PrimitiveType;
|
|
28
|
-
export type Relax<T extends PrimitiveType | Converter<any, any> | BidirectionalConverter<any, any>> = T extends PrimitiveType ? BaseRelax<T> : T extends Converter<
|
|
28
|
+
export type Relax<T extends PrimitiveType | Converter<any, any> | BidirectionalConverter<any, any>> = T extends PrimitiveType ? BaseRelax<T> : T extends Converter<unknown, unknown> ? RelaxConverter<T> : RelaxBidirectionalConverter<T>;
|
|
29
29
|
/**
|
|
30
30
|
* Bidirectional converter with forward and reverse transformations.
|
|
31
31
|
*
|
|
@@ -53,10 +53,34 @@ export type BidirectionalConverter<TInput, TOutput> = {
|
|
|
53
53
|
from: Converter<TOutput, TInput>;
|
|
54
54
|
};
|
|
55
55
|
export type RelaxBidirectionalConverter<ConverterType> = ConverterType extends BidirectionalConverter<infer A extends PrimitiveType, infer B extends PrimitiveType> ? {
|
|
56
|
-
to: (input: BaseRelax<A>) =>
|
|
57
|
-
from: (input: BaseRelax<B>) =>
|
|
56
|
+
to: (input: BaseRelax<A>) => B;
|
|
57
|
+
from: (input: BaseRelax<B>) => A;
|
|
58
58
|
} : {
|
|
59
59
|
to: (input: PrimitiveType) => PrimitiveType;
|
|
60
60
|
from: (input: PrimitiveType) => PrimitiveType;
|
|
61
61
|
};
|
|
62
|
+
/**
|
|
63
|
+
* A converter that accepts the branded input type but returns
|
|
64
|
+
* unwrapped output. This eliminates the need to cast return values
|
|
65
|
+
* to branded types inside converter functions, while preserving
|
|
66
|
+
* full autocompletion on the input parameter.
|
|
67
|
+
*
|
|
68
|
+
* Since `Tagged<T, ...> extends T`, strict converters returning branded
|
|
69
|
+
* types are also assignable to this type.
|
|
70
|
+
*
|
|
71
|
+
* @template TInput - Source unit-tagged type
|
|
72
|
+
* @template TOutput - Destination unit-tagged type
|
|
73
|
+
*/
|
|
74
|
+
export type RelaxedConverter<TInput, TOutput> = (input: TInput) => Unwrap<TOutput>;
|
|
75
|
+
/**
|
|
76
|
+
* A bidirectional converter with relaxed (unwrapped) output types.
|
|
77
|
+
* Input remains branded for full autocompletion.
|
|
78
|
+
*
|
|
79
|
+
* @template TInput - First unit-tagged type
|
|
80
|
+
* @template TOutput - Second unit-tagged type
|
|
81
|
+
*/
|
|
82
|
+
export type RelaxedBidirectionalConverter<TInput, TOutput> = {
|
|
83
|
+
to: RelaxedConverter<TInput, TOutput>;
|
|
84
|
+
from: RelaxedConverter<TOutput, TInput>;
|
|
85
|
+
};
|
|
62
86
|
//# sourceMappingURL=converters.d.ts.map
|
package/dist/converters.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"converters.d.ts","sourceRoot":"","sources":["../src/converters.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"converters.d.ts","sourceRoot":"","sources":["../src/converters.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAE5E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,SAAS,CAAC,MAAM,EAAE,OAAO,IAAI,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;AAEpE,MAAM,MAAM,cAAc,CAAC,aAAa,IACtC,aAAa,SAAS,SAAS,CAAC,MAAM,CAAC,SAAS,aAAa,EAAE,MAAM,CAAC,SAAS,aAAa,CAAC,GACzF,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,GACrC,CAAC,KAAK,EAAE,aAAa,KAAK,aAAa,CAAC;AAE9C,MAAM,MAAM,KAAK,CACf,CAAC,SAAS,aAAa,GAAG,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,sBAAsB,CAAC,GAAG,EAAE,GAAG,CAAC,IAC9E,CAAC,SAAS,aAAa,GACvB,SAAS,CAAC,CAAC,CAAC,GACZ,CAAC,SAAS,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,GACnC,cAAc,CAAC,CAAC,CAAC,GACjB,2BAA2B,CAAC,CAAC,CAAC,CAAC;AAErC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,sBAAsB,CAAC,MAAM,EAAE,OAAO,IAAI;IACpD,EAAE,EAAE,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,IAAI,EAAE,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,2BAA2B,CAAC,aAAa,IACnD,aAAa,SAAS,sBAAsB,CAC1C,MAAM,CAAC,SAAS,aAAa,EAC7B,MAAM,CAAC,SAAS,aAAa,CAC9B,GACG;IACE,EAAE,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC/B,IAAI,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;CAClC,GACD;IACE,EAAE,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,aAAa,CAAC;IAC5C,IAAI,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,aAAa,CAAC;CAC/C,CAAC;AAER;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,gBAAgB,CAAC,MAAM,EAAE,OAAO,IAAI,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,OAAO,CAAC,CAAC;AAEnF;;;;;;GAMG;AACH,MAAM,MAAM,6BAA6B,CAAC,MAAM,EAAE,OAAO,IAAI;IAC3D,EAAE,EAAE,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,IAAI,EAAE,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;CACzC,CAAC"}
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,UAAW,SAAQ,KAAK;IACnC,YAAY,OAAe,EAAE;QAC3B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QAEzB,wDAAwD;QACxD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC;IAAA,CACnD;CACF;AAED;;GAEG;AACH,MAAM,OAAO,UAAW,SAAQ,UAAU;IACxB,IAAI,CAAgB;IAEpC,YAAY,IAAmB,EAAE;QAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,UAAW,SAAQ,KAAK;IACnC,YAAY,OAAe,EAAE;QAC3B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QAEzB,wDAAwD;QACxD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC;IAAA,CACnD;CACF;AAED;;GAEG;AACH,MAAM,OAAO,UAAW,SAAQ,UAAU;IACxB,IAAI,CAAgB;IAEpC,YAAY,IAAmB,EAAE;QAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7C,KAAK,CAAC,sCAAsC,OAAO,EAAE,CAAC,CAAC;QACvD,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAAA,CAClB;CACF;AAED;;GAEG;AACH,MAAM,OAAO,aAAc,SAAQ,UAAU;IAC3B,IAAI,CAAc;IAClB,EAAE,CAAc;IAChB,QAAQ,CAAS;IAEjC,YAAY,IAAiB,EAAE,EAAe,EAAE,QAAgB,EAAE;QAChE,KAAK,CACH,+BAA+B,QAAQ,kCAAkC,MAAM,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,EAAE,CAAC,EAAE,CACzG,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAAA,CAC1B;CACF;AAED;;GAEG;AACH,MAAM,OAAO,eAAgB,SAAQ,UAAU;IAC7B,IAAI,CAAc;IAClB,EAAE,CAAc;IAEhC,YAAY,IAAiB,EAAE,EAAe,EAAE,MAAe,EAAE;QAC/D,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9C,KAAK,CAAC,uBAAuB,MAAM,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,CAAC;QAC1E,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IAAA,CACd;CACF;AAED;;GAEG;AACH,MAAM,OAAO,UAAW,SAAQ,UAAU;IACxB,MAAM,CAAS;IACf,KAAK,CAAS;IACd,MAAM,CAAS;IAE/B,YAAY,MAAc,EAAE,KAAa,EAAE,MAAc,EAAE;QACzD,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;QAC9E,MAAM,YAAY,GAAG,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC;QAE1D,KAAK,CAAC,iBAAiB,YAAY,QAAQ,MAAM,KAAK,MAAM,EAAE,CAAC,CAAC;QAChE,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IAAA,CACtB;CACF"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
* Unacy Core - Type-safe unit and format conversion library
|
|
3
3
|
* @packageDocumentation
|
|
4
4
|
*/
|
|
5
|
-
export type { WithUnits, WithFormat, UnitMetadata, Relax, PrimitiveType,
|
|
6
|
-
export type { Converter, BidirectionalConverter } from './converters.js';
|
|
5
|
+
export type { WithUnits, WithTypedUnits, WithFormat, BaseMetadata, TypedMetadata, UnitMetadata, Relax, PrimitiveType, SupportedType, EnumType, ClassType, RecordSchema, TupleSchema, ToPrimitiveTypeName } from './types.js';
|
|
6
|
+
export type { Converter, BidirectionalConverter, RelaxedConverter, RelaxedBidirectionalConverter } from './converters.js';
|
|
7
7
|
export type { Formatter, Parser, FormatterParser } from './formatters.js';
|
|
8
|
-
export type {
|
|
8
|
+
export type { UnitRegistry, UnitMap, UnitAccessor } from './registry.js';
|
|
9
9
|
export { createRegistry } from './registry.js';
|
|
10
10
|
export { UnacyError, CycleError, MaxDepthError, ConversionError, ParseError } from './errors.js';
|
|
11
|
-
export { createParserWithSchema } from './utils/validation.js';
|
|
11
|
+
export { createParserWithSchema, validateEnum, validateClass, validateRecordSchema, validateTupleSchema, isEnumMetadata, isClassMetadata, isRecordMetadata, isTupleMetadata, detectMetadataKind } from './utils/validation.js';
|
|
12
|
+
export type { PrimitiveTypeFromName, InferFromRecordSchema, InferFromTupleSchema } from './types.js';
|
|
12
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,YAAY,EACV,SAAS,EACT,cAAc,EACd,UAAU,EACV,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,KAAK,EACL,aAAa,EACb,aAAa,EACb,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,WAAW,EACX,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAGpB,YAAY,EACV,SAAS,EACT,sBAAsB,EACtB,gBAAgB,EAChB,6BAA6B,EAC9B,MAAM,iBAAiB,CAAC;AAGzB,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAG1E,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAG/C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGjG,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EACnB,MAAM,uBAAuB,CAAC;AAG/B,YAAY,EACV,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -6,5 +6,5 @@ export { createRegistry } from './registry.js';
|
|
|
6
6
|
// Errors
|
|
7
7
|
export { UnacyError, CycleError, MaxDepthError, ConversionError, ParseError } from './errors.js';
|
|
8
8
|
// Utilities
|
|
9
|
-
export { createParserWithSchema } from './utils/validation.js';
|
|
9
|
+
export { createParserWithSchema, validateEnum, validateClass, validateRecordSchema, validateTupleSchema, isEnumMetadata, isClassMetadata, isRecordMetadata, isTupleMetadata, detectMetadataKind } from './utils/validation.js';
|
|
10
10
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAiCH,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,SAAS;AACT,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEjG,YAAY;AACZ,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EACnB,MAAM,uBAAuB,CAAC"}
|
package/dist/registry.d.ts
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
* Converter registry with auto-composition via BFS
|
|
3
3
|
* @packageDocumentation
|
|
4
4
|
*/
|
|
5
|
-
import type { Converter,
|
|
6
|
-
import type { UnitsFor, WithUnits,
|
|
5
|
+
import type { Converter, RelaxedConverter, RelaxedBidirectionalConverter } from './converters.js';
|
|
6
|
+
import type { UnitsFor, WithUnits, TypedMetadata, NameFor, WithTypedUnits, UnitsOf, BaseMetadata, SupportedType, InferCallableArgs, Relax as RelaxUnits } from './types.js';
|
|
7
7
|
/**
|
|
8
8
|
* Represents a conversion edge from one unit to another
|
|
9
9
|
* Edges store the unit names as strings, but the type system ensures
|
|
10
10
|
* they correspond to valid WithUnits types
|
|
11
11
|
*/
|
|
12
|
-
type Edge<From extends
|
|
12
|
+
type Edge<From extends WithTypedUnits<any> = WithTypedUnits<TypedMetadata<SupportedType>>, To extends WithTypedUnits<any> = WithTypedUnits<TypedMetadata<SupportedType>>> = readonly [From, To];
|
|
13
13
|
/**
|
|
14
14
|
* Extract all unique 'from' units from a list of edges
|
|
15
15
|
*/
|
|
@@ -17,79 +17,77 @@ type FromUnits<Edges extends readonly Edge[]> = Edges[number][0];
|
|
|
17
17
|
/**
|
|
18
18
|
* Extract all 'to' units for a specific 'from' unit string
|
|
19
19
|
*/
|
|
20
|
-
type ToUnitsFor<Edges extends readonly Edge[], FromUnit extends
|
|
20
|
+
type ToUnitsFor<Edges extends readonly Edge[], FromUnit extends WithTypedUnits<any>> = Extract<Edges[number], readonly [FromUnit, any]>[1];
|
|
21
|
+
/**
|
|
22
|
+
* Extract metadata type from a WithUnits type
|
|
23
|
+
*/
|
|
21
24
|
/**
|
|
22
25
|
* Type for unit accessor with metadata and conversion methods
|
|
23
26
|
* Can be called as a function to create branded unit values
|
|
24
27
|
*/
|
|
25
|
-
export type UnitAccessor<From extends
|
|
28
|
+
export type UnitAccessor<From extends WithTypedUnits<TypedMetadata<SupportedType>>, Edges extends readonly Edge[]> = {
|
|
26
29
|
/**
|
|
27
|
-
* Create a branded value with this unit
|
|
28
|
-
*
|
|
30
|
+
* Create a branded value with this unit.
|
|
31
|
+
* For tuples, pass members as individual arguments.
|
|
32
|
+
* For classes, pass constructor parameters directly.
|
|
33
|
+
* @param args - The value(s) to brand
|
|
29
34
|
* @returns The value branded with this unit type
|
|
30
35
|
*/
|
|
31
|
-
(
|
|
36
|
+
(...args: InferCallableArgs<From>): From;
|
|
32
37
|
to: {
|
|
33
|
-
[To in ToUnitsFor<Edges, From> as UnitsFor<To>]: (value: RelaxUnits<From>) =>
|
|
38
|
+
[To in ToUnitsFor<Edges, From> as UnitsFor<To>]: (value: RelaxUnits<From>) => To;
|
|
34
39
|
};
|
|
35
40
|
/**
|
|
36
41
|
* Add metadata to this unit
|
|
37
42
|
*/
|
|
38
|
-
addMetadata(metadata:
|
|
43
|
+
addMetadata<NewM extends Record<string, unknown>>(metadata: NewM): UnitRegistry<Edges extends readonly (infer E)[] ? E[] : never> & UnitMap<Edges>;
|
|
39
44
|
/**
|
|
40
45
|
* Register a converter from this unit to another unit
|
|
41
46
|
*/
|
|
42
|
-
register<To extends
|
|
43
|
-
register<To extends
|
|
44
|
-
} &
|
|
45
|
-
[K: string]: unknown;
|
|
46
|
-
};
|
|
47
|
+
register<To extends WithTypedUnits<ToMeta>, ToMeta extends TypedMetadata<SupportedType>>(to: UnitsFor<To> | ToMeta, converter: RelaxedConverter<From, To>): UnitRegistry<[...Edges, Edge<From, To>]> & UnitMap<[...Edges, Edge<From, To>]>;
|
|
48
|
+
register<To extends WithTypedUnits<ToMeta>, ToMeta extends TypedMetadata<SupportedType>>(to: UnitsFor<To> | ToMeta, converter: RelaxedBidirectionalConverter<From, To>): UnitRegistry<[...Edges, Edge<From, To>, Edge<To, From>]> & UnitMap<[...Edges, Edge<From, To>, Edge<To, From>]>;
|
|
49
|
+
} & UnitsOf<From>;
|
|
47
50
|
/**
|
|
48
51
|
* Type for unit-based conversion accessors
|
|
49
52
|
* Provides the shape: registry.Celsius.to.Fahrenheit(value)
|
|
50
53
|
* Only allows conversions that have been registered
|
|
51
54
|
*/
|
|
52
|
-
export type
|
|
53
|
-
[FU in FromUnits<Edges> as UnitsFor<FU>]: UnitAccessor<
|
|
55
|
+
export type UnitMap<Edges extends readonly Edge[]> = {
|
|
56
|
+
[FU in FromUnits<Edges> as UnitsFor<FU>]: UnitAccessor<FU, Edges>;
|
|
54
57
|
};
|
|
55
58
|
/**
|
|
56
59
|
* Registry for managing and composing unit converters
|
|
57
60
|
*/
|
|
58
|
-
export interface
|
|
61
|
+
export interface UnitRegistry<Edges extends Edge[] = []> {
|
|
62
|
+
register<From extends WithTypedUnits<FromMeta>, FromMeta extends TypedMetadata<SupportedType>>(unit: FromMeta): this & {
|
|
63
|
+
[K in NameFor<From>]: UnitAccessor<From, Edges>;
|
|
64
|
+
};
|
|
59
65
|
/**
|
|
60
66
|
* Register a unidirectional converter
|
|
61
67
|
*
|
|
62
|
-
* @param from - Source unit
|
|
63
|
-
* @param to - Destination unit
|
|
64
|
-
* @param converter - Converter function
|
|
68
|
+
* @param from - Source unit (string name or metadata object)
|
|
69
|
+
* @param to - Destination unit (string name or metadata object)
|
|
70
|
+
* @param converter - Converter function (input is branded, output can be plain or branded)
|
|
65
71
|
* @returns New registry instance with the converter registered
|
|
66
72
|
*/
|
|
67
|
-
register<From extends
|
|
73
|
+
register<From extends WithTypedUnits<FromMeta>, To extends WithTypedUnits<ToMeta>, FromMeta extends TypedMetadata<SupportedType>, ToMeta extends TypedMetadata<SupportedType>>(from: UnitsFor<From> | FromMeta, to: UnitsFor<To> | ToMeta, converter: RelaxedConverter<From, To>): UnitRegistry<[...Edges, Edge<From, To>]> & UnitMap<[...Edges, Edge<From, To>]>;
|
|
68
74
|
/**
|
|
69
75
|
* Register a bidirectional converter (both directions)
|
|
70
76
|
*
|
|
71
|
-
* @param from - First unit
|
|
72
|
-
* @param to - Second unit
|
|
73
|
-
* @param converter - Bidirectional converter object
|
|
77
|
+
* @param from - First unit (string name or metadata object)
|
|
78
|
+
* @param to - Second unit (string name or metadata object)
|
|
79
|
+
* @param converter - Bidirectional converter object (input branded, output can be plain or branded)
|
|
74
80
|
* @returns New registry instance with both converters registered
|
|
75
81
|
*/
|
|
76
|
-
register<From extends
|
|
77
|
-
...Edges,
|
|
78
|
-
Edge<From, To>,
|
|
79
|
-
Edge<To, From>
|
|
80
|
-
]> & ConverterMap<[
|
|
81
|
-
...Edges,
|
|
82
|
-
Edge<From, To>,
|
|
83
|
-
Edge<To, From>
|
|
84
|
-
]>;
|
|
82
|
+
register<From extends WithTypedUnits<FromMeta>, To extends WithTypedUnits<ToMeta>, FromMeta extends TypedMetadata<SupportedType>, ToMeta extends TypedMetadata<SupportedType>>(from: UnitsFor<From> | FromMeta, to: UnitsFor<To> | ToMeta, converter: RelaxedBidirectionalConverter<From, To>): UnitRegistry<[...Edges, Edge<From, To>, Edge<To, From>]> & UnitMap<[...Edges, Edge<From, To>, Edge<To, From>]>;
|
|
85
83
|
/**
|
|
86
84
|
* Explicitly allow a conversion path in the type system (for multi-hop conversions)
|
|
87
85
|
*
|
|
88
86
|
* This method verifies that a conversion path exists at runtime (via BFS) and adds it
|
|
89
87
|
* to the type system so it can be used with type-safe accessor syntax.
|
|
90
88
|
*
|
|
91
|
-
* @param from - Source unit string
|
|
92
|
-
* @param to - Destination unit string
|
|
89
|
+
* @param from - Source unit (string name or metadata object)
|
|
90
|
+
* @param to - Destination unit (string name or metadata object)
|
|
93
91
|
* @returns New registry instance with the conversion path enabled in types
|
|
94
92
|
* @throws ConversionError if no path exists between the units
|
|
95
93
|
*
|
|
@@ -104,7 +102,7 @@ export interface ConverterRegistry<Edges extends Edge[] = []> {
|
|
|
104
102
|
* const f = registry.Celsius.to.Fahrenheit(temp);
|
|
105
103
|
* ```
|
|
106
104
|
*/
|
|
107
|
-
allow<From extends
|
|
105
|
+
allow<From extends WithTypedUnits<FromMeta>, To extends WithTypedUnits<ToMeta>, FromMeta extends TypedMetadata<SupportedType>, ToMeta extends TypedMetadata<SupportedType>>(from: UnitsFor<From> | FromMeta, to: UnitsFor<To> | ToMeta): UnitRegistry<[...Edges, Edge<From, To>]> & UnitMap<[...Edges, Edge<From, To>]>;
|
|
108
106
|
/**
|
|
109
107
|
* Get a converter (direct or composed via BFS)
|
|
110
108
|
*
|
|
@@ -112,7 +110,7 @@ export interface ConverterRegistry<Edges extends Edge[] = []> {
|
|
|
112
110
|
* @param to - Destination unit
|
|
113
111
|
* @returns Converter function, or undefined if no path exists
|
|
114
112
|
*/
|
|
115
|
-
getConverter<From extends WithUnits<
|
|
113
|
+
getConverter<From extends WithUnits<SupportedType, BaseMetadata>, To extends WithUnits<SupportedType, BaseMetadata>>(from: UnitsFor<From>, to: UnitsFor<To>): Converter<From, To> | undefined;
|
|
116
114
|
/**
|
|
117
115
|
* Convert a value using fluent API
|
|
118
116
|
*
|
|
@@ -120,8 +118,8 @@ export interface ConverterRegistry<Edges extends Edge[] = []> {
|
|
|
120
118
|
* @param fromUnit - Source unit
|
|
121
119
|
* @returns Object with to() method for conversion
|
|
122
120
|
*/
|
|
123
|
-
convert<From extends WithUnits<
|
|
124
|
-
to<To extends WithUnits<
|
|
121
|
+
convert<From extends WithUnits<SupportedType, BaseMetadata>>(value: From, fromUnit: UnitsFor<From>): {
|
|
122
|
+
to<To extends WithUnits<SupportedType, BaseMetadata>>(unit: UnitsFor<To>): To;
|
|
125
123
|
};
|
|
126
124
|
}
|
|
127
125
|
/**
|
|
@@ -150,6 +148,6 @@ export interface ConverterRegistry<Edges extends Edge[] = []> {
|
|
|
150
148
|
* console.log(fahrenheit); // 77
|
|
151
149
|
* ```
|
|
152
150
|
*/
|
|
153
|
-
export declare function createRegistry<Edges extends readonly Edge[] = []>():
|
|
151
|
+
export declare function createRegistry<Edges extends readonly Edge[] = []>(): UnitRegistry<Edges extends readonly (infer E)[] ? E[] : never> & UnitMap<Edges>;
|
|
154
152
|
export {};
|
|
155
153
|
//# sourceMappingURL=registry.d.ts.map
|