mnemonica 0.9.99778 → 0.9.99779
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 -827
- 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,482 @@ 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
|
-
|
|
48
|
+
---
|
|
38
49
|
|
|
39
|
-
##
|
|
50
|
+
## Overview
|
|
40
51
|
|
|
41
|
-
|
|
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.
|
|
42
53
|
|
|
43
|
-
|
|
54
|
+
Think of it as a mathematical function `f(x) => y` where `this` is your persistent data structure and transformations are applied sequentially.
|
|
44
55
|
|
|
56
|
+
> *"O Great Mnemosyne! Please! Save us from Oblivion..."*
|
|
57
|
+
> — from the source, where memory persists
|
|
45
58
|
|
|
46
|
-
|
|
59
|
+

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

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