mnemonica 0.9.99777 → 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 (49) hide show
  1. package/README.md +704 -545
  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 +21 -11
  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 +3 -3
  22. package/build/api/utils/index.js +13 -5
  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/index.js +5 -2
  29. package/build/descriptors/types/index.d.ts +2 -2
  30. package/build/descriptors/types/index.js +7 -6
  31. package/build/index.d.ts +15 -16
  32. package/build/index.js +47 -27
  33. package/build/types/index.d.ts +141 -29
  34. package/build/types/index.js +1 -1
  35. package/build/utils/collectConstructors.js +1 -1
  36. package/build/utils/extract.d.ts +2 -2
  37. package/build/utils/extract.js +1 -1
  38. package/build/utils/index.d.ts +1 -1
  39. package/build/utils/index.js +9 -7
  40. package/build/utils/merge.d.ts +1 -1
  41. package/build/utils/merge.js +4 -3
  42. package/build/utils/parent.d.ts +1 -1
  43. package/build/utils/parent.js +1 -1
  44. package/build/utils/parse.d.ts +12 -1
  45. package/build/utils/parse.js +12 -7
  46. package/build/utils/pick.d.ts +2 -2
  47. package/build/utils/pick.js +3 -2
  48. package/build/utils/toJSON.js +1 -1
  49. package/package.json +22 -21
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,823 +11,981 @@ 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)
47
+
48
+ ---
49
+
50
+ ## Overview
29
51
 
30
- # core concept
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.
31
53
 
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:
54
+ Think of it as a mathematical function `f(x) => y` where `this` is your persistent data structure and transformations are applied sequentially.
33
55
 
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)
56
+ > *"O Great Mnemosyne! Please! Save us from Oblivion..."*
57
+ > from the source, where memory persists
37
58
 
59
+ ![concept](https://raw.githubusercontent.com/mythographica/stash/master/img/LifeCycle/LifeCycle.png)
60
+
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
38
67
 
39
- ## TypeScript note
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)
40
72
 
41
- **define** function now fully supports TypeScript definitions
73
+ ---
42
74
 
43
- for more easy types writing nested~sub constructors might be applied using just direct apply, call or bind functions
75
+ ## Installation
44
76
 
77
+ ```bash
78
+ npm install mnemonica
79
+ ```
80
+
81
+ **Requirements:** Node.js >=16 <24
82
+
83
+ ---
45
84
 
46
- ## Factory of Constructors
85
+ ## Quick Start
47
86
 
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:
87
+ ### CommonJS
49
88
 
50
89
  ```js
51
90
  const { define } = require('mnemonica');
52
91
 
53
- const TypeModificationProcedure = function (opts) {
54
- Object.assign(this, opts);
55
- };
92
+ // Define a type
93
+ const UserType = define('UserType', function (data) {
94
+ Object.assign(this, data);
95
+ });
56
96
 
57
- // SomeTypeConstructor -- is a constructor.name
58
- const SomeType = define('SomeTypeConstructor',
59
- TypeModificationProcedure,
60
- );
97
+ // Create an instance
98
+ const user = new UserType({ name: 'John', email: 'john@example.com' });
99
+
100
+ // Define a subtype
101
+ const AdminType = UserType.define('AdminType', function () {
102
+ this.role = 'admin';
103
+ });
61
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)
62
109
  ```
63
110
 
64
- Or, we can define `SomeType` like this:
111
+ ### ESM
65
112
 
66
113
  ```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';
114
+ import { define, lookup } from 'mnemonica/module';
115
+ ```
80
116
 
81
- return SomeTypeConstructor;
82
- };
117
+ ---
83
118
 
84
- const SomeType = define(TypeModificationConstructorFactory);
85
- ```
86
-
87
- Or using Classes:
88
-
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
- };
119
+ ## Core Concepts
120
+
121
+ ### Factory of Constructors
122
+
123
+ Define types using constructors, factory functions, or classes:
124
+
125
+ ```js
126
+ // Using a constructor function
127
+ const SomeType = define('SomeType', function (opts) {
128
+ Object.assign(this, opts);
129
+ });
112
130
 
113
- const SomeType = define(TypeModificationConstructorFactory);
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
+ });
139
+
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
+ });
114
149
  ```
115
150
 
116
- Then we can define some nested type, using our crafted `SomeType` definition:
151
+ ### Nested Type Definition
117
152
 
118
153
  ```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;
154
+ // Define nested types
155
+ SomeType.define('SubType', function (opts) {
156
+ this.other = opts.other;
129
157
  }, {
130
- description : 'SomeSubType Constructor'
158
+ description: 'SomeSubType Constructor'
131
159
  });
