@oazmi/superbuild 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/esm/_dnt.shims.d.ts +2 -0
- package/esm/_dnt.shims.d.ts.map +1 -0
- package/esm/_dnt.shims.js +57 -0
- package/esm/deps/jsr.io/@oazmi/esbuild-types/0.28.0/src/mod.d.ts +598 -0
- package/esm/deps/jsr.io/@oazmi/esbuild-types/0.28.0/src/mod.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/esbuild-types/0.28.0/src/mod.js +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/alias.d.ts +617 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/alias.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/alias.js +671 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/array1d.d.ts +487 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/array1d.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/array1d.js +536 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/array2d.d.ts +266 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/array2d.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/array2d.js +318 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/binder.d.ts +368 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/binder.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/binder.js +380 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/crossenv.d.ts +711 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/crossenv.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/crossenv.js +1173 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/cryptoman.d.ts +171 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/cryptoman.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/cryptoman.js +308 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/deps.d.ts +10 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/deps.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/deps.js +10 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/eightpack.d.ts +168 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/eightpack.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/eightpack.js +236 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/eightpack_varint.d.ts +90 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/eightpack_varint.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/eightpack_varint.js +237 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/numericarray.d.ts +213 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/numericarray.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/numericarray.js +363 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/numericmethods.d.ts +233 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/numericmethods.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/numericmethods.js +256 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/pathman.d.ts +1436 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/pathman.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/pathman.js +1730 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/promiseman.d.ts +647 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/promiseman.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/promiseman.js +762 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/stringman.d.ts +538 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/stringman.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/stringman.js +626 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/struct.d.ts +734 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/struct.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/struct.js +764 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/typedbuffer.d.ts +137 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/typedbuffer.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/typedbuffer.js +234 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/typedefs.d.ts +391 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/typedefs.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/typedefs.js +8 -0
- package/esm/deps.d.ts +56 -0
- package/esm/deps.d.ts.map +1 -0
- package/esm/deps.js +37 -0
- package/esm/esbuild/metafile.d.ts +90 -0
- package/esm/esbuild/metafile.d.ts.map +1 -0
- package/esm/esbuild/metafile.js +275 -0
- package/esm/esbuild/native.d.ts +95 -0
- package/esm/esbuild/native.d.ts.map +1 -0
- package/esm/esbuild/native.js +127 -0
- package/esm/esbuild/outputfile.d.ts +86 -0
- package/esm/esbuild/outputfile.d.ts.map +1 -0
- package/esm/esbuild/outputfile.js +221 -0
- package/esm/esbuild/strongtypes.d.ts +90 -0
- package/esm/esbuild/strongtypes.d.ts.map +1 -0
- package/esm/esbuild/strongtypes.js +8 -0
- package/esm/esbuild/typedefs.d.ts +121 -0
- package/esm/esbuild/typedefs.d.ts.map +1 -0
- package/esm/esbuild/typedefs.js +55 -0
- package/esm/esbuild/weaktypes.d.ts +46 -0
- package/esm/esbuild/weaktypes.d.ts.map +1 -0
- package/esm/esbuild/weaktypes.js +8 -0
- package/esm/funcdefs.d.ts +89 -0
- package/esm/funcdefs.d.ts.map +1 -0
- package/esm/funcdefs.js +145 -0
- package/esm/mod.d.ts +4 -0
- package/esm/mod.d.ts.map +1 -0
- package/esm/mod.js +2 -0
- package/esm/package.json +3 -0
- package/esm/plugins/emissions_driver.d.ts +33 -0
- package/esm/plugins/emissions_driver.d.ts.map +1 -0
- package/esm/plugins/emissions_driver.js +260 -0
- package/esm/plugins/long_build.d.ts +138 -0
- package/esm/plugins/long_build.d.ts.map +1 -0
- package/esm/plugins/long_build.js +288 -0
- package/esm/plugins/native_replica.d.ts +48 -0
- package/esm/plugins/native_replica.d.ts.map +1 -0
- package/esm/plugins/native_replica.js +122 -0
- package/esm/super/build.d.ts +53 -0
- package/esm/super/build.d.ts.map +1 -0
- package/esm/super/build.js +39 -0
- package/esm/super/build_context.d.ts +83 -0
- package/esm/super/build_context.d.ts.map +1 -0
- package/esm/super/build_context.js +124 -0
- package/esm/super/mod.d.ts +12 -0
- package/esm/super/mod.d.ts.map +1 -0
- package/esm/super/mod.js +9 -0
- package/esm/super/plugin.d.ts +23 -0
- package/esm/super/plugin.d.ts.map +1 -0
- package/esm/super/plugin.js +31 -0
- package/esm/super/plugin_build.d.ts +38 -0
- package/esm/super/plugin_build.d.ts.map +1 -0
- package/esm/super/plugin_build.js +198 -0
- package/esm/super/typedefs.d.ts +323 -0
- package/esm/super/typedefs.d.ts.map +1 -0
- package/esm/super/typedefs.js +10 -0
- package/esm/typedefs.d.ts +21 -0
- package/esm/typedefs.d.ts.map +1 -0
- package/esm/typedefs.js +5 -0
- package/license.md +37 -0
- package/package.json +88 -0
- package/readme.md +181 -0
|
@@ -0,0 +1,734 @@
|
|
|
1
|
+
/** utility functions for common object structures and `Object` manipulation.
|
|
2
|
+
*
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
import type { ConstructorOf, PrototypeOf } from "./typedefs.js";
|
|
6
|
+
/** represents a 2d rectangle. compatible with {@link DOMRect}, without its inherited annoying readonly fields. */
|
|
7
|
+
export interface Rect {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
}
|
|
13
|
+
/** represents an `ImageData` with optional color space information. */
|
|
14
|
+
export interface SimpleImageData extends Omit<ImageData, "colorSpace" | "data"> {
|
|
15
|
+
data: Uint8ClampedArray | Uint8Array;
|
|
16
|
+
colorSpace?: PredefinedColorSpace;
|
|
17
|
+
}
|
|
18
|
+
/** get an equivalent rectangle where the `height` and `width` are positive.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { assertEquals } from "jsr:@std/assert"
|
|
23
|
+
*
|
|
24
|
+
* const
|
|
25
|
+
* my_rect: Rect = { x: -20, y: 100, width: 50, height: -30 },
|
|
26
|
+
* my_abs_rect = positiveRect(my_rect)
|
|
27
|
+
*
|
|
28
|
+
* assertEquals(my_abs_rect, {
|
|
29
|
+
* x: -20,
|
|
30
|
+
* y: 70,
|
|
31
|
+
* width: 50,
|
|
32
|
+
* height: 30,
|
|
33
|
+
* })
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare const positiveRect: (r: Rect) => Rect;
|
|
37
|
+
/** get the constructor of a class's instance.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* import { assertEquals } from "jsr:@std/assert"
|
|
42
|
+
*
|
|
43
|
+
* class K { constructor(public value: any) { } }
|
|
44
|
+
*
|
|
45
|
+
* const a = new K(1)
|
|
46
|
+
* const b = new (constructorOf(a))(2) // equivalent to `const b = new K(2)`
|
|
47
|
+
*
|
|
48
|
+
* a satisfies K
|
|
49
|
+
* b satisfies K
|
|
50
|
+
* assertEquals(a !== b, true)
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare const constructorOf: <T, Args extends any[] = any[]>(class_instance: T) => ConstructorOf<T, Args>;
|
|
54
|
+
/** use the constructor of a class's instance to construct a new instance.
|
|
55
|
+
*
|
|
56
|
+
* this is useful for avoiding pollution of code with `new` keyword along with some wonky placement of braces to make your code work.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* class K {
|
|
61
|
+
* value: number
|
|
62
|
+
*
|
|
63
|
+
* constructor(value1: number, value2: number) {
|
|
64
|
+
* this.value = value1 + value2
|
|
65
|
+
* }
|
|
66
|
+
* }
|
|
67
|
+
*
|
|
68
|
+
* const a = new K(1, 1)
|
|
69
|
+
* const b = constructFrom(a, 2, 2) // equivalent to `const b = new K(2, 2)`
|
|
70
|
+
*
|
|
71
|
+
* // vanilla way of constructing `const c = new K(3, 3)` using `a`
|
|
72
|
+
* const c = new (Object.getPrototypeOf(a).constructor)(3, 3)
|
|
73
|
+
*
|
|
74
|
+
* a satisfies K
|
|
75
|
+
* b satisfies K
|
|
76
|
+
* c satisfies K
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export declare const constructFrom: <T, Args extends any[] = any[]>(class_instance: T, ...args: Args) => T;
|
|
80
|
+
/** get the prototype object of a class.
|
|
81
|
+
*
|
|
82
|
+
* this is useful when you want to access bound-methods of an instance of a class, such as the ones declared as:
|
|
83
|
+
*
|
|
84
|
+
* ```ts ignore
|
|
85
|
+
* class X {
|
|
86
|
+
* methodOfProto() { }
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* these bound methods are not available via destructure of an instance, because they then lose their `this` context.
|
|
91
|
+
* the only functions that can be destructured without losing their `this` context are the ones declared via assignment:
|
|
92
|
+
*
|
|
93
|
+
* ```ts ignore
|
|
94
|
+
* class X {
|
|
95
|
+
* fn = () => { }
|
|
96
|
+
* fn2 = function () { }
|
|
97
|
+
* }
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```ts
|
|
102
|
+
* import { assertEquals } from "jsr:@std/assert"
|
|
103
|
+
*
|
|
104
|
+
* const
|
|
105
|
+
* array_proto = prototypeOfClass(Array<number>),
|
|
106
|
+
* arr = [1, 2, 3, 4, 5]
|
|
107
|
+
*
|
|
108
|
+
* array_proto.push.call(arr, 6)
|
|
109
|
+
* assertEquals(arr, [1, 2, 3, 4, 5, 6])
|
|
110
|
+
*
|
|
111
|
+
* const slow_push_to_arr = (...values: number[]) => (arr.push(...values))
|
|
112
|
+
* // the following declaration is more performant than `slow_push_to_arr`,
|
|
113
|
+
* // and it also has lower memory footprint.
|
|
114
|
+
* const fast_push_to_arr = array_proto.push.bind(arr)
|
|
115
|
+
*
|
|
116
|
+
* slow_push_to_arr(7, 8) // sloww & bigg
|
|
117
|
+
* fast_push_to_arr(9, 10) // quicc & smol
|
|
118
|
+
* assertEquals(arr, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
export declare const prototypeOfClass: <T, Args extends any[] = any[]>(cls: ConstructorOf<T, Args>) => PrototypeOf<typeof cls>;
|
|
122
|
+
/** configuration options for slicing the prototype chain returned by {@link prototypeChainOfObject}.
|
|
123
|
+
*
|
|
124
|
+
* only the following combination of options are supported:
|
|
125
|
+
* - `start` and `end`
|
|
126
|
+
* - `start` and `delta`
|
|
127
|
+
* - `end` and `delta`
|
|
128
|
+
*
|
|
129
|
+
* if all three options are defined, then the `delta` option will be ignored.
|
|
130
|
+
*/
|
|
131
|
+
export interface PrototypeChainOfObjectConfig {
|
|
132
|
+
/** the inclusive starting depth of the returned prototype chain. defaults to `0`.
|
|
133
|
+
*
|
|
134
|
+
* it can be one of the following:
|
|
135
|
+
* - a positive integer: slices the full prototype chain starting from the given index.
|
|
136
|
+
* - a negative integer: slices the full prototype chain starting from the end of the sequence.
|
|
137
|
+
* - an object: slices the full prototype chain starting from the point where the given object is found (inclusive).
|
|
138
|
+
* if the object is not found then the `start` option will be treated as `0` (i.e. starting from beginning of the chain array).
|
|
139
|
+
*/
|
|
140
|
+
start?: number | Object;
|
|
141
|
+
/** the exclusive ending depth of the returned prototype chain. defaults to `-1`.
|
|
142
|
+
*
|
|
143
|
+
* it can be one of the following:
|
|
144
|
+
* - a positive integer: slices the full prototype chain ending at the given index.
|
|
145
|
+
* - a negative integer: slices the full prototype chain from the end of the sequence.
|
|
146
|
+
* - an object or `null`: slices the full prototype chain ending at the point where the given object is found (exclusive).
|
|
147
|
+
* if the object is not found then the `end` option will be treated as `-1` (i.e. ending at the end of the chain array).
|
|
148
|
+
*/
|
|
149
|
+
end?: number | Object | null;
|
|
150
|
+
/** the additional depth to traverse on top of either {@link start} or {@link end}.
|
|
151
|
+
* make sure that you always provide a positive number.
|
|
152
|
+
*
|
|
153
|
+
* - when the `start` option is specified, you will be given `delta` number of prototype elements after the starting point.
|
|
154
|
+
* - when the `end` option is specified, you will be given `delta` number of prototype elements before the ending point.
|
|
155
|
+
*/
|
|
156
|
+
delta?: number;
|
|
157
|
+
}
|
|
158
|
+
/** get the prototype chain of an object, with optional slicing options.
|
|
159
|
+
*
|
|
160
|
+
* @param obj the object whose prototype chain is to be found.
|
|
161
|
+
* @param config optional configuration for slicing the full prototype chain.
|
|
162
|
+
* @returns the sliced prototype chain of the given object.
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```ts
|
|
166
|
+
* import { assertEquals, assertThrows } from "jsr:@std/assert"
|
|
167
|
+
*
|
|
168
|
+
* // aliasing our functions for brevity
|
|
169
|
+
* const
|
|
170
|
+
* fn = prototypeChainOfObject,
|
|
171
|
+
* eq = assertEquals
|
|
172
|
+
*
|
|
173
|
+
* class A extends Array { }
|
|
174
|
+
* class B extends A { }
|
|
175
|
+
* class C extends B { }
|
|
176
|
+
* class D extends C { }
|
|
177
|
+
*
|
|
178
|
+
* const
|
|
179
|
+
* a = new A(0),
|
|
180
|
+
* b = new B(0),
|
|
181
|
+
* c = new C(0),
|
|
182
|
+
* d = new D(0)
|
|
183
|
+
*
|
|
184
|
+
* eq(fn(d), [D.prototype, C.prototype, B.prototype, A.prototype, Array.prototype, Object.prototype, null])
|
|
185
|
+
* eq(fn(b), [B.prototype, A.prototype, Array.prototype, Object.prototype, null])
|
|
186
|
+
*
|
|
187
|
+
* // slicing the prototype chain, starting from index 2 till the end
|
|
188
|
+
* eq(fn(d, { start: 2 }), [B.prototype, A.prototype, Array.prototype, Object.prototype, null])
|
|
189
|
+
*
|
|
190
|
+
* // slicing using a negative index
|
|
191
|
+
* eq(fn(d, { start: -2 }), [Object.prototype, null])
|
|
192
|
+
*
|
|
193
|
+
* // slicing using an object
|
|
194
|
+
* eq(fn(d, { start: B.prototype }), [B.prototype, A.prototype, Array.prototype, Object.prototype, null])
|
|
195
|
+
*
|
|
196
|
+
* // when the slicing object is not found, the start index will be assumed to be `0` (default value)
|
|
197
|
+
* eq(fn(d, { start: Set.prototype }), [D.prototype, C.prototype, B.prototype, A.prototype, Array.prototype, Object.prototype, null])
|
|
198
|
+
*
|
|
199
|
+
* // slicing between the `start` index (inclusive) and the end index
|
|
200
|
+
* eq(fn(d, { start: 2, end: 6 }), [B.prototype, A.prototype, Array.prototype, Object.prototype])
|
|
201
|
+
* eq(fn(d, { start: 2, end: -1 }), [B.prototype, A.prototype, Array.prototype, Object.prototype])
|
|
202
|
+
* eq(fn(d, { start: 2, end: null }), [B.prototype, A.prototype, Array.prototype, Object.prototype])
|
|
203
|
+
*
|
|
204
|
+
* // if the end index is not found, the slicing will occur till the end
|
|
205
|
+
* eq(fn(d, { end: Set.prototype}), [D.prototype, C.prototype, B.prototype, A.prototype, Array.prototype, Object.prototype, null])
|
|
206
|
+
*
|
|
207
|
+
* // slicing using a `delta` argument will let you define how many elements you wish to:
|
|
208
|
+
* // - traverse forward from the `start` index
|
|
209
|
+
* // - traverse backwards from the `end` index
|
|
210
|
+
* eq(fn(d, { start: 2, delta: 3 }), [B.prototype, A.prototype, Array.prototype])
|
|
211
|
+
* eq(fn(d, { end: -2, delta: 2 }), [A.prototype, Array.prototype])
|
|
212
|
+
* eq(fn(d, { end: null, delta: 4 }), [B.prototype, A.prototype, Array.prototype, Object.prototype])
|
|
213
|
+
*
|
|
214
|
+
* eq(fn(d, { start: 1, delta: 1 }), fn(c, { start: 0, delta: 1 }))
|
|
215
|
+
* eq(fn(c, { start: 1, delta: 1 }), fn(b, { start: 0, delta: 1 }))
|
|
216
|
+
* eq(fn(b, { start: 1, delta: 1 }), fn(a, { start: 0, delta: 1 }))
|
|
217
|
+
* eq(fn(a, { start: 1, delta: 1 }), fn([], { start: 0, delta: 1 }))
|
|
218
|
+
* eq(fn([], { start: 1, delta: 1 }), fn({}, { start: 0, delta: 1 }))
|
|
219
|
+
*
|
|
220
|
+
* // you may also traverse through the inheritance chain of a class, but it will be a good idea to set your `end` point to `Function.prototype`,
|
|
221
|
+
* // since all class objects are effectively functions (i.e. their common ancestral prototype if `Function.prototype`).
|
|
222
|
+
* eq(fn(D, { start: 0, end: Function.prototype }), [C, B, A, Array])
|
|
223
|
+
* eq(fn(D), [C, B, A, Array, Function.prototype, Object.prototype, null])
|
|
224
|
+
* eq(fn(class {}), [Function.prototype, Object.prototype, null])
|
|
225
|
+
* eq(fn(class extends Object {}), [Object, Function.prototype, Object.prototype, null])
|
|
226
|
+
* eq(fn(class extends Map {}), [Map, Function.prototype, Object.prototype, null])
|
|
227
|
+
*
|
|
228
|
+
* // you cannot acquire the prototype chain of the `null` object
|
|
229
|
+
* assertThrows(() => { fn(null) })
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
export declare function prototypeChainOfObject(obj: any, config?: PrototypeChainOfObjectConfig): object[];
|
|
233
|
+
/** get an object's list of **owned** keys (string keys and symbol keys).
|
|
234
|
+
*
|
|
235
|
+
* > [!note]
|
|
236
|
+
* > **owned** keys of an object are not the same as just _any_ key of the object.
|
|
237
|
+
* > an owned key is one that it **directly** owned by the object, not owned through inheritance, such as the class methods.
|
|
238
|
+
* > more precisely, in javascript, which ever member of an object that we call a _property_, is an **owned** key.
|
|
239
|
+
*
|
|
240
|
+
* if you wish to acquire **all remaining** inherited keys of an object, you will want use {@link getInheritedPropertyKeys}.
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```ts
|
|
244
|
+
* import { assertEquals } from "jsr:@std/assert"
|
|
245
|
+
*
|
|
246
|
+
* const
|
|
247
|
+
* symbol_h = Symbol("symbol h"),
|
|
248
|
+
* symbol_i = Symbol("symbol i"),
|
|
249
|
+
* symbol_j = Symbol("symbol j")
|
|
250
|
+
*
|
|
251
|
+
* class A {
|
|
252
|
+
* a = { v: 1 }
|
|
253
|
+
* b = { v: 2 }
|
|
254
|
+
* c: { v: number }
|
|
255
|
+
* d() { return { v: 4 } }
|
|
256
|
+
* e() { return { v: 5 } }
|
|
257
|
+
* f = () => { return { v: 6 } }
|
|
258
|
+
* g: () => ({ v: number })
|
|
259
|
+
* [symbol_h]() { return { v: 8 } }
|
|
260
|
+
* [symbol_i] = () => { return { v: 9 } }
|
|
261
|
+
*
|
|
262
|
+
* constructor() {
|
|
263
|
+
* this.c = { v: 3 }
|
|
264
|
+
* this.g = () => { return { v: 7 } }
|
|
265
|
+
* }
|
|
266
|
+
* }
|
|
267
|
+
*
|
|
268
|
+
* class B extends A {
|
|
269
|
+
* override a = { v: 11 }
|
|
270
|
+
* override e() { return { v: 15 } }
|
|
271
|
+
* //@ts-ignore: typescript does not permit defining a method over the name of an existing property
|
|
272
|
+
* override g() { return { v: 17 } }
|
|
273
|
+
* [symbol_j] = () => { return { v: 20 } }
|
|
274
|
+
*
|
|
275
|
+
* constructor() { super() }
|
|
276
|
+
* }
|
|
277
|
+
*
|
|
278
|
+
* const
|
|
279
|
+
* a = new A(),
|
|
280
|
+
* b = new B()
|
|
281
|
+
*
|
|
282
|
+
* assertEquals(b.a, { v: 11 })
|
|
283
|
+
* assertEquals(b.b, { v: 2 })
|
|
284
|
+
* assertEquals(b.c, { v: 3 })
|
|
285
|
+
* assertEquals(b.d(), { v: 4 })
|
|
286
|
+
* assertEquals(b.e(), { v: 15 })
|
|
287
|
+
* assertEquals(b.f(), { v: 6 })
|
|
288
|
+
* assertEquals(b.g(), { v: 7 }) // notice that the overridden method is not called, and the property is called instead
|
|
289
|
+
* assertEquals(Object.getPrototypeOf(b).g(), { v: 17 })
|
|
290
|
+
* assertEquals(b[symbol_h](), { v: 8 })
|
|
291
|
+
* assertEquals(b[symbol_i](), { v: 9 })
|
|
292
|
+
* assertEquals(b[symbol_j](), { v: 20 })
|
|
293
|
+
*
|
|
294
|
+
* assertEquals(
|
|
295
|
+
* new Set(getOwnPropertyKeys(a)),
|
|
296
|
+
* new Set(["a", "b", "c", "f", "g", symbol_i]),
|
|
297
|
+
* )
|
|
298
|
+
* assertEquals(
|
|
299
|
+
* new Set(getOwnPropertyKeys(Object.getPrototypeOf(a))),
|
|
300
|
+
* new Set(["constructor", "d", "e", symbol_h]),
|
|
301
|
+
* )
|
|
302
|
+
* assertEquals(
|
|
303
|
+
* new Set(getOwnPropertyKeys(b)),
|
|
304
|
+
* new Set(["a", "b", "c", "f", "g", symbol_i, symbol_j]),
|
|
305
|
+
* )
|
|
306
|
+
* assertEquals(
|
|
307
|
+
* new Set(getOwnPropertyKeys(Object.getPrototypeOf(b))),
|
|
308
|
+
* new Set(["constructor", "e", "g"]),
|
|
309
|
+
* )
|
|
310
|
+
* ```
|
|
311
|
+
*/
|
|
312
|
+
export declare const getOwnPropertyKeys: <T extends object>(obj: T) => (keyof T)[];
|
|
313
|
+
/** get all **inherited** list of keys (string keys and symbol keys) of an object, up till a certain `depth`.
|
|
314
|
+
*
|
|
315
|
+
* directly owned keys will not be returned.
|
|
316
|
+
* for that, you should use the {@link getOwnPropertyKeys} function.
|
|
317
|
+
*
|
|
318
|
+
* the optional `depth` parameter lets you control how deep you'd like to go collecting the inherited keys.
|
|
319
|
+
*
|
|
320
|
+
* @param obj the object whose inherited keys are to be listed.
|
|
321
|
+
* @param depth the inheritance depth until which the function will accumulate keys for.
|
|
322
|
+
* - if an object `A` is provided as the `depth`,
|
|
323
|
+
* then all inherited keys up until `A` is reached in the inheritance chain will be collected, but not including the keys of `A`.
|
|
324
|
+
* - if a number `N` is provided as the `depth`,
|
|
325
|
+
* then the function will collect keys from `N` number of prototypes up the inheritance chain.
|
|
326
|
+
* - a depth of `0` would imply no traversal.
|
|
327
|
+
* - a depth of `1` would only traverse the first direct prototype of `obj` (i.e. `getOwnPropertyKeys(Object.getPrototypeOf(obj))`).
|
|
328
|
+
* @defaultValue `Object.prototype`
|
|
329
|
+
* @returns an array of keys that the object has inherited (string or symbolic keys).
|
|
330
|
+
*
|
|
331
|
+
* @example
|
|
332
|
+
* ```ts
|
|
333
|
+
* import { assertEquals } from "jsr:@std/assert"
|
|
334
|
+
*
|
|
335
|
+
* const
|
|
336
|
+
* symbol_h = Symbol("symbol h"),
|
|
337
|
+
* symbol_i = Symbol("symbol i"),
|
|
338
|
+
* symbol_j = Symbol("symbol j")
|
|
339
|
+
*
|
|
340
|
+
* class A {
|
|
341
|
+
* a = { v: 1 }
|
|
342
|
+
* b = { v: 2 }
|
|
343
|
+
* c: { v: number }
|
|
344
|
+
* d() { return { v: 4 } }
|
|
345
|
+
* e() { return { v: 5 } }
|
|
346
|
+
* f = () => { return { v: 6 } }
|
|
347
|
+
* g: () => ({ v: number })
|
|
348
|
+
* [symbol_h]() { return { v: 8 } }
|
|
349
|
+
* [symbol_i] = () => { return { v: 9 } }
|
|
350
|
+
*
|
|
351
|
+
* constructor() {
|
|
352
|
+
* this.c = { v: 3 }
|
|
353
|
+
* this.g = () => { return { v: 7 } }
|
|
354
|
+
* }
|
|
355
|
+
* }
|
|
356
|
+
*
|
|
357
|
+
* class B extends A {
|
|
358
|
+
* override a = { v: 11 }
|
|
359
|
+
* override e() { return { v: 15 } }
|
|
360
|
+
* //@ts-ignore: typescript does not permit defining a method over the name of an existing property
|
|
361
|
+
* override g() { return { v: 17 } }
|
|
362
|
+
* [symbol_j] = () => { return { v: 20 } }
|
|
363
|
+
*
|
|
364
|
+
* constructor() { super() }
|
|
365
|
+
* }
|
|
366
|
+
*
|
|
367
|
+
* const
|
|
368
|
+
* a = new A(),
|
|
369
|
+
* b = new B()
|
|
370
|
+
*
|
|
371
|
+
* assertEquals(
|
|
372
|
+
* new Set(getInheritedPropertyKeys(a)),
|
|
373
|
+
* new Set(["constructor", "d", "e", symbol_h]),
|
|
374
|
+
* )
|
|
375
|
+
*
|
|
376
|
+
* // below, notice how the inherited keys of `a` equal to its prototype's owned keys.
|
|
377
|
+
* // this is because methods of instances of `A` are defined on the prototype (i.e. properties of the prototype, rather than the instances').
|
|
378
|
+
* assertEquals(
|
|
379
|
+
* new Set(getInheritedPropertyKeys(a)),
|
|
380
|
+
* new Set(getOwnPropertyKeys(A.prototype)),
|
|
381
|
+
* )
|
|
382
|
+
*
|
|
383
|
+
* // also notice that inherited keys of `A.prototype` comes out as empty here,
|
|
384
|
+
* // even though it does techinally inherit members from its own prototype (which is `Object.prototype`).
|
|
385
|
+
* // the reason is that by default, we do not go deeper than `Object.prototype` to look for more keys.
|
|
386
|
+
* // this is because from an end-user's perspective, those keys are not useful.
|
|
387
|
+
* assertEquals(
|
|
388
|
+
* getInheritedPropertyKeys(A.prototype),
|
|
389
|
+
* [],
|
|
390
|
+
* )
|
|
391
|
+
*
|
|
392
|
+
* assertEquals(
|
|
393
|
+
* new Set(getInheritedPropertyKeys(b)),
|
|
394
|
+
* new Set(["constructor", "e", "g", "d", symbol_h]),
|
|
395
|
+
* )
|
|
396
|
+
* assertEquals(
|
|
397
|
+
* new Set(getInheritedPropertyKeys(b)),
|
|
398
|
+
* new Set([
|
|
399
|
+
* ...getOwnPropertyKeys(B.prototype),
|
|
400
|
+
* ...getInheritedPropertyKeys(B.prototype),
|
|
401
|
+
* ]),
|
|
402
|
+
* )
|
|
403
|
+
* assertEquals(
|
|
404
|
+
* new Set(getInheritedPropertyKeys(B.prototype)),
|
|
405
|
+
* new Set(["constructor", "e", "d", symbol_h]),
|
|
406
|
+
* )
|
|
407
|
+
*
|
|
408
|
+
* // testing out various depth
|
|
409
|
+
* assertEquals(
|
|
410
|
+
* new Set(getInheritedPropertyKeys(a, 1)),
|
|
411
|
+
* new Set(getOwnPropertyKeys(A.prototype)),
|
|
412
|
+
* )
|
|
413
|
+
* assertEquals(
|
|
414
|
+
* new Set(getInheritedPropertyKeys(b, 1)),
|
|
415
|
+
* new Set(getOwnPropertyKeys(B.prototype)),
|
|
416
|
+
* )
|
|
417
|
+
* assertEquals(
|
|
418
|
+
* new Set(getInheritedPropertyKeys(b, A.prototype)),
|
|
419
|
+
* new Set(getOwnPropertyKeys(B.prototype)),
|
|
420
|
+
* )
|
|
421
|
+
* assertEquals(
|
|
422
|
+
* new Set(getInheritedPropertyKeys(b, 2)),
|
|
423
|
+
* new Set([
|
|
424
|
+
* ...getOwnPropertyKeys(B.prototype),
|
|
425
|
+
* ...getOwnPropertyKeys(A.prototype),
|
|
426
|
+
* ]),
|
|
427
|
+
* )
|
|
428
|
+
* // below, we collect all inherited keys of `b`, including those that come from `Object.prototype`,
|
|
429
|
+
* // which is the base ancestral prototype of all objects.
|
|
430
|
+
* // to do that, we set the `depth` to `null`, which is the prototype of `Object.prototype`.
|
|
431
|
+
* // the test below may fail in new versions of javascript, where
|
|
432
|
+
* assertEquals(
|
|
433
|
+
* new Set(getInheritedPropertyKeys(b, null)),
|
|
434
|
+
* new Set([
|
|
435
|
+
* "constructor", "e", "g", "d", symbol_h,
|
|
436
|
+
* "__defineGetter__", "__defineSetter__", "hasOwnProperty", "__lookupGetter__", "__lookupSetter__",
|
|
437
|
+
* "isPrototypeOf", "propertyIsEnumerable", "toString", "valueOf", "toLocaleString",
|
|
438
|
+
* ]),
|
|
439
|
+
* )
|
|
440
|
+
* ```
|
|
441
|
+
*/
|
|
442
|
+
export declare const getInheritedPropertyKeys: <T extends object>(obj: T, depth?: (number | Object | null)) => (keyof T)[];
|
|
443
|
+
/** get all **owned** getter property keys of an object `obj` (string keys and symbol keys).
|
|
444
|
+
*
|
|
445
|
+
* TODO: in the future, consider creating a `getInheritedGetterKeys` function with the same signature as `getInheritedPropertyKeys`.
|
|
446
|
+
*
|
|
447
|
+
* > [!note]
|
|
448
|
+
* > inherited getter property keys will not be included.
|
|
449
|
+
* > only directly defined getter property keys (aka owned keys) will be listed.
|
|
450
|
+
*/
|
|
451
|
+
export declare const getOwnGetterKeys: <T extends object>(obj: T) => (keyof T)[];
|
|
452
|
+
/** get all **owned** setter property keys of an object `obj` (string keys and symbol keys).
|
|
453
|
+
*
|
|
454
|
+
* TODO: in the future, consider creating a `getInheritedSetterKeys` function with the same signature as `getInheritedPropertyKeys`.
|
|
455
|
+
*
|
|
456
|
+
* > [!note]
|
|
457
|
+
* > inherited setter property keys will not be included.
|
|
458
|
+
* > only directly defined setter property keys (aka owned keys) will be listed.
|
|
459
|
+
*/
|
|
460
|
+
export declare const getOwnSetterKeys: <T extends object>(obj: T) => (keyof T)[];
|
|
461
|
+
/** a utility type that mirrors a type `T`, in addition to enclosing the object `T` under the composition property key `P`.
|
|
462
|
+
*
|
|
463
|
+
* this utility type is used by the functions {@link mirrorObjectThroughComposition} and {@link subclassThroughComposition}.
|
|
464
|
+
*
|
|
465
|
+
* @example
|
|
466
|
+
* ```ts
|
|
467
|
+
* const obj_a = {
|
|
468
|
+
* hello: "world",
|
|
469
|
+
* goodbye: "earth",
|
|
470
|
+
* answer() { return 42 },
|
|
471
|
+
* }
|
|
472
|
+
*
|
|
473
|
+
* const obj_b = {
|
|
474
|
+
* _super: obj_a, // composing/enclosing `obj_a`
|
|
475
|
+
* ...obj_a, // mirroring the methods and properties of `obj_a`
|
|
476
|
+
* }
|
|
477
|
+
*
|
|
478
|
+
* obj_b satisfies MirrorComposition<typeof obj_a, "_super">
|
|
479
|
+
* ```
|
|
480
|
+
*/
|
|
481
|
+
export type MirrorComposition<T, P extends PropertyKey> = (T & {
|
|
482
|
+
[composition_key in P]: T;
|
|
483
|
+
});
|
|
484
|
+
/** configuration options for the function {@link mirrorObjectThroughComposition}. */
|
|
485
|
+
export interface MirrorObjectThroughCompositionConfig<P extends PropertyKey = string> {
|
|
486
|
+
/** the key to use to access the composed base object. */
|
|
487
|
+
baseKey: P;
|
|
488
|
+
/** specify whether or not the given object's prototype methods and properties should also be mimicked/mirrored.
|
|
489
|
+
*
|
|
490
|
+
* for fine-grained control of _which_ prototypes from the full prototype chain get mimicked, you can provide one of the following configuration objects:
|
|
491
|
+
* - `Array<Object>`: a manually assembled array of prototype objects, starting with immediate prototype of `obj`, and ending with the last ancestral prototype object.
|
|
492
|
+
* - {@link PrototypeChainOfObjectConfig | `PrototypeChainOfObjectConfig`}: a description object for a slice of continuous prototype chain, used by the function {@link prototypeChainOfObject}.
|
|
493
|
+
* - `true`: equivalent to the {@link PrototypeChainOfObjectConfig | prototype slice description} `{ start: 0, end: Object.prototype }`.
|
|
494
|
+
* - `false`: equivalent to the manually assembled prototype chain `[]` (empty array).
|
|
495
|
+
*
|
|
496
|
+
* @defaultValue `true`
|
|
497
|
+
*/
|
|
498
|
+
mirrorPrototype?: boolean | PrototypeChainOfObjectConfig | Array<Object>;
|
|
499
|
+
/** specify additional property keys that should be mirrored.
|
|
500
|
+
*
|
|
501
|
+
* this would be needed in situations where not all property keys of the given `obj` are immediately discoverable via `Object.getOwnPropertyNames` and `Object.getOwnPropertySymbols`.
|
|
502
|
+
* for instance, dynamically assigned property keys, and class-instance bound keys cannot be deduced beforehand.
|
|
503
|
+
* and so, for such cases, you will need to address those non-discoverable keys in this config option, should you wish for them to be mirrored later on.
|
|
504
|
+
*
|
|
505
|
+
* @defaultValue `[]` (empty array)
|
|
506
|
+
*/
|
|
507
|
+
propertyKeys?: Iterable<PropertyKey>;
|
|
508
|
+
/** specify a set of keys that should **not** be mirrored.
|
|
509
|
+
*
|
|
510
|
+
* @defaultValue `[]` (empty array)
|
|
511
|
+
*/
|
|
512
|
+
ignoreKeys?: Iterable<PropertyKey>;
|
|
513
|
+
/** specify an optional existing target object on which the provided `obj` gets mirrored onto.
|
|
514
|
+
*
|
|
515
|
+
* if none is specified, then a new empty object is used as the target.
|
|
516
|
+
* if a target object is provided, then the same object will be returned by the {@link mirrorObjectThroughComposition} function.
|
|
517
|
+
*
|
|
518
|
+
* @defaultValue `{}` (new empty object)
|
|
519
|
+
*/
|
|
520
|
+
target?: object;
|
|
521
|
+
}
|
|
522
|
+
/** create a new object that mirrors that functionality of an existing object `obj`, through composition.
|
|
523
|
+
*
|
|
524
|
+
* @param obj the object that is to be mimicked and composed.
|
|
525
|
+
* @param config control how the mirroring composition should behave.
|
|
526
|
+
* refer to the docs of {@link MirrorObjectThroughCompositionConfig} for more details.
|
|
527
|
+
*
|
|
528
|
+
* @example
|
|
529
|
+
* ```ts
|
|
530
|
+
* import { assertEquals } from "jsr:@std/assert"
|
|
531
|
+
*
|
|
532
|
+
* type TypeofB = Array<number> & { getLength(): number }
|
|
533
|
+
* type TypeofC = TypeofB & { countZeros(): number }
|
|
534
|
+
*
|
|
535
|
+
* const a = Array.prototype
|
|
536
|
+
* const b = {
|
|
537
|
+
* getLength(): number { return this.length }
|
|
538
|
+
* } as TypeofB
|
|
539
|
+
* const c = {
|
|
540
|
+
* countZeros(): number { return [...this].filter((value) => (value === 0)).length }
|
|
541
|
+
* } as TypeofC
|
|
542
|
+
*
|
|
543
|
+
* Object.setPrototypeOf(b, a)
|
|
544
|
+
* Object.setPrototypeOf(c, b)
|
|
545
|
+
*
|
|
546
|
+
* // below, we create an object `d` that mirrors the methods and protperties of `c`, but does not actually inherit it.
|
|
547
|
+
* const d = mirrorObjectThroughComposition(c, {
|
|
548
|
+
* baseKey: "_super",
|
|
549
|
+
* propertyKeys: ["length"],
|
|
550
|
+
* })
|
|
551
|
+
*
|
|
552
|
+
* // notice that `d` does not inherit `c` as its prototype, despite being able to utilize its methods and properties.
|
|
553
|
+
* assertEquals(Object.getPrototypeOf(d), Object.prototype, "`d` does not inherit `c`")
|
|
554
|
+
*
|
|
555
|
+
* d.push(0, 0, 0, 0, 1)
|
|
556
|
+
* assertEquals([...d], [0, 0, 0, 0, 1], "`d` also mirrors symbolic keys (such as iterators)")
|
|
557
|
+
* assertEquals([...c], [0, 0, 0, 0, 1], "mutations made to `d` are applied to `c`")
|
|
558
|
+
* assertEquals(d._super, c, "`c` is accessible via the `baseKey` (\"_super\") property")
|
|
559
|
+
* assertEquals(d.length, 5)
|
|
560
|
+
* assertEquals(c.length, 5)
|
|
561
|
+
* assertEquals(d.getLength(), 5)
|
|
562
|
+
* assertEquals(d.countZeros(), 4)
|
|
563
|
+
* d.splice(0, 3)
|
|
564
|
+
* assertEquals(d.countZeros(), 1)
|
|
565
|
+
* assertEquals(c.countZeros(), 1)
|
|
566
|
+
*
|
|
567
|
+
* // you may even hot-swap the object that is being composed inside of `d`.
|
|
568
|
+
* const e = [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
569
|
+
* Object.setPrototypeOf(e, c)
|
|
570
|
+
* d._super = e as TypeofC
|
|
571
|
+
* assertEquals(d.length, 9)
|
|
572
|
+
* assertEquals(d.getLength(), 9)
|
|
573
|
+
* assertEquals(d.countZeros(), 0)
|
|
574
|
+
*
|
|
575
|
+
* // it is also possible for you to provide an existing `target` object onto which the mirroring should occur.
|
|
576
|
+
* // moreover, you can ignore specific keys which you would like not to be mirrored using the `ignoreKeys` option.
|
|
577
|
+
* class F {
|
|
578
|
+
* methodF() { return "press f for your fallen comrades" }
|
|
579
|
+
* // to stop typescript from complaining, we declare the instance methods and properties that will be mirrored.
|
|
580
|
+
* declare _super: typeof c
|
|
581
|
+
* declare length: number
|
|
582
|
+
* declare getLength: undefined
|
|
583
|
+
* declare countZeros: () => number
|
|
584
|
+
* }
|
|
585
|
+
* mirrorObjectThroughComposition(c, {
|
|
586
|
+
* target: F.prototype,
|
|
587
|
+
* baseKey: "_super",
|
|
588
|
+
* propertyKeys: ["length"],
|
|
589
|
+
* ignoreKeys: ["getLength"],
|
|
590
|
+
* })
|
|
591
|
+
* const f = new F()
|
|
592
|
+
* assertEquals(f instanceof F, true)
|
|
593
|
+
* assertEquals(f._super, c)
|
|
594
|
+
* assertEquals(f.length, 2)
|
|
595
|
+
* assertEquals(f.countZeros(), 1)
|
|
596
|
+
* assertEquals(f.getLength, undefined) // the `getLength` is not mirrored because it was present in the `ignoreKeys` option
|
|
597
|
+
* assertEquals(f.methodF(), "press f for your fallen comrades")
|
|
598
|
+
* ```
|
|
599
|
+
*/
|
|
600
|
+
export declare const mirrorObjectThroughComposition: <T, P extends PropertyKey>(obj: T, config: MirrorObjectThroughCompositionConfig<P>) => MirrorComposition<T, P>;
|
|
601
|
+
/** configuration options for the function {@link subclassThroughComposition}.
|
|
602
|
+
*
|
|
603
|
+
* this configuration effectively specifies the {@link MirrorObjectThroughCompositionConfig} configuration for the `class` and its `instance`s.
|
|
604
|
+
*
|
|
605
|
+
* by default, the following subconfiguration is used for both `class` and `instance`:
|
|
606
|
+
* `{ baseKey: "_super", mirrorPrototype: true, propertyKeys: [] }`
|
|
607
|
+
*
|
|
608
|
+
* - if your class's instances contain properties that are not defined in the prototype (i.e. dynamically assigned properties),
|
|
609
|
+
* then you will need to define them in {@link MirrorObjectThroughCompositionConfig.propertyKeys | `instance.propertyKeys`}.
|
|
610
|
+
* in a similar way, if your class has dynamically assigned static properties, then you'll need to define them in
|
|
611
|
+
* {@link MirrorObjectThroughCompositionConfig.propertyKeys | `class.propertyKeys`} for them to get mirrored.
|
|
612
|
+
*
|
|
613
|
+
* - the `baseKey` option lets you pick the key that is used for accessing the composed base object from the derived subclass.
|
|
614
|
+
* assuming that `class.baseKey = "_super"` and `instance.baseKey = "_super"`, then the generated "subclass" will be able to access the enclosed class in the following way:
|
|
615
|
+
* - inside a static class method: `this._super satisfies typeof cls`
|
|
616
|
+
* - inside an instance method: `this._super satisfies InstanceType<typeof cls>`
|
|
617
|
+
*/
|
|
618
|
+
export interface SubclassThroughCompositionConfig<CLASS_KEY extends PropertyKey = string, INSTANCE_KEY extends PropertyKey = string> {
|
|
619
|
+
class?: Partial<Omit<MirrorObjectThroughCompositionConfig<CLASS_KEY>, "target">>;
|
|
620
|
+
instance?: Partial<Omit<MirrorObjectThroughCompositionConfig<INSTANCE_KEY>, "target">>;
|
|
621
|
+
}
|
|
622
|
+
/** a utility type for the return type of {@link subclassThroughComposition}. */
|
|
623
|
+
export type MirrorCompositionClass<CLS extends ConstructorOf<any, any>, CLASS_KEY extends PropertyKey, INSTANCE_KEY extends PropertyKey> = CLS extends (new (...args: any[]) => infer T) ? MirrorComposition<CLS, CLASS_KEY> & {
|
|
624
|
+
new (...args: any[]): MirrorComposition<T, INSTANCE_KEY>;
|
|
625
|
+
} : MirrorComposition<CLS, CLASS_KEY>;
|
|
626
|
+
/** create a subclass of the given `cls` class through composition rather than ES6 inheritance (aka `extends`).
|
|
627
|
+
* the composed instance resides under the property `this._super`, and all instance methods of the super class are copied/mirrored in the output class.
|
|
628
|
+
*
|
|
629
|
+
* TODO: provide a motivation/justification when compositional-mirroring subclass might be necessary to use instead of ES6 `extends` inheritance.
|
|
630
|
+
*
|
|
631
|
+
* @param cls the class to subclass through composition.
|
|
632
|
+
* @param property_keys specify additional property keys that exist within the instance of the class that need to be mirrored.
|
|
633
|
+
* @returns a class whose instances fully mirror the provided `cls` class's instance, without actually inheriting it.
|
|
634
|
+
*
|
|
635
|
+
* @example
|
|
636
|
+
* ```ts
|
|
637
|
+
* import { assertEquals } from "jsr:@std/assert"
|
|
638
|
+
*
|
|
639
|
+
* class A<T> extends Array<T> { constructor(quantity: number) { super(quantity) } }
|
|
640
|
+
* class B<T> extends subclassThroughComposition(A, {
|
|
641
|
+
* class: {},
|
|
642
|
+
* instance: { propertyKeys: ["length"] },
|
|
643
|
+
* })<T> { }
|
|
644
|
+
*
|
|
645
|
+
* // `B` mirrors the constructor of `A`, as well as provide an additional `"_super"` property to access the enclosed (class which is `A`)
|
|
646
|
+
* B satisfies { new(amount: number): B<any> }
|
|
647
|
+
* B._super satisfies typeof A
|
|
648
|
+
* // the following cannot be satisfied due to `A`'s restrictive constructor: `B satisfies { new(item1: string, item2: string, item3: string): B<string> }`
|
|
649
|
+
* // even though `A`'s super class (`Array`) does permit that kind of constructor signature:
|
|
650
|
+
* Array satisfies { new(item1: string, item2: string, item3: string): Array<string> }
|
|
651
|
+
*
|
|
652
|
+
* const my_array = new B<number>(5)
|
|
653
|
+
*
|
|
654
|
+
* // `my_array` encloses an instance of its "subclass" (which is an instance of class `A`) under the `"_super"` key.
|
|
655
|
+
* assertEquals(my_array instanceof B, true)
|
|
656
|
+
* assertEquals(my_array._super instanceof A, true)
|
|
657
|
+
* my_array._super satisfies A<unknown> // this should have been narrowed to `satisfies A<number>`, but typing class extensions with generics is nearly impossible
|
|
658
|
+
*
|
|
659
|
+
* // `my_array` mirrors the properties and methods of the instances of the "subclass" that it encloses.
|
|
660
|
+
* my_array.fill(1)
|
|
661
|
+
* my_array.push(2)
|
|
662
|
+
* my_array.push(3)
|
|
663
|
+
* assertEquals(my_array.at(-1), 3)
|
|
664
|
+
* assertEquals(my_array._super.at(-1), 3)
|
|
665
|
+
* assertEquals(my_array.length, 7)
|
|
666
|
+
* assertEquals(my_array._super.length, 7)
|
|
667
|
+
*
|
|
668
|
+
* // `my_array` mirrors the symbolic properties and methods as well.
|
|
669
|
+
* assertEquals([...my_array], [1, 1, 1, 1, 1, 2, 3]) // the `Symbol.iterator` method is mirrored successfully
|
|
670
|
+
*
|
|
671
|
+
* // `my_array` when a method that returns `new this.constructor(...)` (such as `Array.prototype.splice`), then an instance of
|
|
672
|
+
* // the enclosed subclass `A` will be created instead of `B` (had we had a regular inheritance via `class B extends A { }`).
|
|
673
|
+
* const
|
|
674
|
+
* splice_of_my_array = my_array.splice(0, 4, 0, 0),
|
|
675
|
+
* slice_of_my_array = my_array.slice(3, 4)
|
|
676
|
+
* assertEquals(splice_of_my_array instanceof A, true)
|
|
677
|
+
* assertEquals(slice_of_my_array instanceof A, true)
|
|
678
|
+
* assertEquals([...splice_of_my_array], [1, 1, 1, 1])
|
|
679
|
+
* assertEquals([...slice_of_my_array], [2])
|
|
680
|
+
* assertEquals([...my_array], [0, 0, 1, 2, 3])
|
|
681
|
+
* assertEquals([...my_array._super], [0, 0, 1, 2, 3])
|
|
682
|
+
*
|
|
683
|
+
* // the class `B` also mirrors static properties and static methods of `A` (and its inherited ones).
|
|
684
|
+
* // this means that any static method that creates a new instance via `new this(...)` will create an instance of `A` instead of `B`.
|
|
685
|
+
* const
|
|
686
|
+
* new_array_1 = B.from(["hello", "world"]),
|
|
687
|
+
* new_array_2 = B.of("goodbye", "world")
|
|
688
|
+
* assertEquals(new_array_1 instanceof A, true)
|
|
689
|
+
* assertEquals(new_array_2 instanceof A, true)
|
|
690
|
+
* assertEquals(new_array_1, A.from(["hello", "world"]))
|
|
691
|
+
* assertEquals(new_array_2, A.of("goodbye", "world"))
|
|
692
|
+
* ```
|
|
693
|
+
*/
|
|
694
|
+
export declare const subclassThroughComposition: <CLS extends ConstructorOf<any, any>, CLASS_KEY extends PropertyKey = "_super", INSTANCE_KEY extends PropertyKey = "_super">(cls: CLS, config?: SubclassThroughCompositionConfig<CLASS_KEY, INSTANCE_KEY>) => MirrorCompositionClass<CLS, CLASS_KEY, INSTANCE_KEY>;
|
|
695
|
+
/** monkey patch the prototype of a class.
|
|
696
|
+
*
|
|
697
|
+
* TODO: give usage examples and situations where this will be useful.
|
|
698
|
+
*/
|
|
699
|
+
export declare const monkeyPatchPrototypeOfClass: <T, Args extends any[] = any[]>(cls: ConstructorOf<T, Args>, key: keyof T, value: T[typeof key]) => void;
|
|
700
|
+
/** type definition of a primitive javascript object. */
|
|
701
|
+
export type PrimitiveObject = string | number | bigint | boolean | symbol | undefined;
|
|
702
|
+
/** type definition of a non-primitive javascript object. */
|
|
703
|
+
export type ComplexObject = object | Function;
|
|
704
|
+
/** check if `obj` is either an object or function. */
|
|
705
|
+
export declare const isComplex: (obj: any) => obj is ComplexObject;
|
|
706
|
+
/** check if `obj` is neither an object nor a function. */
|
|
707
|
+
export declare const isPrimitive: (obj: any) => obj is PrimitiveObject;
|
|
708
|
+
/** check if `obj` is a `function`.
|
|
709
|
+
*
|
|
710
|
+
* TODO: consider if it would be a good idea to include a generic parameter for the function's signature.
|
|
711
|
+
* i.e.: `<FN extends Function = Function>(obj: any): obj is FN`
|
|
712
|
+
*/
|
|
713
|
+
export declare const isFunction: (obj: any) => obj is Function;
|
|
714
|
+
/** check if `obj` is an `Object`. */
|
|
715
|
+
export declare const isObject: <T extends object = object>(obj: any) => obj is T;
|
|
716
|
+
/** check if `obj` is an `Array`. */
|
|
717
|
+
export declare const isArray: (<T = any>(obj: any) => obj is Array<T>);
|
|
718
|
+
/** check if `obj` is a `Record`, which is any non-nullable object that isn't an array;
|
|
719
|
+
* kind of like a dictionary.
|
|
720
|
+
*/
|
|
721
|
+
export declare const isRecord: <R extends Record<any, any> = any>(obj: any) => obj is R;
|
|
722
|
+
/** check if `obj` is a `string`. */
|
|
723
|
+
export declare const isString: (obj: any) => obj is string;
|
|
724
|
+
/** check if `obj` is a `number`. */
|
|
725
|
+
export declare const isNumber: (obj: any) => obj is number;
|
|
726
|
+
/** check if `obj` is a `bigint`. */
|
|
727
|
+
export declare const isBigint: (obj: any) => obj is bigint;
|
|
728
|
+
/** check if `obj` is either a `number` or a `bigint`. */
|
|
729
|
+
export declare const isNumeric: (obj: any) => obj is (number | bigint);
|
|
730
|
+
/** check if `obj` is `boolean`. */
|
|
731
|
+
export declare const isBoolean: (obj: any) => obj is boolean;
|
|
732
|
+
/** check if `obj` is a `symbol`. */
|
|
733
|
+
export declare const isSymbol: (obj: any) => obj is symbol;
|
|
734
|
+
//# sourceMappingURL=struct.d.ts.map
|