mnemonica 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.ai/AGENTS.md +1 -1
- package/.ai/ONBOARDING.md +2 -1
- package/.ai/PROTOTYPE-CHAIN.md +122 -0
- package/.ai/TACTICA-DEEP-DIVE.md +52 -49
- package/.ai/TACTICA-RULES.md +8 -8
- package/.ai/rules-skill/lookup-typed.md +17 -19
- package/AGENTS.md +19 -13
- package/CONTRIBUTING.md +1 -1
- package/FOR_HUMANS.md +51 -20
- package/README.md +14 -12
- package/SKILL.md +4 -4
- package/build/api/types/createInstanceModificator.js +1 -1
- package/build/descriptors/types/index.js +1 -1
- package/build/index.d.ts +6 -7
- package/build/index.js +6 -13
- package/build/types/index.d.ts +25 -2
- package/build/types/index.js +1 -1
- package/build/utils/parent.d.ts +4 -1
- package/build/utils/parent.js +5 -6
- package/docs/UTILS.md +1 -1
- package/docs/ai-learning-trajectory.md +8 -8
- package/docs/async-constructors.md +18 -0
- package/docs/prototype-chain.md +127 -0
- package/docs/purpose.md +4 -4
- package/docs/tactica-pattern.md +10 -10
- package/docs/typed-lookup.md +19 -15
- package/module/index.js +0 -1
- package/package.json +2 -1
- package/src/api/types/createInstanceModificator.ts +13 -0
- package/src/descriptors/types/index.ts +1 -1
- package/src/index.ts +35 -53
- package/src/types/index.ts +88 -2
- package/src/utils/parent.ts +13 -2
package/src/index.ts
CHANGED
|
@@ -14,7 +14,6 @@ import type {
|
|
|
14
14
|
TypeClass,
|
|
15
15
|
TypeAbsorber,
|
|
16
16
|
MnemonicaModule,
|
|
17
|
-
TypeConstructor,
|
|
18
17
|
InstanceResult,
|
|
19
18
|
Merge
|
|
20
19
|
} from './types';
|
|
@@ -26,9 +25,37 @@ export const {
|
|
|
26
25
|
} = TypesUtils;
|
|
27
26
|
|
|
28
27
|
export type {
|
|
29
|
-
IDEF, TypeConstructor,
|
|
28
|
+
IDEF, TypeConstructor, TypeConstructorBase,
|
|
29
|
+
InstanceOfTypeRegistry, LiteralKeysOf, ParentPath, PathOfInstance,
|
|
30
|
+
AllParentPrefixes, ParentPathOfInstance,
|
|
31
|
+
_Internal_TC_, Proto, ProtoFlat,
|
|
30
32
|
hooksOpts, hook, hooksTypes, TypesCollection
|
|
31
33
|
} from './types';
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Type-safe registry for mnemonica types.
|
|
37
|
+
*
|
|
38
|
+
* This interface starts empty. Application code or `@mnemonica/tactica`
|
|
39
|
+
* augments it through TypeScript module declaration merging:
|
|
40
|
+
*
|
|
41
|
+
* ```ts
|
|
42
|
+
* declare module 'mnemonica' {
|
|
43
|
+
* interface TypeRegistry {
|
|
44
|
+
* 'MyType': TypeConstructor<MyTypeInstance>;
|
|
45
|
+
* 'MyType.SubType': TypeConstructor<SubTypeInstance>;
|
|
46
|
+
* }
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* Once augmented, `lookup('MyType')` and `utils.parent(instance, 'MyType')`
|
|
51
|
+
* resolve keys against this registry. Unaugmented keys fall back to the broad
|
|
52
|
+
* `TypeClass | undefined` return type.
|
|
53
|
+
*/
|
|
54
|
+
export interface TypeRegistry {
|
|
55
|
+
// Intentionally empty. Augment this interface via declaration merging
|
|
56
|
+
// (hand-written or generated by @mnemonica/tactica) to enable typed
|
|
57
|
+
// utilities like lookup() and parent().
|
|
58
|
+
}
|
|
32
59
|
export {
|
|
33
60
|
getProps, setProps
|
|
34
61
|
} from './api/types/Props';
|
|
@@ -78,7 +105,12 @@ export const define = function <
|
|
|
78
105
|
return defineResult;
|
|
79
106
|
} as TypeAbsorber;
|
|
80
107
|
|
|
81
|
-
export
|
|
108
|
+
export function lookup<const K extends keyof TypeRegistry>(
|
|
109
|
+
this: unknown,
|
|
110
|
+
TypeNestedPath: K
|
|
111
|
+
): TypeRegistry[K] | undefined;
|
|
112
|
+
export function lookup(this: unknown, TypeNestedPath: string): TypeClass | undefined;
|
|
113
|
+
export function lookup(
|
|
82
114
|
this: unknown,
|
|
83
115
|
TypeNestedPath: string
|
|
84
116
|
): TypeClass | undefined {
|
|
@@ -86,58 +118,8 @@ export const lookup = function (
|
|
|
86
118
|
// Type assertion needed because TypesCollectionProxy is a Proxy
|
|
87
119
|
const lookupResult = (types as { lookup: (path: string) => TypeClass | undefined }).lookup(TypeNestedPath);
|
|
88
120
|
return lookupResult;
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Default TypeRegistry interface - augment this in your project via
|
|
93
|
-
* TypeScript declaration merging. The augmentation can be hand-written
|
|
94
|
-
* in a .d.ts file (small projects) or generated by @mnemonica/tactica.
|
|
95
|
-
*
|
|
96
|
-
* Uses `TypeConstructor<never>` as the index value type to enforce
|
|
97
|
-
* augmentation: without it, any key lookup resolves to a useless type
|
|
98
|
-
* because `TypeConstructor<never>` is not assignable to concrete types.
|
|
99
|
-
*
|
|
100
|
-
* Example (in a hand-written .d.ts, or generated by tactica in
|
|
101
|
-
* .tactica/registry.ts):
|
|
102
|
-
* declare module 'mnemonica' {
|
|
103
|
-
* interface TypeRegistry {
|
|
104
|
-
* 'MyType': new (...args: unknown[]) => MyTypeInstance;
|
|
105
|
-
* }
|
|
106
|
-
* }
|
|
107
|
-
*
|
|
108
|
-
* See docs/typed-lookup.md for both paths side by side.
|
|
109
|
-
*/
|
|
110
|
-
export interface TypeRegistry {
|
|
111
|
-
[key: string]: TypeConstructor<never>;
|
|
112
121
|
}
|
|
113
122
|
|
|
114
|
-
/**
|
|
115
|
-
* Type-safe lookup function. Requires a TypeRegistry augmentation —
|
|
116
|
-
* hand-written in a .d.ts (small projects) or generated by
|
|
117
|
-
* @mnemonica/tactica (auto-synced from your define() calls).
|
|
118
|
-
*
|
|
119
|
-
* At runtime this delegates to lookup(). The type safety is
|
|
120
|
-
* compile-time only: TypeScript resolves the key against the augmented
|
|
121
|
-
* TypeRegistry and returns the constructor's type signature.
|
|
122
|
-
*
|
|
123
|
-
* Usage (once TypeRegistry is augmented):
|
|
124
|
-
* const SomeType = lookupTyped('SomeType');
|
|
125
|
-
* const instance = new SomeType({ ... }); // Full type safety!
|
|
126
|
-
*
|
|
127
|
-
* See docs/typed-lookup.md for both augmentation paths side by side.
|
|
128
|
-
*/
|
|
129
|
-
export const lookupTyped = function <
|
|
130
|
-
const K extends keyof TypeRegistry
|
|
131
|
-
>(
|
|
132
|
-
this: unknown,
|
|
133
|
-
TypeNestedPath: K
|
|
134
|
-
): TypeRegistry[K] {
|
|
135
|
-
const types = checkThis(this) ? defaultTypes : this || defaultTypes;
|
|
136
|
-
const lookupResult = (types as { lookup: (path: string) => unknown })
|
|
137
|
-
.lookup(TypeNestedPath as string) as TypeRegistry[K];
|
|
138
|
-
return lookupResult;
|
|
139
|
-
};
|
|
140
|
-
|
|
141
123
|
|
|
142
124
|
const $run = function <E extends object, T extends object, S extends Proto<E, T>>(
|
|
143
125
|
entity: E,
|
package/src/types/index.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
/* eslint no-unused-vars: "off" */
|
|
3
3
|
|
|
4
|
+
import type { TypeRegistry } from '../index';
|
|
5
|
+
|
|
4
6
|
// Props type for getProps/setProps
|
|
5
7
|
export type PropsType = Record<string, unknown>;
|
|
6
8
|
|
|
@@ -78,6 +80,79 @@ export interface _Internal_TC_<ConstructorInstance extends object> {
|
|
|
78
80
|
*/
|
|
79
81
|
export type TypeConstructor<ConstructorInstance extends object> = _Internal_TC_<ConstructorInstance>;
|
|
80
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Minimal constructor shape used for the TypeRegistry index signature.
|
|
85
|
+
* It accepts any mnemonica-compatible constructor, but deliberately returns
|
|
86
|
+
* `object` so unaugmented registry lookups are not useful without an explicit
|
|
87
|
+
* per-key constructor type.
|
|
88
|
+
*/
|
|
89
|
+
export interface TypeConstructorBase {
|
|
90
|
+
new (...args: unknown[]): object;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Instance type produced by a TypeRegistry constructor.
|
|
95
|
+
*/
|
|
96
|
+
export type InstanceOfTypeRegistry<K extends keyof TypeRegistry> =
|
|
97
|
+
TypeRegistry[K] extends new (...args: unknown[]) => infer R ? R : never;
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Extract only the literal string keys of a type, filtering out generic
|
|
102
|
+
* index signatures. This lets us iterate over augmented TypeRegistry keys
|
|
103
|
+
* without picking up the `[key: string]` signature.
|
|
104
|
+
*/
|
|
105
|
+
export type LiteralKeysOf<T> = keyof T extends infer K
|
|
106
|
+
? K extends string
|
|
107
|
+
? string extends K ? never : K
|
|
108
|
+
: never
|
|
109
|
+
: never;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Given a dotted TypeRegistry key, extract the parent path.
|
|
113
|
+
* `ParentPath<'A.B.C'>` → `'A.B'`.
|
|
114
|
+
*/
|
|
115
|
+
export type ParentPath<K extends string> =
|
|
116
|
+
K extends `${infer P}.${string}` ? P : never;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Given a dotted TypeRegistry key, return the union of all ancestor prefixes.
|
|
120
|
+
* `AllParentPrefixes<'A.B.C'>` → `'A' | 'A.B'`.
|
|
121
|
+
*/
|
|
122
|
+
export type AllParentPrefixes<K extends string> =
|
|
123
|
+
K extends `${infer P}.${string}` ? P | AllParentPrefixes<P> : never;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Given a parent path, return the union of TypeRegistry keys that are direct
|
|
127
|
+
* or indirect children of that path.
|
|
128
|
+
*/
|
|
129
|
+
export type ChildKeysOf<P extends string> = {
|
|
130
|
+
[K in keyof TypeRegistry]: K extends `${P}.${string}` ? K : never
|
|
131
|
+
}[keyof TypeRegistry];
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Given an instance type, find the TypeRegistry key(s) whose constructor
|
|
135
|
+
* returns that instance type. This inverts the registry at the type level
|
|
136
|
+
* so utilities like `parent()` can derive an instance's path from its
|
|
137
|
+
* type alone.
|
|
138
|
+
*/
|
|
139
|
+
export type PathOfInstance<T extends object> = {
|
|
140
|
+
[K in LiteralKeysOf<TypeRegistry>]: TypeRegistry[K] extends new (...args: unknown[]) => infer R
|
|
141
|
+
? T extends R ? K : never
|
|
142
|
+
: never
|
|
143
|
+
}[LiteralKeysOf<TypeRegistry>];
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Given an instance type, return the union of TypeRegistry paths that are
|
|
147
|
+
* valid parent lookups for that instance. Root types produce `never` because
|
|
148
|
+
* they have no parent path.
|
|
149
|
+
*/
|
|
150
|
+
export type ParentPathOfInstance<T extends object> = {
|
|
151
|
+
[K in LiteralKeysOf<TypeRegistry>]: TypeRegistry[K] extends new (...args: unknown[]) => infer R
|
|
152
|
+
? T extends R ? AllParentPrefixes<K> : never
|
|
153
|
+
: never
|
|
154
|
+
}[LiteralKeysOf<TypeRegistry>];
|
|
155
|
+
|
|
81
156
|
// Hook types
|
|
82
157
|
export type hooksTypes = 'preCreation' | 'postCreation' | 'creationError';
|
|
83
158
|
|
|
@@ -288,6 +363,9 @@ export interface MnemonicaInstance<T extends object = object> {
|
|
|
288
363
|
pick<K extends keyof T>(...keys: (K | K[])[]): { [P in K]: T[P] } & {};
|
|
289
364
|
pick(...keys: string[]): Record<string, unknown>;
|
|
290
365
|
parent(): object | undefined;
|
|
366
|
+
parent<K extends ParentPathOfInstance<this> & string>(
|
|
367
|
+
constructorLookupPath: K
|
|
368
|
+
): InstanceOfTypeRegistry<K> | undefined;
|
|
291
369
|
parent(constructorLookupPath: string): object | undefined;
|
|
292
370
|
readonly clone: this;
|
|
293
371
|
fork(...forkArgs: unknown[]): this;
|
|
@@ -507,7 +585,12 @@ export interface UtilsCollection {
|
|
|
507
585
|
...args: unknown[]
|
|
508
586
|
): InstanceResult<Merge<B, A>>;
|
|
509
587
|
parse<T extends object>(self: T): Parsed<T>;
|
|
510
|
-
parent<T extends object>(instance: T
|
|
588
|
+
parent<T extends object>(instance: T): object | undefined;
|
|
589
|
+
parent<T extends object, K extends ParentPathOfInstance<T> & string>(
|
|
590
|
+
instance: T,
|
|
591
|
+
path: K
|
|
592
|
+
): InstanceOfTypeRegistry<K> | undefined;
|
|
593
|
+
parent<T extends object>(instance: T, path: string): object | undefined;
|
|
511
594
|
toJSON<T extends object>(instance: T): string;
|
|
512
595
|
[key: string]: CallableFunction;
|
|
513
596
|
}
|
|
@@ -516,7 +599,10 @@ export interface UtilsCollection {
|
|
|
516
599
|
export interface MnemonicaModule {
|
|
517
600
|
// Core functions
|
|
518
601
|
define: TypeAbsorber;
|
|
519
|
-
lookup:
|
|
602
|
+
lookup: {
|
|
603
|
+
(TypeNestedPath: string): TypeClass | undefined;
|
|
604
|
+
<const K extends keyof TypeRegistry>(TypeNestedPath: K): TypeRegistry[K] | undefined;
|
|
605
|
+
};
|
|
520
606
|
apply: ApplyFunction;
|
|
521
607
|
call: CallFunction;
|
|
522
608
|
bind: BindFunction;
|
package/src/utils/parent.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
import type {
|
|
4
|
+
InstanceOfTypeRegistry,
|
|
5
|
+
ParentPathOfInstance
|
|
6
|
+
} from '../types';
|
|
7
|
+
|
|
3
8
|
import { ErrorsTypes } from '../descriptors/errors';
|
|
4
9
|
const { WRONG_INSTANCE_INVOCATION } = ErrorsTypes;
|
|
5
10
|
|
|
@@ -10,7 +15,13 @@ import {
|
|
|
10
15
|
// seek for firts parent instance
|
|
11
16
|
// of instance prototype chain
|
|
12
17
|
// with constructors of path
|
|
13
|
-
export
|
|
18
|
+
export function parent <T extends object> (instance: T): object | undefined;
|
|
19
|
+
export function parent <T extends object, K extends ParentPathOfInstance<T> & string> (
|
|
20
|
+
instance: T,
|
|
21
|
+
path: K
|
|
22
|
+
): InstanceOfTypeRegistry<K> | undefined;
|
|
23
|
+
export function parent (instance: object, path: string): object | undefined;
|
|
24
|
+
export function parent <T extends object> (instance: T, path?: string): object | undefined {
|
|
14
25
|
|
|
15
26
|
// at this situation this check is enough
|
|
16
27
|
if ( instance !== Object( instance ) ) {
|
|
@@ -37,4 +48,4 @@ export const parent = <T extends object>( instance: T, path?: string ): object |
|
|
|
37
48
|
p : parent( p as object, path );
|
|
38
49
|
return result;
|
|
39
50
|
|
|
40
|
-
}
|
|
51
|
+
}
|