132
160
 
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;
161
+ // Or using assignment
162
+ SomeType.SubType = function (opts) {
163
+ this.other = opts.other;
144
164
  };
145
- SomeType.SomeSubType.prototype = {
146
- description : 'SomeSubType Constructor'
165
+ SomeType.SubType.prototype = {
166
+ description: 'SomeSubType Constructor'
147
167
  };
148
168
  ```
149
169
 
150
- Now our type modification chain looks like this:
170
+ ### Instance Creation and Inheritance
151
171
 
152
172
  ```js
153
- // 1.
154
- SomeType
155
- // 1.1
156
- .SomeSubType;
157
- ```
173
+ const someInstance = new SomeType({
174
+ some: 'arguments',
175
+ data: 'necessary'
176
+ });
177
+
178
+ const subInstance = new someInstance.SubType({
179
+ other: 'data needed'
180
+ });
158
181
 
159
- And we can continue nesting sub-types as far as it might be necessary for our code and our software architecture... :^)
182
+ // All properties are inherited
183
+ console.log(subInstance.some); // 'arguments' (inherited)
184
+ console.log(subInstance.other); // 'data needed' (own)
185
+ ```
160
186
 
161
- ## **How it Works then**
187
+ ### The `.extract()` Method
162
188
 
163
- Let's create an instance, using `SomeType` construtor, we earlier.
189
+ Extract all inherited properties into a flat object:
164
190
 
165
191
  ```js
166
- const someTypeInstance = new SomeType({
167
- some : 'arguments',
168
- data : 'necessary',
169
- inside : 'of SomeType definition'
170
- });
192
+ const extracted = subInstance.extract();
193
+ // Result: { data, description, other, some }
194
+
195
+ // Or use the standalone utility
196
+ const { utils: { extract } } = require('mnemonica');
197
+ const extracted2 = extract(subInstance);
171
198
  ```
172
199
 
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.
200
+ ---
174
201
 
175
- ```js
202
+ ## TypeScript Support
176
203
 
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
- });
204
+ The `define` function has full TypeScript support with comprehensive type definitions:
196
205
 
197
- ```
206
+ ```typescript
207
+ import { define, apply, call, bind } from 'mnemonica';
198
208
 
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`.
209
+ interface UserData {
210
+ email: string;
211
+ password: string;
212
+ }
200
213
 
214
+ const UserType = define('UserType', function (this: UserData, data: UserData) {
215
+ Object.assign(this, data);
216
+ });
201
217
 
202
- And now let's ponder on our Instances:
218
+ // Nested constructors work with apply/call/bind for type inference
219
+ const user = new UserType({ email: 'test@test.com', password: 'secret' });
220
+ ```
203
221
 
204
- ```js
222
+ For complex nested types, use `apply`, `call`, or `bind` for better type inference:
205
223
 
206
- console.log(someTypeInstance);
224
+ ```typescript
225
+ const SomeSubType = SomeType.define('SomeSubType', function (...args: string[]) {
226
+ // ...
227
+ });
207
228
 
208
- some : 'arguments'
209
- data : 'necessary'
210
- inside : 'of SomeType definition'
229
+ const someInstance = new SomeType();
230
+ const subInstance = call(someInstance, SomeSubType, 'arg1', 'arg2');
231
+ ```
211
232
 
212
- console.log(someSubTypeInstance);
233
+ ### Exported Type Definitions
213
234
 
214
- other : 'data needed'
215
- inside : ' of ... etc ...'
235
+ The following types are available for advanced TypeScript usage:
216
236
 
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';
217
267
  ```
218
268
 
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** ...
269
+ ### Generic Type Patterns
220
270
 
221
- # .extract()
271
+ Define types with proper generic constraints for full type safety:
222
272
 
223
- So, here is a situation we need all previously defined props and all the nested props collected to the one-same object:
273
+ ```typescript
274
+ // Using IDEF with interface definitions
275
+ interface UserData {
276
+ email: string;
277
+ password: string;
278
+ }
224
279
 
225
- ```js
280
+ // Type-safe constructor with 'this' context
281
+ const UserType = define('UserType', function (this: UserData, data: UserData) {
282
+ Object.assign(this, data);
283
+ });
284
+
285
+ // Type-safe nested types with merged interfaces
286
+ interface AdminData {
287
+ role: string;
288
+ }
226
289
 
227
- const extracted = someSubTypeInstance.extract();
290
+ const AdminType = UserType.define('AdminType', function (this: UserData & AdminData, role: string) {
291
+ this.role = role;
292
+ this.email; // string - inherited from UserData
293
+ });
294
+ ```
228
295
 
229
- console.log(extracted);
296
+ ### Async Constructor Type Patterns
230
297
 
231
- data : "necessary"
232
- description : "SomeSubType Constructor"
233
- inside : " of ... etc ..."
234
- other : "data needed"
235
- some : "arguments"
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 });
303
+ });
236
304
 
