@tstdl/base 0.93.139 → 0.93.141
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +166 -0
- package/ai/genkit/multi-region.plugin.js +5 -3
- package/ai/genkit/tests/multi-region.test.d.ts +1 -0
- package/ai/genkit/tests/multi-region.test.js +5 -2
- package/ai/parser/parser.js +2 -2
- package/ai/prompts/build.js +1 -0
- package/ai/prompts/instructions-formatter.d.ts +15 -2
- package/ai/prompts/instructions-formatter.js +36 -31
- package/ai/prompts/prompt-builder.js +5 -5
- package/ai/prompts/steering.d.ts +3 -2
- package/ai/prompts/steering.js +3 -1
- package/ai/tests/instructions-formatter.test.js +1 -0
- package/api/README.md +403 -0
- package/api/client/client.js +7 -13
- package/api/client/tests/api-client.test.js +10 -10
- package/api/default-error-handlers.js +1 -1
- package/api/response.d.ts +2 -2
- package/api/response.js +22 -33
- package/api/server/api-controller.d.ts +1 -1
- package/api/server/api-controller.js +3 -3
- package/api/server/api-request-token.provider.d.ts +1 -0
- package/api/server/api-request-token.provider.js +1 -0
- package/api/server/middlewares/allowed-methods.middleware.js +2 -1
- package/api/server/middlewares/content-type.middleware.js +2 -1
- package/api/types.d.ts +3 -2
- package/application/README.md +240 -0
- package/application/application.d.ts +1 -1
- package/application/application.js +3 -3
- package/application/providers.d.ts +20 -2
- package/application/providers.js +34 -7
- package/audit/README.md +267 -0
- package/audit/module.d.ts +5 -0
- package/audit/module.js +9 -1
- package/authentication/README.md +288 -0
- package/authentication/client/authentication.service.d.ts +12 -11
- package/authentication/client/authentication.service.js +21 -21
- package/authentication/client/http-client.middleware.js +2 -2
- package/authentication/server/module.d.ts +5 -0
- package/authentication/server/module.js +9 -1
- package/authentication/tests/authentication.api-controller.test.js +1 -1
- package/authentication/tests/authentication.api-request-token.provider.test.js +1 -1
- package/authentication/tests/authentication.client-error-handling.test.js +2 -1
- package/authentication/tests/authentication.client-service-refresh.test.js +5 -3
- package/authentication/tests/authentication.client-service.test.js +1 -1
- package/browser/README.md +401 -0
- package/cancellation/README.md +156 -0
- package/cancellation/tests/coverage.test.d.ts +1 -0
- package/cancellation/tests/coverage.test.js +49 -0
- package/cancellation/tests/leak.test.js +24 -29
- package/cancellation/tests/token.test.d.ts +1 -0
- package/cancellation/tests/token.test.js +136 -0
- package/cancellation/token.d.ts +53 -177
- package/cancellation/token.js +132 -208
- package/circuit-breaker/postgres/module.d.ts +1 -0
- package/circuit-breaker/postgres/module.js +5 -1
- package/context/README.md +174 -0
- package/cookie/README.md +161 -0
- package/css/README.md +157 -0
- package/data-structures/README.md +320 -0
- package/decorators/README.md +140 -0
- package/distributed-loop/README.md +231 -0
- package/distributed-loop/distributed-loop.js +1 -1
- package/document-management/README.md +403 -0
- package/document-management/server/configure.js +5 -1
- package/document-management/server/module.d.ts +1 -1
- package/document-management/server/module.js +1 -1
- package/document-management/server/services/document-management-ancillary.service.js +1 -1
- package/document-management/server/services/document-management.service.js +9 -7
- package/document-management/tests/ai-config-hierarchy.test.js +0 -5
- package/document-management/tests/document-management-ai-overrides.test.js +0 -1
- package/document-management/tests/document-management-core.test.js +2 -7
- package/document-management/tests/document-management.api.test.js +6 -7
- package/document-management/tests/document-statistics.service.test.js +11 -12
- package/document-management/tests/document-validation-ai-overrides.test.js +0 -1
- package/document-management/tests/document.service.test.js +3 -3
- package/document-management/tests/enum-helpers.test.js +2 -3
- package/dom/README.md +213 -0
- package/enumerable/README.md +259 -0
- package/enumeration/README.md +121 -0
- package/errors/README.md +267 -0
- package/examples/document-management/main.d.ts +1 -0
- package/examples/document-management/main.js +14 -11
- package/file/README.md +191 -0
- package/formats/README.md +210 -0
- package/function/README.md +144 -0
- package/http/README.md +318 -0
- package/http/client/adapters/undici.adapter.js +1 -1
- package/http/client/http-client-request.d.ts +6 -5
- package/http/client/http-client-request.js +8 -9
- package/http/server/node/node-http-server.js +1 -2
- package/image-service/README.md +137 -0
- package/injector/README.md +491 -0
- package/intl/README.md +113 -0
- package/json-path/README.md +182 -0
- package/jsx/README.md +154 -0
- package/key-value-store/README.md +191 -0
- package/key-value-store/postgres/module.d.ts +1 -0
- package/key-value-store/postgres/module.js +5 -1
- package/lock/README.md +249 -0
- package/lock/postgres/module.d.ts +1 -0
- package/lock/postgres/module.js +5 -1
- package/lock/web/web-lock.js +119 -47
- package/logger/README.md +287 -0
- package/mail/README.md +256 -0
- package/mail/module.d.ts +5 -1
- package/mail/module.js +11 -6
- package/memory/README.md +144 -0
- package/message-bus/README.md +244 -0
- package/message-bus/message-bus-base.js +1 -1
- package/module/README.md +182 -0
- package/module/module.d.ts +1 -1
- package/module/module.js +77 -17
- package/module/modules/web-server.module.js +3 -4
- package/notification/server/module.d.ts +1 -0
- package/notification/server/module.js +5 -1
- package/notification/tests/notification-flow.test.js +2 -2
- package/notification/tests/notification-type.service.test.js +24 -15
- package/object-storage/README.md +300 -0
- package/openid-connect/README.md +274 -0
- package/orm/README.md +423 -0
- package/orm/decorators.d.ts +5 -1
- package/orm/decorators.js +1 -1
- package/orm/server/drizzle/schema-converter.js +17 -30
- package/orm/server/encryption.d.ts +0 -1
- package/orm/server/encryption.js +1 -4
- package/orm/server/index.d.ts +1 -6
- package/orm/server/index.js +1 -6
- package/orm/server/migration.d.ts +19 -0
- package/orm/server/migration.js +72 -0
- package/orm/server/repository.d.ts +1 -1
- package/orm/server/transaction.d.ts +5 -10
- package/orm/server/transaction.js +22 -26
- package/orm/server/transactional.js +3 -3
- package/orm/tests/database-migration.test.d.ts +1 -0
- package/orm/tests/database-migration.test.js +82 -0
- package/orm/tests/encryption.test.js +3 -4
- package/orm/utils.d.ts +17 -2
- package/orm/utils.js +49 -1
- package/package.json +9 -6
- package/password/README.md +164 -0
- package/pdf/README.md +246 -0
- package/polyfills.js +1 -0
- package/pool/README.md +198 -0
- package/process/README.md +237 -0
- package/promise/README.md +252 -0
- package/promise/cancelable-promise.js +1 -1
- package/random/README.md +193 -0
- package/rate-limit/postgres/module.d.ts +1 -0
- package/rate-limit/postgres/module.js +5 -1
- package/reflection/README.md +305 -0
- package/reflection/decorator-data.js +11 -12
- package/rpc/README.md +386 -0
- package/rxjs-utils/README.md +262 -0
- package/schema/README.md +342 -0
- package/serializer/README.md +342 -0
- package/signals/implementation/README.md +134 -0
- package/sse/README.md +278 -0
- package/task-queue/README.md +293 -0
- package/task-queue/postgres/drizzle/{0000_simple_invisible_woman.sql → 0000_wakeful_sunspot.sql} +22 -14
- package/task-queue/postgres/drizzle/meta/0000_snapshot.json +160 -82
- package/task-queue/postgres/drizzle/meta/_journal.json +2 -2
- package/task-queue/postgres/module.d.ts +1 -0
- package/task-queue/postgres/module.js +5 -1
- package/task-queue/postgres/schemas.d.ts +9 -6
- package/task-queue/postgres/schemas.js +4 -3
- package/task-queue/postgres/task-queue.d.ts +4 -13
- package/task-queue/postgres/task-queue.js +462 -355
- package/task-queue/postgres/task.model.d.ts +12 -5
- package/task-queue/postgres/task.model.js +51 -25
- package/task-queue/task-context.d.ts +2 -2
- package/task-queue/task-context.js +8 -8
- package/task-queue/task-queue.d.ts +53 -19
- package/task-queue/task-queue.js +121 -55
- package/task-queue/tests/cascading-cancellations.test.d.ts +1 -0
- package/task-queue/tests/cascading-cancellations.test.js +38 -0
- package/task-queue/tests/complex.test.js +45 -229
- package/task-queue/tests/coverage-branch.test.d.ts +1 -0
- package/task-queue/tests/coverage-branch.test.js +407 -0
- package/task-queue/tests/coverage-enhancement.test.d.ts +1 -0
- package/task-queue/tests/coverage-enhancement.test.js +144 -0
- package/task-queue/tests/dag-dependencies.test.d.ts +1 -0
- package/task-queue/tests/dag-dependencies.test.js +41 -0
- package/task-queue/tests/dependencies.test.js +28 -26
- package/task-queue/tests/extensive-dependencies.test.js +64 -139
- package/task-queue/tests/fan-out-spawning.test.d.ts +1 -0
- package/task-queue/tests/fan-out-spawning.test.js +53 -0
- package/task-queue/tests/idempotent-replacement.test.d.ts +1 -0
- package/task-queue/tests/idempotent-replacement.test.js +61 -0
- package/task-queue/tests/missing-idempotent-tasks.test.d.ts +1 -0
- package/task-queue/tests/missing-idempotent-tasks.test.js +38 -0
- package/task-queue/tests/queue.test.js +128 -8
- package/task-queue/tests/worker.test.js +39 -16
- package/task-queue/tests/zombie-parent.test.d.ts +1 -0
- package/task-queue/tests/zombie-parent.test.js +45 -0
- package/task-queue/tests/zombie-recovery.test.d.ts +1 -0
- package/task-queue/tests/zombie-recovery.test.js +51 -0
- package/templates/README.md +287 -0
- package/test5.js +5 -5
- package/testing/README.md +157 -0
- package/testing/integration-setup.d.ts +4 -4
- package/testing/integration-setup.js +54 -29
- package/text/README.md +346 -0
- package/text/localization.service.js +2 -2
- package/threading/README.md +238 -0
- package/types/README.md +311 -0
- package/utils/README.md +322 -0
- package/utils/async-iterable-helpers/observable-iterable.d.ts +1 -1
- package/utils/async-iterable-helpers/observable-iterable.js +4 -8
- package/utils/async-iterable-helpers/take-until.js +4 -4
- package/utils/backoff.js +89 -30
- package/utils/file-reader.js +1 -2
- package/utils/retry-with-backoff.js +1 -1
- package/utils/timer.d.ts +1 -1
- package/utils/timer.js +5 -7
- package/utils/timing.d.ts +1 -1
- package/utils/timing.js +2 -4
- package/utils/z-base32.d.ts +1 -0
- package/utils/z-base32.js +1 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
# Reflection
|
|
2
|
+
|
|
3
|
+
A powerful and unified toolkit for creating and managing TypeScript decorators with a robust runtime reflection system. It simplifies decorator creation, manages metadata storage, and supports inheritance, enabling advanced runtime introspection.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [✨ Features](#-features)
|
|
8
|
+
- [Core Concepts](#core-concepts)
|
|
9
|
+
- [🚀 Basic Usage](#-basic-usage)
|
|
10
|
+
- [🔧 Advanced Topics](#-advanced-topics)
|
|
11
|
+
- [📚 API](#-api)
|
|
12
|
+
|
|
13
|
+
## ✨ Features
|
|
14
|
+
|
|
15
|
+
- **Unified Decorator API**: Consistent factory functions (`Class`, `Property`, `Method`, etc.) to create type-safe decorators for specific targets.
|
|
16
|
+
- **Centralized Registry**: A global `reflectionRegistry` automatically collects and organizes metadata from all decorators.
|
|
17
|
+
- **Metadata Storage**: Attach arbitrary custom data to classes, properties, methods, and parameters via a `ContextDataMap`. Supports merging complex data structures.
|
|
18
|
+
- **Inheritance Support**: Metadata is automatically inherited from parent classes, allowing for polymorphic behavior in frameworks.
|
|
19
|
+
- **Static Member Support**: Reflect on both instance and static properties and methods.
|
|
20
|
+
- **Decorator Wrapping**: Utilities to wrap third-party decorators, integrating them into the reflection system without modifying their source.
|
|
21
|
+
- **Inclusive Decorators**: Apply multiple decorators simultaneously via a single wrapper, simplifying complex decoration logic.
|
|
22
|
+
- **Type Inspection**: Helper functions to visualize and inspect registered type information at runtime.
|
|
23
|
+
|
|
24
|
+
## Core Concepts
|
|
25
|
+
|
|
26
|
+
### Decorator Factories
|
|
27
|
+
|
|
28
|
+
Instead of writing raw decorator functions that handle `target`, `propertyKey`, and `descriptor` manually, this module provides factories. These factories accept an options object, often including a `handler` function where you define your logic.
|
|
29
|
+
|
|
30
|
+
- **`Class()`**: Creates a class decorator.
|
|
31
|
+
- **`Property()`**: Creates a property decorator.
|
|
32
|
+
- **`Method()`**: Creates a method decorator.
|
|
33
|
+
- **`Parameter()`**: Creates a parameter decorator (constructor or method).
|
|
34
|
+
- **`Decorate()`**: Creates a universal decorator applicable to multiple targets.
|
|
35
|
+
|
|
36
|
+
### Reflection Registry
|
|
37
|
+
|
|
38
|
+
The `reflectionRegistry` is a singleton that stores `TypeMetadata` for every class decorated with this library. When a decorator is applied, it registers the target (class, method, property) and allows you to attach data to it.
|
|
39
|
+
|
|
40
|
+
You can later retrieve this metadata using `reflectionRegistry.getMetadata(Constructor)`. This metadata object contains a structured view of the class, including its properties, methods, parameters, and any custom data attached.
|
|
41
|
+
|
|
42
|
+
### Context Data
|
|
43
|
+
|
|
44
|
+
Every metadata object (for a type, property, method, etc.) has a `data` property, which is a `ContextDataMap`. This acts as a key-value store for your custom metadata (e.g., serialization rules, validation constraints, dependency injection tokens).
|
|
45
|
+
|
|
46
|
+
## 🚀 Basic Usage
|
|
47
|
+
|
|
48
|
+
### Creating and Using a Class Decorator
|
|
49
|
+
|
|
50
|
+
This example demonstrates how to create a decorator to mark a class as a "Service" and retrieve that information at runtime.
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { Class, reflectionRegistry } from '@tstdl/base/reflection';
|
|
54
|
+
|
|
55
|
+
// 1. Define a key for the metadata
|
|
56
|
+
const SERVICE_NAME_KEY = Symbol('ServiceName');
|
|
57
|
+
|
|
58
|
+
// 2. Create the decorator factory
|
|
59
|
+
function Service(name: string) {
|
|
60
|
+
return Class({
|
|
61
|
+
handler: (data, metadata) => {
|
|
62
|
+
// 'metadata' is the TypeMetadata for the class
|
|
63
|
+
metadata.data.set(SERVICE_NAME_KEY, name);
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 3. Apply the decorator
|
|
69
|
+
@Service('UserManagement')
|
|
70
|
+
class UserService {
|
|
71
|
+
// ...
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// 4. Inspect metadata at runtime
|
|
75
|
+
const metadata = reflectionRegistry.getMetadata(UserService);
|
|
76
|
+
|
|
77
|
+
if (metadata) {
|
|
78
|
+
const serviceName = metadata.data.get(SERVICE_NAME_KEY);
|
|
79
|
+
console.log(`Service Name: ${serviceName}`); // Output: Service Name: UserManagement
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Property and Parameter Decorators
|
|
84
|
+
|
|
85
|
+
Decorators are often used for defining schemas or dependency injection.
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { Property, Parameter, reflectionRegistry } from '@tstdl/base/reflection';
|
|
89
|
+
|
|
90
|
+
const SERIALIZE_KEY = Symbol('Serialize');
|
|
91
|
+
const INJECT_KEY = Symbol('Inject');
|
|
92
|
+
|
|
93
|
+
// Property decorator to mark fields for serialization
|
|
94
|
+
function Serializable() {
|
|
95
|
+
return Property({
|
|
96
|
+
handler: (data, metadata) => {
|
|
97
|
+
metadata.data.set(SERIALIZE_KEY, true);
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Parameter decorator for dependency injection
|
|
103
|
+
function Inject(token: string) {
|
|
104
|
+
return Parameter({
|
|
105
|
+
handler: (data, metadata) => {
|
|
106
|
+
metadata.data.set(INJECT_KEY, token);
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
class Database {}
|
|
112
|
+
|
|
113
|
+
class User {
|
|
114
|
+
@Serializable()
|
|
115
|
+
id: string;
|
|
116
|
+
|
|
117
|
+
@Serializable()
|
|
118
|
+
username: string;
|
|
119
|
+
|
|
120
|
+
passwordHash: string; // Not marked
|
|
121
|
+
|
|
122
|
+
constructor(@Inject('DbConnection') db: Database) {}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Inspecting the class
|
|
126
|
+
const meta = reflectionRegistry.getMetadata(User);
|
|
127
|
+
|
|
128
|
+
// Find serializable properties
|
|
129
|
+
for (const [key, propMeta] of meta.properties) {
|
|
130
|
+
if (propMeta.data.get(SERIALIZE_KEY)) {
|
|
131
|
+
console.log(`Property '${String(key)}' is serializable.`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Output:
|
|
135
|
+
// Property 'id' is serializable.
|
|
136
|
+
// Property 'username' is serializable.
|
|
137
|
+
|
|
138
|
+
// Check constructor parameters
|
|
139
|
+
const ctorParams = meta.parameters; // Array of ConstructorParameterMetadata
|
|
140
|
+
if (ctorParams) {
|
|
141
|
+
const firstParamToken = ctorParams[0].data.get(INJECT_KEY);
|
|
142
|
+
console.log(`Constructor param 0 injects: ${firstParamToken}`);
|
|
143
|
+
// Output: Constructor param 0 injects: DbConnection
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## 🔧 Advanced Topics
|
|
148
|
+
|
|
149
|
+
### Method Interception
|
|
150
|
+
|
|
151
|
+
You can use `Method` decorators to wrap or intercept method calls. The handler receives the property descriptor, allowing you to modify the `value`.
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import { Method } from '@tstdl/base/reflection';
|
|
155
|
+
|
|
156
|
+
function Log() {
|
|
157
|
+
return Method({
|
|
158
|
+
handler: (data, metadata, [target, propertyKey, descriptor]) => {
|
|
159
|
+
const originalMethod = descriptor.value;
|
|
160
|
+
|
|
161
|
+
descriptor.value = function (...args: any[]) {
|
|
162
|
+
console.log(`Calling ${String(data.methodKey)} with`, args);
|
|
163
|
+
return originalMethod.apply(this, args);
|
|
164
|
+
};
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
class Calculator {
|
|
170
|
+
@Log()
|
|
171
|
+
add(a: number, b: number) {
|
|
172
|
+
return a + b;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
new Calculator().add(2, 3);
|
|
177
|
+
// Console: Calling add with [2, 3]
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Wrapping Third-Party Decorators
|
|
181
|
+
|
|
182
|
+
If you use decorators from other libraries (like an ORM or validation library), you can wrap them to ensure they also register metadata in the `reflectionRegistry`.
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
import { wrapDecorator } from '@tstdl/base/reflection';
|
|
186
|
+
|
|
187
|
+
// Assume this comes from an external library
|
|
188
|
+
function ExternalEntity(tableName: string) {
|
|
189
|
+
return (target: any) => {
|
|
190
|
+
/* ... external logic ... */
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Wrap it
|
|
195
|
+
const Entity = (tableName: string) =>
|
|
196
|
+
wrapDecorator(ExternalEntity(tableName), {
|
|
197
|
+
data: { tableName }, // Automatically attach this data to metadata
|
|
198
|
+
handler: (data, metadata) => {
|
|
199
|
+
console.log(`Registered entity: ${tableName}`);
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
@Entity('users')
|
|
204
|
+
class User {}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Inheritance
|
|
208
|
+
|
|
209
|
+
Metadata is inherited. If you request metadata for a subclass, it includes properties and methods decorated in the parent class, marked with `inherited: true`.
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
import { Property, reflectionRegistry } from '@tstdl/base/reflection';
|
|
213
|
+
|
|
214
|
+
function Prop() {
|
|
215
|
+
return Property();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
class Base {
|
|
219
|
+
@Prop() baseField: string;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
class Child extends Base {
|
|
223
|
+
@Prop() childField: string;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const meta = reflectionRegistry.getMetadata(Child);
|
|
227
|
+
console.log(meta.properties.has('baseField')); // true
|
|
228
|
+
console.log(meta.properties.get('baseField').inherited); // true
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Inclusive Decorators
|
|
232
|
+
|
|
233
|
+
The `include` option allows you to trigger other decorators when your decorator is applied. This is useful for creating "composite" decorators.
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
import { Class, Property } from '@tstdl/base/reflection';
|
|
237
|
+
|
|
238
|
+
const MyClassDecorator = Class();
|
|
239
|
+
const MyPropertyDecorator = Property();
|
|
240
|
+
|
|
241
|
+
function Composite() {
|
|
242
|
+
return Class({
|
|
243
|
+
include: [MyClassDecorator, MyPropertyDecorator] // Error in this specific case as targets differ, but shows the concept
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
*Note: The included decorators must be compatible with the target where the main decorator is applied.*
|
|
249
|
+
|
|
250
|
+
### Data Merging
|
|
251
|
+
|
|
252
|
+
When setting data on metadata, you can choose to merge instead of overwrite by setting `mergeData: true`. This works for objects, arrays, maps, and sets.
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
import { Class } from '@tstdl/base/reflection';
|
|
256
|
+
|
|
257
|
+
const KEY = Symbol('Tags');
|
|
258
|
+
|
|
259
|
+
function Tag(tag: string) {
|
|
260
|
+
return Class({
|
|
261
|
+
data: { [KEY]: [tag] },
|
|
262
|
+
mergeData: true
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
@Tag('alpha')
|
|
267
|
+
@Tag('beta')
|
|
268
|
+
class MyClass {}
|
|
269
|
+
|
|
270
|
+
// Metadata for MyClass will have [KEY]: ['alpha', 'beta']
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## 📚 API
|
|
274
|
+
|
|
275
|
+
| Function / Object | Description |
|
|
276
|
+
| :---------------------------------------- | :---------------------------------------------------------------------------------------------------------- |
|
|
277
|
+
| `reflectionRegistry` | The global singleton instance of `ReflectionRegistry`. Use this to retrieve metadata (`getMetadata(Type)`), check for registration (`hasType(Type)`), or manually unregister types (`unregister(Type)`). |
|
|
278
|
+
| `Class(options?)` | Factory for creating a class decorator. |
|
|
279
|
+
| `Property(options?)` | Factory for creating a property decorator. |
|
|
280
|
+
| `Method(options?)` | Factory for creating a method decorator. |
|
|
281
|
+
| `Accessor(options?)` | Factory for creating an accessor (getter/setter) decorator. |
|
|
282
|
+
| `PropertyOrAccessor(options?)` | Factory for creating a decorator that can target both properties and accessors. |
|
|
283
|
+
| `Parameter(options?)` | Factory for creating a parameter decorator (works on constructor and method parameters). |
|
|
284
|
+
| `ConstructorParameter(options?)` | Factory for creating a decorator specifically for constructor parameters. |
|
|
285
|
+
| `MethodParameter(options?)` | Factory for creating a decorator specifically for method parameters. |
|
|
286
|
+
| `Decorate(options?)` | Factory for creating a universal decorator that can target multiple types (class, property, etc.). |
|
|
287
|
+
| `createDecorator(options, handler?)` | Low-level primitive for creating highly customized decorators. |
|
|
288
|
+
| `wrapDecorator(decorator, options?)` | Wraps an existing decorator instance to integrate it with the reflection system. |
|
|
289
|
+
| `wrapDecoratorFactory(factory, options?)` | Wraps a decorator factory function. |
|
|
290
|
+
| `getDecoratorData(...)` | Utility to parse standard decorator arguments into a structured `DecoratorData` object. |
|
|
291
|
+
| `getConstructor(target)` | Utility to get the constructor from either a constructor function or an instance prototype. |
|
|
292
|
+
| `getTypeInfoString(constructor)` | Debug utility that returns a string representation of the type structure. |
|
|
293
|
+
| `printType(constructor)` | Debug utility that prints the structure of a type based on registered metadata to the console. |
|
|
294
|
+
|
|
295
|
+
### Types
|
|
296
|
+
|
|
297
|
+
| Type | Description |
|
|
298
|
+
| :------------------ | :---------------------------------------------------------------------------------------- |
|
|
299
|
+
| `TypeMetadata` | Metadata for a class, containing maps of properties, methods, and constructor parameters. |
|
|
300
|
+
| `PropertyMetadata` | Metadata for a specific property (instance or static). |
|
|
301
|
+
| `MethodMetadata` | Metadata for a method, including its parameters and return type (instance or static). |
|
|
302
|
+
| `ParameterMetadata` | Metadata for a parameter (index, type). |
|
|
303
|
+
| `DecoratorData` | Object passed to handlers containing context (e.g., `propertyKey`, `index`, `static`). |
|
|
304
|
+
| `DecoratorHandler` | Function signature for the logic inside a decorator factory. |
|
|
305
|
+
| `MetadataType` | Union of possible metadata types (`'type'`, `'property'`, `'method'`, etc.). |
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { DetailsError } from '../errors/details.error.js';
|
|
2
2
|
import { isDefined, isFunction, isNumber, isObject, isUndefined } from '../utils/type-guards.js';
|
|
3
3
|
import { getConstructor } from './utils.js';
|
|
4
|
-
// eslint-disable-next-line max-lines-per-function
|
|
5
4
|
export function getDecoratorData(target, propertyKey, descriptorOrParameterIndex) {
|
|
6
5
|
const constructor = getConstructor(target);
|
|
7
6
|
const prototype = constructor.prototype;
|
|
@@ -10,54 +9,54 @@ export function getDecoratorData(target, propertyKey, descriptorOrParameterIndex
|
|
|
10
9
|
return {
|
|
11
10
|
type: 'class',
|
|
12
11
|
constructor,
|
|
13
|
-
prototype
|
|
12
|
+
prototype,
|
|
14
13
|
};
|
|
15
14
|
}
|
|
16
|
-
|
|
15
|
+
if (isDefined(propertyKey) && isUndefined(descriptorOrParameterIndex)) {
|
|
17
16
|
return {
|
|
18
17
|
type: 'property',
|
|
19
18
|
constructor,
|
|
20
19
|
prototype,
|
|
21
20
|
static: isStatic,
|
|
22
|
-
propertyKey
|
|
21
|
+
propertyKey,
|
|
23
22
|
};
|
|
24
23
|
}
|
|
25
|
-
|
|
24
|
+
if (isDefined(propertyKey) && isObject(descriptorOrParameterIndex) && (isFunction(descriptorOrParameterIndex.get ?? descriptorOrParameterIndex.set))) { // eslint-disable-line @typescript-eslint/unbound-method
|
|
26
25
|
return {
|
|
27
26
|
type: 'accessor',
|
|
28
27
|
constructor,
|
|
29
28
|
prototype,
|
|
30
29
|
static: isStatic,
|
|
31
30
|
propertyKey,
|
|
32
|
-
descriptor: descriptorOrParameterIndex
|
|
31
|
+
descriptor: descriptorOrParameterIndex,
|
|
33
32
|
};
|
|
34
33
|
}
|
|
35
|
-
|
|
34
|
+
if (isDefined(propertyKey) && isObject(descriptorOrParameterIndex) && isFunction(descriptorOrParameterIndex.value)) {
|
|
36
35
|
return {
|
|
37
36
|
type: 'method',
|
|
38
37
|
constructor,
|
|
39
38
|
prototype,
|
|
40
39
|
static: isStatic,
|
|
41
40
|
methodKey: propertyKey,
|
|
42
|
-
descriptor: descriptorOrParameterIndex
|
|
41
|
+
descriptor: descriptorOrParameterIndex,
|
|
43
42
|
};
|
|
44
43
|
}
|
|
45
|
-
|
|
44
|
+
if (isDefined(propertyKey) && isNumber(descriptorOrParameterIndex)) {
|
|
46
45
|
return {
|
|
47
46
|
type: 'method-parameter',
|
|
48
47
|
constructor,
|
|
49
48
|
prototype,
|
|
50
49
|
static: isStatic,
|
|
51
50
|
methodKey: propertyKey,
|
|
52
|
-
index: descriptorOrParameterIndex
|
|
51
|
+
index: descriptorOrParameterIndex,
|
|
53
52
|
};
|
|
54
53
|
}
|
|
55
|
-
|
|
54
|
+
if (isNumber(descriptorOrParameterIndex)) {
|
|
56
55
|
return {
|
|
57
56
|
type: 'constructor-parameter',
|
|
58
57
|
constructor,
|
|
59
58
|
prototype,
|
|
60
|
-
index: descriptorOrParameterIndex
|
|
59
|
+
index: descriptorOrParameterIndex,
|
|
61
60
|
};
|
|
62
61
|
}
|
|
63
62
|
throw new DetailsError('unknown type', { type: constructor, isStatic, propertyKey, descriptorOrParameterIndex });
|