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.
Files changed (48) hide show
  1. package/README.md +622 -827
  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,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
  [![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
-
48
+ ---
38
49
 
39
- ## TypeScript note
50
+ ## Overview
40
51
 
41
- **define** function now fully supports TypeScript definitions
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
- for more easy types writing nested~sub constructors might be applied using just direct apply, call or bind functions
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
- ## Factory of Constructors
59
+ ![concept](https://raw.githubusercontent.com/mythographica/stash/master/img/LifeCycle/LifeCycle.png)
47
60
 
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:
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
- ```js
51
- const { define } = require('mnemonica');
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
- const TypeModificationProcedure = function (opts) {
54
- Object.assign(this, opts);
55
- };
73
+ ---
56
74
 
57
- // SomeTypeConstructor -- is a constructor.name
58
- const SomeType = define('SomeTypeConstructor',
59
- TypeModificationProcedure,
60
- );
75
+ ## Installation
61
76
 
77
+ ```bash
78
+ npm install mnemonica
62
79
  ```
63
80
 
64
- Or, we can define `SomeType` like this:
81
+ **Requirements:** Node.js >=16 <24
65
82
 
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
- };
83
+ ---
83
84
 
84
- const SomeType = define(TypeModificationConstructorFactory);
85
- ```
85
+ ## Quick Start
86
86
 
87
- Or using Classes:
87
+ ### CommonJS
88
88
 
89
89
  ```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:
90
+ const { define } = require('mnemonica');
117
91
 
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'
92
+ // Define a type
93
+ const UserType = define('UserType', function (data) {
94
+ Object.assign(this, data);
131
95
  });
132
96
 
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**
97
+ // Create an instance
98
+ const user = new UserType({ name: 'John', email: 'john@example.com' });
162
99
 
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'
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
- 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:
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
- ![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
-
114
+ import { define, lookup } from 'mnemonica/module';
274
115
  ```
275
116
 
276
- But this is not the end... it might be discouraging, but this is only the begining.
117
+ ---
277
118
 
278
- ## How do we use defined "mnemonicas"
119
+ ## Core Concepts
279
120
 
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)**.
121
+ ### Factory of Constructors
281
122
 
282
- Let's create Constructor for this sort of data.
123
+ Define types using constructors, factory functions, or classes:
283
124
 
284
125
  ```js
285
- const RequestDataTypeModificator =
286
- define('RequestData',
287
- FactoryOfRequestHandlerCostructor);
288
- ```
126
+ // Using a constructor function
127
+ const SomeType = define('SomeType', function (opts) {
128
+ Object.assign(this, opts);
129
+ });
289
130
 
290
- Then we will use it in our code like this:
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
- ```js
293
- (req, res) => {
294
- const requestInstance =
295
- RequestDataTypeModificator(req.body);
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
- And then it might be necessary to jump to the next part of code, which cooperate with some Storage or Daba Base.
151
+ ### Nested Type Definition
300
152
 
301
153
  ```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
154
+ // Define nested types
155
+ SomeType.define('SubType', function (opts) {
156
+ this.other = opts.other;
157
+ }, {
158
+ description: 'SomeSubType Constructor'
159
+ });
312
160
 
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
161
+ // Or using assignment
162
+ SomeType.SubType = function (opts) {
163
+ this.other = opts.other;
334
164
  };
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
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
- 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:
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
- GoneToTheDataBase
379
- .registerHook(
380
- 'preCreation', // ...
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
- 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
-
189
+ Extract all inherited properties into a flat object:
392
190
 
393
191
  ```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
-
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
- 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');
200
+ ---
438
201
 
439
- const SomeType = lookup('SomeType');
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
- 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:
206
+ ```typescript
207
+ import { define, apply, call, bind } from 'mnemonica';
445
208
 
446
- ```js
209
+ interface UserData {
210
+ email: string;
211
+ password: string;
212
+ }
447
213
 
448
- define('SomeExistentType.SomeExistentNestedType.NewType', function () {
449
- // operators
214
+ const UserType = define('UserType', function (this: UserData, data: UserData) {
215
+ Object.assign(this, data);
450
216
  });
451
217
 
452
- // or from tm descriptor
453
- // if you have reference
454
- SomeExistentType.define('SomeExistentNestedType.NewType', function () {
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
- // you can also use
222
+ For complex nested types, use `apply`, `call`, or `bind` for better type inference:
459
223
 
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
- };
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
- # .parent('TypeName')
233
+ ### Exported Type Definitions
473
234
 
474
- Let assume our `instance` has indeed deep prototype chain:
235
+ The following types are available for advanced TypeScript usage:
475
236
 
476
- ```js
477
- EvenMore
478
- .MoreOver
479
- .OverMore
480
- // ...
481
- // ...
482
- .InitialType
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
- 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' );
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
- # 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'
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
- const root = document.getElementById("root");
527
- usingReactAsProto.render("just works", root);
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
- # 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
- // ...
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
- 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);
311
+ ---
555
312
 
556
- // or for delayed construction
557
- const someSubInstanceConstructor =
558
- bind( someInstance, SomeSubType );
313
+ ## API Reference
559
314
 
560
- const someSubInstance = someSubInstanceConstructor(...args);
315
+ ### Core Functions
561
316
 
562
- ```
317
+ #### `define(typeName, constructHandler, config?)`
563
318
 
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:
319
+ Defines a new type constructor. Returns a TypeClass.
567
320
 
568
321
  ```js
569
- const AsyncType = define('AsyncType', async function (data) {
570
- return Object.assign(this, {
571
- data
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
- Also nothing will warn you from doing this for SubTypes:
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
- ```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
- ```
335
+ #### `lookup(typeNestedPath)`
603
336
 
604
- Also for the first instance in chain you can do for example inherit from singletone:
337
+ Looks up a type by its nested path.
605
338
 
606
339
  ```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
340
+ const { lookup } = require('mnemonica');
341
+ const SomeType = lookup('SomeType');
342
+ const SomeNestedType = lookup('SomeType.SomeNestedType');
614
343
  ```
615
344
 
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
- ```
345
+ #### `apply(entity, Constructor, args?)`
647
346
 
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:
347
+ Applies a constructor to an entity with an array of arguments.
649
348
 
650
349
  ```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
- };
350
+ const { apply } = require('mnemonica');
351
+ const subInstance = apply(parentInstance, SubType, ['arg1', 'arg2']);
674
352
  ```
675
353
 
676
- And with using `.then()` of general promises it will look much more badly, even over than "callback hell".
354
+ #### `call(entity, Constructor, ...args)`
677
355
 
678
- And, if so, starting from `v.0.5.8` we are able to use async chains for async constructors:
356
+ Calls a constructor on an entity with spread arguments.
679
357
 
680
358
  ```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
- };
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
- ## `.__parent__`
725
- If instance is nested, then it is a reference of it's parent.
363
+ #### `bind(entity, Constructor)`
726
364
 
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:
365
+ Binds a constructor to an entity, returning a function.
750
366
 
751
367
  ```js
752
- // the following equals
753
- A.fork.call(B, ...args);
754
- A.fork.apply(B, [args]);
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
- ## 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
- ---
375
+ TypeScript decorator for class-based definitions.
766
376
 
767
- # ESM Support
768
- Starting from v0.6.8 you can try to import ESM using the following scenario:
377
+ ```typescript
378
+ import { decorate } from 'mnemonica';
769
379
 
770
- ```js
771
- import { define, lookup } from 'mnemonica/module';
772
- ```
380
+ @decorate()
381
+ class MyClass {
382
+ field: number = 123;
383
+ }
773
384
 
774
- # Config Options
385
+ // With configuration
386
+ @decorate({ strictChain: false })
387
+ class ConfiguredClass {
388
+ // ...
389
+ }
775
390
 
776
- While making `define` we can provide some config data about how instance should be created, default values and descriptions are below:
391
+ // Nested decoration
392
+ @decorate()
393
+ class ParentClass {}
777
394
 
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
- })
395
+ @decorate(ParentClass)
396
+ class ChildClass {}
804
397
  ```
805
398
 
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:
399
+ #### `registerHook(Constructor, hookType, callback)`
807
400
 
808
- ```js
809
- import {
810
- defaultTypes,
811
- SymbolConfig
812
- } from 'mnemonica';
401
+ Registers a hook for a specific constructor.
813
402
 
814
- defaultTypes[SymbolConfig].blockErrors = false;
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
- # API Reference
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
- ## 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.
437
+ ---
832
438
 
833
- ### `call(entity, Constructor, ...args)`
834
- Calls a constructor on an entity with spread arguments.
439
+ ### Type Management
835
440
 
836
- ### `bind(entity, Constructor)`
837
- Binds a constructor to an entity, returning a function that can be called later.
441
+ #### `defaultTypes`
838
442
 
839
- ### `registerHook(Constructor, hookType, callback)`
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
- ## Type Management
445
+ ```js
446
+ const { defaultTypes } = require('mnemonica');
447
+ const MyType = defaultTypes.MyType;
448
+ ```
843
449
 
844
- ### `defaultTypes`
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
- ### `getProps(instance)` / `setProps(instance, values)`
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
- ## Instance Methods
474
+ ---
475
+
476
+ ### Instance Methods
865
477
 
866
478
  All mnemonica instances have the following methods:
867
479
 
868
- ### `.extract()`
480
+ #### `.extract()`
481
+
869
482
  Extracts all inherited properties into a single flat object.
870
483
 
871
- ### `.pick(...keys)` / `.pick([keys])`
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
- ### `.parent(constructorName?)`
881
- Gets the parent instance. If `constructorName` is provided, walks up the chain to find that specific parent.
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
- ### `.clone`
889
- Property that returns a cloned instance (same as `.fork()` with no arguments).
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
- ### `.fork(...args)`
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(); // same args
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
- ### `.fork.call(thisArg, ...args)` / `.fork.apply(thisArg, args)`
900
- Forks with a different `this` context (useful for DAG construction).
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
- ### `.exception(error, ...args)`
907
- Creates an exception instance from the current instance. Useful for typed errors.
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
- ### `.sibling(typeName)` / `.sibling.TypeName`
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
- ## Utils
552
+ ---
553
+
554
+ ### Instance Properties (via `getProps`)
925
555
 
926
- ### `utils.extract(instance)`
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
- ### `utils.pick(instance, ...keys)`
583
+ #### `utils.pick(instance, ...keys)`
930
584
  Standalone pick function.
931
585
 
932
- ### `utils.parent(instance, constructorName?)`
586
+ #### `utils.parent(instance, constructorName?)`
933
587
  Standalone parent function.
934
588
 
935
- ### `utils.parse(instance)`
936
- Parses an instance structure, returning detailed information about:
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
- ### `utils.merge(A, B, ...args)`
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
- ### `utils.toJSON(instance)`
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
- ### `utils.collectConstructors(instance, flat?)`
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
- ## 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 |
625
+ ---
985
626
 
986
- ## Hooks
627
+ ### Hooks
987
628
 
988
- ### Hook Types
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
- ### `type.registerHook(hookType, callback)`
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
- console.log('Creating:', hookData.TypeName);
641
+ console.log('Creating:', hookData.TypeName);
1000
642
  });