305
+ // With explicit awaitReturn option (no return required)
306
+ const AsyncTypeNoReturn = define('AsyncType', async function () {
307
+ // No return needed
308
+ }, { awaitReturn: false });
237
309
  ```
238
310
 
239
- or, with the same behaviour:
311
+ ---
240
312
 
241
- ```js
242
- const { extract } = require('mnemonica').utils;
243
- const extracted = extract(someSubTypeInstance);
313
+ ## API Reference
244
314
 
245
- data : "necessary"
246
- description : "SomeSubType Constructor"
247
- inside : " of ... etc ..."
248
- other : "data needed"
249
- some : "arguments"
315
+ ### Core Functions
250
316
 
251
- console.log(extract(someTypeInstance));
317
+ #### `define(typeName, constructHandler, config?)`
252
318
 
253
- data : "necessary"
254
- description : "SomeType Constructor"
255
- inside : "of SomeType definition"
256
- some : "arguments"
319
+ Defines a new type constructor. Returns a TypeClass.
257
320
 
321
+ ```js
322
+ const MyType = define('MyType', function (data) {
323
+ Object.assign(this, data);
324
+ }, {
325
+ strictChain: true,
326
+ blockErrors: true
327
+ });
258
328
  ```
259
329
 
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):
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
261
334
 
262
- ![Inheritance of someSubTypeInstance](https://raw.githubusercontent.com/mythographica/stash/master/img/doc.example.png)
335
+ #### `lookup(typeNestedPath)`
263
336
 
264
- And back to definitions, for sure, all of the following is true:
337
+ Looks up a type by its nested path.
265
338
 
266
339
  ```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
-
340
+ const { lookup } = require('mnemonica');
341
+ const SomeType = lookup('SomeType');
342
+ const SomeNestedType = lookup('SomeType.SomeNestedType');
274
343
  ```
275
344
 
276
- But this is not the end... it might be discouraging, but this is only the begining.
277
-
278
- ## How do we use defined "mnemonicas"
345
+ #### `apply(entity, Constructor, args?)`
279
346
 
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)**.
281
-
282
- Let's create Constructor for this sort of data.
347
+ Applies a constructor to an entity with an array of arguments.
283
348
 
284
349
  ```js
285
- const RequestDataTypeModificator =
286
- define('RequestData',
287
- FactoryOfRequestHandlerCostructor);
350
+ const { apply } = require('mnemonica');
351
+ const subInstance = apply(parentInstance, SubType, ['arg1', 'arg2']);
288
352
  ```
289
353
 
290
- Then we will use it in our code like this:
354
+ #### `call(entity, Constructor, ...args)`
355
+
356
+ Calls a constructor on an entity with spread arguments.
291
357
 
292
358
  ```js
293
- (req, res) => {
294
- const requestInstance =
295
- RequestDataTypeModificator(req.body);
296
- };
359
+ const { call } = require('mnemonica');
360
+ const subInstance = call(parentInstance, SubType, 'arg1', 'arg2');
297
361
  ```
298
362
 
299
- And then it might be necessary to jump to the next part of code, which cooperate with some Storage or Daba Base.
363
+ #### `bind(entity, Constructor)`
364
+
365
+ Binds a constructor to an entity, returning a function.
300
366
 
301
367
  ```js
302
- const GoneToTheDataBase =
303
- RequestDataTypeModificator.
304
- // jumped data definition
305
- define('GoneToTheDataBase',
306
- DataBaseRequestHandlerCostructor);
368
+ const { bind } = require('mnemonica');
369
+ const createSub = bind(parentInstance, SubType);
370
+ const subInstance = createSub('arg1', 'arg2');
307
371
  ```
308
372
 
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...
373
+ #### `decorate(target?, config?)`
310
374
 
311
- # Pre & Post creation Hooks
375
+ TypeScript decorator for class-based definitions.
312
376
 
