utilium 0.5.10 → 0.6.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.
@@ -6,7 +6,6 @@ export interface MemberInit {
6
6
  length?: number;
7
7
  }
8
8
  export declare const init: unique symbol;
9
- export type init = typeof init;
10
9
  /**
11
10
  * Options for struct initialization
12
11
  */
@@ -25,16 +24,31 @@ export interface Metadata {
25
24
  size: number;
26
25
  }
27
26
  export declare const metadata: unique symbol;
28
- export type metadata = typeof metadata;
27
+ export interface _DecoratorMetadata<T extends Metadata = Metadata> extends DecoratorMetadata {
28
+ [metadata]?: T;
29
+ [init]?: MemberInit[];
30
+ }
31
+ export interface DecoratorContext<T extends Metadata = Metadata> {
32
+ metadata: _DecoratorMetadata<T>;
33
+ }
34
+ export type MemberContext = ClassMemberDecoratorContext & DecoratorContext;
29
35
  export interface Static<T extends Metadata = Metadata> {
30
- [metadata]: T;
31
- new (): Instance;
32
- prototype: Instance;
36
+ [Symbol.metadata]: DecoratorMetadata & {
37
+ [metadata]: T;
38
+ };
39
+ new (): Instance<T>;
40
+ prototype: Instance<T>;
33
41
  }
34
42
  export interface StaticLike<T extends Metadata = Metadata> extends ClassLike {
35
- [metadata]?: T;
36
- [init]?: MemberInit[];
43
+ [Symbol.metadata]?: _DecoratorMetadata<T> | null;
37
44
  }
45
+ export declare function isValidMetadata<T extends Metadata = Metadata>(arg: unknown): arg is DecoratorMetadata & {
46
+ [metadata]: T;
47
+ };
48
+ /**
49
+ * Gets a reference to Symbol.metadata, even on platforms that do not expose it globally (like Node)
50
+ */
51
+ export declare function symbol_metadata(arg: ClassLike): typeof Symbol.metadata;
38
52
  export declare function isStatic<T extends Metadata = Metadata>(arg: unknown): arg is Static<T>;
