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.
Files changed (48) hide show
  1. package/README.md +622 -828
  2. package/build/api/errors/exceptionConstructor.d.ts +1 -1
  3. package/build/api/errors/exceptionConstructor.js +1 -1
  4. package/build/api/errors/index.js +1 -1
  5. package/build/api/errors/throwModificationError.d.ts +20 -1
  6. package/build/api/errors/throwModificationError.js +1 -1
  7. package/build/api/index.d.ts +2 -2
  8. package/build/api/types/InstanceCreator.d.ts +26 -5
  9. package/build/api/types/InstanceCreator.js +1 -1
  10. package/build/api/types/InstanceModificator.js +1 -1
  11. package/build/api/types/Mnemosyne.d.ts +23 -7
  12. package/build/api/types/Mnemosyne.js +1 -1
  13. package/build/api/types/Props.d.ts +4 -40
  14. package/build/api/types/Props.js +1 -1
  15. package/build/api/types/TypeProxy.d.ts +22 -2
  16. package/build/api/types/TypeProxy.js +5 -5
  17. package/build/api/types/compileNewModificatorFunctionBody.d.ts +1 -1
  18. package/build/api/types/compileNewModificatorFunctionBody.js +1 -1
  19. package/build/api/types/index.d.ts +3 -2
  20. package/build/api/types/index.js +12 -7
  21. package/build/api/utils/index.d.ts +2 -2
  22. package/build/api/utils/index.js +4 -1
  23. package/build/constants/index.d.ts +1 -1
  24. package/build/constants/index.js +1 -1
  25. package/build/descriptors/errors/index.d.ts +2 -1
  26. package/build/descriptors/errors/index.js +3 -3
  27. package/build/descriptors/index.d.ts +3 -3
  28. package/build/descriptors/types/index.d.ts +2 -2
  29. package/build/descriptors/types/index.js +7 -6
  30. package/build/index.d.ts +14 -18
  31. package/build/index.js +21 -16
  32. package/build/types/index.d.ts +141 -29
  33. package/build/types/index.js +1 -1
  34. package/build/utils/collectConstructors.js +1 -1
  35. package/build/utils/extract.d.ts +2 -2
  36. package/build/utils/extract.js +1 -1
  37. package/build/utils/index.d.ts +1 -1
  38. package/build/utils/index.js +1 -1
  39. package/build/utils/merge.d.ts +1 -1
  40. package/build/utils/merge.js +4 -3
  41. package/build/utils/parent.d.ts +1 -1
  42. package/build/utils/parent.js +1 -1
  43. package/build/utils/parse.d.ts +12 -1
  44. package/build/utils/parse.js +11 -6
  45. package/build/utils/pick.d.ts +2 -2
  46. package/build/utils/pick.js +3 -2
  47. package/build/utils/toJSON.js +1 -1
  48. package/package.json +19 -19