313
- ```js
314
- // callback will be called Before requestInstance creation
377
+ ```typescript
378
+ import { decorate } from 'mnemonica';
315
379
 
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
334
- };
380
+ @decorate()
381
+ class MyClass {
382
+ field: number = 123;
383
+ }
335
384
 
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
365
- };
385
+ // With configuration
386
+ @decorate({ strictChain: false })
387
+ class ConfiguredClass {
388
+ // ...
389
+ }
366
390
 
367
- // callback will be called After requestInstance creation
368
- RequestDataTypeModificator
369
- .registerHook(
370
- 'postCreation',
371
- postCreationCallback);
391
+ // Nested decoration
392
+ @decorate()
393
+ class ParentClass {}
394
+
395
+ @decorate(ParentClass)
396
+ class ChildClass {}
372
397
  ```
373
398
 
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:
399
+ #### `registerHook(Constructor, hookType, callback)`
375
400
 
376
- ```js
401
+ Registers a hook for a specific constructor.
377
402
 
378
- GoneToTheDataBase
379
- .registerHook(
380
- 'preCreation', // ...
381
-
382
- GoneToTheDataBase
383
- .registerHook(
384
- 'postCreation', // ...
385
-
403
+ ```js
404
+ const { registerHook } = require('mnemonica');
386
405
 
406
+ registerHook(MyType, 'preCreation', (hookData) => {
407
+ console.log('Creating:', hookData.TypeName);
408
+ });
387
409
  ```
388
410
 
411
+ ---
412
+
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.
436
+
437
+ ---
438
+
439
+ ### Type Management
389
440
 
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:
441
+ #### `defaultTypes`
391
442
 
443
+ The default types collection. All types defined with the top-level `define()` are stored here.
392
444
 
393
445
  ```js
394
- const {
395
- defaultTypes
396
- } = require('mnemonica');
446
+ const { defaultTypes } = require('mnemonica');
447
+ const MyType = defaultTypes.MyType;
448
+ ```
397
449
 
398
- defaultTypes
399
- .registerHook(
400
- 'preCreation', preCreationTypesCollectionCallback);
401
-
402
- defaultTypes
403
- .registerHook(
404
- 'postCreation', postCreationTypesCollectionCallback);
450
+ #### `createTypesCollection(config?)`
405
451
 
452
+ Creates a new isolated types collection.
406
453
 
454
+ ```js
455
+ const { createTypesCollection } = require('mnemonica');
456
+ const myCollection = createTypesCollection();
457
+ const MyType = myCollection.define('MyType', function () {});
407
458
  ```
408
459
 
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:
460
+ #### `getProps(instance)` / `setProps(instance, values)`
461
+
462
+ Get or set internal properties of an instance.
410
463
 
411
464
  ```js
465
+ const { getProps, setProps } = require('mnemonica');
412
466
 
413
- // 1.
414
- typecollection.invokeHook('preCreation', // ...
467
+ const props = getProps(instance);
468
+ console.log(props.__type__, props.__args__);
415
469
 
416
- // 2.
417
- type.invokeHook('preCreation', // ...
470
+ // Set properties
471
+ setProps(instance, { __timestamp__: Date.now() });
472
+ ```
418
473
 
419
- // 3. instance creation is here
474
+ ---
420
475
 
421
- // 4.
422
- type.invokeHook('postCreation', // ...
476
+ ### Instance Methods
423
477
 
424
- // 5.
425
- typecollection.invokeHook('postCreation', // ...
478
+ All mnemonica instances have the following methods:
426
479
 
480
+ #### `.extract()`
427
481
 
482
+ Extracts all inherited properties into a single flat object.
483
+
484
+ ```js
485
+ const extracted = instance.extract();
428
486
  ```
429
487
 
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:
488
+ #### `.pick(...keys)` / `.pick([keys])`
431
489
 
432
- # .lookup('TypeName')
490
+ Picks specific properties from the instance and its inheritance chain.
433
491
 
434
492
  ```js
435
- const {
436
- lookup
437
- } = require('mnemonica');
493
+ const picked = instance.pick('email', 'password');
494
+ // or
495
+ const picked = instance.pick(['email', 'password']);
496
+ ```
438
497
 
439
- const SomeType = lookup('SomeType');
440
- const SomeNestedType = lookup('SomeType.SomeNestedType');
498
+ #### `.parent(constructorName?)`
499
+
500
+ Gets the parent instance. If `constructorName` is provided, walks up the chain.
441
501
 
502
+ ```js
503
+ const immediateParent = instance.parent();
504
+ const specificParent = instance.parent('UserType');
442
505
  ```
443
506
 
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:
507
+ #### `.clone`
508
+
509
+ Property that returns a cloned instance (same parent, same args).
445
510
 
446
511
  ```js
512
+ const cloned = instance.clone;
513
+ // Note: For async constructors, use: await instance.clone
514
+ ```
447
515
 
448
- define('SomeExistentType.SomeExistentNestedType.NewType', function () {
449
- // operators
450
- });
516
+ #### `.fork(...args)`
451
517
 
452
- // or from tm descriptor
453
- // if you have reference
454
- SomeExistentType.define('SomeExistentNestedType.NewType', function () {
455
- // operators
456
- });
518
+ Creates a forked instance from the same parent with optional new arguments.
457
519
 
458
- // you can also use
520
+ ```js
521
+ const forked = instance.fork(); // same args
522
+ const forkedWithNewArgs = instance.fork('new', 'args');
523
+ // Note: For async constructors, use: await instance.fork(...)
524
+ ```
459
525
 
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
- };
468
- });
526
+ #### `.fork.call(thisArg, ...args)` / `.fork.apply(thisArg, args)`
469
527
 
528
+ Forks with a different `this` context (useful for Directed Acyclic Graphs).
529
+
530
+ ```js
531
+ const dagInstance = instanceA.fork.call(instanceB, 'args');
470
532
  ```
471
533
 
472
- # .parent('TypeName')
534
+ #### `.exception(error, ...args)`
473
535
 
474
- Let assume our `instance` has indeed deep prototype chain:
536
+ Creates an exception instance from the current instance.
475
537
 
476
538
  ```js
477
- EvenMore
478
- .MoreOver
479
- .OverMore
480
- // ...
481
- // ...
482
- .InitialType
539
+ const error = someInstance.exception(new Error('Something went wrong'));
540
+ throw error;
483
541
  ```
484
542
 
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:
543
+ #### `.sibling(typeName)` / `.sibling.TypeName`
544
+
545
+ Access sibling types from the same collection.
486
546
 
487
547
  ```js
548
+ const siblingType = instance.sibling('OtherType');
549
+ const sibling = instance.sibling.OtherType;
550
+ ```
488
551
 
489
- // fisrst parent
490
- // simply equal to getProps(instance).__parent__
491
- const parent = instance.parent();
552
+ ---
492
553
 
493
- // deep parent from chain
494
- const parent = instance
495
- .parent( 'DeepParentName' );
554
+ ### Instance Properties (via `getProps`)
496
555
 
497
- ```
556
+ All instances have non-enumerable internal properties:
498
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 |
499
569
 
500
- # SomeType.call ( this_obj, ...args)
501
- You can combine existing TypeConstructor with any instance, even with Singletones:
570
+ ---
502
571
 
503
- ```js
504
- const usingProcessAsProto = Singletoned.call(process, {
505
- some : 'arguments',
506
- data : 'necessary',
507
- inside : 'for definition'
508
- });
509
- console.log(typeof instanceUsingProcessSingletone.on) // function
510
- ```
572
+ ### Utilities
511
573
 
512
- or you can combine with window, or document or...
574
+ Access via `utils` export:
513
575
 
514
576
  ```js
577
+ const { utils } = require('mnemonica');
578
+ ```
515
579
 
516
- const usingWindowAsProto = Windowed.call(window);
517
- const usingDocumentAsProto = Documented.call(document);
518
- const usingJQueryAsProto = JQueried.call(jQuery);
580
+ #### `utils.extract(instance)`
581
+ Standalone extract function.
519
582
 
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);
583
+ #### `utils.pick(instance, ...keys)`
584
+ Standalone pick function.
525
585
 
526
- const root = document.getElementById("root");
527
- usingReactAsProto.render("just works", root);
586
+ #### `utils.parent(instance, constructorName?)`
587
+ Standalone parent function.
528
588
 
589
+ #### `utils.parse(instance)`
590
+ Parses an instance structure, returning:
591
+ - `name`: constructor name
592
+ - `props`: extracted properties
593
+ - `self`: the instance itself
594
+ - `proto`: prototype object
595
+ - `joint`: prototype properties
596
+ - `parent`: parent prototype
597
+
598
+ ```js
599
+ const { utils: { parse } } = require('mnemonica');
600
+ const parsed = parse(instance);
529
601
  ```
530
602
 
603
+ #### `utils.merge(A, B, ...args)`
604
+ Merges two instances using fork semantics.
531
605
 
532
- # call, apply & bind ( existent, ItsNestedType, ...args)
606
+ ```js
607
+ const merged = utils.merge(instanceA, instanceB, 'args');
608
+ // Note: For async constructors, use: await utils.merge(...)
609
+ ```
533
610
 
534
- mostly for TypeScript purpose you may do this
611
+ #### `utils.toJSON(instance)`
612
+ Serializes an instance to JSON.
535
613
 
536
614
  ```js
537
- const SomeType = define('SomeType', function () {
538
- // ...
539
- });
615
+ const json = utils.toJSON(instance);
616
+ ```
540
617
 
618
+ #### `utils.collectConstructors(instance, flat?)`
619
+ Collects all constructors in the instance's prototype chain.
541
620
 
542
- const SomeSubType = SomeType
543
- .define('SomeSubType', function (...args) {
544
- // ...
545
- });
621
+ ```js
622
+ const constructors = utils.collectConstructors(instance, true);
623
+ ```
546
624
 
547
- const someInstance = new SomeType;
625
+ ---
548
626
 
549
- const someSubInstance = call(
550
- someInstance, SomeSubType, ...args);
627
+ ### Hooks
551
628
 
552
- // or for array of args
553
- const someSubInstance = apply(
554
- someInstance, SomeSubType, args);
629
+ #### Hook Types
555
630
 
556
- // or for delayed construction
557
- const someSubInstanceConstructor =
558
- bind( someInstance, SomeSubType );
631
+ - `'preCreation'` - Called before instance creation
632
+ - `'postCreation'` - Called after instance creation
633
+ - `'creationError'` - Called when instance creation throws an error
559
634
 
560
- const someSubInstance = someSubInstanceConstructor(...args);
635
+ #### `type.registerHook(hookType, callback)`
561
636
 
637
+ Register a hook on a specific type.
638
+
639
+ ```js
640
+ MyType.registerHook('preCreation', (hookData) => {
641
+ console.log('Creating:', hookData.TypeName);
642
+ });
562
643
  ```
563
644
 
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:
645
+ #### `collection.registerHook(hookType, callback)`
646
+
647
+ Register a hook on a types collection.
567
648
 
568
649
  ```js
569
- const AsyncType = define('AsyncType', async function (data) {
570
- return Object.assign(this, {
571
- data
572
- });
650
+ defaultTypes.registerHook('postCreation', (hookData) => {
651
+ console.log('Created:', hookData.inheritedInstance.constructor.name);
573
652
  });
653
+ ```
574
654
 
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
- };
655
+ #### `collection.registerFlowChecker(callback)`
580
656
 
581
- asyncCall();
657
+ Register a flow checker that runs before hooks.
658
+
659
+ ```js
660
+ defaultTypes.registerFlowChecker((opts) => {
661
+ console.log('Flow check:', opts.TypeName);
662
+ });
582
663
  ```
583
664
 
584
- Also nothing will warn you from doing this for SubTypes:
665
+ #### Hook Data Structure
666
+
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
675
+ }
676
+ ```
585
677
 
586
678
  ```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
- });
679
+ MyType.registerHook('postCreation', (hookData) => {
680
+ // Throw custom error from hook
681
+ hookData.throwModificationError(new Error('Custom hook error'));
682
+ });
683
+ ```
595
684
 
596
- const nestedAsyncTypeInstance = await new
597
- asyncConstructedInstance.NestedAsyncType('boom');
685
+ **Note:** In preCreation hooks, `existentInstance` refers to the parent; in postCreation hooks, it refers to the instance used for inheritance.
598
686
 
599
- console.log(nestedAsyncTypeInstance instanceof AsyncType) // true
600
- console.log(nestedAsyncTypeInstance instanceof NestedAsyncType) // true
601
- console.log(nestedAsyncTypeInstance.description); // 'async of nested'
602
- ```
687
+ ---
688
+
689
+ ### Error Handling
603
690
 
604
- Also for the first instance in chain you can do for example inherit from singletone:
691
+ #### Error Types
692
+
693
+ All mnemonica errors extend `BASE_MNEMONICA_ERROR`:
605
694
 
606
695
  ```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
696
+ const { errors } = require('mnemonica');
697
+
698
+ // Available error types:
699
+ errors.BASE_MNEMONICA_ERROR
700
+ errors.WRONG_TYPE_DEFINITION
701
+ errors.WRONG_INSTANCE_INVOCATION
702
+ errors.WRONG_MODIFICATION_PATTERN
703
+ errors.ALREADY_DECLARED
704
+ errors.TYPENAME_MUST_BE_A_STRING
705
+ errors.HANDLER_MUST_BE_A_FUNCTION
706
+ errors.WRONG_ARGUMENTS_USED
707
+ errors.WRONG_HOOK_TYPE
708
+ errors.MISSING_HOOK_CALLBACK
709
+ errors.MISSING_CALLBACK_ARGUMENT
710
+ errors.FLOW_CHECKER_REDEFINITION
711
+ errors.OPTIONS_ERROR
712
+ errors.WRONG_STACK_CLEANER
614
713
  ```
615
714
 
616
- # Asynch Chain & single await
715
+ #### Exception Instances
617
716
 
618
- Let for example suppose you need the following code:
717
+ When creating exceptions using `instance.exception()`:
619
718
 
620
719
  ```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
- };
720
+ const error = instance.exception(new Error('Original error'));
721
+
722
+ // Properties:
723
+ error.originalError // The original error
724
+ error.exceptionReason // { methodName, ... }
725
+ error.BaseStack // Base stack trace
726
+ error.parse() // Parse the exception structure
727
+ error.extract() // Extract properties from the exception
646
728
  ```
647
729
 
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:
730
+ #### Stack Cleaning
649
731
 
650
732
  ```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
- };
733
+ const { defineStackCleaner } = require('mnemonica');
734
+
735
+ // Add regex patterns to clean stack traces
736
+ defineStackCleaner(/node_modules\/some-package/);
674
737
  ```
675
738
 
676
- And with using `.then()` of general promises it will look much more badly, even over than "callback hell".
739
+ ---
677
740
 
678
- And, if so, starting from `v.0.5.8` we are able to use async chains for async constructors:
741
+ ### Symbols & Constants
679
742
 
680
743
  ```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
- };
744
+ const {
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
751
+ } = require('mnemonica');
700
752
  ```
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
753
 
703
- ## require('util').callbackify
754
+ ---
704
755
 
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.
756
+ ## Configuration Options
706
757
 
758
+ Pass options as the third argument to `define()`:
707
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
+ });
769
+ ```
708
770
 
