unacy 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-present Pradeep Mouli
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,232 @@
1
+ # @unacy/core
2
+
3
+ Type-safe unit and format conversion library with automatic multi-hop composition.
4
+
5
+ ## Features
6
+
7
+ - 🔒 **Type-safe conversions** - Compile-time checks prevent mixing incompatible units
8
+ - 🔄 **Auto-composition** - Automatically chains converters (A→B→C for A→C)
9
+ - 🚀 **Zero runtime overhead** - Phantom types have no performance cost
10
+ - 🎯 **Shortest path** - BFS finds optimal conversion routes
11
+ - 🛡️ **Cycle detection** - Prevents infinite conversion loops
12
+ - 📦 **Tree-shakeable** - Only bundle converters you use
13
+ - ✨ **Fluent API** - Clean, readable conversion syntax
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ pnpm add @unacy/core
19
+ ```
20
+
21
+ ## Quick Start
22
+
23
+ ```typescript
24
+ import { createRegistry, type WithUnits } from '@unacy/core';
25
+
26
+ // Define your unit types
27
+ type Celsius = WithUnits<number, 'Celsius'>;
28
+ type Fahrenheit = WithUnits<number, 'Fahrenheit'>;
29
+
30
+ // Create a registry
31
+ const tempRegistry = createRegistry()
32
+ .register('Celsius', 'Fahrenheit', (c) => ((c * 9/5) + 32) as Fahrenheit);
33
+
34
+ // Convert with type safety - two ways:
35
+ const temp: Celsius = 25 as Celsius;
36
+
37
+ // Method 1: unit accessor API
38
+ const fahrenheit2 = tempRegistry.Celsius.to.Fahrenheit(temp as Celsius) satisfies Fahrenheit;
39
+
40
+ console.log(fahrenheit2); // 77
41
+ ```
42
+
43
+ ## Usage Examples
44
+
45
+ ### Basic Unit Conversions
46
+
47
+ ```typescript
48
+ // Same registry as above
49
+ const distance: Meters = 10 as Meters;
50
+
51
+ // Access units directly via property syntax
52
+ const feet = distanceRegistry.meters.to.feet(distance);
53
+ console.log(feet); // 32.8084
54
+
55
+ // Works in both directions
56
+ const meters = distanceRegistry.feet.to.meters(32.8084 as Feet) satisfies Meters;
57
+ console.log(meters); // 10
58
+ ```
59
+
60
+ ### Bidirectional Converters
61
+
62
+ ```typescript
63
+ import { createRegistry, type WithUnits } from '@unacy/core';
64
+
65
+ type Meters = WithUnits<number, 'meters'>;
66
+ type Kilometers = WithUnits<number, 'kilometers'>;
67
+
68
+ const registry = createRegistry<'meters' | 'kilometers'>()
69
+ .registerBidirectional('meters', 'kilometers', {
70
+ to: (m) => (m / 1000) as Kilometers,
71
+ from: (km) => (km * 1000) as Meters
72
+ });
73
+
74
+ // Both directions work automatically
75
+ const km = registry.convert(5000 as Meters, 'meters').to('kilometers'); // 5
76
+ const m = registry.convert(5 as Kilometers, 'kilometers').to('meters'); // 5000
77
+ ```
78
+
79
+ ### Multi-Hop Auto-Composition
80
+
81
+ The registry automatically composes converters via shortest path:
82
+
83
+ ```typescript
84
+ type Meters = WithUnits<number, 'meters'>;
85
+ type Kilometers = WithUnits<number, 'kilometers'>;
86
+ type Miles = WithUnits<number, 'miles'>;
87
+
88
+ const registry = createRegistry<'meters' | 'kilometers' | 'miles'>()
89
+ .registerBidirectional('meters', 'kilometers', {
90
+ to: (m) => (m / 1000) as Kilometers,
91
+ from: (km) => (km * 1000) as Meters
92
+ })
93
+ .registerBidirectional('kilometers', 'miles', {
94
+ to: (km) => (km * 0.621371) as Miles,
95
+ from: (mi) => (mi / 0.621371) as Kilometers
96
+ });
97
+
98
+ // No direct meters→miles converter registered!
99
+ // Registry auto-composes: meters → kilometers → miles
100
+ const meters: Meters = 5000 as Meters;
101
+ const miles = registry.convert(meters, 'meters').to('miles');
102
+ console.log(miles); // 3.106855
103
+ ```
104
+
105
+ ### Format-Tagged Values
106
+
107
+ ```typescript
108
+ import { type WithFormat, type FormatterParser, ParseError } from '@unacy/core';
109
+ import { z } from 'zod';
110
+
111
+ type ISO8601 = WithFormat<Date, 'ISO8601'>;
112
+
113
+ const iso8601: FormatterParser<ISO8601> = {
114
+ format: (date) => date.toISOString(),
115
+ parse: (input) => {
116
+ const schema = z.string().datetime();
117
+ try {
118
+ return new Date(schema.parse(input)) as ISO8601;
119
+ } catch {
120
+ throw new ParseError('ISO8601', input, 'Invalid date format');
121
+ }
122
+ }
123
+ };
124
+
125
+ // Format
126
+ const now: ISO8601 = new Date() as ISO8601;
127
+ const str = iso8601.format(now); // "2026-01-06T12:00:00.000Z"
128
+
129
+ // Parse
130
+ const date = iso8601.parse('2026-01-06T12:00:00.000Z');
131
+ ```
132
+
133
+ ## API Reference
134
+
135
+ ### Types
136
+
137
+ #### `WithUnits<T, U>`
138
+ Brand a value with a unit identifier for compile-time safety.
139
+
140
+ ```typescript
141
+ type Celsius = WithUnits<number, 'Celsius'>;
142
+ const temp: Celsius = 25 as Celsius;
143
+ ```
144
+
145
+ #### `WithFormat<T, F>`
146
+ Brand a value with a format identifier for serialization safety.
147
+
148
+ ```typescript
149
+ type ISO8601 = WithFormat<Date, 'ISO8601'>;
150
+ const date: ISO8601 = new Date() as ISO8601;
151
+ ```
152
+
153
+ #### `Converter<TInput, TOutput>`
154
+ Unidirectional converter function.
155
+
156
+ ```typescript
157
+ const c2f: Converter<Celsius, Fahrenheit> = (c) =>
158
+ ((c * 9/5) + 32) as Fahrenheit;
159
+ ```
160
+
161
+ #### `BidirectionalConverter<TInput, TOutput>`
162
+ Pair of converters for two-way transformations.
163
+
164
+ ```typescript
165
+ const meterKm: BidirectionalConverter<Meters, Kilometers> = {
166
+ to: (m) => (m / 1000) as Kilometers,
167
+ from: (km) => (km * 1000) as Meters
168
+ };
169
+ ```
170
+
171
+ ### Registry
172
+
173
+ #### `createRegistry<Units>()`
174
+ Create a new converter registry.
175
+
176
+ ```typescript
177
+ const registry = createRegistry<'A' | 'B' | 'C'>();
178
+ ```
179
+
180
+ #### `register(from, to, converter)`
181
+ Register a unidirectional converter.
182
+
183
+ ```typescript
184
+ registry.register('Celsius', 'Fahrenheit', celsiusToFahrenheit);
185
+ ```
186
+
187
+ #### `registerBidirectional(from, to, converter)`
188
+ Register both directions at once.
189
+
190
+ ```typescript
191
+ registry.registerBidirectional('meters', 'kilometers', meterKm);
192
+ ```
193
+
194
+ #### `convert(value, fromUnit).to(toUnit)`
195
+ Fluent API for type-safe conversions.
196
+
197
+ ```typescript
198
+ const result = registry.convert(value, 'Celsius').to('Fahrenheit');
199
+ ```
200
+
201
+ ### Errors
202
+
203
+ - `UnacyError` - Base error class
204
+ - `CycleError` - Cycle detected in conversion graph
205
+ - `MaxDepthError` - Exceeded maximum conversion depth (5 hops)
206
+ - `ConversionError` - No conversion path found
207
+ - `ParseError` - Invalid input during parsing
208
+
209
+ ## Best Practices
210
+
211
+ 1. **Define unit types at module boundaries** for consistency
212
+ 2. **Use bidirectional converters** when both directions are needed
213
+ 3. **Document precision loss** in converters
214
+ 4. **Cache registries** for performance
215
+ 5. **Validate with Zod** in parsers
216
+
217
+ ## Performance
218
+
219
+ - Direct conversions: O(1) lookup
220
+ - Multi-hop conversions: O(V+E) BFS with caching
221
+ - Type checking: <1s for typical graphs (<100 units)
222
+ - Zero runtime overhead for type brands
223
+
224
+ ## License
225
+
226
+ MIT
227
+
228
+ ## Links
229
+
230
+ - [Specification](../../specs/001-unacy-core/spec.md)
231
+ - [Quickstart Guide](../../specs/001-unacy-core/quickstart.md)
232
+ - [API Contracts](../../specs/001-unacy-core/contracts/api.md)
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/types.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,115 @@
1
+ import { describe, it, expect, expectTypeOf } from 'vitest';
2
+ describe('WithUnits Type Safety', () => {
3
+ it('allows assignment with explicit cast', () => {
4
+ const temp = 25;
5
+ expect(temp).toBe(25);
6
+ });
7
+ it('preserves numeric operations at runtime', () => {
8
+ const temp1 = 10;
9
+ const temp2 = 20;
10
+ // Runtime operations work normally
11
+ expect(temp1 + temp2).toBe(30);
12
+ });
13
+ it('compile-time: prevents assignment without cast', () => {
14
+ // @ts-expect-error - Cannot assign plain number to branded type
15
+ const temp = 25;
16
+ expect(temp).toBe(25); // Runtime still works, but type error at compile time
17
+ });
18
+ it('compile-time: prevents mixing different unit types', () => {
19
+ const temp = 25;
20
+ // @ts-expect-error - Cannot assign Celsius to Fahrenheit
21
+ const fahrenheit = temp;
22
+ expect(fahrenheit).toBe(temp); // Runtime value is same, but type mismatch
23
+ });
24
+ it('compile-time: different units are not compatible', () => {
25
+ const distance = 100;
26
+ // @ts-expect-error - Cannot assign Meters to Celsius
27
+ const temp = distance;
28
+ expect(temp).toBe(distance);
29
+ });
30
+ it('type inference: maintains branded type through variables', () => {
31
+ const temp1 = 25;
32
+ const temp2 = temp1; // Type should be inferred as Celsius
33
+ expectTypeOf(temp2).toEqualTypeOf();
34
+ });
35
+ it('type inference: array of branded types', () => {
36
+ const temps = [10, 20, 30].map((n) => n);
37
+ expectTypeOf(temps).toEqualTypeOf();
38
+ expect(temps).toHaveLength(3);
39
+ });
40
+ it('supports different base types', () => {
41
+ const distance = 1000n;
42
+ const money = '100.50';
43
+ expectTypeOf(distance).toEqualTypeOf();
44
+ expectTypeOf(money).toEqualTypeOf();
45
+ expect(distance).toBe(1000n);
46
+ expect(money).toBe('100.50');
47
+ });
48
+ it('supports string literal as unit identifier', () => {
49
+ const value = 42;
50
+ expectTypeOf(value).toEqualTypeOf();
51
+ expect(value).toBe(42);
52
+ });
53
+ });
54
+ describe('WithFormat Type Safety', () => {
55
+ it('allows assignment with explicit cast', () => {
56
+ const date = new Date();
57
+ expect(date).toBeInstanceOf(Date);
58
+ });
59
+ it('compile-time: prevents assignment without cast', () => {
60
+ const now = new Date();
61
+ // @ts-expect-error - Cannot assign Date to branded ISO8601
62
+ const date = now;
63
+ expect(date).toBe(now);
64
+ });
65
+ it('compile-time: prevents mixing different format types', () => {
66
+ const timestamp = Date.now();
67
+ // @ts-expect-error - Cannot assign UnixTimestamp to HexColor
68
+ const color = timestamp;
69
+ expect(color).toBe(timestamp);
70
+ });
71
+ it('compile-time: different formats of same base type are incompatible', () => {
72
+ const date = new Date();
73
+ // Both are Dates, and branded types are assignable to base types
74
+ const plainDate = date;
75
+ expect(plainDate).toBe(date);
76
+ });
77
+ it('type inference: maintains branded type', () => {
78
+ const color1 = '#FF5733';
79
+ const color2 = color1;
80
+ expectTypeOf(color2).toEqualTypeOf();
81
+ });
82
+ it('supports different base types with same format name', () => {
83
+ const str = 'test';
84
+ const num = 123;
85
+ expectTypeOf(str).toEqualTypeOf();
86
+ expectTypeOf(num).toEqualTypeOf();
87
+ // These should be different types
88
+ expectTypeOf(str).not.toEqualTypeOf();
89
+ });
90
+ it('type inference: array of formatted values', () => {
91
+ const colors = ['#FF0000', '#00FF00', '#0000FF'].map((c) => c);
92
+ expectTypeOf(colors).toEqualTypeOf();
93
+ expect(colors).toHaveLength(3);
94
+ });
95
+ it('supports complex format identifiers', () => {
96
+ const value = '2026-01-06T12:00:00.000+00:00';
97
+ expectTypeOf(value).toEqualTypeOf();
98
+ expect(value).toContain('T');
99
+ });
100
+ });
101
+ describe('WithUnits and WithFormat Interaction', () => {
102
+ it('units and formats are independent type brands', () => {
103
+ const temp = 25;
104
+ const date = new Date();
105
+ expectTypeOf(temp).toEqualTypeOf();
106
+ expectTypeOf(date).toEqualTypeOf();
107
+ // Different brand systems
108
+ expectTypeOf(temp).not.toEqualTypeOf();
109
+ });
110
+ it('can apply both brands (theoretical, but should type-check)', () => {
111
+ const value = 25;
112
+ expectTypeOf(value).toEqualTypeOf();
113
+ });
114
+ });
115
+ //# sourceMappingURL=types.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.test.js","sourceRoot":"","sources":["../../src/__tests__/types.test.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "unacy",
3
+ "version": "0.1.0",
4
+ "description": "Type-safe unit and format conversion library",
5
+ "type": "module",
6
+ "private": false,
7
+ "author": "Pradeep Mouli",
8
+ "license": "MIT",
9
+ "main": "./dist/index.js",
10
+ "module": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "README.md"
21
+ ],
22
+ "dependencies": {
23
+ "type-fest": "^5.3.1",
24
+ "zod": "^3.24.1"
25
+ },
26
+ "devDependencies": {
27
+ "@types/node": "^25.0.3",
28
+ "typescript": "^5.9.3",
29
+ "vitest": "^4.0.16"
30
+ },
31
+ "engines": {
32
+ "node": ">=20.0.0"
33
+ },
34
+ "scripts": {
35
+ "build": "tsc",
36
+ "clean": "rm -rf dist",
37
+ "type-check": "tsc --noEmit",
38
+ "test": "vitest run",
39
+ "test:watch": "vitest"
40
+ }
41
+ }