39
53
  export interface Instance<T extends Metadata = Metadata> {
40
54
  constructor: Static<T>;
@@ -1,10 +1,23 @@
1
1
  export const init = Symbol('struct_init');
2
2
  export const metadata = Symbol('struct');
3
+ export function isValidMetadata(arg) {
4
+ return arg != null && typeof arg == 'object' && metadata in arg;
5
+ }
6
+ /**
7
+ * Gets a reference to Symbol.metadata, even on platforms that do not expose it globally (like Node)
8
+ */
9
+ export function symbol_metadata(arg) {
10
+ const symbol_metadata = Symbol.metadata || Object.getOwnPropertySymbols(arg).find(s => s.description == 'Symbol.metadata');
11
+ if (!symbol_metadata) {
12
+ throw new ReferenceError('Could not get a reference to Symbol.metadata');
13
+ }
14
+ return symbol_metadata;
15
+ }
3
16
  export function isStatic(arg) {
4
- return typeof arg == 'function' && metadata in arg;
17
+ return typeof arg == 'function' && symbol_metadata(arg) in arg && isValidMetadata(arg[symbol_metadata(arg)]);
5
18
  }
6
19
  export function isInstance(arg) {
7
- return metadata in (arg?.constructor || {});
20
+ return arg != null && typeof arg == 'object' && isStatic(arg.constructor);
8
21
  }
9
22
  export function isStruct(arg) {
10
23
  return isInstance(arg) || isStatic(arg);
package/dist/struct.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- import * as Struct from './internal/struct.js';
2
- import { ClassLike } from './types.js';
3
1
  import * as primitive from './internal/primitives.js';
4
- export { Struct };
2
+ import { DecoratorContext, InstanceLike, Options, Size, StaticLike, type MemberContext } from './internal/struct.js';
3
+ import { ClassLike } from './types.js';
4
+ export * as Struct from './internal/struct.js';
5
5
  /**
6
6
  * Gets the size in bytes of a type
7
7
  */
8
- export declare function sizeof<T extends primitive.Valid | Struct.StaticLike | Struct.InstanceLike>(type: T): Struct.Size<T>;
8
+ export declare function sizeof<T extends primitive.Valid | StaticLike | InstanceLike>(type: T): Size<T>;
9
9
  /**
10
10
  * Aligns a number
11
11
  */
@@ -13,11 +13,11 @@ export declare function align(value: number, alignment: number): number;
13
13
  /**
14
14
  * Decorates a class as a struct
15
15
  */
16
- export declare function struct(options?: Partial<Struct.Options>): (target: Struct.StaticLike, _?: ClassDecoratorContext) => void;
16
+ export declare function struct(options?: Partial<Options>): <const T extends StaticLike>(target: T, context: ClassDecoratorContext & DecoratorContext) => T;
17
17
  /**
18
18
  * Decorates a class member to be serialized
19
19
  */
20
- export declare function member(type: primitive.Valid | ClassLike, length?: number): (target: object, context?: ClassMemberDecoratorContext | string | symbol) => void;
20
+ export declare function member(type: primitive.Valid | ClassLike, length?: number): <V>(value: V, context: MemberContext) => V;
21
21
  /**
22
22
  * Serializes a struct into a Uint8Array
23
23
  */
@@ -26,13 +26,9 @@ export declare function serialize(instance: unknown): Uint8Array;
26
26
  * Deserializes a struct from a Uint8Array
27
27
  */
28
28
  export declare function deserialize(instance: unknown, _buffer: ArrayBuffer | ArrayBufferView): void;
29
- /**
30
- * Also can be a name when legacy decorators are used
31
- */
32
- type Context = string | symbol | ClassMemberDecoratorContext;
33
29
  declare function _member<T extends primitive.Valid>(type: T): {
34
- (length: number): (target: object, context?: Context) => void;
35
- (target: object, context?: Context): void;
30
+ <const V>(length: number): (value: V, context: MemberContext) => V;
31
+ <const V>(value: V, context: MemberContext): V;
36
32
  };
37
33
  /**
38
34
  * Shortcut types
package/dist/struct.js CHANGED
@@ -1,7 +1,7 @@
1
- import * as Struct from './internal/struct.js';
2
- import { capitalize } from './string.js';
3
1
  import * as primitive from './internal/primitives.js';
4
- export { Struct };
2
+ import { symbol_metadata, init, isInstance, isStatic, isStruct, metadata, } from './internal/struct.js';
3
+ import { capitalize } from './string.js';
4
+ export * as Struct from './internal/struct.js';
5
5
  /**
6
6
  * Gets the size in bytes of a type
7
7
  */
@@ -13,11 +13,11 @@ export function sizeof(type) {
13
13
  }
14
14
  return (+primitive.normalize(type).match(primitive.regex)[2] / 8);
15
15
  }
16
- if (!Struct.isStruct(type)) {
16
+ if (!isStruct(type)) {
17
17
  throw new TypeError('Not a struct');
18
18
  }
19
- const meta = Struct.isStatic(type) ? type[Struct.metadata] : type.constructor[Struct.metadata];
20
- return meta.size;
19
+ const struct = isStatic(type) ? type : type.constructor;
20
+ return struct[symbol_metadata(struct)][metadata].size;
21
21
  }
22
22
  /**
23
23
  * Aligns a number
@@ -30,12 +30,13 @@ export function align(value, alignment) {
30
30
  */
31
31
  export function struct(options = {}) {
32
32
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
33
- return function (target, _) {
34
- target[Struct.init] ||= [];
33
+ return function __decorateStruct(target, context) {
34
+ context.metadata[init] ||= [];
35
35
  let size = 0;
36
36
  const members = new Map();
37
- for (const { name, type, length } of target[Struct.init]) {
38
- if (!primitive.isValid(type) && !Struct.isStatic(type)) {
37
+ for (const _ of context.metadata[init]) {
38
+ const { name, type, length } = _;
39
+ if (!primitive.isValid(type) && !isStatic(type)) {
39
40
  throw new TypeError('Not a valid type: ' + type);
40
41
  }
41
42
  members.set(name, {
@@ -46,15 +47,16 @@ export function struct(options = {}) {
46
47
  size += sizeof(type) * (length || 1);
47
48
  size = align(size, options.align || 1);
48
49
  }
49
- target[Struct.metadata] = { options, members, size };
50
+ context.metadata[metadata] = { options, members, size };
51
+ return target;
50
52
  };
51
53
  }
52
54
  /**
53
55
  * Decorates a class member to be serialized
54
56
  */
55
57
  export function member(type, length) {
56
- return function (target, context) {
57
- let name = typeof context == 'object' ? context.name : context;
58
+ return function (value, context) {
59
+ let name = context.name;
58
60
  if (typeof name == 'symbol') {
59
61
  console.warn('Symbol used for struct member name will be coerced to string: ' + name.toString());
60
62
  name = name.toString();
@@ -62,25 +64,19 @@ export function member(type, length) {
62
64
  if (!name) {
63
65
  throw new ReferenceError('Invalid name for struct member');
64
66
  }
65
- if (typeof target != 'object') {
66
- throw new TypeError('Invalid member for struct field');
67
- }
68
- if (!('constructor' in target)) {
69
- throw new TypeError('Invalid member for struct field');
70
- }
71
- const struct = target.constructor;
72
- struct[Struct.init] ||= [];
73
- struct[Struct.init].push({ name, type, length });
67
+ context.metadata[init] ||= [];
68
+ context.metadata[init].push({ name, type, length });
69
+ return value;
74
70
  };
75
71
  }
76
72
  /**
77
73
  * Serializes a struct into a Uint8Array
78
74
  */
79
75
  export function serialize(instance) {
80
- if (!Struct.isInstance(instance)) {
76
+ if (!isInstance(instance)) {
81
77
  throw new TypeError('Can not serialize, not a struct instance');
82
78
  }
83
- const { options, members } = instance.constructor[Struct.metadata];
79
+ const { options, members } = instance.constructor[symbol_metadata(instance.constructor)][metadata];
84
80
  const buffer = new Uint8Array(sizeof(instance));
85
81
  const view = new DataView(buffer.buffer);
86
82
  for (const [name, { type, length, offset }] of members) {
@@ -114,10 +110,10 @@ export function serialize(instance) {
114
110
  * Deserializes a struct from a Uint8Array
115
111
  */
116
112
  export function deserialize(instance, _buffer) {
117
- if (!Struct.isInstance(instance)) {
113
+ if (!isInstance(instance)) {
118
114
  throw new TypeError('Can not deserialize, not a struct instance');
119
115
  }
120
- const { options, members } = instance.constructor[Struct.metadata];
116
+ const { options, members } = instance.constructor[symbol_metadata(instance.constructor)][metadata];
121
117
  const buffer = new Uint8Array('buffer' in _buffer ? _buffer.buffer : _buffer);
122
118
  const view = new DataView(buffer.buffer);
123
119
  for (const [name, { type, offset, length }] of members) {
@@ -156,13 +152,13 @@ export function deserialize(instance, _buffer) {
156
152
  }
157
153
  }
158
154
  function _member(type) {
159
- function _(targetOrLength, context) {
160
- if (typeof targetOrLength == 'number') {
161
- return member(type, targetOrLength);
155
+ function _structMemberDecorator(valueOrLength, context) {
156
+ if (typeof valueOrLength == 'number') {
157
+ return member(type, valueOrLength);
162
158
  }
163
- return member(type)(targetOrLength, context);
159
+ return member(type)(valueOrLength, context);
164
160
  }
165
- return _;
161
+ return _structMemberDecorator;
166
162
  }
167
163
  /**
168
164
  * Shortcut types
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "utilium",
3
- "version": "0.5.10",
3
+ "version": "0.6.0",
4
4
  "description": "Typescript utilies",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -7,9 +7,7 @@ export interface MemberInit {
7
7
  length?: number;
8
8
  }
9
9
 
10
- export const init = Symbol('struct_init');
11
-
12
- export type init = typeof init;
10
+ export const init: unique symbol = Symbol('struct_init');
13
11
 
14
12
  /**
15
13
  * Options for struct initialization
@@ -31,23 +29,53 @@ export interface Metadata {
31
29
  size: number;
32
30
  }
33
31
 
34
- export const metadata = Symbol('struct');
32
+ export const metadata: unique symbol = Symbol('struct');
35
33
 
36
- export type metadata = typeof metadata;
34
+ export interface _DecoratorMetadata<T extends Metadata = Metadata> extends DecoratorMetadata {
35
+ [metadata]?: T;
36
+ [init]?: MemberInit[];
37
+ }
38
+
39
+ export interface DecoratorContext<T extends Metadata = Metadata> {
40
+ metadata: _DecoratorMetadata<T>;
41
+ }
42
+
43
+ export type MemberContext = ClassMemberDecoratorContext & DecoratorContext;
37
44
 
38
45
  export interface Static<T extends Metadata = Metadata> {
39
- [metadata]: T;
40
- new (): Instance;
41
- prototype: Instance;
46
+ [Symbol.metadata]: DecoratorMetadata & {
47
+ [metadata]: T;
48
+ };
49
+ new (): Instance<T>;
50
+ prototype: Instance<T>;
42
51
  }
43
52
 
44
53
  export interface StaticLike<T extends Metadata = Metadata> extends ClassLike {
45
- [metadata]?: T;
46
- [init]?: MemberInit[];
54
+ [Symbol.metadata]?: _DecoratorMetadata<T> | null;
55
+ }
56
+
57
+ export function isValidMetadata<T extends Metadata = Metadata>(
58
+ arg: unknown
59
+ ): arg is DecoratorMetadata & {
60
+ [metadata]: T;
61
+ } {
62
+ return arg != null && typeof arg == 'object' && metadata in arg;
63
+ }
64
+
65
+ /**
66
+ * Gets a reference to Symbol.metadata, even on platforms that do not expose it globally (like Node)
67
+ */
68
+ export function symbol_metadata(arg: ClassLike): typeof Symbol.metadata {
69
+ const symbol_metadata = Symbol.metadata || Object.getOwnPropertySymbols(arg).find(s => s.description == 'Symbol.metadata');
70
+ if (!symbol_metadata) {
71
+ throw new ReferenceError('Could not get a reference to Symbol.metadata');
72
+ }
73
+
74
+ return symbol_metadata as typeof Symbol.metadata;
47
75
  }
48
76
 
49
77
  export function isStatic<T extends Metadata = Metadata>(arg: unknown): arg is Static<T> {
50
- return typeof arg == 'function' && metadata in arg;
78
+ return typeof arg == 'function' && symbol_metadata(arg as ClassLike) in arg && isValidMetadata(arg[symbol_metadata(arg as ClassLike)]);
51
79
  }
52
80
 
53
81
  export interface Instance<T extends Metadata = Metadata> {
@@ -59,7 +87,7 @@ export interface InstanceLike<T extends Metadata = Metadata> {
59
87
  }
60
88
 
61
89
  export function isInstance<T extends Metadata = Metadata>(arg: unknown): arg is Instance<T> {
62
- return metadata in (arg?.constructor || {});
90
+ return arg != null && typeof arg == 'object' && isStatic(arg.constructor);
63
91
  }
64
92
 
65
93
  export function isStruct<T extends Metadata = Metadata>(arg: unknown): arg is Instance<T> | Static<T> {
package/src/struct.ts CHANGED
@@ -1,29 +1,44 @@
1
- import * as Struct from './internal/struct.js';
1
+ import * as primitive from './internal/primitives.js';
2
+ import {
3
+ DecoratorContext,
4
+ InstanceLike,
5
+ MemberInit,
6
+ Metadata,
7
+ Options,
8
+ Size,
9
+ StaticLike,
10
+ symbol_metadata,
11
+ init,
12
+ isInstance,
13
+ isStatic,
14
+ isStruct,
15
+ metadata,
16
+ type MemberContext,
17
+ } from './internal/struct.js';
2
18
  import { capitalize } from './string.js';
3
19
  import { ClassLike } from './types.js';
4
- import * as primitive from './internal/primitives.js';
5
- export { Struct };
20
+ export * as Struct from './internal/struct.js';
6
21
 
7
22
  /**
8
23
  * Gets the size in bytes of a type
9
24
  */
10
- export function sizeof<T extends primitive.Valid | Struct.StaticLike | Struct.InstanceLike>(type: T): Struct.Size<T> {
25
+ export function sizeof<T extends primitive.Valid | StaticLike | InstanceLike>(type: T): Size<T> {
11
26
  // primitive
12
27
  if (typeof type == 'string') {
13
28
  if (!primitive.isValid(type)) {
14
29
  throw new TypeError('Invalid primitive type: ' + type);
15
30
  }
16
31
 
17
- return (+primitive.normalize(type).match(primitive.regex)![2] / 8) as Struct.Size<T>;
32
+ return (+primitive.normalize(type).match(primitive.regex)![2] / 8) as Size<T>;
18
33
  }
19
34
 
20
- if (!Struct.isStruct(type)) {
35
+ if (!isStruct(type)) {
21
36
  throw new TypeError('Not a struct');
22
37
  }
23
38
 
24
- const meta: Struct.Metadata = Struct.isStatic(type) ? type[Struct.metadata] : type.constructor[Struct.metadata];
39
+ const struct = isStatic(type) ? type : type.constructor;
25
40
 
26
- return meta.size as Struct.Size<T>;
41
+ return struct[symbol_metadata(struct)][metadata].size as Size<T>;
27
42
  }
28
43
 
29
44
  /**
@@ -36,14 +51,15 @@ export function align(value: number, alignment: number): number {
36
51
  /**
37
52
  * Decorates a class as a struct
38
53
  */
39
- export function struct(options: Partial<Struct.Options> = {}) {
54
+ export function struct(options: Partial<Options> = {}) {
40
55
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
41
- return function (target: Struct.StaticLike, _?: ClassDecoratorContext) {
42
- target[Struct.init] ||= [];
56
+ return function __decorateStruct<const T extends StaticLike>(target: T, context: ClassDecoratorContext & DecoratorContext): T {
57
+ context.metadata[init] ||= [];
43
58
  let size = 0;
44
59
  const members = new Map();
45
- for (const { name, type, length } of target[Struct.init]) {
46
- if (!primitive.isValid(type) && !Struct.isStatic(type)) {
60
+ for (const _ of context.metadata[init]) {
61
+ const { name, type, length } = _;
62
+ if (!primitive.isValid(type) && !isStatic(type)) {
47
63
  throw new TypeError('Not a valid type: ' + type);
48
64
  }
49
65
  members.set(name, {
@@ -55,7 +71,8 @@ export function struct(options: Partial<Struct.Options> = {}) {
55
71
  size = align(size, options.align || 1);
56
72
  }
57
73
 
58
- target[Struct.metadata] = { options, members, size } satisfies Struct.Metadata;
74
+ context.metadata[metadata] = { options, members, size } satisfies Metadata;
75
+ return target;
59
76
  };
60
77
  }
61
78
 
@@ -63,8 +80,8 @@ export function struct(options: Partial<Struct.Options> = {}) {
63
80
  * Decorates a class member to be serialized
64
81
  */
65
82
  export function member(type: primitive.Valid | ClassLike, length?: number) {
66
- return function (target: object, context?: ClassMemberDecoratorContext | string | symbol) {
67
- let name = typeof context == 'object' ? context.name : context;
83
+ return function <V>(value: V, context: MemberContext): V {
84
+ let name = context.name;
68
85
  if (typeof name == 'symbol') {
69
86
  console.warn('Symbol used for struct member name will be coerced to string: ' + name.toString());
70
87
  name = name.toString();
@@ -74,18 +91,9 @@ export function member(type: primitive.Valid | ClassLike, length?: number) {
74
91
  throw new ReferenceError('Invalid name for struct member');
75
92
  }
76
93
 
77
- if (typeof target != 'object') {
78
- throw new TypeError('Invalid member for struct field');
79
- }
80
-
81
- if (!('constructor' in target)) {
82
- throw new TypeError('Invalid member for struct field');
83
- }
84
-
85
- const struct = (target as Struct.InstanceLike).constructor;
86
-
87
- struct[Struct.init] ||= [];
88
- struct[Struct.init].push({ name, type, length } satisfies Struct.MemberInit);
94
+ context.metadata[init] ||= [];
95
+ context.metadata[init].push({ name, type, length } satisfies MemberInit);
96
+ return value;
89
97
  };
90
98
  }
91
99
 
@@ -93,10 +101,10 @@ export function member(type: primitive.Valid | ClassLike, length?: number) {
93
101
  * Serializes a struct into a Uint8Array
94
102
  */
95
103
  export function serialize(instance: unknown): Uint8Array {
96
- if (!Struct.isInstance(instance)) {
104
+ if (!isInstance(instance)) {
97
105
  throw new TypeError('Can not serialize, not a struct instance');
98
106
  }
99
- const { options, members } = instance.constructor[Struct.metadata];
107
+ const { options, members } = instance.constructor[symbol_metadata(instance.constructor)][metadata];
100
108
 
101
109
  const buffer = new Uint8Array(sizeof(instance));
102
110
  const view = new DataView(buffer.buffer);
@@ -139,10 +147,10 @@ export function serialize(instance: unknown): Uint8Array {
139
147
  * Deserializes a struct from a Uint8Array
140
148
  */
141
149
  export function deserialize(instance: unknown, _buffer: ArrayBuffer | ArrayBufferView) {
142
- if (!Struct.isInstance(instance)) {
150
+ if (!isInstance(instance)) {
143
151
  throw new TypeError('Can not deserialize, not a struct instance');
144
152
  }
145
- const { options, members } = instance.constructor[Struct.metadata];
153
+ const { options, members } = instance.constructor[symbol_metadata(instance.constructor)][metadata];
146
154
 
147
155
  const buffer = new Uint8Array('buffer' in _buffer ? _buffer.buffer : _buffer);
148
156
 
@@ -191,22 +199,17 @@ export function deserialize(instance: unknown, _buffer: ArrayBuffer | ArrayBuffe
191
199
  }
192
200
  }
193
201
 
194
- /**
195
- * Also can be a name when legacy decorators are used
196
- */
197
- type Context = string | symbol | ClassMemberDecoratorContext;
198
-
199
202
  function _member<T extends primitive.Valid>(type: T) {
200
- function _(length: number): (target: object, context?: Context) => void;
201
- function _(target: object, context?: Context): void;
202
- function _(targetOrLength: object | number, context?: Context) {
203
- if (typeof targetOrLength == 'number') {
204
- return member(type, targetOrLength);
203
+ function _structMemberDecorator<const V>(length: number): (value: V, context: MemberContext) => V;
204
+ function _structMemberDecorator<const V>(value: V, context: MemberContext): V;
205
+ function _structMemberDecorator<const V>(valueOrLength: V | number, context?: MemberContext): V | ((value: V, context: MemberContext) => V) {
206
+ if (typeof valueOrLength == 'number') {
207
+ return member(type, valueOrLength);
205
208
  }
206
209
 
207
- return member(type)(targetOrLength, context);
210
+ return member(type)(valueOrLength, context!);
208
211
  }
209
- return _;
212
+ return _structMemberDecorator;
210
213
  }
211
214
 
212
215
  /**
package/tsconfig.json CHANGED
@@ -10,7 +10,6 @@
10
10
  "esModuleInterop": true,
11
11
  "noImplicitThis": true,
12
12
  "declaration": true,
13
- "experimentalDecorators": true,
14
13
  "strict": true
15
14
  },
16
15
  "typedocOptions": {