709
- # Instance Properties
771
+ ### Override Default Config for Collection
710
772
 
711
- Also starting from `v0.3.8` the following non enumerable props are availiable from instance itself (`instance.hasOwnProperty(__prop__)`):
773
+ ```js
774
+ import { defaultTypes, SymbolConfig } from 'mnemonica';
712
775
 
713
- ## Breaking Changes for 0.9.995
776
+ defaultTypes[SymbolConfig].blockErrors = false;
777
+ ```
714
778
 
715
- ### all props below available from `getProps(instance)` :
779
+ ---
716
780
 
717
- ## `.__args__`
781
+ ## AI Agent Usage Guide
718
782
 
719
- Arguments, used for calling instance creation constructor.
783
+ This section helps AI agents understand and work with mnemonica programmatically.
720
784
 
721
- ## `.__type__`
722
- The definition of instance type.
785
+ ### 1. Type Introspection
723
786
 
724
- ## `.__parent__`
725
- If instance is nested, then it is a reference of it's parent.
787
+ Use `utils.parse(instance)` to understand instance structure:
726
788
 
727
- ## `.__subtypes__`
728
- What you can craft from this instance accordingly with it's defined Type, the same as `__type__.subtypes`.
789
+ ```js
790
+ const { utils: { parse } } = require('mnemonica');
729
791
 
730
- ## `.__collection__`
731
- Collection of types where `__type__` was defined.
792
+ const parsed = parse(instance);
793
+ // Returns: { name, props, self, proto, joint, parent, constructor }
794
+ ```
732
795
 
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.
796
+ ### 2. Safe Property Access
797
+
798
+ Always use `getProps()` instead of direct property access:
799
+
800
+ ```js
801
+ const { getProps } = require('mnemonica');
735
802
 
736
- _Note_: if you are cloning instance, which has `async Constructor`, you should `await` it;
803
+ const props = getProps(instance);
804
+ // props.__type__, props.__args__, props.__parent__, props.__subtypes__, etc.
805
+ ```
737
806
 
