mnemonica 0.9.99778 → 0.9.99780
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +622 -828
- package/build/api/errors/exceptionConstructor.d.ts +1 -1
- package/build/api/errors/exceptionConstructor.js +1 -1
- package/build/api/errors/index.js +1 -1
- package/build/api/errors/throwModificationError.d.ts +20 -1
- package/build/api/errors/throwModificationError.js +1 -1
- package/build/api/index.d.ts +2 -2
- package/build/api/types/InstanceCreator.d.ts +26 -5
- package/build/api/types/InstanceCreator.js +1 -1
- package/build/api/types/InstanceModificator.js +1 -1
- package/build/api/types/Mnemosyne.d.ts +23 -7
- package/build/api/types/Mnemosyne.js +1 -1
- package/build/api/types/Props.d.ts +4 -40
- package/build/api/types/Props.js +1 -1
- package/build/api/types/TypeProxy.d.ts +22 -2
- package/build/api/types/TypeProxy.js +5 -5
- package/build/api/types/compileNewModificatorFunctionBody.d.ts +1 -1
- package/build/api/types/compileNewModificatorFunctionBody.js +1 -1
- package/build/api/types/index.d.ts +3 -2
- package/build/api/types/index.js +12 -7
- package/build/api/utils/index.d.ts +2 -2
- package/build/api/utils/index.js +4 -1
- package/build/constants/index.d.ts +1 -1
- package/build/constants/index.js +1 -1
- package/build/descriptors/errors/index.d.ts +2 -1
- package/build/descriptors/errors/index.js +3 -3
- package/build/descriptors/index.d.ts +3 -3
- package/build/descriptors/types/index.d.ts +2 -2
- package/build/descriptors/types/index.js +7 -6
- package/build/index.d.ts +14 -18
- package/build/index.js +21 -16
- package/build/types/index.d.ts +141 -29
- package/build/types/index.js +1 -1
- package/build/utils/collectConstructors.js +1 -1
- package/build/utils/extract.d.ts +2 -2
- package/build/utils/extract.js +1 -1
- package/build/utils/index.d.ts +1 -1
- package/build/utils/index.js +1 -1
- package/build/utils/merge.d.ts +1 -1
- package/build/utils/merge.js +4 -3
- package/build/utils/parent.d.ts +1 -1
- package/build/utils/parent.js +1 -1
- package/build/utils/parse.d.ts +12 -1
- package/build/utils/parse.js +11 -6
- package/build/utils/pick.d.ts +2 -2
- package/build/utils/pick.js +3 -2
- package/build/utils/toJSON.js +1 -1
- package/package.json +19 -19
package/README.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
# mnemonica
|
|
2
|
-
|
|
1
|
+
# mnemonica
|
|
2
|
+
|
|
3
|
+
**Abstract technique that aids information retention: Instance Inheritance System**
|
|
3
4
|
|
|
4
5
|
... allows us to make inherited descriptions of mappings of transformations from predecessor structured data types to the successors, as if it was math `f(x)=>y` ... and we will use `this` keyword as a persistent data structure where we will apply that transformations
|
|
5
6
|
|
|
@@ -10,865 +11,481 @@ abstract technique that aids information retention : instance inheritance system
|
|
|
10
11
|
|
|
11
12
|
# shortcuts
|
|
12
13
|
|
|
14
|
+
* ?. : state : **mad science**
|
|
13
15
|
* ?. : type : **asynchronous monad descriptor** => this
|
|
14
16
|
* ?. : prod ready : **we wonder about**
|
|
15
17
|
* ?. : example : **git clone && npm run example**
|
|
16
18
|
|
|
17
19
|
---
|
|
18
|
-
|
|
19
20
|
[](https://coveralls.io/github/wentout/mnemonica?branch=master)
|
|
20
|
-
|
|
21
21
|

|
|
22
22
|

|
|
23
23
|

|
|
24
|
-
|
|
25
24
|
[](https://www.npmjs.com/package/mnemonica)
|
|
26
25
|
|
|
27
26
|
---
|
|
28
27
|
|
|
28
|
+
## Table of Contents
|
|
29
|
+
|
|
30
|
+
- [Overview](#overview)
|
|
31
|
+
- [Installation](#installation)
|
|
32
|
+
- [Quick Start](#quick-start)
|
|
33
|
+
- [Core Concepts](#core-concepts)
|
|
34
|
+
- [TypeScript Support](#typescript-support)
|
|
35
|
+
- [API Reference](#api-reference)
|
|
36
|
+
- [Core Functions](#core-functions)
|
|
37
|
+
- [Type Reference](#type-reference)
|
|
38
|
+
- [Type Management](#type-management)
|
|
39
|
+
- [Instance Methods](#instance-methods)
|
|
40
|
+
- [Utilities](#utilities)
|
|
41
|
+
- [Hooks](#hooks)
|
|
42
|
+
- [Error Handling](#error-handling)
|
|
43
|
+
- [Symbols & Constants](#symbols--constants)
|
|
44
|
+
- [Configuration Options](#configuration-options)
|
|
45
|
+
- [AI Agent Usage Guide](#ai-agent-usage-guide)
|
|
46
|
+
- [Examples](#examples)
|
|
29
47
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
This lib might help to create some sort of order or sequence or precedence of how we modify data inside of our code. It utilizes the concept of tree or [Trie](https://en.wikipedia.org/wiki/Trie) by combining both: Object Instances and Inheritance through the Prototype Chain, where we are able to create new instance inherited from existing one as much times as we need. It might look like obvious, but ... we tell about Instances, not about Classes, meaning Plain Objects, crafted from real Constructors before we start the process of inheriting them one from another. In an attempt to describe this approach let me suggest this articles:
|
|
33
|
-
|
|
34
|
-
* [Inheritance in JavaScript : Factory of Constructors with Prototype Chain](https://github.com/mythographica/stash/blob/master/inheritance.md)
|
|
35
|
-
* [Architecture of Prototype Inheritance in JavaScript](https://dev.to/wentout/architecture-of-prototype-inheritance-in-javascript-ce6)
|
|
36
|
-
* [Dead Simple type checker for JavaScript](https://dev.to/wentout/dead-simple-type-checker-for-javascript-4l40)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
## TypeScript note
|
|
48
|
+
---
|
|
40
49
|
|
|
41
|
-
|
|
50
|
+
## Overview
|
|
42
51
|
|
|
43
|
-
|
|
52
|
+
Mnemonica helps create ordered sequences of data transformations using prototype chain inheritance. It combines Object Instances with Inheritance through the Prototype Chain, enabling you to create new instances inherited from existing ones.
|
|
44
53
|
|
|
54
|
+
Think of it as a mathematical function `f(x) => y` where `this` is your persistent data structure and transformations are applied sequentially.
|
|
45
55
|
|
|
46
|
-
|
|
56
|
+
> *"O Great Mnemosyne! Please! Save us from Oblivion..."*
|
|
57
|
+
>
|
|
58
|
+
> — from the source, where memory persists
|
|
47
59
|
|
|
48
|
-
|
|
60
|
+
**Key Features:**
|
|
61
|
+
- Factory of Constructors with Prototype Chain Inheritance
|
|
62
|
+
- Instance-level inheritance (not just class-level)
|
|
63
|
+
- Async constructor support with chainable awaits
|
|
64
|
+
- Type-safe data flow definition
|
|
65
|
+
- Comprehensive hook system for lifecycle events
|
|
49
66
|
|
|
50
|
-
|
|
51
|
-
|
|
67
|
+
**Related Reading:**
|
|
68
|
+
- [Inheritance in JavaScript: Factory of Constructors with Prototype Chain](https://github.com/mythographica/stash/blob/master/inheritance.md)
|
|
69
|
+
- [Architecture of Prototype Inheritance in JavaScript](https://dev.to/wentout/architecture-of-prototype-inheritance-in-javascript-ce6)
|
|
70
|
+
- [Dead Simple type checker for JavaScript](https://dev.to/wentout/dead-simple-type-checker-for-javascript-4l40)
|
|
52
71
|
|
|
53
|
-
|
|
54
|
-
Object.assign(this, opts);
|
|
55
|
-
};
|
|
72
|
+
---
|
|
56
73
|
|
|
57
|
-
|
|
58
|
-
const SomeType = define('SomeTypeConstructor',
|
|
59
|
-
TypeModificationProcedure,
|
|
60
|
-
);
|
|
74
|
+
## Installation
|
|
61
75
|
|
|
76
|
+
```bash
|
|
77
|
+
npm install mnemonica
|
|
62
78
|
```
|
|
63
79
|
|
|
64
|
-
|
|
80
|
+
**Requirements:** Node.js >=16 <24
|
|
65
81
|
|
|
66
|
-
|
|
67
|
-
const TypeModificationConstructorFactory = () => {
|
|
68
|
-
// SomeTypeConstructor -- is a constructor.name
|
|
69
|
-
const SomeTypeConstructor = function (opts) {
|
|
70
|
-
// as this is absolutely the same behaviour
|
|
71
|
-
// we described upper
|
|
72
|
-
// in TypeModificationProcedure
|
|
73
|
-
// we allowed to do the following
|
|
74
|
-
// for shortening this example lines
|
|
75
|
-
Object.assign(this, opts);
|
|
76
|
-
};
|
|
77
|
-
// prototype definition is NOT obligatory
|
|
78
|
-
SomeTypeConstructor.prototype
|
|
79
|
-
.description = 'SomeType Constructor';
|
|
80
|
-
|
|
81
|
-
return SomeTypeConstructor;
|
|
82
|
-
};
|
|
82
|
+
---
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
```
|
|
84
|
+
## Quick Start
|
|
86
85
|
|
|
87
|
-
|
|
86
|
+
### CommonJS
|
|
88
87
|
|
|
89
88
|
```js
|
|
90
|
-
const
|
|
91
|
-
// SomeTypeConstructor -- is a constructor.name
|
|
92
|
-
class SomeTypeConstructor {
|
|
93
|
-
constructor (opts) {
|
|
94
|
-
// all this definitions
|
|
95
|
-
// just to show the example
|
|
96
|
-
// of how it works
|
|
97
|
-
const {
|
|
98
|
-
some,
|
|
99
|
-
data,
|
|
100
|
-
// we will re-define
|
|
101
|
-
// "inside" property later
|
|
102
|
-
// using nested sub-type
|
|
103
|
-
inside
|
|
104
|
-
} = opts;
|
|
105
|
-
this.some = some;
|
|
106
|
-
this.data = data;
|
|
107
|
-
this.inside = inside;
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
return SomeTypeConstructor;
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
const SomeType = define(TypeModificationConstructorFactory);
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
Then we can define some nested type, using our crafted `SomeType` definition:
|
|
89
|
+
const { define } = require('mnemonica');
|
|
117
90
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
other,
|
|
122
|
-
inside // again
|
|
123
|
-
} = opts;
|
|
124
|
-
this.other = other;
|
|
125
|
-
// here we will re-define
|
|
126
|
-
// our previously defined property
|
|
127
|
-
// with the new value
|
|
128
|
-
this.inside = inside;
|
|
129
|
-
}, {
|
|
130
|
-
description : 'SomeSubType Constructor'
|
|
91
|
+
// Define a type
|
|
92
|
+
const UserType = define('UserType', function (data) {
|
|
93
|
+
Object.assign(this, data);
|
|
131
94
|
});
|
|
132
95
|
|
|
133
|
-
//
|
|
134
|
-
|
|
135
|
-
const {
|
|
136
|
-
other,
|
|
137
|
-
inside // again
|
|
138
|
-
} = opts;
|
|
139
|
-
this.other = other;
|
|
140
|
-
// here we will re-define
|
|
141
|
-
// our previously defined property
|
|
142
|
-
// with the new value
|
|
143
|
-
this.inside = inside;
|
|
144
|
-
};
|
|
145
|
-
SomeType.SomeSubType.prototype = {
|
|
146
|
-
description : 'SomeSubType Constructor'
|
|
147
|
-
};
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
Now our type modification chain looks like this:
|
|
151
|
-
|
|
152
|
-
```js
|
|
153
|
-
// 1.
|
|
154
|
-
SomeType
|
|
155
|
-
// 1.1
|
|
156
|
-
.SomeSubType;
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
And we can continue nesting sub-types as far as it might be necessary for our code and our software architecture... :^)
|
|
160
|
-
|
|
161
|
-
## **How it Works then**
|
|
96
|
+
// Create an instance
|
|
97
|
+
const user = new UserType({ name: 'John', email: 'john@example.com' });
|
|
162
98
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
const someTypeInstance = new SomeType({
|
|
167
|
-
some : 'arguments',
|
|
168
|
-
data : 'necessary',
|
|
169
|
-
inside : 'of SomeType definition'
|
|
99
|
+
// Define a subtype
|
|
100
|
+
const AdminType = UserType.define('AdminType', function () {
|
|
101
|
+
this.role = 'admin';
|
|
170
102
|
});
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
Then, there might be situation, when we reached the place in code, where we have to use the next, nested -- `SomeSubType` -- constructor, to apply our `someTypeInstance` to the next one Inherited and **`Sub-Type'd`** Instance.
|
|
174
|
-
|
|
175
|
-
```js
|
|
176
|
-
|
|
177
|
-
const someSubTypeInstance =
|
|
178
|
-
// someTypeInstance is an instance
|
|
179
|
-
// we did before, through the referenced
|
|
180
|
-
// SomeType constructor we made using
|
|
181
|
-
// define at the first step
|
|
182
|
-
// of this fabulous adventure
|
|
183
|
-
someTypeInstance
|
|
184
|
-
// we defined SomeSubType
|
|
185
|
-
// as a nested constructor
|
|
186
|
-
// so we have to use it
|
|
187
|
-
// utilising instance
|
|
188
|
-
// crafted from it's parent
|
|
189
|
-
.SomeSubType({
|
|
190
|
-
other : 'data needed',
|
|
191
|
-
// and this is -re-definition
|
|
192
|
-
// of "inside" property
|
|
193
|
-
// as we promised before
|
|
194
|
-
inside : ' of ... etc ...'
|
|
195
|
-
});
|
|
196
103
|
|
|
104
|
+
// Create nested instance (inherits from user)
|
|
105
|
+
const admin = new user.AdminType();
|
|
106
|
+
console.log(admin.name); // 'John' (inherited)
|
|
107
|
+
console.log(admin.role); // 'admin' (own property)
|
|
197
108
|
```
|
|
198
109
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
And now let's ponder on our Instances:
|
|
110
|
+
### ESM
|
|
203
111
|
|
|
204
112
|
```js
|
|
205
|
-
|
|
206
|
-
console.log(someTypeInstance);
|
|
207
|
-
|
|
208
|
-
some : 'arguments'
|
|
209
|
-
data : 'necessary'
|
|
210
|
-
inside : 'of SomeType definition'
|
|
211
|
-
|
|
212
|
-
console.log(someSubTypeInstance);
|
|
213
|
-
|
|
214
|
-
other : 'data needed'
|
|
215
|
-
inside : ' of ... etc ...'
|
|
216
|
-
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
So, here it might be looking miscouraging... but this is not the end of the story, cause we have the magic of **built-in** ...
|
|
220
|
-
|
|
221
|
-
# .extract()
|
|
222
|
-
|
|
223
|
-
So, here is a situation we need all previously defined props and all the nested props collected to the one-same object:
|
|
224
|
-
|
|
225
|
-
```js
|
|
226
|
-
|
|
227
|
-
const extracted = someSubTypeInstance.extract();
|
|
228
|
-
|
|
229
|
-
console.log(extracted);
|
|
230
|
-
|
|
231
|
-
data : "necessary"
|
|
232
|
-
description : "SomeSubType Constructor"
|
|
233
|
-
inside : " of ... etc ..."
|
|
234
|
-
other : "data needed"
|
|
235
|
-
some : "arguments"
|
|
236
|
-
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
or, with the same behaviour:
|
|
240
|
-
|
|
241
|
-
```js
|
|
242
|
-
const { extract } = require('mnemonica').utils;
|
|
243
|
-
const extracted = extract(someSubTypeInstance);
|
|
244
|
-
|
|
245
|
-
data : "necessary"
|
|
246
|
-
description : "SomeSubType Constructor"
|
|
247
|
-
inside : " of ... etc ..."
|
|
248
|
-
other : "data needed"
|
|
249
|
-
some : "arguments"
|
|
250
|
-
|
|
251
|
-
console.log(extract(someTypeInstance));
|
|
252
|
-
|
|
253
|
-
data : "necessary"
|
|
254
|
-
description : "SomeType Constructor"
|
|
255
|
-
inside : "of SomeType definition"
|
|
256
|
-
some : "arguments"
|
|
257
|
-
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
Here `extracted` object will contain all iterable props of `someSubTypeInstance`. It means props are accessible via `Symbol.iterator`. So if you will define some hidden props, it will not consume them. This technique allows us acheive concentration only on meaningfull parts of [Data Flow Definition](https://en.wikipedia.org/wiki/Data-flow_diagram). So, all this might help to cover the gap between declared data flow and indeed flow written in code through describing flow itself with that simple way. For sure you are free to make your own `.extractor()` functions on the top of acheived multiplie inherited data object (storage):
|
|
261
|
-
|
|
262
|
-

|
|
263
|
-
|
|
264
|
-
And back to definitions, for sure, all of the following is true:
|
|
265
|
-
|
|
266
|
-
```js
|
|
267
|
-
|
|
268
|
-
console.log(someTypeInstance instanceof SomeType); // true
|
|
269
|
-
console.log(someSubTypeInstance instanceof SomeType); // true
|
|
270
|
-
console.log(someSubTypeInstance instanceof SomeSubType); // true
|
|
271
|
-
// who there can care... but, yes, it is again: true
|
|
272
|
-
console.log(someSubTypeInstance instanceof someTypeInstance);
|
|
273
|
-
|
|
113
|
+
import { define, lookup } from 'mnemonica/module';
|
|
274
114
|
```
|
|
275
115
|
|
|
276
|
-
|
|
116
|
+
---
|
|
277
117
|
|
|
278
|
-
##
|
|
118
|
+
## Core Concepts
|
|
279
119
|
|
|
280
|
-
|
|
120
|
+
### Factory of Constructors
|
|
281
121
|
|
|
282
|
-
|
|
122
|
+
Define types using constructors, factory functions, or classes:
|
|
283
123
|
|
|
284
124
|
```js
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
125
|
+
// Using a constructor function
|
|
126
|
+
const SomeType = define('SomeType', function (opts) {
|
|
127
|
+
Object.assign(this, opts);
|
|
128
|
+
});
|
|
289
129
|
|
|
290
|
-
|
|
130
|
+
// Using a factory function
|
|
131
|
+
const AnotherType = define(() => {
|
|
132
|
+
const AnotherTypeConstructor = function (opts) {
|
|
133
|
+
Object.assign(this, opts);
|
|
134
|
+
};
|
|
135
|
+
AnotherTypeConstructor.prototype.description = 'SomeType Constructor';
|
|
136
|
+
return AnotherTypeConstructor;
|
|
137
|
+
});
|
|
291
138
|
|
|
292
|
-
|
|
293
|
-
(
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
139
|
+
// Using a class
|
|
140
|
+
const ClassType = define(() => {
|
|
141
|
+
class MyClass {
|
|
142
|
+
constructor(opts) {
|
|
143
|
+
Object.assign(this, opts);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return MyClass;
|
|
147
|
+
});
|
|
297
148
|
```
|
|
298
149
|
|
|
299
|
-
|
|
150
|
+
### Nested Type Definition
|
|
300
151
|
|
|
301
152
|
```js
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
Here we might choose what to do: inspect some collected data or probably we wish to extract it for **tests** or **log** or even grab them with the other consumer. And yes, we already saw `.extract()` method, but there are also two other methods could be much more helpfull...
|
|
310
|
-
|
|
311
|
-
# Pre & Post creation Hooks
|
|
153
|
+
// Define nested types
|
|
154
|
+
SomeType.define('SubType', function (opts) {
|
|
155
|
+
this.other = opts.other;
|
|
156
|
+
}, {
|
|
157
|
+
description: 'SomeSubType Constructor'
|
|
158
|
+
});
|
|
312
159
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
const preCreationCallback = (hookData) => {
|
|
317
|
-
const {
|
|
318
|
-
|
|
319
|
-
// { string }
|
|
320
|
-
TypeName : TypeModificatorConstructor.name,
|
|
321
|
-
|
|
322
|
-
// 1. [ array ]
|
|
323
|
-
// ...args of TypeModificator
|
|
324
|
-
// for instance creation
|
|
325
|
-
argumentsOfTypeModificator,
|
|
326
|
-
|
|
327
|
-
// 2. { object }
|
|
328
|
-
// instance we will craft from
|
|
329
|
-
// using our TypeModificator
|
|
330
|
-
instanceUsedForInheritance
|
|
331
|
-
|
|
332
|
-
} = hookData;
|
|
333
|
-
// some necessary pre-investigations
|
|
160
|
+
// Or using assignment
|
|
161
|
+
SomeType.SubType = function (opts) {
|
|
162
|
+
this.other = opts.other;
|
|
334
163
|
};
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
.registerHook(
|
|
338
|
-
'preCreation',
|
|
339
|
-
preCreationCallback);
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
const postCreationCallback = (hookData) => {
|
|
343
|
-
const {
|
|
344
|
-
// { string }
|
|
345
|
-
TypeName : TypeModificatorConstructor.name,
|
|
346
|
-
|
|
347
|
-
// 1. [ array ]
|
|
348
|
-
argumentsOfTypeModificator,
|
|
349
|
-
|
|
350
|
-
// 2. { object }
|
|
351
|
-
instanceUsedForInheritance,
|
|
352
|
-
|
|
353
|
-
// 3. { object }
|
|
354
|
-
// instance we just crafted
|
|
355
|
-
// from instanceUsedForInheritance
|
|
356
|
-
// using our TypeModificator
|
|
357
|
-
// with argumentsOfTypeModificator
|
|
358
|
-
// and ... inheritedInstance
|
|
359
|
-
// .constructor.name is
|
|
360
|
-
// TypeName
|
|
361
|
-
inheritedInstance
|
|
362
|
-
|
|
363
|
-
} = hookData;
|
|
364
|
-
// some necessary post-investigations
|
|
164
|
+
SomeType.SubType.prototype = {
|
|
165
|
+
description: 'SomeSubType Constructor'
|
|
365
166
|
};
|
|
366
|
-
|
|
367
|
-
// callback will be called After requestInstance creation
|
|
368
|
-
RequestDataTypeModificator
|
|
369
|
-
.registerHook(
|
|
370
|
-
'postCreation',
|
|
371
|
-
postCreationCallback);
|
|
372
167
|
```
|
|
373
168
|
|
|
374
|
-
|
|
169
|
+
### Instance Creation and Inheritance
|
|
375
170
|
|
|
376
171
|
```js
|
|
172
|
+
const someInstance = new SomeType({
|
|
173
|
+
some: 'arguments',
|
|
174
|
+
data: 'necessary'
|
|
175
|
+
});
|
|
377
176
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
GoneToTheDataBase
|
|
383
|
-
.registerHook(
|
|
384
|
-
'postCreation', // ...
|
|
385
|
-
|
|
177
|
+
const subInstance = new someInstance.SubType({
|
|
178
|
+
other: 'data needed'
|
|
179
|
+
});
|
|
386
180
|
|
|
181
|
+
// All properties are inherited
|
|
182
|
+
console.log(subInstance.some); // 'arguments' (inherited)
|
|
183
|
+
console.log(subInstance.other); // 'data needed' (own)
|
|
387
184
|
```
|
|
388
185
|
|
|
186
|
+
### The `.extract()` Method
|
|
389
187
|
|
|
390
|
-
|
|
391
|
-
|
|
188
|
+
Extract all inherited properties into a flat object:
|
|
392
189
|
|
|
393
190
|
```js
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
} = require('mnemonica');
|
|
397
|
-
|
|
398
|
-
defaultTypes
|
|
399
|
-
.registerHook(
|
|
400
|
-
'preCreation', preCreationTypesCollectionCallback);
|
|
401
|
-
|
|
402
|
-
defaultTypes
|
|
403
|
-
.registerHook(
|
|
404
|
-
'postCreation', postCreationTypesCollectionCallback);
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
'Pre' hooks for Types Collections invoked before Type Hook invocation. 'Post' hooks for Types Collections invoked after Type Hook invocation. So, actually it looks like:
|
|
410
|
-
|
|
411
|
-
```js
|
|
412
|
-
|
|
413
|
-
// 1.
|
|
414
|
-
typecollection.invokeHook('preCreation', // ...
|
|
415
|
-
|
|
416
|
-
// 2.
|
|
417
|
-
type.invokeHook('preCreation', // ...
|
|
418
|
-
|
|
419
|
-
// 3. instance creation is here
|
|
420
|
-
|
|
421
|
-
// 4.
|
|
422
|
-
type.invokeHook('postCreation', // ...
|
|
423
|
-
|
|
424
|
-
// 5.
|
|
425
|
-
typecollection.invokeHook('postCreation', // ...
|
|
426
|
-
|
|
191
|
+
const extracted = subInstance.extract();
|
|
192
|
+
// Result: { data, description, other, some }
|
|
427
193
|
|
|
194
|
+
// Or use the standalone utility
|
|
195
|
+
const { utils: { extract } } = require('mnemonica');
|
|
196
|
+
const extracted2 = extract(subInstance);
|
|
428
197
|
```
|
|
429
198
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
# .lookup('TypeName')
|
|
433
|
-
|
|
434
|
-
```js
|
|
435
|
-
const {
|
|
436
|
-
lookup
|
|
437
|
-
} = require('mnemonica');
|
|
199
|
+
---
|
|
438
200
|
|
|
439
|
-
|
|
440
|
-
const SomeNestedType = lookup('SomeType.SomeNestedType');
|
|
201
|
+
## TypeScript Support
|
|
441
202
|
|
|
442
|
-
|
|
203
|
+
The `define` function has full TypeScript support with comprehensive type definitions:
|
|
443
204
|
|
|
444
|
-
|
|
205
|
+
```typescript
|
|
206
|
+
import { define, apply, call, bind } from 'mnemonica';
|
|
445
207
|
|
|
446
|
-
|
|
208
|
+
interface UserData {
|
|
209
|
+
email: string;
|
|
210
|
+
password: string;
|
|
211
|
+
}
|
|
447
212
|
|
|
448
|
-
define('
|
|
449
|
-
|
|
213
|
+
const UserType = define('UserType', function (this: UserData, data: UserData) {
|
|
214
|
+
Object.assign(this, data);
|
|
450
215
|
});
|
|
451
216
|
|
|
452
|
-
//
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
// operators
|
|
456
|
-
});
|
|
217
|
+
// Nested constructors work with apply/call/bind for type inference
|
|
218
|
+
const user = new UserType({ email: 'test@test.com', password: 'secret' });
|
|
219
|
+
```
|
|
457
220
|
|
|
458
|
-
|
|
221
|
+
For complex nested types, use `apply`, `call`, or `bind` for better type inference:
|
|
459
222
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
return class NewType {
|
|
464
|
-
constructor (str) {
|
|
465
|
-
// operators
|
|
466
|
-
}
|
|
467
|
-
};
|
|
223
|
+
```typescript
|
|
224
|
+
const SomeSubType = SomeType.define('SomeSubType', function (...args: string[]) {
|
|
225
|
+
// ...
|
|
468
226
|
});
|
|
469
227
|
|
|
228
|
+
const someInstance = new SomeType();
|
|
229
|
+
const subInstance = call(someInstance, SomeSubType, 'arg1', 'arg2');
|
|
470
230
|
```
|
|
471
231
|
|
|
472
|
-
|
|
232
|
+
### Exported Type Definitions
|
|
473
233
|
|
|
474
|
-
|
|
234
|
+
The following types are available for advanced TypeScript usage:
|
|
475
235
|
|
|
476
|
-
```
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
236
|
+
```typescript
|
|
237
|
+
import {
|
|
238
|
+
// Core constructor types
|
|
239
|
+
IDEF, // Base constructor function type: { new(): T } | { (this: T, ...args): void }
|
|
240
|
+
ConstructorFunction, // Constructor with prototype
|
|
241
|
+
Constructor, // Generic constructor type
|
|
242
|
+
|
|
243
|
+
// Instance types
|
|
244
|
+
MnemonicaInstance, // Instance methods interface (extract, pick, parent, fork, etc.)
|
|
245
|
+
Props, // Internal instance properties (__type__, __args__, __parent__, etc.)
|
|
246
|
+
SiblingAccessor, // Sibling type accessor type
|
|
247
|
+
|
|
248
|
+
// Type definition types
|
|
249
|
+
TypeClass, // Base type constructor returned by define()
|
|
250
|
+
IDefinitorInstance, // Definitor instance with define/lookup methods and subtypes
|
|
251
|
+
DecoratedClass, // Type for @decorate decorated classes
|
|
252
|
+
TypeDef, // Type definition object structure
|
|
253
|
+
|
|
254
|
+
// Configuration types
|
|
255
|
+
constructorOptions, // Type config options (strictChain, blockErrors, etc.)
|
|
256
|
+
hooksTypes, // 'preCreation' | 'postCreation' | 'creationError'
|
|
257
|
+
hook, // Hook callback type
|
|
258
|
+
hooksOpts, // Hook options passed to callbacks
|
|
259
|
+
CollectionDef, // Types collection definition
|
|
260
|
+
|
|
261
|
+
// Utility function types
|
|
262
|
+
ApplyFunction, // apply(entity, Ctor, args) => S
|
|
263
|
+
CallFunction, // call(entity, Ctor, ...args) => S
|
|
264
|
+
BindFunction, // bind(entity, Ctor) => (...args) => S
|
|
265
|
+
} from 'mnemonica';
|
|
483
266
|
```
|
|
484
267
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
```js
|
|
488
|
-
|
|
489
|
-
// fisrst parent
|
|
490
|
-
// simply equal to getProps(instance).__parent__
|
|
491
|
-
const parent = instance.parent();
|
|
492
|
-
|
|
493
|
-
// deep parent from chain
|
|
494
|
-
const parent = instance
|
|
495
|
-
.parent( 'DeepParentName' );
|
|
268
|
+
### Generic Type Patterns
|
|
496
269
|
|
|
497
|
-
|
|
270
|
+
Define types with proper generic constraints for full type safety:
|
|
498
271
|
|
|
272
|
+
```typescript
|
|
273
|
+
// Using IDEF with interface definitions
|
|
274
|
+
interface UserData {
|
|
275
|
+
email: string;
|
|
276
|
+
password: string;
|
|
277
|
+
}
|
|
499
278
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
```js
|
|
504
|
-
const usingProcessAsProto = Singletoned.call(process, {
|
|
505
|
-
some : 'arguments',
|
|
506
|
-
data : 'necessary',
|
|
507
|
-
inside : 'for definition'
|
|
279
|
+
// Type-safe constructor with 'this' context
|
|
280
|
+
const UserType = define('UserType', function (this: UserData, data: UserData) {
|
|
281
|
+
Object.assign(this, data);
|
|
508
282
|
});
|
|
509
|
-
console.log(typeof instanceUsingProcessSingletone.on) // function
|
|
510
|
-
```
|
|
511
|
-
|
|
512
|
-
or you can combine with window, or document or...
|
|
513
|
-
|
|
514
|
-
```js
|
|
515
|
-
|
|
516
|
-
const usingWindowAsProto = Windowed.call(window);
|
|
517
|
-
const usingDocumentAsProto = Documented.call(document);
|
|
518
|
-
const usingJQueryAsProto = JQueried.call(jQuery);
|
|
519
|
-
|
|
520
|
-
// or even ReactDOM
|
|
521
|
-
import ReactDOM from "react-dom";
|
|
522
|
-
import { define } from "mnemonica";
|
|
523
|
-
const ReactDOOMed = define("ReactDOOMed", function() {});
|
|
524
|
-
const usingReactAsProto = ReactDOOMed.call(ReactDOM);
|
|
525
283
|
|
|
526
|
-
|
|
527
|
-
|
|
284
|
+
// Type-safe nested types with merged interfaces
|
|
285
|
+
interface AdminData {
|
|
286
|
+
role: string;
|
|
287
|
+
}
|
|
528
288
|
|
|
289
|
+
const AdminType = UserType.define('AdminType', function (this: UserData & AdminData, role: string) {
|
|
290
|
+
this.role = role;
|
|
291
|
+
this.email; // string - inherited from UserData
|
|
292
|
+
});
|
|
529
293
|
```
|
|
530
294
|
|
|
295
|
+
### Async Constructor Type Patterns
|
|
531
296
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
const SomeType = define('SomeType', function () {
|
|
538
|
-
// ...
|
|
297
|
+
```typescript
|
|
298
|
+
// Async type with proper return type
|
|
299
|
+
const AsyncType = define('AsyncType', async function (this: UserData, data: string) {
|
|
300
|
+
await someAsyncOperation();
|
|
301
|
+
return Object.assign(this, { data });
|
|
539
302
|
});
|
|
540
303
|
|
|
304
|
+
// With explicit awaitReturn option (no return required)
|
|
305
|
+
const AsyncTypeNoReturn = define('AsyncType', async function () {
|
|
306
|
+
// No return needed
|
|
307
|
+
}, { awaitReturn: false });
|
|
308
|
+
```
|
|
541
309
|
|
|
542
|
-
|
|
543
|
-
.define('SomeSubType', function (...args) {
|
|
544
|
-
// ...
|
|
545
|
-
});
|
|
546
|
-
|
|
547
|
-
const someInstance = new SomeType;
|
|
548
|
-
|
|
549
|
-
const someSubInstance = call(
|
|
550
|
-
someInstance, SomeSubType, ...args);
|
|
551
|
-
|
|
552
|
-
// or for array of args
|
|
553
|
-
const someSubInstance = apply(
|
|
554
|
-
someInstance, SomeSubType, args);
|
|
310
|
+
---
|
|
555
311
|
|
|
556
|
-
|
|
557
|
-
const someSubInstanceConstructor =
|
|
558
|
-
bind( someInstance, SomeSubType );
|
|
312
|
+
## API Reference
|
|
559
313
|
|
|
560
|
-
|
|
314
|
+
### Core Functions
|
|
561
315
|
|
|
562
|
-
|
|
316
|
+
#### `define(typeName, constructHandler, config?)`
|
|
563
317
|
|
|
564
|
-
|
|
565
|
-
First of all you should understand what you wish to are doing!
|
|
566
|
-
Then you should understand what you wish. And only after doing so you might use this technic:
|
|
318
|
+
Defines a new type constructor. Returns a TypeClass.
|
|
567
319
|
|
|
568
320
|
```js
|
|
569
|
-
const
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
321
|
+
const MyType = define('MyType', function (data) {
|
|
322
|
+
Object.assign(this, data);
|
|
323
|
+
}, {
|
|
324
|
+
strictChain: true,
|
|
325
|
+
blockErrors: true
|
|
573
326
|
});
|
|
574
|
-
|
|
575
|
-
const asyncCall = async function () {
|
|
576
|
-
const asyncConstructedInstance = await new AsyncType('tada');
|
|
577
|
-
console.log(asyncConstructedInstance) // { data: "tada" }
|
|
578
|
-
console.log(asyncConstructedInstance instanceof AsyncType) // true
|
|
579
|
-
};
|
|
580
|
-
|
|
581
|
-
asyncCall();
|
|
582
327
|
```
|
|
583
328
|
|
|
584
|
-
|
|
329
|
+
**Parameters:**
|
|
330
|
+
- `typeName` (string): Name of the type (optional if using factory function)
|
|
331
|
+
- `constructHandler` (Function): Constructor function
|
|
332
|
+
- `config` (object, optional): Configuration options
|
|
585
333
|
|
|
586
|
-
|
|
587
|
-
const NestedAsyncType = AsyncType
|
|
588
|
-
.define('NestedAsyncType', async function (data) {
|
|
589
|
-
return Object.assign(this, {
|
|
590
|
-
data
|
|
591
|
-
});
|
|
592
|
-
}, {
|
|
593
|
-
description: 'async of nested'
|
|
594
|
-
});
|
|
595
|
-
|
|
596
|
-
const nestedAsyncTypeInstance = await new
|
|
597
|
-
asyncConstructedInstance.NestedAsyncType('boom');
|
|
598
|
-
|
|
599
|
-
console.log(nestedAsyncTypeInstance instanceof AsyncType) // true
|
|
600
|
-
console.log(nestedAsyncTypeInstance instanceof NestedAsyncType) // true
|
|
601
|
-
console.log(nestedAsyncTypeInstance.description); // 'async of nested'
|
|
602
|
-
```
|
|
334
|
+
#### `lookup(typeNestedPath)`
|
|
603
335
|
|
|
604
|
-
|
|
336
|
+
Looks up a type by its nested path.
|
|
605
337
|
|
|
606
338
|
```js
|
|
607
|
-
const
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
const asyncCalledInstance = await AsyncType
|
|
611
|
-
.apply(process, ['wat']);
|
|
612
|
-
console.log(asyncCalledInstance) // { data: "wat" }
|
|
613
|
-
console.log(asyncCalledInstance instanceof AsyncType) // true
|
|
339
|
+
const { lookup } = require('mnemonica');
|
|
340
|
+
const SomeType = lookup('SomeType');
|
|
341
|
+
const SomeNestedType = lookup('SomeType.SomeNestedType');
|
|
614
342
|
```
|
|
615
343
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
Let for example suppose you need the following code:
|
|
619
|
-
|
|
620
|
-
```js
|
|
621
|
-
async (req, res) => {
|
|
622
|
-
|
|
623
|
-
const {
|
|
624
|
-
email // : 'async@check.mail',
|
|
625
|
-
password // : 'some password'
|
|
626
|
-
} = req.body
|
|
627
|
-
|
|
628
|
-
const user = await
|
|
629
|
-
new UserTypeConstructor({
|
|
630
|
-
email,
|
|
631
|
-
password
|
|
632
|
-
})
|
|
633
|
-
.UserEntityValidate('valid sign') // sync
|
|
634
|
-
.WithoutPassword() // sync, rid of password
|
|
635
|
-
|
|
636
|
-
const storagePushResult =
|
|
637
|
-
await user.AsyncPushToStorage();
|
|
638
|
-
const storageGetResult =
|
|
639
|
-
await storagePushResult.AsyncGetStorageResponse();
|
|
640
|
-
const storageValidateResult =
|
|
641
|
-
storagePushResult.SyncValidateStorageData()
|
|
642
|
-
const requestRplyResult =
|
|
643
|
-
await StorageValidateResult.AsyncReplyToRequest(res);
|
|
644
|
-
return requestRplyResult;
|
|
645
|
-
};
|
|
646
|
-
```
|
|
344
|
+
#### `apply(entity, Constructor, args?)`
|
|
647
345
|
|
|
648
|
-
|
|
346
|
+
Applies a constructor to an entity with an array of arguments.
|
|
649
347
|
|
|
650
348
|
```js
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
const {
|
|
654
|
-
email, // : 'async@check.mail',
|
|
655
|
-
password // : 'some password'
|
|
656
|
-
} = req.body
|
|
657
|
-
|
|
658
|
-
const user =
|
|
659
|
-
await (
|
|
660
|
-
(
|
|
661
|
-
await (
|
|
662
|
-
await (
|
|
663
|
-
new UserTypeConstructor({
|
|
664
|
-
email,
|
|
665
|
-
password
|
|
666
|
-
})
|
|
667
|
-
.UserEntityValidate('valid sign')
|
|
668
|
-
.WithoutPassword()
|
|
669
|
-
).AsyncPushToStorage()
|
|
670
|
-
).AsyncGetStorageResponse()
|
|
671
|
-
).SyncValidateStorageData()
|
|
672
|
-
).AsyncReplyToRequest(res);
|
|
673
|
-
};
|
|
349
|
+
const { apply } = require('mnemonica');
|
|
350
|
+
const subInstance = apply(parentInstance, SubType, ['arg1', 'arg2']);
|
|
674
351
|
```
|
|
675
352
|
|
|
676
|
-
|
|
353
|
+
#### `call(entity, Constructor, ...args)`
|
|
677
354
|
|
|
678
|
-
|
|
355
|
+
Calls a constructor on an entity with spread arguments.
|
|
679
356
|
|
|
680
357
|
```js
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
const {
|
|
684
|
-
email, // : 'async@check.mail',
|
|
685
|
-
password // : 'some password'
|
|
686
|
-
} = req.body
|
|
687
|
-
|
|
688
|
-
const user =
|
|
689
|
-
await new UserTypeConstructor({
|
|
690
|
-
email,
|
|
691
|
-
password
|
|
692
|
-
})
|
|
693
|
-
.UserEntityValidate('valid sign')
|
|
694
|
-
.WithoutPassword()
|
|
695
|
-
.AsyncPushToStorage()
|
|
696
|
-
.AsyncGetStorageResponse()
|
|
697
|
-
.SyncValidateStorageData()
|
|
698
|
-
.AsyncReplyToRequest(res);
|
|
699
|
-
};
|
|
358
|
+
const { call } = require('mnemonica');
|
|
359
|
+
const subInstance = call(parentInstance, SubType, 'arg1', 'arg2');
|
|
700
360
|
```
|
|
701
|
-
So now you don't have to care if this constructor is async or sync and where to put brakets and how many of them. It is enough to type constructor name after the dot and pass necessary arguments. That's it.
|
|
702
|
-
|
|
703
|
-
## require('util').callbackify
|
|
704
|
-
|
|
705
|
-
It is important: if we make `util.callbackify` from our instance async creation method, we shall [`.call`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/call) it then.
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
# Instance Properties
|
|
710
|
-
|
|
711
|
-
Also starting from `v0.3.8` the following non enumerable props are availiable from instance itself (`instance.hasOwnProperty(__prop__)`):
|
|
712
|
-
|
|
713
|
-
## Breaking Changes for 0.9.995
|
|
714
|
-
|
|
715
|
-
### all props below available from `getProps(instance)` :
|
|
716
|
-
|
|
717
|
-
## `.__args__`
|
|
718
|
-
|
|
719
|
-
Arguments, used for calling instance creation constructor.
|
|
720
|
-
|
|
721
|
-
## `.__type__`
|
|
722
|
-
The definition of instance type.
|
|
723
361
|
|
|
724
|
-
|
|
725
|
-
If instance is nested, then it is a reference of it's parent.
|
|
362
|
+
#### `bind(entity, Constructor)`
|
|
726
363
|
|
|
727
|
-
|
|
728
|
-
What you can craft from this instance accordingly with it's defined Type, the same as `__type__.subtypes`.
|
|
729
|
-
|
|
730
|
-
## `.__collection__`
|
|
731
|
-
Collection of types where `__type__` was defined.
|
|
732
|
-
|
|
733
|
-
# `instance.clone`
|
|
734
|
-
Returns cloned instance, with the following condition `instance !== instance.clone`. Cloning includes all the inheritance, with hooks invocations and so on. Therfore cloned instance is not the same as instance, but both made from the same `.__parent__` instance.
|
|
735
|
-
|
|
736
|
-
_Note_: if you are cloning instance, which has `async Constructor`, you should `await` it;
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
# **`instance.fork( some, new, args )`**
|
|
740
|
-
Returns forked instance. Behaviour is same as for cloned instance, both made from the same `.__parent__`. But this is a method, not the property, so you can apply another arguments to the constructor.
|
|
741
|
-
|
|
742
|
-
_Note_: if you are forking instance, which has `async Constructor`, you should `await` it;
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
# Directed Acyclic Graphs
|
|
746
|
-
|
|
747
|
-
## **`instance.fork.call( thisArg, ...args )`**
|
|
748
|
-
## **`instance.fork.apply( thisArg, [args] )`**
|
|
749
|
-
Let assume you nedd [Directed Acyclic Graph](https://en.wikipedia.org/wiki/Directed_acyclic_graph). Then you have to be able to construct it somehow. Starting from `v0.6.1` you can use `fork.call` or `fork.apply` for doing this:
|
|
364
|
+
Binds a constructor to an entity, returning a function.
|
|
750
365
|
|
|
751
366
|
```js
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
A.fork.bind(B)(...args);
|
|
367
|
+
const { bind } = require('mnemonica');
|
|
368
|
+
const createSub = bind(parentInstance, SubType);
|
|
369
|
+
const subInstance = createSub('arg1', 'arg2');
|
|
756
370
|
```
|
|
757
|
-
_Note_: if you are `fork.clone`'ing instance, which has `async Constructor`, you should `await` it;
|
|
758
371
|
|
|
372
|
+
#### `decorate(target?, config?)`
|
|
759
373
|
|
|
760
|
-
|
|
761
|
-
The same as `fork.call` but providing instsnces directly.
|
|
762
|
-
|
|
763
|
-
_Note_: if you are `merge`'ing instances, where A.constructor is `async Constructor`, you should `await` it;
|
|
764
|
-
|
|
765
|
-
---
|
|
374
|
+
TypeScript decorator for class-based definitions.
|
|
766
375
|
|
|
767
|
-
|
|
768
|
-
|
|
376
|
+
```typescript
|
|
377
|
+
import { decorate } from 'mnemonica';
|
|
769
378
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
379
|
+
@decorate()
|
|
380
|
+
class MyClass {
|
|
381
|
+
field: number = 123;
|
|
382
|
+
}
|
|
773
383
|
|
|
774
|
-
|
|
384
|
+
// With configuration
|
|
385
|
+
@decorate({ strictChain: false })
|
|
386
|
+
class ConfiguredClass {
|
|
387
|
+
// ...
|
|
388
|
+
}
|
|
775
389
|
|
|
776
|
-
|
|
390
|
+
// Nested decoration
|
|
391
|
+
@decorate()
|
|
392
|
+
class ParentClass {}
|
|
777
393
|
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
// shall or not we use strict checking
|
|
782
|
-
// for creation sub-instances Only from current type
|
|
783
|
-
// or we might use up-nested sub-instances from chain
|
|
784
|
-
strictChain: true,
|
|
785
|
-
|
|
786
|
-
// should we use forced errors checking
|
|
787
|
-
// to make all inherited types errored
|
|
788
|
-
// if there is an error somewhere in chain
|
|
789
|
-
// disallow instance construction
|
|
790
|
-
// if there is an error in prototype chain
|
|
791
|
-
blockErrors: true,
|
|
792
|
-
|
|
793
|
-
// if it is necessary to collect stack
|
|
794
|
-
// as a __stack__ prototype property
|
|
795
|
-
// during the process of instance creation
|
|
796
|
-
submitStack: false,
|
|
797
|
-
|
|
798
|
-
// await new Constructor()
|
|
799
|
-
// must return value
|
|
800
|
-
// optional ./issues/106
|
|
801
|
-
awaitReturn: true,
|
|
802
|
-
|
|
803
|
-
})
|
|
394
|
+
@decorate(ParentClass)
|
|
395
|
+
class ChildClass {}
|
|
804
396
|
```
|
|
805
397
|
|
|
806
|
-
|
|
398
|
+
#### `registerHook(Constructor, hookType, callback)`
|
|
807
399
|
|
|
808
|
-
|
|
809
|
-
import {
|
|
810
|
-
defaultTypes,
|
|
811
|
-
SymbolConfig
|
|
812
|
-
} from 'mnemonica';
|
|
400
|
+
Registers a hook for a specific constructor.
|
|
813
401
|
|
|
814
|
-
|
|
402
|
+
```js
|
|
403
|
+
const { registerHook } = require('mnemonica');
|
|
815
404
|
|
|
405
|
+
registerHook(MyType, 'preCreation', (hookData) => {
|
|
406
|
+
console.log('Creating:', hookData.TypeName);
|
|
407
|
+
});
|
|
816
408
|
```
|
|
817
409
|
|
|
818
410
|
---
|
|
819
411
|
|
|
820
|
-
|
|
412
|
+
### Type Reference
|
|
413
|
+
|
|
414
|
+
For advanced TypeScript usage, the following types are exported from `mnemonica`:
|
|
415
|
+
|
|
416
|
+
| Type | Description | Usage |
|
|
417
|
+
|------|-------------|-------|
|
|
418
|
+
| `IDEF<T>` | Base constructor function type | `define('Name', fn: IDEF<MyType>)` |
|
|
419
|
+
| `MnemonicaInstance` | Instance methods interface | `instance.extract()`, `instance.pick()` |
|
|
420
|
+
| `TypeClass` | Base type constructor | `const MyType: TypeClass = define(...)` |
|
|
421
|
+
| `DecoratedClass<T>` | Decorated class type | `@decorate() class MyClass {}` |
|
|
422
|
+
| `IDefinitorInstance<N, S>` | Constructor with subtypes | Returned by `define()` with `.define()` method |
|
|
423
|
+
| `ConstructorFunction<T>` | Constructor with prototype | Generic constructor function signature |
|
|
424
|
+
| `constructorOptions` | Configuration options | `{ strictChain: true, blockErrors: true }` |
|
|
425
|
+
| `hooksTypes` | Hook type literals | `'preCreation' \| 'postCreation' \| 'creationError'` |
|
|
426
|
+
| `hook` | Hook callback type | `(opts: hooksOpts) => void` |
|
|
427
|
+
| `hooksOpts` | Hook options object | Passed to hook callbacks |
|
|
428
|
+
| `TypeDef` | Type definition structure | `instance.__type__` structure |
|
|
429
|
+
| `CollectionDef` | Types collection | `instance.__collection__` structure |
|
|
430
|
+
| `ApplyFunction` | apply() function type | `apply<E, T, S>(entity, Ctor, args) => S` |
|
|
431
|
+
| `CallFunction` | call() function type | `call<E, T, S>(entity, Ctor, ...args) => S` |
|
|
432
|
+
| `BindFunction` | bind() function type | `bind<E, T, S>(entity, Ctor) => (...args) => S` |
|
|
433
|
+
|
|
434
|
+
These types enable complete type safety when defining and using mnemonica types in TypeScript projects.
|
|
821
435
|
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
### `define(typeName, constructHandler, config?)`
|
|
825
|
-
Defines a new type constructor. Returns a TypeClass that can be used to create instances.
|
|
826
|
-
|
|
827
|
-
### `lookup(typeNestedPath)`
|
|
828
|
-
Looks up a type by its nested path (e.g., `'SomeType.SomeNestedType'`).
|
|
829
|
-
|
|
830
|
-
### `apply(entity, Constructor, args?)`
|
|
831
|
-
Applies a constructor to an entity with the given arguments array.
|
|
436
|
+
---
|
|
832
437
|
|
|
833
|
-
###
|
|
834
|
-
Calls a constructor on an entity with spread arguments.
|
|
438
|
+
### Type Management
|
|
835
439
|
|
|
836
|
-
|
|
837
|
-
Binds a constructor to an entity, returning a function that can be called later.
|
|
440
|
+
#### `defaultTypes`
|
|
838
441
|
|
|
839
|
-
|
|
840
|
-
Registers a hook for a specific constructor.
|
|
442
|
+
The default types collection. All types defined with the top-level `define()` are stored here.
|
|
841
443
|
|
|
842
|
-
|
|
444
|
+
```js
|
|
445
|
+
const { defaultTypes } = require('mnemonica');
|
|
446
|
+
const MyType = defaultTypes.MyType;
|
|
447
|
+
```
|
|
843
448
|
|
|
844
|
-
|
|
845
|
-
The default types collection. All types defined with the top-level `define()` function are stored here.
|
|
449
|
+
#### `createTypesCollection(config?)`
|
|
846
450
|
|
|
847
|
-
### `createTypesCollection()`
|
|
848
451
|
Creates a new isolated types collection.
|
|
849
452
|
|
|
850
453
|
```js
|
|
454
|
+
const { createTypesCollection } = require('mnemonica');
|
|
851
455
|
const myCollection = createTypesCollection();
|
|
852
|
-
const MyType = myCollection.define('MyType', function() {});
|
|
456
|
+
const MyType = myCollection.define('MyType', function () {});
|
|
853
457
|
```
|
|
854
458
|
|
|
855
|
-
|
|
459
|
+
#### `getProps(instance)` / `setProps(instance, values)`
|
|
460
|
+
|
|
856
461
|
Get or set internal properties of an instance.
|
|
857
462
|
|
|
858
463
|
```js
|
|
859
464
|
const { getProps, setProps } = require('mnemonica');
|
|
465
|
+
|
|
860
466
|
const props = getProps(instance);
|
|
861
467
|
console.log(props.__type__, props.__args__);
|
|
468
|
+
|
|
469
|
+
// Set properties
|
|
470
|
+
setProps(instance, { __timestamp__: Date.now() });
|
|
862
471
|
```
|
|
863
472
|
|
|
864
|
-
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
### Instance Methods
|
|
865
476
|
|
|
866
477
|
All mnemonica instances have the following methods:
|
|
867
478
|
|
|
868
|
-
|
|
479
|
+
#### `.extract()`
|
|
480
|
+
|
|
869
481
|
Extracts all inherited properties into a single flat object.
|
|
870
482
|
|
|
871
|
-
|
|
483
|
+
```js
|
|
484
|
+
const extracted = instance.extract();
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
#### `.pick(...keys)` / `.pick([keys])`
|
|
488
|
+
|
|
872
489
|
Picks specific properties from the instance and its inheritance chain.
|
|
873
490
|
|
|
874
491
|
```js
|
|
@@ -877,63 +494,99 @@ const picked = instance.pick('email', 'password');
|
|
|
877
494
|
const picked = instance.pick(['email', 'password']);
|
|
878
495
|
```
|
|
879
496
|
|
|
880
|
-
|
|
881
|
-
|
|
497
|
+
#### `.parent(constructorName?)`
|
|
498
|
+
|
|
499
|
+
Gets the parent instance. If `constructorName` is provided, walks up the chain.
|
|
882
500
|
|
|
883
501
|
```js
|
|
884
502
|
const immediateParent = instance.parent();
|
|
885
503
|
const specificParent = instance.parent('UserType');
|
|
886
504
|
```
|
|
887
505
|
|
|
888
|
-
|
|
889
|
-
|
|
506
|
+
#### `.clone`
|
|
507
|
+
|
|
508
|
+
Property that returns a cloned instance (same parent, same args).
|
|
509
|
+
|
|
510
|
+
```js
|
|
511
|
+
const cloned = instance.clone;
|
|
512
|
+
// Note: For async constructors, use: await instance.clone
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
#### `.fork(...args)`
|
|
890
516
|
|
|
891
|
-
|
|
892
|
-
Creates a forked instance from the same parent, optionally with different arguments.
|
|
517
|
+
Creates a forked instance from the same parent with optional new arguments.
|
|
893
518
|
|
|
894
519
|
```js
|
|
895
|
-
const forked = instance.fork();
|
|
520
|
+
const forked = instance.fork(); // same args
|
|
896
521
|
const forkedWithNewArgs = instance.fork('new', 'args');
|
|
522
|
+
// Note: For async constructors, use: await instance.fork(...)
|
|
897
523
|
```
|
|
898
524
|
|
|
899
|
-
|
|
900
|
-
|
|
525
|
+
#### `.fork.call(thisArg, ...args)` / `.fork.apply(thisArg, args)`
|
|
526
|
+
|
|
527
|
+
Forks with a different `this` context (useful for Directed Acyclic Graphs).
|
|
901
528
|
|
|
902
529
|
```js
|
|
903
530
|
const dagInstance = instanceA.fork.call(instanceB, 'args');
|
|
904
531
|
```
|
|
905
532
|
|
|
906
|
-
|
|
907
|
-
|
|
533
|
+
#### `.exception(error, ...args)`
|
|
534
|
+
|
|
535
|
+
Creates an exception instance from the current instance.
|
|
908
536
|
|
|
909
537
|
```js
|
|
910
538
|
const error = someInstance.exception(new Error('Something went wrong'));
|
|
911
539
|
throw error;
|
|
912
540
|
```
|
|
913
541
|
|
|
914
|
-
|
|
542
|
+
#### `.sibling(typeName)` / `.sibling.TypeName`
|
|
543
|
+
|
|
915
544
|
Access sibling types from the same collection.
|
|
916
545
|
|
|
917
546
|
```js
|
|
918
547
|
const siblingType = instance.sibling('OtherType');
|
|
919
|
-
const siblingInstance = new siblingType();
|
|
920
|
-
// or
|
|
921
548
|
const sibling = instance.sibling.OtherType;
|
|
922
549
|
```
|
|
923
550
|
|
|
924
|
-
|
|
551
|
+
---
|
|
552
|
+
|
|
553
|
+
### Instance Properties (via `getProps`)
|
|
925
554
|
|
|
926
|
-
|
|
555
|
+
All instances have non-enumerable internal properties:
|
|
556
|
+
|
|
557
|
+
| Property | Type | Description |
|
|
558
|
+
|----------|------|-------------|
|
|
559
|
+
| `.__args__` | `unknown[]` | Arguments used for instance creation |
|
|
560
|
+
| `.__type__` | `TypeDef` | Type definition object |
|
|
561
|
+
| `.__parent__` | `object` | Parent instance reference |
|
|
562
|
+
| `.__subtypes__` | `Map<string, object>` | Map of available subtypes |
|
|
563
|
+
| `.__collection__` | `CollectionDef` | Types collection where type was defined |
|
|
564
|
+
| `.__stack__` | `string` | Stack trace (if `submitStack: true` in config) |
|
|
565
|
+
| `.__creator__` | `TypeDef` | Instance creator reference |
|
|
566
|
+
| `.__timestamp__` | `number` | Creation timestamp (ms since epoch) |
|
|
567
|
+
| `.__self__` | `object` | Self reference to the instance |
|
|
568
|
+
|
|
569
|
+
---
|
|
570
|
+
|
|
571
|
+
### Utilities
|
|
572
|
+
|
|
573
|
+
Access via `utils` export:
|
|
574
|
+
|
|
575
|
+
```js
|
|
576
|
+
const { utils } = require('mnemonica');
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
#### `utils.extract(instance)`
|
|
927
580
|
Standalone extract function.
|
|
928
581
|
|
|
929
|
-
|
|
582
|
+
#### `utils.pick(instance, ...keys)`
|
|
930
583
|
Standalone pick function.
|
|
931
584
|
|
|
932
|
-
|
|
585
|
+
#### `utils.parent(instance, constructorName?)`
|
|
933
586
|
Standalone parent function.
|
|
934
587
|
|
|
935
|
-
|
|
936
|
-
Parses an instance structure, returning
|
|
588
|
+
#### `utils.parse(instance)`
|
|
589
|
+
Parses an instance structure, returning:
|
|
937
590
|
- `name`: constructor name
|
|
938
591
|
- `props`: extracted properties
|
|
939
592
|
- `self`: the instance itself
|
|
@@ -946,95 +599,97 @@ const { utils: { parse } } = require('mnemonica');
|
|
|
946
599
|
const parsed = parse(instance);
|
|
947
600
|
```
|
|
948
601
|
|
|
949
|
-
|
|
602
|
+
#### `utils.merge(A, B, ...args)`
|
|
950
603
|
Merges two instances using fork semantics.
|
|
951
604
|
|
|
952
605
|
```js
|
|
953
|
-
const merged = merge(instanceA, instanceB, 'args');
|
|
606
|
+
const merged = utils.merge(instanceA, instanceB, 'args');
|
|
607
|
+
// Note: For async constructors, use: await utils.merge(...)
|
|
954
608
|
```
|
|
955
609
|
|
|
956
|
-
|
|
610
|
+
#### `utils.toJSON(instance)`
|
|
957
611
|
Serializes an instance to JSON.
|
|
958
612
|
|
|
959
613
|
```js
|
|
960
614
|
const json = utils.toJSON(instance);
|
|
961
615
|
```
|
|
962
616
|
|
|
963
|
-
|
|
617
|
+
#### `utils.collectConstructors(instance, flat?)`
|
|
964
618
|
Collects all constructors in the instance's prototype chain.
|
|
965
619
|
|
|
966
620
|
```js
|
|
967
621
|
const constructors = utils.collectConstructors(instance, true);
|
|
968
622
|
```
|
|
969
623
|
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
All instances have non-enumerable internal properties accessible via `getProps()`:
|
|
973
|
-
|
|
974
|
-
| Property | Description |
|
|
975
|
-
|----------|-------------|
|
|
976
|
-
| `.__args__` | Arguments used for instance creation |
|
|
977
|
-
| `.__type__` | Type definition object |
|
|
978
|
-
| `.__parent__` | Parent instance reference |
|
|
979
|
-
| `.__subtypes__` | Map of available subtypes |
|
|
980
|
-
| `.__collection__` | Types collection where type was defined |
|
|
981
|
-
| `.__stack__` | Stack trace (if `submitStack: true` in config) |
|
|
982
|
-
| `.__creator__` | Instance creator reference |
|
|
983
|
-
| `.__timestamp__` | Creation timestamp (ms since epoch) |
|
|
984
|
-
| `.__self__` | Self reference to the instance |
|
|
624
|
+
---
|
|
985
625
|
|
|
986
|
-
|
|
626
|
+
### Hooks
|
|
987
627
|
|
|
988
|
-
|
|
628
|
+
#### Hook Types
|
|
989
629
|
|
|
990
630
|
- `'preCreation'` - Called before instance creation
|
|
991
631
|
- `'postCreation'` - Called after instance creation
|
|
992
632
|
- `'creationError'` - Called when instance creation throws an error
|
|
993
633
|
|
|
994
|
-
|
|
634
|
+
#### `type.registerHook(hookType, callback)`
|
|
635
|
+
|
|
995
636
|
Register a hook on a specific type.
|
|
996
637
|
|
|
997
638
|
```js
|
|
998
639
|
MyType.registerHook('preCreation', (hookData) => {
|
|
999
|
-
|
|
640
|
+
console.log('Creating:', hookData.TypeName);
|
|
1000
641
|
});
|
|
1001
642
|
```
|
|
1002
643
|
|
|
1003
|
-
|
|
644
|
+
#### `collection.registerHook(hookType, callback)`
|
|
645
|
+
|
|
1004
646
|
Register a hook on a types collection.
|
|
1005
647
|
|
|
1006
648
|
```js
|
|
1007
649
|
defaultTypes.registerHook('postCreation', (hookData) => {
|
|
1008
|
-
|
|
650
|
+
console.log('Created:', hookData.inheritedInstance.constructor.name);
|
|
1009
651
|
});
|
|
1010
652
|
```
|
|
1011
653
|
|
|
1012
|
-
|
|
654
|
+
#### `collection.registerFlowChecker(callback)`
|
|
655
|
+
|
|
1013
656
|
Register a flow checker that runs before hooks.
|
|
1014
657
|
|
|
1015
658
|
```js
|
|
1016
659
|
defaultTypes.registerFlowChecker((opts) => {
|
|
1017
|
-
|
|
1018
|
-
console.log('Flow check:', opts.TypeName);
|
|
660
|
+
console.log('Flow check:', opts.TypeName);
|
|
1019
661
|
});
|
|
1020
662
|
```
|
|
1021
663
|
|
|
1022
|
-
|
|
664
|
+
#### Hook Data Structure
|
|
1023
665
|
|
|
1024
|
-
```
|
|
1025
|
-
{
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
666
|
+
```typescript
|
|
667
|
+
interface HookData {
|
|
668
|
+
TypeName: string; // Constructor name
|
|
669
|
+
type: TypeDef; // The type being constructed
|
|
670
|
+
args: unknown[]; // Arguments passed to constructor
|
|
671
|
+
existentInstance: object; // Parent instance
|
|
672
|
+
inheritedInstance: object; // New instance (postCreation only)
|
|
673
|
+
throwModificationError(error: Error): void; // Throw error from hook
|
|
1030
674
|
}
|
|
1031
675
|
```
|
|
1032
676
|
|
|
1033
|
-
|
|
677
|
+
```js
|
|
678
|
+
MyType.registerHook('postCreation', (hookData) => {
|
|
679
|
+
// Throw custom error from hook
|
|
680
|
+
hookData.throwModificationError(new Error('Custom hook error'));
|
|
681
|
+
});
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
**Note:** In preCreation hooks, `existentInstance` refers to the parent; in postCreation hooks, it refers to the instance used for inheritance.
|
|
685
|
+
|
|
686
|
+
---
|
|
1034
687
|
|
|
1035
|
-
###
|
|
688
|
+
### Error Handling
|
|
1036
689
|
|
|
1037
|
-
|
|
690
|
+
#### Error Types
|
|
691
|
+
|
|
692
|
+
All mnemonica errors extend `BASE_MNEMONICA_ERROR`:
|
|
1038
693
|
|
|
1039
694
|
```js
|
|
1040
695
|
const { errors } = require('mnemonica');
|
|
@@ -1056,9 +711,9 @@ errors.OPTIONS_ERROR
|
|
|
1056
711
|
errors.WRONG_STACK_CLEANER
|
|
1057
712
|
```
|
|
1058
713
|
|
|
1059
|
-
|
|
714
|
+
#### Exception Instances
|
|
1060
715
|
|
|
1061
|
-
When
|
|
716
|
+
When creating exceptions using `instance.exception()`:
|
|
1062
717
|
|
|
1063
718
|
```js
|
|
1064
719
|
const error = instance.exception(new Error('Original error'));
|
|
@@ -1071,126 +726,265 @@ error.parse() // Parse the exception structure
|
|
|
1071
726
|
error.extract() // Extract properties from the exception
|
|
1072
727
|
```
|
|
1073
728
|
|
|
1074
|
-
|
|
729
|
+
#### Stack Cleaning
|
|
730
|
+
|
|
731
|
+
```js
|
|
732
|
+
const { defineStackCleaner } = require('mnemonica');
|
|
733
|
+
|
|
734
|
+
// Add regex patterns to clean stack traces
|
|
735
|
+
defineStackCleaner(/node_modules\/some-package/);
|
|
736
|
+
```
|
|
1075
737
|
|
|
1076
|
-
|
|
738
|
+
---
|
|
739
|
+
|
|
740
|
+
### Symbols & Constants
|
|
1077
741
|
|
|
1078
742
|
```js
|
|
1079
743
|
const {
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
744
|
+
SymbolParentType, // Parent type symbol
|
|
745
|
+
SymbolConstructorName, // Constructor name symbol
|
|
746
|
+
SymbolDefaultTypesCollection, // Default collection symbol
|
|
747
|
+
SymbolConfig, // Config symbol
|
|
748
|
+
MNEMONICA, // Library name
|
|
749
|
+
MNEMOSYNE // Collection identifier
|
|
1084
750
|
} = require('mnemonica');
|
|
1085
751
|
```
|
|
1086
752
|
|
|
1087
|
-
|
|
753
|
+
---
|
|
1088
754
|
|
|
1089
|
-
|
|
755
|
+
## Configuration Options
|
|
1090
756
|
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
hook, // Hook callback type
|
|
1103
|
-
constructorOptions // Configuration options type
|
|
1104
|
-
} from 'mnemonica';
|
|
757
|
+
Pass options as the third argument to `define()`:
|
|
758
|
+
|
|
759
|
+
```js
|
|
760
|
+
define('SomeType', function () {}, {
|
|
761
|
+
strictChain: true, // Only allow sub-instances from current type
|
|
762
|
+
blockErrors: true, // Disallow construction if error in prototype chain
|
|
763
|
+
submitStack: false, // Collect stack trace as __stack__ property
|
|
764
|
+
awaitReturn: true, // Ensure await new Constructor() returns value
|
|
765
|
+
ModificationConstructor: fn, // Custom modification constructor
|
|
766
|
+
asClass: false // Force class mode (auto-detected by default)
|
|
767
|
+
});
|
|
1105
768
|
```
|
|
1106
769
|
|
|
1107
|
-
|
|
770
|
+
### Override Default Config for Collection
|
|
1108
771
|
|
|
1109
|
-
|
|
772
|
+
```js
|
|
773
|
+
import { defaultTypes, SymbolConfig } from 'mnemonica';
|
|
1110
774
|
|
|
1111
|
-
|
|
775
|
+
defaultTypes[SymbolConfig].blockErrors = false;
|
|
776
|
+
```
|
|
1112
777
|
|
|
1113
|
-
|
|
1114
|
-
import { decorate } from 'mnemonica';
|
|
778
|
+
---
|
|
1115
779
|
|
|
1116
|
-
|
|
1117
|
-
class MyClass {
|
|
1118
|
-
field: number;
|
|
1119
|
-
constructor() {
|
|
1120
|
-
this.field = 123;
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
780
|
+
## AI Agent Usage Guide
|
|
1123
781
|
|
|
1124
|
-
|
|
782
|
+
This section helps AI agents understand and work with mnemonica programmatically.
|
|
783
|
+
|
|
784
|
+
### 1. Type Introspection
|
|
785
|
+
|
|
786
|
+
Use `utils.parse(instance)` to understand instance structure:
|
|
787
|
+
|
|
788
|
+
```js
|
|
789
|
+
const { utils: { parse } } = require('mnemonica');
|
|
790
|
+
|
|
791
|
+
const parsed = parse(instance);
|
|
792
|
+
// Returns: { name, props, self, proto, joint, parent, constructor }
|
|
1125
793
|
```
|
|
1126
794
|
|
|
1127
|
-
###
|
|
795
|
+
### 2. Safe Property Access
|
|
1128
796
|
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
797
|
+
Always use `getProps()` instead of direct property access:
|
|
798
|
+
|
|
799
|
+
```js
|
|
800
|
+
const { getProps } = require('mnemonica');
|
|
801
|
+
|
|
802
|
+
const props = getProps(instance);
|
|
803
|
+
// props.__type__, props.__args__, props.__parent__, props.__subtypes__, etc.
|
|
1134
804
|
```
|
|
1135
805
|
|
|
1136
|
-
###
|
|
806
|
+
### 3. Type Discovery
|
|
1137
807
|
|
|
1138
|
-
```
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
808
|
+
```js
|
|
809
|
+
const { defaultTypes } = require('mnemonica');
|
|
810
|
+
|
|
811
|
+
// List all types in default collection
|
|
812
|
+
const typeNames = [...defaultTypes.subtypes.keys()];
|
|
813
|
+
|
|
814
|
+
// List subtypes of a specific type
|
|
815
|
+
const myType = defaultTypes.MyType;
|
|
816
|
+
const subTypeNames = [...myType.subtypes.keys()];
|
|
817
|
+
|
|
818
|
+
// Check if a type exists
|
|
819
|
+
const hasType = defaultTypes.lookup('MyType') !== undefined;
|
|
820
|
+
```
|
|
821
|
+
|
|
822
|
+
### 4. Instance Traversal
|
|
823
|
+
|
|
824
|
+
```js
|
|
825
|
+
const { getProps } = require('mnemonica');
|
|
826
|
+
|
|
827
|
+
// Walk up the inheritance chain
|
|
828
|
+
function traverseChain(instance) {
|
|
829
|
+
const chain = [];
|
|
830
|
+
let current = instance;
|
|
831
|
+
|
|
832
|
+
while (current) {
|
|
833
|
+
const props = getProps(current);
|
|
834
|
+
if (!props) break;
|
|
835
|
+
|
|
836
|
+
chain.push({
|
|
837
|
+
typeName: props.__type__.TypeName,
|
|
838
|
+
timestamp: props.__timestamp__,
|
|
839
|
+
args: props.__args__
|
|
840
|
+
});
|
|
841
|
+
|
|
842
|
+
current = props.__parent__;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
return chain;
|
|
1142
846
|
}
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
### 5. Safe Construction Patterns
|
|
1143
850
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
851
|
+
```js
|
|
852
|
+
const { lookup } = require('mnemonica');
|
|
853
|
+
|
|
854
|
+
// Always check if type exists before construction
|
|
855
|
+
const MyType = lookup('MyType');
|
|
856
|
+
if (MyType) {
|
|
857
|
+
const instance = new MyType(data);
|
|
1147
858
|
}
|
|
1148
859
|
|
|
1149
|
-
|
|
1150
|
-
|
|
860
|
+
// For nested construction with proper error handling
|
|
861
|
+
try {
|
|
862
|
+
const subInstance = new instance.SubType(data);
|
|
863
|
+
} catch (error) {
|
|
864
|
+
// Handle WRONG_MODIFICATION_PATTERN if SubType not defined
|
|
865
|
+
console.error('Subtype not available:', error.message);
|
|
866
|
+
}
|
|
1151
867
|
```
|
|
1152
868
|
|
|
1153
|
-
###
|
|
869
|
+
### 6. Analyzing Type Structure
|
|
1154
870
|
|
|
1155
|
-
|
|
871
|
+
```js
|
|
872
|
+
const { getProps } = require('mnemonica');
|
|
1156
873
|
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
874
|
+
function analyzeType(typeConstructor) {
|
|
875
|
+
return {
|
|
876
|
+
name: typeConstructor.TypeName,
|
|
877
|
+
isSubType: typeConstructor.isSubType,
|
|
878
|
+
subTypesCount: typeConstructor.subtypes?.size || 0,
|
|
879
|
+
hasHooks: Object.keys(typeConstructor.hooks || {}).length > 0,
|
|
880
|
+
config: typeConstructor.config
|
|
881
|
+
};
|
|
1161
882
|
}
|
|
883
|
+
```
|
|
1162
884
|
|
|
1163
|
-
|
|
1164
|
-
class Extended {
|
|
1165
|
-
// ...
|
|
1166
|
-
}
|
|
885
|
+
### 7. Working with Collections
|
|
1167
886
|
|
|
1168
|
-
|
|
1169
|
-
const
|
|
887
|
+
```js
|
|
888
|
+
const { createTypesCollection, defaultTypes } = require('mnemonica');
|
|
889
|
+
|
|
890
|
+
// Create isolated collection for testing
|
|
891
|
+
const testCollection = createTypesCollection({
|
|
892
|
+
strictChain: false,
|
|
893
|
+
blockErrors: false
|
|
894
|
+
});
|
|
895
|
+
|
|
896
|
+
// Define types in isolation
|
|
897
|
+
const TestType = testCollection.define('TestType', function () {});
|
|
898
|
+
|
|
899
|
+
// Register collection-level hooks
|
|
900
|
+
testCollection.registerHook('preCreation', (data) => {
|
|
901
|
+
console.log('Creating in test collection:', data.TypeName);
|
|
902
|
+
});
|
|
1170
903
|
```
|
|
1171
904
|
|
|
1172
|
-
|
|
905
|
+
---
|
|
906
|
+
|
|
907
|
+
## Examples
|
|
908
|
+
|
|
909
|
+
### Asynchronous Constructors
|
|
910
|
+
|
|
911
|
+
```js
|
|
912
|
+
const AsyncType = define('AsyncType', async function (data) {
|
|
913
|
+
await someAsyncOperation();
|
|
914
|
+
return Object.assign(this, { data });
|
|
915
|
+
});
|
|
916
|
+
|
|
917
|
+
// Usage
|
|
918
|
+
const asyncInstance = await new AsyncType('tada');
|
|
919
|
+
|
|
920
|
+
// Nested async types
|
|
921
|
+
const NestedAsync = AsyncType.define('NestedAsync', async function (data) {
|
|
922
|
+
return Object.assign(this, { nestedData: data });
|
|
923
|
+
});
|
|
1173
924
|
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
| `strictChain` | `boolean` | `true` | Only allow sub-instances from current type, not up-nested |
|
|
1177
|
-
| `blockErrors` | `boolean` | `true` | Disallow instance construction if error in prototype chain |
|
|
1178
|
-
| `submitStack` | `boolean` | `false` | Collect stack trace as `__stack__` property |
|
|
1179
|
-
| `awaitReturn` | `boolean` | `true` | Ensure `await new Constructor()` returns value |
|
|
1180
|
-
| `ModificationConstructor` | `Function` | internal | Custom modification constructor |
|
|
1181
|
-
| `asClass` | `boolean` | auto | Force class mode (auto-detected by default) |
|
|
925
|
+
const nested = await new asyncInstance.NestedAsync('nested');
|
|
926
|
+
```
|
|
1182
927
|
|
|
1183
|
-
|
|
928
|
+
### Async Chain with Single Await
|
|
1184
929
|
|
|
1185
|
-
|
|
930
|
+
```js
|
|
931
|
+
async (req, res) => {
|
|
932
|
+
const result = await new UserTypeConstructor({
|
|
933
|
+
email: req.body.email,
|
|
934
|
+
password: req.body.password
|
|
935
|
+
})
|
|
936
|
+
.UserEntityValidate('valid sign')
|
|
937
|
+
.WithoutPassword()
|
|
938
|
+
.AsyncPushToStorage()
|
|
939
|
+
.AsyncGetStorageResponse()
|
|
940
|
+
.SyncValidateStorageData()
|
|
941
|
+
.AsyncReplyToRequest(res);
|
|
942
|
+
};
|
|
943
|
+
```
|
|
1186
944
|
|
|
945
|
+
### Using `call` with Existing Objects
|
|
946
|
+
|
|
947
|
+
```js
|
|
948
|
+
// Combine with process, window, document, etc.
|
|
949
|
+
const usingProcessAsProto = Singletoned.call(process, {
|
|
950
|
+
some: 'arguments'
|
|
951
|
+
});
|
|
952
|
+
|
|
953
|
+
// With React
|
|
954
|
+
import ReactDOM from "react-dom";
|
|
955
|
+
const ReactDOOMed = define("ReactDOOMed", function() {});
|
|
956
|
+
const usingReactAsProto = ReactDOOMed.call(ReactDOM);
|
|
957
|
+
```
|
|
958
|
+
|
|
959
|
+
### Directed Acyclic Graphs (DAG)
|
|
960
|
+
|
|
961
|
+
```js
|
|
962
|
+
// Fork from different parent
|
|
963
|
+
const dagInstance = instanceA.fork.call(instanceB, 'args');
|
|
964
|
+
|
|
965
|
+
// Or use merge utility
|
|
966
|
+
const { utils: { merge } } = require('mnemonica');
|
|
967
|
+
const merged = merge(instanceA, instanceB, 'args');
|
|
968
|
+
```
|
|
969
|
+
|
|
970
|
+
---
|
|
971
|
+
|
|
972
|
+
## Epilogue
|
|
973
|
+
|
|
974
|
+
So, now you can craft as many types as you wish, combine them, re-define them and spend much more time playing with them:
|
|
1187
975
|
|
|
1188
976
|
* test : instances & arguments
|
|
1189
977
|
* track : moments of creation
|
|
1190
978
|
* check : if the order of creation is OK
|
|
1191
979
|
* validate : everything, 4 example use sort of TS in runtime
|
|
1192
|
-
* and even
|
|
1193
|
-
|
|
1194
|
-

|
|
980
|
+
* and even `.parse` them using `mnemonica.utils.parse`
|
|
1195
981
|
|
|
1196
982
|
Good Luck!
|
|
983
|
+
|
|
984
|
+
---
|
|
985
|
+
|
|
986
|
+
## License
|
|
987
|
+
|
|
988
|
+
MIT
|
|
989
|
+
|
|
990
|
+
Copyright (c) 2019 https://github.com/wentout
|