package/README.md CHANGED
@@ -1,5 +1,6 @@
1
- # mnemonica is
2
- abstract technique that aids information retention : instance inheritance system
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
  [![Coverage Status](https://coveralls.io/repos/github/wentout/mnemonica/badge.svg?branch=master)](https://coveralls.io/github/wentout/mnemonica?branch=master)
20
-
21
21
  ![NPM](https://img.shields.io/npm/l/mnemonica)
22
22
  ![GitHub package.json version](https://img.shields.io/github/package-json/v/wentout/mnemonica)
23
23
  ![GitHub last commit](https://img.shields.io/github/last-commit/wentout/mnemonica)
24
-
25
24
  [![NPM](https://nodei.co/npm/mnemonica.png?mini=true)](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
- # core concept
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
- **define** function now fully supports TypeScript definitions
50
+ ## Overview
42
51
 
43
- for more easy types writing nested~sub constructors might be applied using just direct apply, call or bind functions
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
- ## Factory of Constructors
56
+ > *"O Great Mnemosyne! Please! Save us from Oblivion..."*
57
+ >
58
+ > — from the source, where memory persists
47
59
 
48
- As we discrovered from that article, we need some tooling, giving us the best experience with Prototype Chain Inheritance pattern. First of all it must be reproducible and maintainable. And from the first point we have to define some sort of Factory Constructor for start crafting our Instances, it might look like so:
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
- ```js
51
- const { define } = require('mnemonica');
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
- const TypeModificationProcedure = function (opts) {
54
- Object.assign(this, opts);
55
- };
72
+ ---
56
73
 
57
- // SomeTypeConstructor -- is a constructor.name
58
- const SomeType = define('SomeTypeConstructor',
59
- TypeModificationProcedure,
60
- );
74
+ ## Installation
61
75
 
76
+ ```bash
77
+ npm install mnemonica
62
78
  ```
63
79
 
64
- Or, we can define `SomeType` like this:
80
+ **Requirements:** Node.js >=16 <24
65
81
 
66
- ```js
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
- const SomeType = define(TypeModificationConstructorFactory);
85
- ```
84
+ ## Quick Start
86
85
 
87
- Or using Classes:
86
+ ### CommonJS
88
87
 
89
88
  ```js
90
- const TypeModificationConstructorFactory = () => {
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
- ```js
119
- SomeType.define('SomeSubType', function (opts) {
120
- const {
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
- // or, absolutely equal
134
- SomeType.SomeSubType = function (opts) {
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
- Let's create an instance, using `SomeType` construtor, we earlier.
164
-
165
- ```js
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
- At this moment all stored data will inherit from `someTypeInstance` to `someSubTypeInstance`. Moreover, `someSubTypeInstance` become instanceof `SomeType` and `SomeSubType` and, let's go deeper, instance of `someTypeInstance`.
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
- ![Inheritance of someSubTypeInstance](https://raw.githubusercontent.com/mythographica/stash/master/img/doc.example.png)
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
- But this is not the end... it might be discouraging, but this is only the begining.
116
+ ---
277
117
 
278
- ## How do we use defined "mnemonicas"
118
+ ## Core Concepts
279
119
 
280
- Suppose we have to handle the `request.data` somewhere in our code and we have to consume it someelsewhere. Let's imagine us inside of **[ETL process](https://en.wikipedia.org/wiki/Extract,_transform,_load)**.
120
+ ### Factory of Constructors
281
121
 
282
- Let's create Constructor for this sort of data.
122
+ Define types using constructors, factory functions, or classes:
283
123
 
284
124
  ```js
285
- const RequestDataTypeModificator =
286
- define('RequestData',
287
- FactoryOfRequestHandlerCostructor);
288
- ```
125
+ // Using a constructor function
126
+ const SomeType = define('SomeType', function (opts) {
127
+ Object.assign(this, opts);
128
+ });
289
129
 
290
- Then we will use it in our code like this:
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
- ```js
293
- (req, res) => {
294
- const requestInstance =
295
- RequestDataTypeModificator(req.body);
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
- And then it might be necessary to jump to the next part of code, which cooperate with some Storage or Daba Base.
150
+ ### Nested Type Definition
300
151
 
301
152
  ```js
302
- const GoneToTheDataBase =
303
- RequestDataTypeModificator.
304
- // jumped data definition
305
- define('GoneToTheDataBase',
306
- DataBaseRequestHandlerCostructor);
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
- ```js
314
- // callback will be called Before requestInstance creation
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
- RequestDataTypeModificator
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
- Thouse hooks will be proceeded if you register them... for each instance you will craft using `RequestDataTypeModificator`. So if you wish to investigate instances of `GoneToTheDataBase` type modificator then you have to register the other hooks for it:
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
- GoneToTheDataBase
379
- .registerHook(
380
- 'preCreation', // ...
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
- And even more. You can use Hooks with Types Collections also (starting from v0.3.1). For doing this just grab referer to collection somewhere, for example:
391
-
188
+ Extract all inherited properties into a flat object:
392
189
 
393
190
  ```js
394
- const {
395
- defaultTypes
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
- As we can see, type hooks are closest one to the type itself. For sure, there can be situations, when you have to register some common hooks, but not for `typecollection`. Assume you have some friendly types, might be from different collections, and you have to register the same hooks definitions for them. And the plase where you wish to do this is the file, other than files you defined that types. There you can use:
431
-
432
- # .lookup('TypeName')
433
-
434
- ```js
435
- const {
436
- lookup
437
- } = require('mnemonica');
199
+ ---
438
200
 
439
- const SomeType = lookup('SomeType');
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
- And now it is not so necessary easy to explain why it could be usefull to use nested definitions. Sure you can do them by using the following technique:
205
+ ```typescript
206
+ import { define, apply, call, bind } from 'mnemonica';
445
207
 
446
- ```js
208
+ interface UserData {
209
+ email: string;
210
+ password: string;
211
+ }
447
212
 
448
- define('SomeExistentType.SomeExistentNestedType.NewType', function () {
449
- // operators
213
+ const UserType = define('UserType', function (this: UserData, data: UserData) {
214
+ Object.assign(this, data);
450
215
  });
451
216
 
452
- // or from tm descriptor
453
- // if you have reference
454
- SomeExistentType.define('SomeExistentNestedType.NewType', function () {
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
- // you can also use
221
+ For complex nested types, use `apply`, `call`, or `bind` for better type inference:
459
222
 
460
- SomeExistentType.define('SomeExistentNestedType', () => {
461
- // name of "NewType" is here
462
- // nested inside of delcaration
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
- # .parent('TypeName')
232
+ ### Exported Type Definitions
473
233
 
474
- Let assume our `instance` has indeed deep prototype chain:
234
+ The following types are available for advanced TypeScript usage:
475
235
 
476
- ```js
477
- EvenMore
478
- .MoreOver
479
- .OverMore
480
- // ...
481
- // ...
482
- .InitialType
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
- And we wish to get reference to one of the prececessors, though we have only reference to insance itself. Here we can use builtin `instance.parent()` method:
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
- # SomeType.call ( this_obj, ...args)
501
- You can combine existing TypeConstructor with any instance, even with Singletones:
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
- const root = document.getElementById("root");
527
- usingReactAsProto.render("just works", root);
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
- # call, apply & bind ( existent, ItsNestedType, ...args)
533
-
534
- mostly for TypeScript purpose you may do this
535
-
536
- ```js
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
- const SomeSubType = SomeType
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
- // or for delayed construction
557
- const someSubInstanceConstructor =
558
- bind( someInstance, SomeSubType );
312
+ ## API Reference
559
313
 
560
- const someSubInstance = someSubInstanceConstructor(...args);
314
+ ### Core Functions
561
315
 
562
- ```
316
+ #### `define(typeName, constructHandler, config?)`
563
317
 
564
- # Asynchronous Constructors
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 AsyncType = define('AsyncType', async function (data) {
570
- return Object.assign(this, {
571
- data
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
- Also nothing will warn you from doing this for SubTypes:
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
- ```js
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
- Also for the first instance in chain you can do for example inherit from singletone:
336
+ Looks up a type by its nested path.
605
337
 
606
338
  ```js
607
- const asyncCalledInstance = await AsyncType
608
- .call(process, 'wat');
609
- // or
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
- # Asynch Chain & single await
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
- Here we have a lot of unnecessary variables. Though we can combine our chain using `.then()` or simpy brakets `(await ...)`, but it will definetely looks weird:
346
+ Applies a constructor to an entity with an array of arguments.
649
347
 
650
348
  ```js
651
- async (req, res) => {
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
- And with using `.then()` of general promises it will look much more badly, even over than "callback hell".
353
+ #### `call(entity, Constructor, ...args)`
677
354
 
678
- And, if so, starting from `v.0.5.8` we are able to use async chains for async constructors:
355
+ Calls a constructor on an entity with spread arguments.
679
356
 
680
357
  ```js
681
- async (req, res) => {
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
- ## `.__parent__`
725
- If instance is nested, then it is a reference of it's parent.
362
+ #### `bind(entity, Constructor)`
726
363
 
727
- ## `.__subtypes__`
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
- // the following equals
753
- A.fork.call(B, ...args);
754
- A.fork.apply(B, [args]);
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
- ## mnemonica.utils.merge(A, B, ...args)
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
- # ESM Support
768
- Starting from v0.6.8 you can try to import ESM using the following scenario:
376
+ ```typescript
377
+ import { decorate } from 'mnemonica';
769
378
 
770
- ```js
771
- import { define, lookup } from 'mnemonica/module';
772
- ```
379
+ @decorate()
380
+ class MyClass {
381
+ field: number = 123;
382
+ }
773
383
 
774
- # Config Options
384
+ // With configuration
385
+ @decorate({ strictChain: false })
386
+ class ConfiguredClass {
387
+ // ...
388
+ }
775
389
 
776
- While making `define` we can provide some config data about how instance should be created, default values and descriptions are below:
390
+ // Nested decoration
391
+ @decorate()
392
+ class ParentClass {}
777
393
 
778
- ```js
779
- define('SomeType', function () {}, {}, {
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
- Also you can override default config options for Types Collection. For example, after doing so all types that have no own config will fall without any error:
398
+ #### `registerHook(Constructor, hookType, callback)`
807
399
 
808
- ```js
809
- import {
810
- defaultTypes,
811
- SymbolConfig
812
- } from 'mnemonica';
400
+ Registers a hook for a specific constructor.
813
401
 
814
- defaultTypes[SymbolConfig].blockErrors = false;
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
- # API Reference
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
- ## Core Functions
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
- ### `call(entity, Constructor, ...args)`
834
- Calls a constructor on an entity with spread arguments.
438
+ ### Type Management
835
439
 
836
- ### `bind(entity, Constructor)`
837
- Binds a constructor to an entity, returning a function that can be called later.
440
+ #### `defaultTypes`
838
441
 
839
- ### `registerHook(Constructor, hookType, callback)`
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
- ## Type Management
444
+ ```js
445
+ const { defaultTypes } = require('mnemonica');
446
+ const MyType = defaultTypes.MyType;
447
+ ```
843
448
 
844
- ### `defaultTypes`
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
- ### `getProps(instance)` / `setProps(instance, values)`
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
- ## Instance Methods
473
+ ---
474
+
475
+ ### Instance Methods
865
476
 
866
477
  All mnemonica instances have the following methods:
867
478
 
868
- ### `.extract()`
479
+ #### `.extract()`
480
+
869
481
  Extracts all inherited properties into a single flat object.
870
482
 
871
- ### `.pick(...keys)` / `.pick([keys])`
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
- ### `.parent(constructorName?)`
881
- Gets the parent instance. If `constructorName` is provided, walks up the chain to find that specific parent.
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
- ### `.clone`
889
- Property that returns a cloned instance (same as `.fork()` with no arguments).
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
- ### `.fork(...args)`
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(); // same args
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
- ### `.fork.call(thisArg, ...args)` / `.fork.apply(thisArg, args)`
900
- Forks with a different `this` context (useful for DAG construction).
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
- ### `.exception(error, ...args)`
907
- Creates an exception instance from the current instance. Useful for typed errors.
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
- ### `.sibling(typeName)` / `.sibling.TypeName`
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
- ## Utils
551
+ ---
552
+
553
+ ### Instance Properties (via `getProps`)
925
554
 
926
- ### `utils.extract(instance)`
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
- ### `utils.pick(instance, ...keys)`
582
+ #### `utils.pick(instance, ...keys)`
930
583
  Standalone pick function.
931
584
 
932
- ### `utils.parent(instance, constructorName?)`
585
+ #### `utils.parent(instance, constructorName?)`
933
586
  Standalone parent function.
934
587
 
935
- ### `utils.parse(instance)`
936
- Parses an instance structure, returning detailed information about:
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
- ### `utils.merge(A, B, ...args)`
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
- ### `utils.toJSON(instance)`
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
- ### `utils.collectConstructors(instance, flat?)`
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
- ## Instance Properties (via getProps)
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
- ## Hooks
626
+ ### Hooks
987
627
 
988
- ### Hook Types
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
- ### `type.registerHook(hookType, callback)`
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
- console.log('Creating:', hookData.TypeName);
640
+ console.log('Creating:', hookData.TypeName);
1000
641
  });
1001
642
  ```
1002
643
 
1003
- ### `collection.registerHook(hookType, callback)`
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
- console.log('Created:', hookData.inheritedInstance.constructor.name);
650
+ console.log('Created:', hookData.inheritedInstance.constructor.name);
1009
651
  });
1010
652
  ```
1011
653
 
1012
- ### `collection.registerFlowChecker(callback)`
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
- // Perform validation or logging
1018
- console.log('Flow check:', opts.TypeName);
660
+ console.log('Flow check:', opts.TypeName);
1019
661
  });
1020
662
  ```
1021
663
 
1022
- ### Hook Data Structure
664
+ #### Hook Data Structure
1023
665
 
1024
- ```js
1025
- {
1026
- TypeName: string, // Constructor name
1027
- argumentsOfTypeModificator: [], // Arguments passed
1028
- instanceUsedForInheritance: {}, // Parent instance
1029
- inheritedInstance: {} // Newly created instance (postCreation only)
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
- ## Error Handling
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
- ### `errors` Object
688
+ ### Error Handling
1036
689
 
1037
- All mnemonica errors are accessible via the `errors` export:
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
- ### Exception Instances
714
+ #### Exception Instances
1060
715
 
1061
- When you create an exception using `instance.exception()`, the resulting error has special properties:
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
- ## Symbols
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
- Mnemonica exports the following symbols:
738
+ ---
739
+
740
+ ### Symbols & Constants
1077
741
 
1078
742
  ```js
1079
743
  const {
1080
- SymbolParentType, // Parent type symbol
1081
- SymbolConstructorName, // Constructor name symbol
1082
- SymbolDefaultTypesCollection, // Default collection symbol
1083
- SymbolConfig // Config symbol
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
- ## TypeScript Types
753
+ ---
1088
754
 
1089
- The following types are exported for TypeScript users:
755
+ ## Configuration Options
1090
756
 
1091
- ```typescript
1092
- import {
1093
- IDEF, // Constructor function type
1094
- ConstructorFunction, // Constructor with prototype
1095
- TypeLookup, // Lookup function type
1096
- TypeClass, // Type class interface
1097
- TypeAbsorber, // Type absorber type
1098
- ITypeClass, // Typed class interface
1099
- IDefinitorInstance, // Definitor instance type
1100
- hooksTypes, // 'preCreation' | 'postCreation' | 'creationError'
1101
- hooksOpts, // Hook options type
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
- ## Decorator API
770
+ ### Override Default Config for Collection
1108
771
 
1109
- The `decorate` function provides TypeScript decorator support:
772
+ ```js
773
+ import { defaultTypes, SymbolConfig } from 'mnemonica';
1110
774
 
1111
- ### Basic Usage
775
+ defaultTypes[SymbolConfig].blockErrors = false;
776
+ ```
1112
777
 
1113
- ```typescript
1114
- import { decorate } from 'mnemonica';
778
+ ---
1115
779
 
1116
- @decorate()
1117
- class MyClass {
1118
- field: number;
1119
- constructor() {
1120
- this.field = 123;
1121
- }
1122
- }
780
+ ## AI Agent Usage Guide
1123
781
 
1124
- const instance = new MyClass();
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
- ### With Configuration
795
+ ### 2. Safe Property Access
1128
796
 
1129
- ```typescript
1130
- @decorate({ strictChain: false, blockErrors: true })
1131
- class MyClass {
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
- ### Nested Decoration
806
+ ### 3. Type Discovery
1137
807
 
1138
- ```typescript
1139
- @decorate()
1140
- class ParentClass {
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
- @decorate(ParentClass, { strictChain: false })
1145
- class ChildClass {
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
- const parent = new ParentClass();
1150
- const child = apply(parent, ChildClass);
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
- ### Decorator as Function
869
+ ### 6. Analyzing Type Structure
1154
870
 
1155
- Decorated classes can be used as decorators themselves:
871
+ ```js
872
+ const { getProps } = require('mnemonica');
1156
873
 
1157
- ```typescript
1158
- @decorate()
1159
- class Base {
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
- @Base() // Use Base as a decorator
1164
- class Extended {
1165
- // ...
1166
- }
885
+ ### 7. Working with Collections
1167
886
 
1168
- const base = new Base();
1169
- const extended = apply(base, Extended);
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
- ## Configuration Options Reference
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
- | Option | Type | Default | Description |
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
- ## finally
928
+ ### Async Chain with Single Await
1184
929
 
1185
- So, now you can craft as much types as you wish, combine them, re-define them and spend much more time playing with them:
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 .parse them using `mnemonica.utils.parse`:
1193
-
1194
- ![Inheritance of someSubTypeInstance](https://raw.githubusercontent.com/mythographica/stash/master/img/doc.example.parse.png)
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