807
+ ### 3. Type Discovery
738
808
 
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.
809
+ ```js
810
+ const { defaultTypes } = require('mnemonica');
741
811
 
742
- _Note_: if you are forking instance, which has `async Constructor`, you should `await` it;
812
+ // List all types in default collection
813
+ const typeNames = [...defaultTypes.subtypes.keys()];
743
814
 
815
+ // List subtypes of a specific type
816
+ const myType = defaultTypes.MyType;
817
+ const subTypeNames = [...myType.subtypes.keys()];
744
818
 
745
- # Directed Acyclic Graphs
819
+ // Check if a type exists
820
+ const hasType = defaultTypes.lookup('MyType') !== undefined;
821
+ ```
746
822
 
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:
823
+ ### 4. Instance Traversal
750
824
 
751
825
  ```js
752
- // the following equals
753
- A.fork.call(B, ...args);
754
- A.fork.apply(B, [args]);
755
- A.fork.bind(B)(...args);
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;
847
+ }
756
848
  ```
757
- _Note_: if you are `fork.clone`'ing instance, which has `async Constructor`, you should `await` it;
758
849
 
850
+ ### 5. Safe Construction Patterns
759
851
 
760
- ## mnemonica.utils.merge(A, B, ...args)
761
- The same as `fork.call` but providing instsnces directly.
852
+ ```js
853
+ const { lookup } = require('mnemonica');
762
854
 
763
- _Note_: if you are `merge`'ing instances, where A.constructor is `async Constructor`, you should `await` it;
855
+ // Always check if type exists before construction
856
+ const MyType = lookup('MyType');
857
+ if (MyType) {
858
+ const instance = new MyType(data);
859
+ }
764
860
 
765
- ---
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
+ }
868
+ ```
766
869
 
