unacy 0.1.1 → 0.2.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/dist/__tests__/converters.test.d.ts +2 -0
- package/dist/__tests__/converters.test.d.ts.map +1 -0
- package/dist/__tests__/converters.test.js +128 -0
- package/dist/__tests__/converters.test.js.map +1 -0
- package/dist/__tests__/errors.test.d.ts +2 -0
- package/dist/__tests__/errors.test.d.ts.map +1 -0
- package/dist/__tests__/errors.test.js +93 -0
- package/dist/__tests__/errors.test.js.map +1 -0
- package/dist/__tests__/formatters.test.d.ts +2 -0
- package/dist/__tests__/formatters.test.js.map +1 -1
- package/dist/__tests__/registry.test.d.ts +2 -0
- package/dist/__tests__/registry.test.d.ts.map +1 -0
- package/dist/__tests__/registry.test.js +250 -0
- package/dist/__tests__/registry.test.js.map +1 -0
- package/dist/__tests__/types.test.d.ts +2 -0
- package/dist/__tests__/types.test.js.map +1 -1
- package/dist/converters.d.ts +53 -0
- package/dist/converters.d.ts.map +1 -0
- package/dist/converters.js +6 -0
- package/dist/converters.js.map +1 -0
- package/dist/errors.d.ts +40 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +70 -0
- package/dist/errors.js.map +1 -0
- package/dist/formatters.d.ts +82 -0
- package/dist/formatters.d.ts.map +1 -0
- package/dist/formatters.js +6 -0
- package/dist/formatters.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/registry.d.ts +141 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +212 -0
- package/dist/registry.js.map +1 -0
- package/dist/types.d.ts +36 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/graph.d.ts +26 -0
- package/dist/utils/graph.d.ts.map +1 -0
- package/dist/utils/graph.js +91 -0
- package/dist/utils/graph.js.map +1 -0
- package/dist/utils/validation.d.ts +26 -0
- package/dist/utils/validation.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type-safe converter function signatures
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
import type { WithUnits } from './types';
|
|
6
|
+
/**
|
|
7
|
+
* Unidirectional converter from one unit to another.
|
|
8
|
+
*
|
|
9
|
+
* @template TInput - Source unit-tagged type
|
|
10
|
+
* @template TOutput - Destination unit-tagged type
|
|
11
|
+
*
|
|
12
|
+
* @param input - Value tagged with source unit
|
|
13
|
+
* @returns Value tagged with destination unit
|
|
14
|
+
*
|
|
15
|
+
* @remarks
|
|
16
|
+
* - Must be a pure function (no side effects)
|
|
17
|
+
* - Should be deterministic (same input → same output)
|
|
18
|
+
* - Document precision loss if applicable
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* const c2f: Converter<Celsius, Fahrenheit> = (c) =>
|
|
23
|
+
* ((c * 9/5) + 32) as Fahrenheit;
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export type Converter<TInput extends WithUnits<unknown, string>, TOutput extends WithUnits<unknown, string>> = (input: TInput) => TOutput;
|
|
27
|
+
/**
|
|
28
|
+
* Bidirectional converter with forward and reverse transformations.
|
|
29
|
+
*
|
|
30
|
+
* @template TInput - First unit type
|
|
31
|
+
* @template TOutput - Second unit type
|
|
32
|
+
*
|
|
33
|
+
* @property to - Forward converter (TInput → TOutput)
|
|
34
|
+
* @property from - Reverse converter (TOutput → TInput)
|
|
35
|
+
*
|
|
36
|
+
* @remarks
|
|
37
|
+
* - Round-trip conversions should preserve value within acceptable tolerance
|
|
38
|
+
* - Both converters must be deterministic
|
|
39
|
+
* - Use when both conversion directions are commonly needed
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const meterKilometer: BidirectionalConverter<Meters, Kilometers> = {
|
|
44
|
+
* to: (m) => (m / 1000) as Kilometers,
|
|
45
|
+
* from: (km) => (km * 1000) as Meters
|
|
46
|
+
* };
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export type BidirectionalConverter<TInput extends WithUnits<unknown, string>, TOutput extends WithUnits<unknown, string>> = {
|
|
50
|
+
to: Converter<TInput, TOutput>;
|
|
51
|
+
from: Converter<TOutput, TInput>;
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=converters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"converters.d.ts","sourceRoot":"","sources":["../src/converters.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,SAAS,CACnB,MAAM,SAAS,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,EACzC,OAAO,SAAS,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,IACxC,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;AAE/B;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,sBAAsB,CAChC,MAAM,SAAS,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,EACzC,OAAO,SAAS,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,IACxC;IACF,EAAE,EAAE,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,IAAI,EAAE,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;CAClC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"converters.js","sourceRoot":"","sources":["../src/converters.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base error class for all Unacy errors
|
|
3
|
+
*/
|
|
4
|
+
export declare class UnacyError extends Error {
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Error thrown when a cycle is detected in the conversion graph
|
|
9
|
+
*/
|
|
10
|
+
export declare class CycleError extends UnacyError {
|
|
11
|
+
readonly path: PropertyKey[];
|
|
12
|
+
constructor(path: PropertyKey[]);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Error thrown when maximum conversion depth is exceeded
|
|
16
|
+
*/
|
|
17
|
+
export declare class MaxDepthError extends UnacyError {
|
|
18
|
+
readonly from: PropertyKey;
|
|
19
|
+
readonly to: PropertyKey;
|
|
20
|
+
readonly maxDepth: number;
|
|
21
|
+
constructor(from: PropertyKey, to: PropertyKey, maxDepth: number);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Error thrown when a conversion cannot be performed
|
|
25
|
+
*/
|
|
26
|
+
export declare class ConversionError extends UnacyError {
|
|
27
|
+
readonly from: PropertyKey;
|
|
28
|
+
readonly to: PropertyKey;
|
|
29
|
+
constructor(from: PropertyKey, to: PropertyKey, reason?: string);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Error thrown when parsing a string into a tagged format fails
|
|
33
|
+
*/
|
|
34
|
+
export declare class ParseError extends UnacyError {
|
|
35
|
+
readonly format: string;
|
|
36
|
+
readonly input: string;
|
|
37
|
+
readonly reason: string;
|
|
38
|
+
constructor(format: string, input: string, reason: string);
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,UAAW,SAAQ,KAAK;IACnC,YAAY,OAAO,EAAE,MAAM,EAM1B;CACF;AAED;;GAEG;AACH,qBAAa,UAAW,SAAQ,UAAU;IACxC,SAAgB,IAAI,EAAE,WAAW,EAAE,CAAC;IAEpC,YAAY,IAAI,EAAE,WAAW,EAAE,EAK9B;CACF;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,UAAU;IAC3C,SAAgB,IAAI,EAAE,WAAW,CAAC;IAClC,SAAgB,EAAE,EAAE,WAAW,CAAC;IAChC,SAAgB,QAAQ,EAAE,MAAM,CAAC;IAEjC,YAAY,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAQ/D;CACF;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,UAAU;IAC7C,SAAgB,IAAI,EAAE,WAAW,CAAC;IAClC,SAAgB,EAAE,EAAE,WAAW,CAAC;IAEhC,YAAY,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,MAAM,EAM9D;CACF;AAED;;GAEG;AACH,qBAAa,UAAW,SAAQ,UAAU;IACxC,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,KAAK,EAAE,MAAM,CAAC;IAC9B,SAAgB,MAAM,EAAE,MAAM,CAAC;IAE/B,YAAY,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EASxD;CACF"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base error class for all Unacy errors
|
|
3
|
+
*/
|
|
4
|
+
export class UnacyError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = 'UnacyError';
|
|
8
|
+
// Maintain proper prototype chain for instanceof checks
|
|
9
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Error thrown when a cycle is detected in the conversion graph
|
|
14
|
+
*/
|
|
15
|
+
export class CycleError extends UnacyError {
|
|
16
|
+
path;
|
|
17
|
+
constructor(path) {
|
|
18
|
+
const pathStr = path.map(String).join(' → ');
|
|
19
|
+
super(`Cycle detected in conversion path: ${pathStr}`);
|
|
20
|
+
this.name = 'CycleError';
|
|
21
|
+
this.path = path;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Error thrown when maximum conversion depth is exceeded
|
|
26
|
+
*/
|
|
27
|
+
export class MaxDepthError extends UnacyError {
|
|
28
|
+
from;
|
|
29
|
+
to;
|
|
30
|
+
maxDepth;
|
|
31
|
+
constructor(from, to, maxDepth) {
|
|
32
|
+
super(`Maximum conversion depth of ${maxDepth} exceeded when converting from ${String(from)} to ${String(to)}`);
|
|
33
|
+
this.name = 'MaxDepthError';
|
|
34
|
+
this.from = from;
|
|
35
|
+
this.to = to;
|
|
36
|
+
this.maxDepth = maxDepth;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Error thrown when a conversion cannot be performed
|
|
41
|
+
*/
|
|
42
|
+
export class ConversionError extends UnacyError {
|
|
43
|
+
from;
|
|
44
|
+
to;
|
|
45
|
+
constructor(from, to, reason) {
|
|
46
|
+
const reasonStr = reason ? `: ${reason}` : '';
|
|
47
|
+
super(`Cannot convert from ${String(from)} to ${String(to)}${reasonStr}`);
|
|
48
|
+
this.name = 'ConversionError';
|
|
49
|
+
this.from = from;
|
|
50
|
+
this.to = to;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Error thrown when parsing a string into a tagged format fails
|
|
55
|
+
*/
|
|
56
|
+
export class ParseError extends UnacyError {
|
|
57
|
+
format;
|
|
58
|
+
input;
|
|
59
|
+
reason;
|
|
60
|
+
constructor(format, input, reason) {
|
|
61
|
+
const truncatedInput = input.length > 50 ? `${input.slice(0, 50)}...` : input;
|
|
62
|
+
const displayInput = input === '' ? '""' : truncatedInput;
|
|
63
|
+
super(`Cannot parse "${displayInput}" as ${format}: ${reason}`);
|
|
64
|
+
this.name = 'ParseError';
|
|
65
|
+
this.format = format;
|
|
66
|
+
this.input = input;
|
|
67
|
+
this.reason = reason;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +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,OAAK,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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formatter and parser types for format-tagged values
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
import type { WithFormat } from './types';
|
|
6
|
+
/**
|
|
7
|
+
* Formatter converts a format-tagged value to a string representation.
|
|
8
|
+
*
|
|
9
|
+
* @template TInput - Format-tagged type to format
|
|
10
|
+
*
|
|
11
|
+
* @param input - Value tagged with format
|
|
12
|
+
* @returns Plain string representation
|
|
13
|
+
*
|
|
14
|
+
* @remarks
|
|
15
|
+
* - Output string must be parseable by corresponding `Parser`
|
|
16
|
+
* - Should produce human-readable or machine-parseable output
|
|
17
|
+
* - Format tag is lost in the output
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* const formatISO: Formatter<ISO8601> = (date) => date.toISOString();
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export type Formatter<TInput extends WithFormat<unknown, string>> = (input: TInput) => string;
|
|
25
|
+
/**
|
|
26
|
+
* Parser converts a string into a format-tagged value with validation.
|
|
27
|
+
*
|
|
28
|
+
* @template TOutput - Format-tagged type to produce
|
|
29
|
+
*
|
|
30
|
+
* @param input - Plain string to parse
|
|
31
|
+
* @returns Value tagged with format
|
|
32
|
+
*
|
|
33
|
+
* @throws {ParseError} When input string is invalid
|
|
34
|
+
*
|
|
35
|
+
* @remarks
|
|
36
|
+
* - Must validate input before tagging
|
|
37
|
+
* - Must throw clear errors (not return invalid tagged values)
|
|
38
|
+
* - Should use Zod or similar for schema validation
|
|
39
|
+
* - Never produces invalid tagged values
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const parseISO: Parser<ISO8601> = (input) => {
|
|
44
|
+
* const schema = z.string().datetime();
|
|
45
|
+
* const validated = schema.parse(input);
|
|
46
|
+
* return new Date(validated) as ISO8601;
|
|
47
|
+
* };
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export type Parser<TOutput extends WithFormat<unknown, string>> = (input: string) => TOutput;
|
|
51
|
+
/**
|
|
52
|
+
* Paired formatter/parser for round-trip format transformations.
|
|
53
|
+
*
|
|
54
|
+
* @template T - Format-tagged type
|
|
55
|
+
*
|
|
56
|
+
* @property format - Converts tagged value → string
|
|
57
|
+
* @property parse - Converts string → tagged value
|
|
58
|
+
*
|
|
59
|
+
* @remarks
|
|
60
|
+
* - Round-trip must succeed for valid values: `parse(format(x)) ≡ x`
|
|
61
|
+
* - Parser must reject invalid strings with clear errors
|
|
62
|
+
* - Use when both formatting and parsing are needed
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const iso8601: FormatterParser<ISO8601> = {
|
|
67
|
+
* format: (date) => date.toISOString(),
|
|
68
|
+
* parse: (str) => {
|
|
69
|
+
* const date = new Date(str);
|
|
70
|
+
* if (isNaN(date.getTime())) {
|
|
71
|
+
* throw new ParseError('ISO8601', str, 'Invalid date');
|
|
72
|
+
* }
|
|
73
|
+
* return date as ISO8601;
|
|
74
|
+
* }
|
|
75
|
+
* };
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export type FormatterParser<T extends WithFormat<unknown, string>> = {
|
|
79
|
+
format: Formatter<T>;
|
|
80
|
+
parse: Parser<T>;
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=formatters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatters.d.ts","sourceRoot":"","sources":["../src/formatters.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,SAAS,CAAC,MAAM,SAAS,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;AAE9F;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,MAAM,MAAM,CAAC,OAAO,SAAS,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;AAE7F;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI;IACnE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;CAClB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatters.js","sourceRoot":"","sources":["../src/formatters.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unacy Core - Type-safe unit and format conversion library
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
export type { WithUnits, WithFormat } from './types';
|
|
6
|
+
export type { Converter, BidirectionalConverter } from './converters';
|
|
7
|
+
export type { Formatter, Parser, FormatterParser } from './formatters';
|
|
8
|
+
export type { ConverterRegistry } from './registry';
|
|
9
|
+
export { createRegistry } from './registry';
|
|
10
|
+
export { UnacyError, CycleError, MaxDepthError, ConversionError, ParseError } from './errors';
|
|
11
|
+
export { createParserWithSchema } from './utils/validation';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unacy Core - Type-safe unit and format conversion library
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
export { createRegistry } from './registry';
|
|
6
|
+
// Errors
|
|
7
|
+
export { UnacyError, CycleError, MaxDepthError, ConversionError, ParseError } from './errors';
|
|
8
|
+
// Utilities
|
|
9
|
+
export { createParserWithSchema } from './utils/validation';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,SAAS;AACT,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE9F,YAAY;AACZ,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converter registry with auto-composition via BFS
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
import type { Converter, BidirectionalConverter } from './converters';
|
|
6
|
+
import type { RelaxedWithUnits, UnitsFor, WithUnits } from './types';
|
|
7
|
+
/**
|
|
8
|
+
* Represents a conversion edge from one unit to another
|
|
9
|
+
*/
|
|
10
|
+
type Edge<From extends string = string, To extends string = string> = readonly [From, To];
|
|
11
|
+
/**
|
|
12
|
+
* Extract all unique 'from' units from a list of edges
|
|
13
|
+
*/
|
|
14
|
+
type FromUnits<Edges extends readonly Edge[]> = Edges[number][0];
|
|
15
|
+
/**
|
|
16
|
+
* Extract all 'to' units for a specific 'from' unit string
|
|
17
|
+
*/
|
|
18
|
+
type ToUnitsFor<Edges extends readonly Edge[], FromUnit extends string> = Extract<Edges[number], readonly [FromUnit, any]>[1];
|
|
19
|
+
/**
|
|
20
|
+
* Type for unit-based conversion accessors
|
|
21
|
+
* Provides the shape: registry.Celsius.to.Fahrenheit(value)
|
|
22
|
+
* Only allows conversions that have been registered
|
|
23
|
+
*/
|
|
24
|
+
export type ConverterMap<Edges extends readonly Edge[]> = {
|
|
25
|
+
[From in FromUnits<Edges>]: {
|
|
26
|
+
to: {
|
|
27
|
+
[To in ToUnitsFor<Edges, From>]: (value: RelaxedWithUnits<number, From>) => WithUnits<number, To>;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Registry for managing and composing unit converters
|
|
33
|
+
*/
|
|
34
|
+
export interface ConverterRegistry<Edges extends Edge[] = []> {
|
|
35
|
+
/**
|
|
36
|
+
* Register a unidirectional converter
|
|
37
|
+
*
|
|
38
|
+
* @param from - Source unit
|
|
39
|
+
* @param to - Destination unit
|
|
40
|
+
* @param converter - Converter function
|
|
41
|
+
* @returns New registry instance with the converter registered
|
|
42
|
+
*/
|
|
43
|
+
register<From extends WithUnits<number, string>, To extends WithUnits<number, string>>(from: UnitsFor<From>, to: UnitsFor<To>, converter: Converter<From, To>): ConverterRegistry<[...Edges, Edge<UnitsFor<From>, UnitsFor<To>>]> & ConverterMap<[...Edges, Edge<UnitsFor<From>, UnitsFor<To>>]>;
|
|
44
|
+
/**
|
|
45
|
+
* Register a bidirectional converter (both directions)
|
|
46
|
+
*
|
|
47
|
+
* @param from - First unit
|
|
48
|
+
* @param to - Second unit
|
|
49
|
+
* @param converter - Bidirectional converter object
|
|
50
|
+
* @returns New registry instance with both converters registered
|
|
51
|
+
*/
|
|
52
|
+
register<From extends WithUnits<number, string>, To extends WithUnits<number, string>>(from: UnitsFor<From>, to: UnitsFor<To>, converter: BidirectionalConverter<From, To>): ConverterRegistry<[
|
|
53
|
+
...Edges,
|
|
54
|
+
Edge<UnitsFor<From>, UnitsFor<To>>,
|
|
55
|
+
Edge<UnitsFor<To>, UnitsFor<From>>
|
|
56
|
+
]> & ConverterMap<[
|
|
57
|
+
...Edges,
|
|
58
|
+
Edge<UnitsFor<From>, UnitsFor<To>>,
|
|
59
|
+
Edge<UnitsFor<To>, UnitsFor<From>>
|
|
60
|
+
]>;
|
|
61
|
+
/**
|
|
62
|
+
* Register a bidirectional converter (both directions)
|
|
63
|
+
* @deprecated Use register() with BidirectionalConverter instead
|
|
64
|
+
*
|
|
65
|
+
* @param from - First unit
|
|
66
|
+
* @param to - Second unit
|
|
67
|
+
* @param converter - Bidirectional converter object
|
|
68
|
+
* @returns New registry instance with both converters registered
|
|
69
|
+
*/
|
|
70
|
+
registerBidirectional<From extends WithUnits<number, string>, To extends WithUnits<number, string>>(from: UnitsFor<From>, to: UnitsFor<To>, converter: BidirectionalConverter<From, To>): ConverterRegistry<[
|
|
71
|
+
...Edges,
|
|
72
|
+
Edge<UnitsFor<From>, UnitsFor<To>>,
|
|
73
|
+
Edge<UnitsFor<To>, UnitsFor<From>>
|
|
74
|
+
]> & ConverterMap<[
|
|
75
|
+
...Edges,
|
|
76
|
+
Edge<UnitsFor<From>, UnitsFor<To>>,
|
|
77
|
+
Edge<UnitsFor<To>, UnitsFor<From>>
|
|
78
|
+
]>;
|
|
79
|
+
/**
|
|
80
|
+
* Explicitly allow a conversion path in the type system (for multi-hop conversions)
|
|
81
|
+
*
|
|
82
|
+
* This method verifies that a conversion path exists at runtime (via BFS) and adds it
|
|
83
|
+
* to the type system so it can be used with type-safe accessor syntax.
|
|
84
|
+
*
|
|
85
|
+
* @param from - Source unit string
|
|
86
|
+
* @param to - Destination unit string
|
|
87
|
+
* @returns New registry instance with the conversion path enabled in types
|
|
88
|
+
* @throws ConversionError if no path exists between the units
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* const registry = createRegistry()
|
|
93
|
+
* .register('Celsius', 'Kelvin', c => (c + 273.15) as Kelvin)
|
|
94
|
+
* .register('Kelvin', 'Fahrenheit', k => ((k - 273.15) * 9/5 + 32) as Fahrenheit)
|
|
95
|
+
* .allow('Celsius', 'Fahrenheit'); // Enable multi-hop path in types
|
|
96
|
+
*
|
|
97
|
+
* // Now type-safe:
|
|
98
|
+
* const f = registry.Celsius.to.Fahrenheit(temp);
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
allow<From extends string, To extends string>(from: From, to: To): ConverterRegistry<[...Edges, Edge<From, To>]> & ConverterMap<[...Edges, Edge<From, To>]>;
|
|
102
|
+
/**
|
|
103
|
+
* Get a converter (direct or composed via BFS)
|
|
104
|
+
*
|
|
105
|
+
* @param from - Source unit
|
|
106
|
+
* @param to - Destination unit
|
|
107
|
+
* @returns Converter function, or undefined if no path exists
|
|
108
|
+
*/
|
|
109
|
+
getConverter<From extends WithUnits<number, string>, To extends WithUnits<number, string>>(from: UnitsFor<From>, to: UnitsFor<To>): Converter<From, To> | undefined;
|
|
110
|
+
/**
|
|
111
|
+
* Convert a value using fluent API
|
|
112
|
+
*
|
|
113
|
+
* @param value - Value to convert
|
|
114
|
+
* @param fromUnit - Source unit
|
|
115
|
+
* @returns Object with to() method for conversion
|
|
116
|
+
*/
|
|
117
|
+
convert<From extends WithUnits<number, string>>(value: From, fromUnit: UnitsFor<From>): {
|
|
118
|
+
to<To extends WithUnits<number, string>>(unit: UnitsFor<To>): To;
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Create a new converter registry
|
|
123
|
+
*
|
|
124
|
+
* @returns Empty converter registry with unit-based accessors
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* type Celsius = WithUnits<number, 'Celsius'>;
|
|
129
|
+
* type Fahrenheit = WithUnits<number, 'Fahrenheit'>;
|
|
130
|
+
*
|
|
131
|
+
* const registry = createRegistry()
|
|
132
|
+
* .register('Celsius', 'Fahrenheit', (c: Celsius) => ((c * 9/5) + 32) as Fahrenheit);
|
|
133
|
+
*
|
|
134
|
+
* const temp: Celsius = 25 as Celsius;
|
|
135
|
+
* const fahrenheit = registry.Celsius.to.Fahrenheit(temp);
|
|
136
|
+
* console.log(fahrenheit); // 77
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
export declare function createRegistry(): ConverterRegistry<[]> & ConverterMap<[]>;
|
|
140
|
+
export {};
|
|
141
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|