1001
643
  ```
1002
644
 
1003
- ### `collection.registerHook(hookType, callback)`
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
- console.log('Created:', hookData.inheritedInstance.constructor.name);
651
+ console.log('Created:', hookData.inheritedInstance.constructor.name);
1009
652
  });
1010
653
  ```
1011
654
 
1012
- ### `collection.registerFlowChecker(callback)`
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
- // Perform validation or logging
1018
- console.log('Flow check:', opts.TypeName);
661
+ console.log('Flow check:', opts.TypeName);
1019
662
  });
1020
663
  ```
1021
664
 
1022
- ### Hook Data Structure
665
+ #### Hook Data Structure
1023
666
 
1024
- ```js
1025
- {
1026
- TypeName: string, // Constructor name
1027
- argumentsOfTypeModificator: [], // Arguments passed
1028
- instanceUsedForInheritance: {}, // Parent instance
1029
- inheritedInstance: {} // Newly created instance (postCreation only)
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
- ## Error Handling
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
- ### `errors` Object
689
+ ### Error Handling
1036
690
 
1037
- All mnemonica errors are accessible via the `errors` export:
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
- ### Exception Instances
715
+ #### Exception Instances
1060
716
 
1061
- When you create an exception using `instance.exception()`, the resulting error has special properties:
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
- ## Symbols
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
- Mnemonica exports the following symbols:
739
+ ---
740
+
741
+ ### Symbols & Constants
1077
742
 
1078
743
  ```js
1079
744
  const {
1080
- SymbolParentType, // Parent type symbol
1081
- SymbolConstructorName, // Constructor name symbol
1082
- SymbolDefaultTypesCollection, // Default collection symbol
1083
- SymbolConfig // Config symbol
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
- ## TypeScript Types
754
+ ---
1088
755
 
1089
- The following types are exported for TypeScript users:
756
+ ## Configuration Options
1090
757
 
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';
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
- ## Decorator API
771
+ ### Override Default Config for Collection
1108
772
 
1109
- The `decorate` function provides TypeScript decorator support:
773
+ ```js
774
+ import { defaultTypes, SymbolConfig } from 'mnemonica';
1110
775
 
1111
- ### Basic Usage
776
+ defaultTypes[SymbolConfig].blockErrors = false;
777
+ ```
1112
778
 
1113
- ```typescript
1114
- import { decorate } from 'mnemonica';
779
+ ---
1115
780
 
1116
- @decorate()
1117
- class MyClass {
1118
- field: number;
1119
- constructor() {
1120
- this.field = 123;
1121
- }
1122
- }
781
+ ## AI Agent Usage Guide
1123
782
 
1124
- const instance = new MyClass();
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
- ### With Configuration
796
+ ### 2. Safe Property Access
1128
797
 
1129
- ```typescript
1130
- @decorate({ strictChain: false, blockErrors: true })
1131
- class MyClass {
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
- ### Nested Decoration
807
+ ### 3. Type Discovery
1137
808
 
1138
- ```typescript
1139
- @decorate()
1140
- class ParentClass {
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
- @decorate(ParentClass, { strictChain: false })
1145
- class ChildClass {
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
- const parent = new ParentClass();
1150
- const child = apply(parent, ChildClass);
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
- ### Decorator as Function
870
+ ### 6. Analyzing Type Structure
1154
871
 
1155
- Decorated classes can be used as decorators themselves:
872
+ ```js
873
+ const { getProps } = require('mnemonica');
1156
874
 
1157
- ```typescript
1158
- @decorate()
1159
- class Base {
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
- @Base() // Use Base as a decorator
1164
- class Extended {
1165
- // ...
1166
- }
886
+ ### 7. Working with Collections
1167
887
 
1168
- const base = new Base();
1169
- const extended = apply(base, Extended);
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
- ## Configuration Options Reference
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
- | 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) |
926
+ const nested = await new asyncInstance.NestedAsync('nested');
927
+ ```
1182
928
 
1183
- ## finally
929
+ ### Async Chain with Single Await
1184
930
 
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:
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 .parse them using `mnemonica.utils.parse`:
1193
-
1194
- ![Inheritance of someSubTypeInstance](https://raw.githubusercontent.com/mythographica/stash/master/img/doc.example.parse.png)
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