767
- # ESM Support
768
- Starting from v0.6.8 you can try to import ESM using the following scenario:
870
+ ### 6. Analyzing Type Structure
769
871
 
770
872
  ```js
771
- import { define, lookup } from 'mnemonica/module';
772
- ```
873
+ const { getProps } = require('mnemonica');
773
874
 
774
- # Config Options
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
+ };
883
+ }
884
+ ```
775
885
 
776
- While making `define` we can provide some config data about how instance should be created, default values and descriptions are below:
886
+ ### 7. Working with Collections
777
887
 
778
888
  ```js
779
- define('SomeType', function () {}, {}, {
889
+ const { createTypesCollection, defaultTypes } = require('mnemonica');
780
890
 
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,
891
+ // Create isolated collection for testing
892
+ const testCollection = createTypesCollection({
893
+ strictChain: false,
894
+ blockErrors: false
895
+ });
785
896
 
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,
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
+ });
904
+ ```
905
+
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
+ });
792
917
 
793
- // if it is necessary to collect stack
794
- // as a __stack__ prototype property
795
- // during the process of instance creation
796
- submitStack: false,
918
+ // Usage
919
+ const asyncInstance = await new AsyncType('tada');
797
920
 
798
- // await new Constructor()
799
- // must return value
800
- // optional ./issues/106
801
- awaitReturn: true,
921
+ // Nested async types
922
+ const NestedAsync = AsyncType.define('NestedAsync', async function (data) {
923
+ return Object.assign(this, { nestedData: data });
924
+ });
802
925
 
803
- })
926
+ const nested = await new asyncInstance.NestedAsync('nested');
804
927
  ```
