unacy 0.5.0 → 0.7.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 +104 -35
- package/dist/converters.d.ts +8 -8
- package/dist/converters.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/registry.d.ts +38 -44
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +44 -14
- package/dist/registry.js.map +1 -1
- package/dist/types.d.ts +44 -11
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/validation.d.ts +1 -2
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js.map +1 -1
- package/package.json +10 -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,7 @@ 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
|
|
14
15
|
|
|
15
16
|
## Installation
|
|
16
17
|
|
|
@@ -21,15 +22,27 @@ pnpm add @unacy/core
|
|
|
21
22
|
## Quick Start
|
|
22
23
|
|
|
23
24
|
```typescript
|
|
24
|
-
import { createRegistry
|
|
25
|
+
import { createRegistry } from '@unacy/core';
|
|
26
|
+
import type { WithTypedUnits } from '@unacy/core';
|
|
25
27
|
|
|
26
|
-
// Define your
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
// Define metadata for your units (name + type)
|
|
29
|
+
const CelsiusMetadata = {
|
|
30
|
+
name: 'Celsius' as const,
|
|
31
|
+
type: 'number' as const
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const FahrenheitMetadata = {
|
|
35
|
+
name: 'Fahrenheit' as const,
|
|
36
|
+
type: 'number' as const
|
|
37
|
+
};
|
|
29
38
|
|
|
30
|
-
//
|
|
39
|
+
// Define your unit types with metadata
|
|
40
|
+
type Celsius = WithTypedUnits<typeof CelsiusMetadata>;
|
|
41
|
+
type Fahrenheit = WithTypedUnits<typeof FahrenheitMetadata>;
|
|
42
|
+
|
|
43
|
+
// Create a registry and register converters
|
|
31
44
|
const tempRegistry = createRegistry()
|
|
32
|
-
.register(
|
|
45
|
+
.register(CelsiusMetadata, FahrenheitMetadata, (c) => ((c * 9/5) + 32));
|
|
33
46
|
|
|
34
47
|
// Create branded values using callable accessors (NEW!)
|
|
35
48
|
const temp = tempRegistry.Celsius(25); // Returns Celsius type
|
|
@@ -57,8 +70,8 @@ Unit accessors are now callable functions that create branded values:
|
|
|
57
70
|
|
|
58
71
|
```typescript
|
|
59
72
|
// Create branded values without manual type casting
|
|
60
|
-
const temp = registry.Celsius(25); // Returns
|
|
61
|
-
const distance = registry.meters(100); // Returns
|
|
73
|
+
const temp = registry.Celsius(25); // Returns WithTypedUnits<typeof CelsiusMetadata>
|
|
74
|
+
const distance = registry.meters(100); // Returns WithTypedUnits<typeof MetersMetadata>
|
|
62
75
|
|
|
63
76
|
// Fluent workflow
|
|
64
77
|
const fahrenheit = registry.Celsius.to.Fahrenheit(registry.Celsius(20));
|
|
@@ -73,6 +86,27 @@ const tempOld: Celsius = 25 as Celsius;
|
|
|
73
86
|
// - Works seamlessly with conversions
|
|
74
87
|
```
|
|
75
88
|
|
|
89
|
+
### Typed Metadata
|
|
90
|
+
|
|
91
|
+
Define metadata with minimal required fields (name + type):
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
const CelsiusMetadata = {
|
|
95
|
+
name: 'Celsius' as const,
|
|
96
|
+
type: 'number' as const
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const EtherMetadata = {
|
|
100
|
+
name: 'ether' as const,
|
|
101
|
+
type: 'bigint' as const
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const FlagMetadata = {
|
|
105
|
+
name: 'enabled' as const,
|
|
106
|
+
type: 'boolean' as const
|
|
107
|
+
};
|
|
108
|
+
```
|
|
109
|
+
|
|
76
110
|
### Basic Unit Conversions
|
|
77
111
|
|
|
78
112
|
```typescript
|
|
@@ -94,16 +128,26 @@ console.log(meters); // 10
|
|
|
94
128
|
### Bidirectional Converters
|
|
95
129
|
|
|
96
130
|
```typescript
|
|
97
|
-
import { createRegistry
|
|
131
|
+
import { createRegistry } from '@unacy/core';
|
|
132
|
+
import type { WithTypedUnits } from '@unacy/core';
|
|
98
133
|
|
|
99
|
-
|
|
100
|
-
|
|
134
|
+
const MetersMetadata = {
|
|
135
|
+
name: 'meters' as const,
|
|
136
|
+
type: 'number' as const
|
|
137
|
+
};
|
|
101
138
|
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
139
|
+
const KilometersMetadata = {
|
|
140
|
+
name: 'kilometers' as const,
|
|
141
|
+
type: 'number' as const
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
type Meters = WithTypedUnits<typeof MetersMetadata>;
|
|
145
|
+
type Kilometers = WithTypedUnits<typeof KilometersMetadata>;
|
|
146
|
+
|
|
147
|
+
const registry = createRegistry()
|
|
148
|
+
.register(MetersMetadata, KilometersMetadata, {
|
|
149
|
+
to: (m: number) => (m / 1000),
|
|
150
|
+
from: (km: number) => (km * 1000)
|
|
107
151
|
});
|
|
108
152
|
|
|
109
153
|
// Both directions work automatically
|
|
@@ -116,18 +160,22 @@ const m = registry.convert(5 as Kilometers, 'kilometers').to('meters'); // 5000
|
|
|
116
160
|
The registry automatically composes converters via shortest path:
|
|
117
161
|
|
|
118
162
|
```typescript
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
163
|
+
const MetersMetadata = { name: 'meters' as const, type: 'number' as const };
|
|
164
|
+
const KilometersMetadata = { name: 'kilometers' as const, type: 'number' as const };
|
|
165
|
+
const MilesMetadata = { name: 'miles' as const, type: 'number' as const };
|
|
166
|
+
|
|
167
|
+
type Meters = WithTypedUnits<typeof MetersMetadata>;
|
|
168
|
+
type Kilometers = WithTypedUnits<typeof KilometersMetadata>;
|
|
169
|
+
type Miles = WithTypedUnits<typeof MilesMetadata>;
|
|
170
|
+
|
|
171
|
+
const registry = createRegistry()
|
|
172
|
+
.register(MetersMetadata, KilometersMetadata, {
|
|
173
|
+
to: (m: number) => (m / 1000),
|
|
174
|
+
from: (km: number) => (km * 1000)
|
|
127
175
|
})
|
|
128
|
-
.
|
|
129
|
-
to: (km) => (km * 0.621371)
|
|
130
|
-
from: (mi) => (mi / 0.621371)
|
|
176
|
+
.register(KilometersMetadata, MilesMetadata, {
|
|
177
|
+
to: (km: number) => (km * 0.621371),
|
|
178
|
+
from: (mi: number) => (mi / 0.621371)
|
|
131
179
|
});
|
|
132
180
|
|
|
133
181
|
// No direct meters→miles converter registered!
|
|
@@ -169,14 +217,34 @@ const date = iso8601.parse('2026-01-06T12:00:00.000Z');
|
|
|
169
217
|
|
|
170
218
|
### Types
|
|
171
219
|
|
|
220
|
+
#### `WithTypedUnits<M extends TypedMetadata<T>>`
|
|
221
|
+
Brand a value with strongly-typed metadata for compile-time unit safety.
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
const CelsiusMetadata = { name: 'Celsius' as const, type: 'number' as const };
|
|
225
|
+
type Celsius = WithTypedUnits<typeof CelsiusMetadata>;
|
|
226
|
+
const temp: Celsius = tempRegistry.Celsius(25);
|
|
227
|
+
```
|
|
228
|
+
|
|
172
229
|
#### `WithUnits<T, U>`
|
|
173
|
-
Brand a value with a unit identifier for compile-time safety.
|
|
230
|
+
Legacy: Brand a value with a unit identifier for compile-time safety.
|
|
174
231
|
|
|
175
232
|
```typescript
|
|
176
233
|
type Celsius = WithUnits<number, 'Celsius'>;
|
|
177
234
|
const temp: Celsius = 25 as Celsius;
|
|
178
235
|
```
|
|
179
236
|
|
|
237
|
+
#### `TypedMetadata<T>`
|
|
238
|
+
Minimal metadata type with name and type information.
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
type NumericMetadata = TypedMetadata<number>;
|
|
242
|
+
// { name: string; type: 'number' }
|
|
243
|
+
|
|
244
|
+
type StringMetadata = TypedMetadata<string>;
|
|
245
|
+
// { name: string; type: 'string' }
|
|
246
|
+
```
|
|
247
|
+
|
|
180
248
|
#### `WithFormat<T, F>`
|
|
181
249
|
Brand a value with a format identifier for serialization safety.
|
|
182
250
|
|
|
@@ -198,8 +266,8 @@ Pair of converters for two-way transformations.
|
|
|
198
266
|
|
|
199
267
|
```typescript
|
|
200
268
|
const meterKm: BidirectionalConverter<Meters, Kilometers> = {
|
|
201
|
-
to: (m) => (m / 1000)
|
|
202
|
-
from: (km) => (km * 1000)
|
|
269
|
+
to: (m: number) => (m / 1000),
|
|
270
|
+
from: (km: number) => (km * 1000)
|
|
203
271
|
};
|
|
204
272
|
```
|
|
205
273
|
|
|
@@ -216,14 +284,14 @@ const registry = createRegistry<'A' | 'B' | 'C'>();
|
|
|
216
284
|
Register a unidirectional converter.
|
|
217
285
|
|
|
218
286
|
```typescript
|
|
219
|
-
registry.register(
|
|
287
|
+
registry.register(CelsiusMetadata, FahrenheitMetadata, celsiusToFahrenheit);
|
|
220
288
|
```
|
|
221
289
|
|
|
222
|
-
#### `
|
|
290
|
+
#### `register(from, to, converter)` (bidirectional)
|
|
223
291
|
Register both directions at once.
|
|
224
292
|
|
|
225
293
|
```typescript
|
|
226
|
-
registry.
|
|
294
|
+
registry.register(MetersMetadata, KilometersMetadata, meterKm);
|
|
227
295
|
```
|
|
228
296
|
|
|
229
297
|
#### `convert(value, fromUnit).to(toUnit)`
|
|
@@ -243,11 +311,12 @@ const result = registry.convert(value, 'Celsius').to('Fahrenheit');
|
|
|
243
311
|
|
|
244
312
|
## Best Practices
|
|
245
313
|
|
|
246
|
-
1. **Define
|
|
314
|
+
1. **Define metadata as const at module boundaries** for consistency
|
|
247
315
|
2. **Use bidirectional converters** when both directions are needed
|
|
248
316
|
3. **Document precision loss** in converters
|
|
249
317
|
4. **Cache registries** for performance
|
|
250
|
-
5. **
|
|
318
|
+
5. **Use `WithTypedUnits`** for brand-new code; leverage type inference
|
|
319
|
+
6. **Validate with Zod** in parsers
|
|
251
320
|
|
|
252
321
|
## Performance
|
|
253
322
|
|
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,
|
|
5
|
+
import type { PrimitiveType, Relax as BaseRelax } from './types.js';
|
|
6
6
|
/**
|
|
7
7
|
* Unidirectional converter from one unit to another.
|
|
8
8
|
*
|
|
@@ -23,9 +23,9 @@ import type { PrimitiveType, Unwrap, WithUnits, Relax as BaseRelax } from './typ
|
|
|
23
23
|
* ((c * 9/5) + 32) as Fahrenheit;
|
|
24
24
|
* ```
|
|
25
25
|
*/
|
|
26
|
-
export type Converter<TInput
|
|
27
|
-
export type RelaxConverter<ConverterType> = ConverterType extends Converter<infer A, infer B> ? (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<
|
|
26
|
+
export type Converter<TInput, TOutput> = (input: TInput) => TOutput;
|
|
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<unknown, unknown> ? RelaxConverter<T> : RelaxBidirectionalConverter<T>;
|
|
29
29
|
/**
|
|
30
30
|
* Bidirectional converter with forward and reverse transformations.
|
|
31
31
|
*
|
|
@@ -48,13 +48,13 @@ export type Relax<T extends PrimitiveType | Converter<any, any> | BidirectionalC
|
|
|
48
48
|
* };
|
|
49
49
|
* ```
|
|
50
50
|
*/
|
|
51
|
-
export type BidirectionalConverter<TInput
|
|
51
|
+
export type BidirectionalConverter<TInput, TOutput> = {
|
|
52
52
|
to: Converter<TInput, TOutput>;
|
|
53
53
|
from: Converter<TOutput, TInput>;
|
|
54
54
|
};
|
|
55
|
-
export type RelaxBidirectionalConverter<ConverterType> = ConverterType extends BidirectionalConverter<infer A, infer B> ? {
|
|
56
|
-
to: (input:
|
|
57
|
-
from: (input:
|
|
55
|
+
export type RelaxBidirectionalConverter<ConverterType> = ConverterType extends BidirectionalConverter<infer A extends PrimitiveType, infer B extends PrimitiveType> ? {
|
|
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;
|
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,EAAE,
|
|
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,YAAY,CAAC;AAEpE;;;;;;;;;;;;;;;;;;;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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* Unacy Core - Type-safe unit and format conversion library
|
|
3
3
|
* @packageDocumentation
|
|
4
4
|
*/
|
|
5
|
-
export type { WithUnits, WithFormat, UnitMetadata } from './types.js';
|
|
5
|
+
export type { WithUnits, WithTypedUnits, WithFormat, BaseMetadata, TypedMetadata, UnitMetadata, Relax, PrimitiveType, ToPrimitiveType, ToPrimitiveTypeName } from './types.js';
|
|
6
6
|
export type { Converter, BidirectionalConverter } 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
11
|
export { createParserWithSchema } from './utils/validation.js';
|
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,eAAe,EACf,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAGpB,YAAY,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAGzE,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,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC"}
|
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;AAwBH,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,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/registry.d.ts
CHANGED
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
* @packageDocumentation
|
|
4
4
|
*/
|
|
5
5
|
import type { Converter, BidirectionalConverter, Relax } from './converters.js';
|
|
6
|
-
import type {
|
|
6
|
+
import type { UnitsFor, WithUnits, TypedMetadata, NameFor, WithTypedUnits, UnitsOf, BaseMetadata, PrimitiveType, Relax as RelaxUnits } from './types.js';
|
|
7
7
|
/**
|
|
8
8
|
* Represents a conversion edge from one unit to another
|
|
9
|
+
* Edges store the unit names as strings, but the type system ensures
|
|
10
|
+
* they correspond to valid WithUnits types
|
|
9
11
|
*/
|
|
10
|
-
type Edge<From extends
|
|
12
|
+
type Edge<From extends WithTypedUnits<any> = WithTypedUnits<TypedMetadata<PrimitiveType>>, To extends WithTypedUnits<any> = WithTypedUnits<TypedMetadata<PrimitiveType>>> = readonly [From, To];
|
|
11
13
|
/**
|
|
12
14
|
* Extract all unique 'from' units from a list of edges
|
|
13
15
|
*/
|
|
@@ -15,83 +17,75 @@ type FromUnits<Edges extends readonly Edge[]> = Edges[number][0];
|
|
|
15
17
|
/**
|
|
16
18
|
* Extract all 'to' units for a specific 'from' unit string
|
|
17
19
|
*/
|
|
18
|
-
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
|
+
*/
|
|
19
24
|
/**
|
|
20
25
|
* Type for unit accessor with metadata and conversion methods
|
|
21
26
|
* Can be called as a function to create branded unit values
|
|
22
27
|
*/
|
|
23
|
-
export type UnitAccessor<From extends
|
|
28
|
+
export type UnitAccessor<From extends WithTypedUnits<TypedMetadata>, Edges extends readonly Edge[]> = {
|
|
24
29
|
/**
|
|
25
30
|
* Create a branded value with this unit
|
|
26
31
|
* @param value - The numeric value to brand
|
|
27
32
|
* @returns The value branded with this unit type
|
|
28
33
|
*/
|
|
29
|
-
(value: number):
|
|
34
|
+
(value: number): From;
|
|
30
35
|
to: {
|
|
31
|
-
[To in ToUnitsFor<Edges, From>]: (value:
|
|
36
|
+
[To in ToUnitsFor<Edges, From> as UnitsFor<To>]: (value: RelaxUnits<From>) => To;
|
|
32
37
|
};
|
|
33
38
|
/**
|
|
34
39
|
* Add metadata to this unit
|
|
35
40
|
*/
|
|
36
|
-
addMetadata(metadata:
|
|
41
|
+
addMetadata<NewM extends Record<string, unknown>>(metadata: NewM): UnitRegistry<Edges extends readonly (infer E)[] ? E[] : never> & UnitMap<Edges>;
|
|
37
42
|
/**
|
|
38
43
|
* Register a converter from this unit to another unit
|
|
39
44
|
*/
|
|
40
|
-
register<To extends
|
|
41
|
-
register<To extends
|
|
42
|
-
} &
|
|
43
|
-
[K: string]: unknown;
|
|
44
|
-
};
|
|
45
|
+
register<To extends WithTypedUnits<ToMeta>, ToMeta extends TypedMetadata<PrimitiveType>>(to: UnitsFor<To> | ToMeta, converter: Relax<Converter<From, To>>): UnitRegistry<[...Edges, Edge<From, To>]> & UnitMap<[...Edges, Edge<From, To>]>;
|
|
46
|
+
register<To extends WithTypedUnits<ToMeta>, ToMeta extends TypedMetadata<PrimitiveType>>(to: UnitsFor<To> | ToMeta, converter: Relax<BidirectionalConverter<From, To>>): UnitRegistry<[...Edges, Edge<From, To>, Edge<To, From>]> & UnitMap<[...Edges, Edge<From, To>, Edge<To, From>]>;
|
|
47
|
+
} & UnitsOf<From>;
|
|
45
48
|
/**
|
|
46
49
|
* Type for unit-based conversion accessors
|
|
47
50
|
* Provides the shape: registry.Celsius.to.Fahrenheit(value)
|
|
48
51
|
* Only allows conversions that have been registered
|
|
49
52
|
*/
|
|
50
|
-
export type
|
|
51
|
-
[
|
|
53
|
+
export type UnitMap<Edges extends readonly Edge[]> = {
|
|
54
|
+
[FU in FromUnits<Edges> as UnitsFor<FU>]: UnitAccessor<FU, Edges>;
|
|
52
55
|
};
|
|
53
56
|
/**
|
|
54
57
|
* Registry for managing and composing unit converters
|
|
55
58
|
*/
|
|
56
|
-
export interface
|
|
59
|
+
export interface UnitRegistry<Edges extends Edge[] = []> {
|
|
60
|
+
register<From extends WithTypedUnits<FromMeta>, FromMeta extends TypedMetadata<PrimitiveType>>(unit: FromMeta): this & {
|
|
61
|
+
[K in NameFor<From>]: UnitAccessor<From, Edges>;
|
|
62
|
+
};
|
|
57
63
|
/**
|
|
58
64
|
* Register a unidirectional converter
|
|
59
65
|
*
|
|
60
|
-
* @param from - Source unit
|
|
61
|
-
* @param to - Destination unit
|
|
66
|
+
* @param from - Source unit (string name or metadata object)
|
|
67
|
+
* @param to - Destination unit (string name or metadata object)
|
|
62
68
|
* @param converter - Converter function
|
|
63
69
|
* @returns New registry instance with the converter registered
|
|
64
70
|
*/
|
|
65
|
-
register<From extends
|
|
71
|
+
register<From extends WithTypedUnits<FromMeta>, To extends WithTypedUnits<ToMeta>, FromMeta extends TypedMetadata<PrimitiveType>, ToMeta extends TypedMetadata<PrimitiveType>>(from: UnitsFor<From> | FromMeta, to: UnitsFor<To> | ToMeta, converter: Converter<From, RelaxUnits<To>>): UnitRegistry<[...Edges, Edge<From, To>]> & UnitMap<[...Edges, Edge<From, To>]>;
|
|
66
72
|
/**
|
|
67
73
|
* Register a bidirectional converter (both directions)
|
|
68
74
|
*
|
|
69
|
-
* @param from - First unit
|
|
70
|
-
* @param to - Second unit
|
|
75
|
+
* @param from - First unit (string name or metadata object)
|
|
76
|
+
* @param to - Second unit (string name or metadata object)
|
|
71
77
|
* @param converter - Bidirectional converter object
|
|
72
78
|
* @returns New registry instance with both converters registered
|
|
73
79
|
*/
|
|
74
|
-
register<From extends
|
|
75
|
-
name: UnitsFor<From>;
|
|
76
|
-
}, to: UnitsFor<To> | {
|
|
77
|
-
name: UnitsFor<To>;
|
|
78
|
-
}, converter: Relax<BidirectionalConverter<From, To>>): ConverterRegistry<[
|
|
79
|
-
...Edges,
|
|
80
|
-
Edge<UnitsFor<From>, UnitsFor<To>>,
|
|
81
|
-
Edge<UnitsFor<To>, UnitsFor<From>>
|
|
82
|
-
]> & ConverterMap<[
|
|
83
|
-
...Edges,
|
|
84
|
-
Edge<UnitsFor<From>, UnitsFor<To>>,
|
|
85
|
-
Edge<UnitsFor<To>, UnitsFor<From>>
|
|
86
|
-
]>;
|
|
80
|
+
register<From extends WithTypedUnits<FromMeta>, To extends WithTypedUnits<ToMeta>, FromMeta extends TypedMetadata<PrimitiveType>, ToMeta extends TypedMetadata<PrimitiveType>>(from: UnitsFor<From> | FromMeta, to: UnitsFor<To> | ToMeta, converter: BidirectionalConverter<RelaxUnits<From>, RelaxUnits<To>>): UnitRegistry<[...Edges, Edge<From, To>, Edge<To, From>]> & UnitMap<[...Edges, Edge<From, To>, Edge<To, From>]>;
|
|
87
81
|
/**
|
|
88
82
|
* Explicitly allow a conversion path in the type system (for multi-hop conversions)
|
|
89
83
|
*
|
|
90
84
|
* This method verifies that a conversion path exists at runtime (via BFS) and adds it
|
|
91
85
|
* to the type system so it can be used with type-safe accessor syntax.
|
|
92
86
|
*
|
|
93
|
-
* @param from - Source unit string
|
|
94
|
-
* @param to - Destination unit string
|
|
87
|
+
* @param from - Source unit (string name or metadata object)
|
|
88
|
+
* @param to - Destination unit (string name or metadata object)
|
|
95
89
|
* @returns New registry instance with the conversion path enabled in types
|
|
96
90
|
* @throws ConversionError if no path exists between the units
|
|
97
91
|
*
|
|
@@ -106,7 +100,7 @@ export interface ConverterRegistry<Edges extends Edge[] = []> {
|
|
|
106
100
|
* const f = registry.Celsius.to.Fahrenheit(temp);
|
|
107
101
|
* ```
|
|
108
102
|
*/
|
|
109
|
-
allow<From extends
|
|
103
|
+
allow<From extends WithTypedUnits<FromMeta>, To extends WithTypedUnits<ToMeta>, FromMeta extends TypedMetadata<PrimitiveType>, ToMeta extends TypedMetadata<PrimitiveType>>(from: UnitsFor<From> | FromMeta, to: UnitsFor<To> | ToMeta): UnitRegistry<[...Edges, Edge<From, To>]> & UnitMap<[...Edges, Edge<From, To>]>;
|
|
110
104
|
/**
|
|
111
105
|
* Get a converter (direct or composed via BFS)
|
|
112
106
|
*
|
|
@@ -114,7 +108,7 @@ export interface ConverterRegistry<Edges extends Edge[] = []> {
|
|
|
114
108
|
* @param to - Destination unit
|
|
115
109
|
* @returns Converter function, or undefined if no path exists
|
|
116
110
|
*/
|
|
117
|
-
getConverter<From extends WithUnits<
|
|
111
|
+
getConverter<From extends WithUnits<PrimitiveType, BaseMetadata>, To extends WithUnits<PrimitiveType, BaseMetadata>>(from: UnitsFor<From>, to: UnitsFor<To>): Converter<From, To> | undefined;
|
|
118
112
|
/**
|
|
119
113
|
* Convert a value using fluent API
|
|
120
114
|
*
|
|
@@ -122,8 +116,8 @@ export interface ConverterRegistry<Edges extends Edge[] = []> {
|
|
|
122
116
|
* @param fromUnit - Source unit
|
|
123
117
|
* @returns Object with to() method for conversion
|
|
124
118
|
*/
|
|
125
|
-
convert<From extends WithUnits<
|
|
126
|
-
to<To extends WithUnits<
|
|
119
|
+
convert<From extends WithUnits<PrimitiveType, BaseMetadata>>(value: From, fromUnit: UnitsFor<From>): {
|
|
120
|
+
to<To extends WithUnits<PrimitiveType, BaseMetadata>>(unit: UnitsFor<To>): To;
|
|
127
121
|
};
|
|
128
122
|
}
|
|
129
123
|
/**
|
|
@@ -134,10 +128,10 @@ export interface ConverterRegistry<Edges extends Edge[] = []> {
|
|
|
134
128
|
*
|
|
135
129
|
* @example
|
|
136
130
|
* ```typescript
|
|
137
|
-
* type Celsius = WithUnits<
|
|
138
|
-
* type Fahrenheit = WithUnits<
|
|
139
|
-
* type Meters = WithUnits<
|
|
140
|
-
* type Kilometers = WithUnits<
|
|
131
|
+
* type Celsius = WithUnits<PrimitiveType, 'Celsius'>;
|
|
132
|
+
* type Fahrenheit = WithUnits<PrimitiveType, 'Fahrenheit'>;
|
|
133
|
+
* type Meters = WithUnits<PrimitiveType, 'meters'>;
|
|
134
|
+
* type Kilometers = WithUnits<PrimitiveType, 'kilometers'>;
|
|
141
135
|
*
|
|
142
136
|
* // Without pre-declared units
|
|
143
137
|
* const registry = createRegistry()
|
|
@@ -152,6 +146,6 @@ export interface ConverterRegistry<Edges extends Edge[] = []> {
|
|
|
152
146
|
* console.log(fahrenheit); // 77
|
|
153
147
|
* ```
|
|
154
148
|
*/
|
|
155
|
-
export declare function createRegistry<Edges extends readonly Edge[] = []>():
|
|
149
|
+
export declare function createRegistry<Edges extends readonly Edge[] = []>(): UnitRegistry<Edges extends readonly (infer E)[] ? E[] : never> & UnitMap<Edges>;
|
|
156
150
|
export {};
|
|
157
151
|
//# sourceMappingURL=registry.d.ts.map
|
package/dist/registry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,sBAAsB,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAChF,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|
package/dist/registry.js
CHANGED
|
@@ -112,38 +112,68 @@ class ConverterRegistryImpl {
|
|
|
112
112
|
this.unitAccessors.set(fromUnit, accessorProxy);
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
|
+
// Implementation
|
|
115
116
|
register(from, to, converter) {
|
|
117
|
+
// Handle single unit registration (overload 1)
|
|
118
|
+
if (to === undefined && converter === undefined) {
|
|
119
|
+
const unitMetadata = from;
|
|
120
|
+
const newMetadata = new Map(this.metadata);
|
|
121
|
+
const unitName = unitMetadata.name;
|
|
122
|
+
const existingMetadata = newMetadata.get(unitName) || {};
|
|
123
|
+
newMetadata.set(unitName, { ...existingMetadata, ...unitMetadata });
|
|
124
|
+
return createRegistryFromGraph(this.graph, this.pathCache, newMetadata);
|
|
125
|
+
}
|
|
126
|
+
// Extract metadata if provided and store unit names
|
|
127
|
+
let fromName;
|
|
128
|
+
let toName;
|
|
129
|
+
const newMetadata = new Map(this.metadata);
|
|
116
130
|
if (typeof from === 'object' && 'name' in from) {
|
|
117
|
-
|
|
131
|
+
fromName = from.name;
|
|
132
|
+
// Store metadata for the from unit
|
|
133
|
+
const existingFromMetadata = newMetadata.get(fromName) || {};
|
|
134
|
+
newMetadata.set(fromName, { ...existingFromMetadata, ...from });
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
fromName = from;
|
|
118
138
|
}
|
|
119
139
|
if (typeof to === 'object' && 'name' in to) {
|
|
120
|
-
|
|
140
|
+
toName = to.name;
|
|
141
|
+
// Store metadata for the to unit
|
|
142
|
+
const existingToMetadata = newMetadata.get(toName) || {};
|
|
143
|
+
newMetadata.set(toName, { ...existingToMetadata, ...to });
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
toName = to;
|
|
121
147
|
}
|
|
122
148
|
// Check if it's a bidirectional converter
|
|
123
149
|
if (typeof converter === 'object' && 'to' in converter && 'from' in converter) {
|
|
124
150
|
// Handle bidirectional converter
|
|
125
151
|
const biConverter = converter;
|
|
152
|
+
// Pass the original metadata objects (not just names) to preserve metadata
|
|
126
153
|
return this.register(from, to, biConverter.to).register(to, from, biConverter.from);
|
|
127
154
|
}
|
|
128
155
|
// Handle unidirectional converter
|
|
129
156
|
const newGraph = new Map(this.graph);
|
|
130
|
-
if (!newGraph.has(
|
|
131
|
-
newGraph.set(
|
|
157
|
+
if (!newGraph.has(fromName)) {
|
|
158
|
+
newGraph.set(fromName, new Map());
|
|
132
159
|
}
|
|
133
|
-
const fromMap = new Map(newGraph.get(
|
|
134
|
-
fromMap.set(
|
|
135
|
-
newGraph.set(
|
|
160
|
+
const fromMap = new Map(newGraph.get(fromName));
|
|
161
|
+
fromMap.set(toName, converter);
|
|
162
|
+
newGraph.set(fromName, fromMap);
|
|
136
163
|
// Return new registry instance (immutable) with proxy
|
|
137
|
-
return createRegistryFromGraph(newGraph, new Map(),
|
|
164
|
+
return createRegistryFromGraph(newGraph, new Map(), newMetadata);
|
|
138
165
|
}
|
|
139
166
|
registerBidirectional(from, to, converter) {
|
|
140
167
|
return this.register(from, to, converter.to).register(to, from, converter.from);
|
|
141
168
|
}
|
|
142
169
|
allow(from, to) {
|
|
170
|
+
// Extract unit names from metadata objects if provided
|
|
171
|
+
const fromName = typeof from === 'object' && 'name' in from ? from.name : from;
|
|
172
|
+
const toName = typeof to === 'object' && 'name' in to ? to.name : to;
|
|
143
173
|
// Verify that a conversion path exists at runtime
|
|
144
|
-
const converter = this.getConverter(
|
|
174
|
+
const converter = this.getConverter(fromName, toName);
|
|
145
175
|
if (!converter) {
|
|
146
|
-
throw new ConversionError(
|
|
176
|
+
throw new ConversionError(fromName, toName, 'No conversion path exists');
|
|
147
177
|
}
|
|
148
178
|
// Return the same registry instance with updated type information
|
|
149
179
|
// The actual conversion already works via BFS, we just need to expose it in types
|
|
@@ -208,10 +238,10 @@ class ConverterRegistryImpl {
|
|
|
208
238
|
*
|
|
209
239
|
* @example
|
|
210
240
|
* ```typescript
|
|
211
|
-
* type Celsius = WithUnits<
|
|
212
|
-
* type Fahrenheit = WithUnits<
|
|
213
|
-
* type Meters = WithUnits<
|
|
214
|
-
* type Kilometers = WithUnits<
|
|
241
|
+
* type Celsius = WithUnits<PrimitiveType, 'Celsius'>;
|
|
242
|
+
* type Fahrenheit = WithUnits<PrimitiveType, 'Fahrenheit'>;
|
|
243
|
+
* type Meters = WithUnits<PrimitiveType, 'meters'>;
|
|
244
|
+
* type Kilometers = WithUnits<PrimitiveType, 'kilometers'>;
|
|
215
245
|
*
|
|
216
246
|
* // Without pre-declared units
|
|
217
247
|
* const registry = createRegistry()
|