805
928
 
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:
929
+ ### Async Chain with Single Await
807
930
 
808
931
  ```js
809
- import {
810
- defaultTypes,
811
- SymbolConfig
812
- } from 'mnemonica';
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
+ ```
813
945
 
814
- defaultTypes[SymbolConfig].blockErrors = false;
946
+ ### Using `call` with Existing Objects
815
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);
816
958
  ```
817
959
 
960
+ ### Directed Acyclic Graphs (DAG)
961
+
962
+ ```js
963
+ // Fork from different parent
964
+ const dagInstance = instanceA.fork.call(instanceB, 'args');
818
965
 
819
- # finally
966
+ // Or use merge utility
967
+ const { utils: { merge } } = require('mnemonica');
968
+ const merged = merge(instanceA, instanceB, 'args');
969
+ ```
970
+
971
+ ---
820
972
 
821
- So, now you can craft as much types as you wish, combine them, re-define them and spend much more time playing with them:
973
+ ## Epilogue
822
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:
823
976
 
824
977
  * test : instances & arguments
825
978
  * track : moments of creation
826
979
  * check : if the order of creation is OK
827
980
  * validate : everything, 4 example use sort of TS in runtime
828
- * and even .parse them using `mnemonica.utils.parse`:
829
-
830
- ![Inheritance of someSubTypeInstance](https://raw.githubusercontent.com/mythographica/stash/master/img/doc.example.parse.png)
981
+ * and even `.parse` them using `mnemonica.utils.parse`
831
982
 
832
983
  Good Luck!
984
+
985
+ ---
986
+
987
+ ## License
988
+
989
+ MIT
990
+
991
+ Copyright (c) 2019 https://github.com/wentout