class-resolver 1.1.1 → 2.1.0
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 +289 -17
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/interface.d.ts +19 -6
- package/dist/interface.js +1 -0
- package/dist/interface.js.map +1 -0
- package/dist/resolver.d.ts +46 -10
- package/dist/resolver.js +52 -10
- package/dist/resolver.js.map +1 -0
- package/index.js +4 -2
- package/libs/index.ts +2 -0
- package/libs/interface.ts +22 -6
- package/libs/resolver.ts +73 -22
- package/package.json +27 -14
- package/readme-ja.md +301 -0
- package/dist/libs/interface.js +0 -2
- package/dist/libs/resolver.js +0 -29
package/README.md
CHANGED
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
# Simple Class resolver
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A lightweight TypeScript/JavaScript library for implementing the Chain of Responsibility pattern with class-based resolvers.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Simple and intuitive API for handling different types of requests
|
|
8
|
+
- Type-safe implementation with TypeScript support
|
|
9
|
+
- Flexible resolver registration (constructor, setUpdaters, addUpdater)
|
|
10
|
+
- Support for multiple resolvers with different handling logic
|
|
11
|
+
- Clear error handling for unsupported types
|
|
12
|
+
- Generic type support for better type safety
|
|
8
13
|
|
|
9
|
-
##
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install class-resolver
|
|
18
|
+
# or
|
|
19
|
+
yarn add class-resolver
|
|
10
20
|
```
|
|
21
|
+
|
|
22
|
+
## Basic Usage
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
11
25
|
const Resolver = require('class-resolver')
|
|
12
26
|
|
|
13
27
|
class ExampleClass {
|
|
@@ -26,32 +40,286 @@ class ExampleClass2 {
|
|
|
26
40
|
return 'fuga'
|
|
27
41
|
}
|
|
28
42
|
}
|
|
29
|
-
|
|
43
|
+
|
|
30
44
|
const resolver = new Resolver(new ExampleClass(), new ExampleClass2())
|
|
31
45
|
const c = resolver.resolve('hoge')
|
|
32
|
-
console.log(c.handle())
|
|
46
|
+
console.log(c.handle()) // Output: hoge
|
|
47
|
+
|
|
33
48
|
const c2 = resolver.resolve('fuga')
|
|
34
|
-
console.log(c2.handle())
|
|
49
|
+
console.log(c2.handle()) // Output: fuga
|
|
35
50
|
|
|
36
51
|
try {
|
|
37
|
-
resolver.resolve('xxx')
|
|
52
|
+
resolver.resolve('xxx') // This will throw an error
|
|
38
53
|
} catch (e) {
|
|
39
|
-
console.log(e)
|
|
54
|
+
console.log(e) // Error: Unsupported type: xxx
|
|
40
55
|
}
|
|
41
56
|
```
|
|
42
57
|
|
|
43
|
-
|
|
58
|
+
## Advanced Usage
|
|
59
|
+
|
|
60
|
+
### With TypeScript and Parameters
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import Resolver from 'class-resolver';
|
|
64
|
+
import { ResolveTarget } from 'class-resolver';
|
|
65
|
+
|
|
66
|
+
// Using generics for better type safety
|
|
67
|
+
class MessageFormatter implements ResolveTarget<[string, number], string> {
|
|
68
|
+
supports(type: string): boolean {
|
|
69
|
+
return type === 'greeting'
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
handle(name: string, count: number): string {
|
|
73
|
+
return `Hello ${name}, this is message #${count}!`
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
class ErrorFormatter implements ResolveTarget<[string, number], string> {
|
|
78
|
+
supports(type: string): boolean {
|
|
79
|
+
return type === 'error'
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
handle(message: string, code: number): string {
|
|
83
|
+
return `Error ${code}: ${message}`
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Specify the generic type for better type safety
|
|
88
|
+
const resolver = new Resolver<ResolveTarget<[string, number], string>>(
|
|
89
|
+
new MessageFormatter(),
|
|
90
|
+
new ErrorFormatter()
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
// Using the greeting formatter
|
|
94
|
+
const greeting = resolver.resolve('greeting')
|
|
95
|
+
console.log(greeting.handle('John', 1)) // Output: Hello John, this is message #1!
|
|
44
96
|
|
|
97
|
+
// Using the error formatter
|
|
98
|
+
const error = resolver.resolve('error')
|
|
99
|
+
console.log(error.handle('Not Found', 404)) // Output: Error 404: Not Found
|
|
45
100
|
```
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
101
|
+
|
|
102
|
+
### Dynamic Resolver Registration
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
// Specify the generic type for better type safety
|
|
106
|
+
const resolver = new Resolver<ResolveTarget<[string, number], string>>()
|
|
107
|
+
|
|
108
|
+
// Add resolvers after initialization
|
|
109
|
+
resolver.setUpdaters(new MessageFormatter(), new ErrorFormatter())
|
|
110
|
+
|
|
111
|
+
// Or add them one by one
|
|
112
|
+
resolver.addUpdater(new MessageFormatter())
|
|
113
|
+
resolver.addUpdater(new ErrorFormatter())
|
|
50
114
|
```
|
|
51
115
|
|
|
52
|
-
##
|
|
116
|
+
## Generic Type Support
|
|
117
|
+
|
|
118
|
+
From version 2.0.0, class-resolver supports generic types for better type safety:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
// Define the interface with generics
|
|
122
|
+
interface ResolveTarget<TArgs extends any[] = any[], TReturn = any, TType = string> {
|
|
123
|
+
supports(type: TType): boolean;
|
|
124
|
+
handle(...args: TArgs): TReturn;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Define a class that implements the interface with specific types
|
|
128
|
+
class StringFormatter implements ResolveTarget<[string], string> {
|
|
129
|
+
supports(type: string): boolean {
|
|
130
|
+
return type === 'string-format';
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
handle(input: string): string {
|
|
134
|
+
return input.toUpperCase();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
53
137
|
|
|
138
|
+
// Create a resolver with the specific type
|
|
139
|
+
const resolver = new Resolver<ResolveTarget<[string], string>>(new StringFormatter());
|
|
140
|
+
const formatter = resolver.resolve('string-format');
|
|
141
|
+
const result = formatter.handle('hello'); // result is typed as string
|
|
54
142
|
```
|
|
143
|
+
|
|
144
|
+
### Advanced Type Support
|
|
145
|
+
|
|
146
|
+
You can now use any type for the `supports` method, not just strings. This is particularly useful for handling complex objects like Stripe events:
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
// Define a complex event type
|
|
150
|
+
interface StripeEvent {
|
|
151
|
+
id: string;
|
|
152
|
+
type: string;
|
|
153
|
+
data: {
|
|
154
|
+
object: {
|
|
155
|
+
id: string;
|
|
156
|
+
amount: number;
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Create handlers for specific event types
|
|
162
|
+
class PaymentEventHandler implements ResolveTarget<[StripeEvent], string, StripeEvent> {
|
|
163
|
+
supports(event: StripeEvent): boolean {
|
|
164
|
+
return event.type === 'payment_intent.succeeded';
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
handle(event: StripeEvent): string {
|
|
168
|
+
return `Payment succeeded: ${event.data.object.amount}`;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
class RefundEventHandler implements ResolveTarget<[StripeEvent], string, StripeEvent> {
|
|
173
|
+
supports(event: StripeEvent): boolean {
|
|
174
|
+
return event.type === 'charge.refunded';
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
handle(event: StripeEvent): string {
|
|
178
|
+
return `Refund processed: ${event.data.object.amount}`;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Create a resolver that handles StripeEvent types
|
|
183
|
+
const resolver = new Resolver<ResolveTarget<[StripeEvent], string, StripeEvent>, StripeEvent>(
|
|
184
|
+
new PaymentEventHandler(),
|
|
185
|
+
new RefundEventHandler()
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
// Handle different event types
|
|
189
|
+
const paymentEvent: StripeEvent = {
|
|
190
|
+
id: 'evt_123',
|
|
191
|
+
type: 'payment_intent.succeeded',
|
|
192
|
+
data: { object: { id: 'pi_123', amount: 1000 } }
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const handler = resolver.resolve(paymentEvent);
|
|
196
|
+
console.log(handler.handle(paymentEvent)); // Output: Payment succeeded: 1000
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
This advanced type support allows you to:
|
|
200
|
+
- Use complex objects as type identifiers instead of simple strings
|
|
201
|
+
- Maintain full type safety throughout the resolution process
|
|
202
|
+
- Handle domain-specific objects like Stripe events, database records, or custom business objects
|
|
203
|
+
- Create more expressive and type-safe event handling systems
|
|
204
|
+
|
|
205
|
+
## Use Cases
|
|
206
|
+
|
|
207
|
+
1. **Command Pattern Implementation**: Handle different types of commands with specific handlers
|
|
208
|
+
2. **Format Conversion**: Convert data between different formats based on type
|
|
209
|
+
3. **Request Processing**: Process different types of requests with dedicated handlers
|
|
210
|
+
4. **Plugin System**: Implement a plugin system where different plugins handle specific types of operations
|
|
211
|
+
5. **Message Formatting**: Format different types of messages with specific formatters
|
|
212
|
+
|
|
213
|
+
## Error Handling
|
|
214
|
+
|
|
215
|
+
The resolver will throw errors in the following cases:
|
|
216
|
+
- When no resolvers are registered: `"Unasigned resolve target."`
|
|
217
|
+
- When trying to resolve an unsupported type: `"Unsupported type: xxx"`
|
|
218
|
+
|
|
219
|
+
## Upgrade Guide
|
|
220
|
+
|
|
221
|
+
### Upgrading from 1.x to 2.0.0
|
|
222
|
+
|
|
223
|
+
Version 2.0.0 introduces generic type support for better type safety. This change is backward compatible for JavaScript users, but TypeScript users may need to update their code.
|
|
224
|
+
|
|
225
|
+
#### Changes for TypeScript Users
|
|
226
|
+
|
|
227
|
+
1. The `ResolveTarget` interface now supports generics:
|
|
228
|
+
```typescript
|
|
229
|
+
// Before (1.x)
|
|
230
|
+
interface ResolveTarget {
|
|
231
|
+
supports(type: string): boolean;
|
|
232
|
+
handle(...args: any[]): any;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// After (2.0.0)
|
|
236
|
+
interface ResolveTarget<TArgs extends any[] = any[], TReturn = any, TType = string> {
|
|
237
|
+
supports(type: TType): boolean;
|
|
238
|
+
handle(...args: TArgs): TReturn;
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
2. The `Resolver` class now supports generics:
|
|
243
|
+
```typescript
|
|
244
|
+
// Before (1.x)
|
|
245
|
+
class Resolver {
|
|
246
|
+
// ...
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// After (2.0.0)
|
|
250
|
+
class Resolver<TBase extends ResolveTarget<any[], any, any> = ResolveTarget<any[], any, any>, TType = string> {
|
|
251
|
+
// ...
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
3. **New in 2.0.0**: You can now specify custom types for the `supports` method:
|
|
256
|
+
```typescript
|
|
257
|
+
// Use custom types instead of strings
|
|
258
|
+
interface CustomEvent {
|
|
259
|
+
type: string;
|
|
260
|
+
data: any;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
class CustomHandler implements ResolveTarget<[CustomEvent], string, CustomEvent> {
|
|
264
|
+
supports(event: CustomEvent): boolean {
|
|
265
|
+
return event.type === 'custom-type';
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
handle(event: CustomEvent): string {
|
|
269
|
+
return `Handled: ${event.type}`;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
#### Migration Steps
|
|
275
|
+
|
|
276
|
+
1. If you're using TypeScript with default `any` types, your code should continue to work without changes.
|
|
277
|
+
|
|
278
|
+
2. To take advantage of the improved type safety, update your class implementations:
|
|
279
|
+
```typescript
|
|
280
|
+
// Before (1.x)
|
|
281
|
+
class MyHandler implements ResolveTarget {
|
|
282
|
+
supports(type: string): boolean {
|
|
283
|
+
return type === 'my-type';
|
|
284
|
+
}
|
|
285
|
+
handle(name: string): string {
|
|
286
|
+
return `Hello ${name}`;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// After (2.0.0)
|
|
291
|
+
class MyHandler implements ResolveTarget<[string], string> {
|
|
292
|
+
supports(type: string): boolean {
|
|
293
|
+
return type === 'my-type';
|
|
294
|
+
}
|
|
295
|
+
handle(name: string): string {
|
|
296
|
+
return `Hello ${name}`;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
3. When creating a new Resolver, specify the generic type:
|
|
302
|
+
```typescript
|
|
303
|
+
// Before (1.x)
|
|
304
|
+
const resolver = new Resolver(new MyHandler());
|
|
305
|
+
|
|
306
|
+
// After (2.0.0)
|
|
307
|
+
const resolver = new Resolver<ResolveTarget<[string], string>>(new MyHandler());
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
4. If you have mixed handler types, you can use a union type or keep using the default `any` type:
|
|
311
|
+
```typescript
|
|
312
|
+
// Using union type
|
|
313
|
+
type MyHandlers = ResolveTarget<[string], string> | ResolveTarget<[number], boolean>;
|
|
314
|
+
const resolver = new Resolver<MyHandlers>(new StringHandler(), new NumberHandler());
|
|
315
|
+
|
|
316
|
+
// Or keep using the default any type
|
|
317
|
+
const resolver = new Resolver(new StringHandler(), new NumberHandler());
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## Contributing
|
|
321
|
+
|
|
322
|
+
```bash
|
|
55
323
|
$ npm install
|
|
56
324
|
$ git checkout -b YOUR_TOPIC_BRANCH
|
|
57
325
|
$ npm test
|
|
@@ -59,4 +327,8 @@ $ npm run build
|
|
|
59
327
|
$ git add ./
|
|
60
328
|
$ git commit -m "YOUR UPDATE DESCRIPTION"
|
|
61
329
|
$ git push YOUR_ORIGIN YOUR_TOPIC_BRANCH
|
|
62
|
-
```
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## License
|
|
333
|
+
|
|
334
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
17
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
18
|
};
|
|
5
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
__exportStar(require("./interface"), exports);
|
|
6
21
|
const resolver_1 = __importDefault(require("./resolver"));
|
|
7
22
|
exports.default = resolver_1.default;
|
|
23
|
+
// Export for CommonJS compatibility
|
|
24
|
+
// @ts-ignore
|
|
8
25
|
module.exports = resolver_1.default;
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../libs/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AAAA,8CAA2B;AAC3B,0DAAiC;AACjC,kBAAe,kBAAQ,CAAA;AACvB,oCAAoC;AACpC,aAAa;AACb,MAAM,CAAC,OAAO,GAAG,kBAAQ,CAAA"}
|
package/dist/interface.d.ts
CHANGED
|
@@ -1,10 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Interface that classes which are targets for the resolver should implement
|
|
3
|
+
*/
|
|
4
|
+
export interface ResolveTarget<TArgs extends any[] = any[], TReturn = any, TType = string> {
|
|
5
|
+
/**
|
|
6
|
+
* Determines whether the specified type is supported
|
|
7
|
+
* @param type The type to check for support
|
|
8
|
+
* @returns true if supported, false otherwise
|
|
9
|
+
*/
|
|
10
|
+
supports(type: TType): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Handles the request
|
|
13
|
+
* @param args Arguments needed for processing
|
|
14
|
+
* @returns Processing result
|
|
15
|
+
*/
|
|
16
|
+
handle(...args: TArgs): TReturn;
|
|
4
17
|
}
|
|
5
18
|
export declare namespace interfaces {
|
|
6
|
-
interface ResolveTarget {
|
|
7
|
-
supports(type:
|
|
8
|
-
handle(...args:
|
|
19
|
+
interface ResolveTarget<TArgs extends any[] = any[], TReturn = any, TType = string> {
|
|
20
|
+
supports(type: TType): boolean;
|
|
21
|
+
handle(...args: TArgs): TReturn;
|
|
9
22
|
}
|
|
10
23
|
}
|
package/dist/interface.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interface.js","sourceRoot":"","sources":["../libs/interface.ts"],"names":[],"mappings":""}
|
package/dist/resolver.d.ts
CHANGED
|
@@ -1,12 +1,48 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import { ResolveTarget } from './interface';
|
|
2
|
+
/**
|
|
3
|
+
* Resolver class implementing the Chain of Responsibility pattern
|
|
4
|
+
* Resolves handlers for specific types
|
|
5
|
+
*/
|
|
6
|
+
declare class Resolver<TBase extends ResolveTarget<any[], any, any> = ResolveTarget<any[], any, any>, TType = string> {
|
|
7
|
+
/**
|
|
8
|
+
* Array of registered resolver targets
|
|
9
|
+
* @private
|
|
10
|
+
*/
|
|
11
|
+
private updaters;
|
|
12
|
+
/**
|
|
13
|
+
* Initializes the resolver
|
|
14
|
+
* @param args Initial resolver targets
|
|
15
|
+
*/
|
|
16
|
+
constructor(...args: TBase[]);
|
|
17
|
+
/**
|
|
18
|
+
* Processes an array of arguments
|
|
19
|
+
* @param args Array of resolver targets
|
|
20
|
+
* @returns Processed array
|
|
21
|
+
* @private
|
|
22
|
+
*/
|
|
23
|
+
private getArgs;
|
|
24
|
+
/**
|
|
25
|
+
* Sets resolver targets
|
|
26
|
+
* @param updaters Array of resolver targets
|
|
27
|
+
*/
|
|
28
|
+
set(updaters: TBase[]): void;
|
|
29
|
+
/**
|
|
30
|
+
* Sets resolver targets (variadic version)
|
|
31
|
+
* @param args Resolver targets
|
|
32
|
+
*/
|
|
33
|
+
setUpdaters(...args: TBase[]): void;
|
|
34
|
+
/**
|
|
35
|
+
* Adds a resolver target
|
|
36
|
+
* @param updater Resolver target to add
|
|
37
|
+
*/
|
|
38
|
+
addUpdater(updater: TBase): void;
|
|
39
|
+
/**
|
|
40
|
+
* Resolves a resolver target for the specified type
|
|
41
|
+
* @param type Type to resolve
|
|
42
|
+
* @returns Resolved resolver target
|
|
43
|
+
* @throws {Error} When no resolver targets are registered
|
|
44
|
+
* @throws {Error} When no resolver target supporting the specified type is found
|
|
45
|
+
*/
|
|
46
|
+
resolve(type: TType): TBase;
|
|
11
47
|
}
|
|
12
48
|
export default Resolver;
|
package/dist/resolver.js
CHANGED
|
@@ -1,29 +1,71 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* Resolver class implementing the Chain of Responsibility pattern
|
|
5
|
+
* Resolves handlers for specific types
|
|
6
|
+
*/
|
|
3
7
|
class Resolver {
|
|
8
|
+
/**
|
|
9
|
+
* Initializes the resolver
|
|
10
|
+
* @param args Initial resolver targets
|
|
11
|
+
*/
|
|
4
12
|
constructor(...args) {
|
|
5
|
-
|
|
6
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Array of registered resolver targets
|
|
15
|
+
* @private
|
|
16
|
+
*/
|
|
17
|
+
this.updaters = [];
|
|
18
|
+
if (args.length > 0) {
|
|
19
|
+
this.set(args);
|
|
20
|
+
}
|
|
7
21
|
}
|
|
8
|
-
|
|
9
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Processes an array of arguments
|
|
24
|
+
* @param args Array of resolver targets
|
|
25
|
+
* @returns Processed array
|
|
26
|
+
* @private
|
|
27
|
+
*/
|
|
28
|
+
getArgs(args) {
|
|
29
|
+
return [...args];
|
|
10
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Sets resolver targets
|
|
33
|
+
* @param updaters Array of resolver targets
|
|
34
|
+
*/
|
|
11
35
|
set(updaters) {
|
|
12
|
-
this.
|
|
36
|
+
this.updaters = updaters;
|
|
13
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Sets resolver targets (variadic version)
|
|
40
|
+
* @param args Resolver targets
|
|
41
|
+
*/
|
|
14
42
|
setUpdaters(...args) {
|
|
15
43
|
this.set(this.getArgs(args));
|
|
16
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Adds a resolver target
|
|
47
|
+
* @param updater Resolver target to add
|
|
48
|
+
*/
|
|
17
49
|
addUpdater(updater) {
|
|
18
|
-
this.
|
|
50
|
+
this.updaters.push(updater);
|
|
19
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Resolves a resolver target for the specified type
|
|
54
|
+
* @param type Type to resolve
|
|
55
|
+
* @returns Resolved resolver target
|
|
56
|
+
* @throws {Error} When no resolver targets are registered
|
|
57
|
+
* @throws {Error} When no resolver target supporting the specified type is found
|
|
58
|
+
*/
|
|
20
59
|
resolve(type) {
|
|
21
|
-
if (this.
|
|
60
|
+
if (this.updaters.length < 1) {
|
|
22
61
|
throw new Error('Unasigned resolve target.');
|
|
23
|
-
|
|
24
|
-
|
|
62
|
+
}
|
|
63
|
+
const target = this.updaters.find(updater => updater.supports(type));
|
|
64
|
+
if (!target) {
|
|
25
65
|
throw new Error(`Unsupported type: ${type}`);
|
|
26
|
-
|
|
66
|
+
}
|
|
67
|
+
return target;
|
|
27
68
|
}
|
|
28
69
|
}
|
|
29
70
|
exports.default = Resolver;
|
|
71
|
+
//# sourceMappingURL=resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../libs/resolver.ts"],"names":[],"mappings":";;AAEA;;;GAGG;AACH,MAAM,QAAQ;IAOZ;;;OAGG;IACH,YAAY,GAAG,IAAa;QAV5B;;;WAGG;QACK,aAAQ,GAAY,EAAE,CAAC;QAO7B,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACK,OAAO,CAAC,IAAa;QAC3B,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;IACnB,CAAC;IAED;;;OAGG;IACI,GAAG,CAAC,QAAiB;QAC1B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED;;;OAGG;IACI,WAAW,CAAC,GAAG,IAAa;QACjC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/B,CAAC;IAED;;;OAGG;IACI,UAAU,CAAC,OAAc;QAC9B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED;;;;;;OAMG;IACI,OAAO,CAAC,IAAW;QACxB,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC/C,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QAErE,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,EAAE,CAAC,CAAC;QAC/C,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAED,kBAAe,QAAQ,CAAC"}
|
package/index.js
CHANGED
package/libs/index.ts
CHANGED
package/libs/interface.ts
CHANGED
|
@@ -1,10 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Interface that classes which are targets for the resolver should implement
|
|
3
|
+
*/
|
|
4
|
+
export interface ResolveTarget<TArgs extends any[] = any[], TReturn = any, TType = string> {
|
|
5
|
+
/**
|
|
6
|
+
* Determines whether the specified type is supported
|
|
7
|
+
* @param type The type to check for support
|
|
8
|
+
* @returns true if supported, false otherwise
|
|
9
|
+
*/
|
|
10
|
+
supports(type: TType): boolean
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Handles the request
|
|
14
|
+
* @param args Arguments needed for processing
|
|
15
|
+
* @returns Processing result
|
|
16
|
+
*/
|
|
17
|
+
handle(...args: TArgs): TReturn
|
|
4
18
|
}
|
|
19
|
+
|
|
20
|
+
// Maintain namespace for backward compatibility
|
|
5
21
|
export namespace interfaces {
|
|
6
|
-
export interface ResolveTarget {
|
|
7
|
-
supports(type:
|
|
8
|
-
handle(...args:
|
|
22
|
+
export interface ResolveTarget<TArgs extends any[] = any[], TReturn = any, TType = string> {
|
|
23
|
+
supports(type: TType): boolean
|
|
24
|
+
handle(...args: TArgs): TReturn
|
|
9
25
|
}
|
|
10
26
|
}
|
package/libs/resolver.ts
CHANGED
|
@@ -1,29 +1,80 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { ResolveTarget } from './interface'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Resolver class implementing the Chain of Responsibility pattern
|
|
5
|
+
* Resolves handlers for specific types
|
|
6
|
+
*/
|
|
7
|
+
class Resolver<TBase extends ResolveTarget<any[], any, any> = ResolveTarget<any[], any, any>, TType = string> {
|
|
8
|
+
/**
|
|
9
|
+
* Array of registered resolver targets
|
|
10
|
+
* @private
|
|
11
|
+
*/
|
|
12
|
+
private updaters: TBase[] = [];
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Initializes the resolver
|
|
16
|
+
* @param args Initial resolver targets
|
|
17
|
+
*/
|
|
18
|
+
constructor(...args: TBase[]) {
|
|
19
|
+
if (args.length > 0) {
|
|
20
|
+
this.set(args);
|
|
21
|
+
}
|
|
9
22
|
}
|
|
10
|
-
|
|
11
|
-
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Processes an array of arguments
|
|
26
|
+
* @param args Array of resolver targets
|
|
27
|
+
* @returns Processed array
|
|
28
|
+
* @private
|
|
29
|
+
*/
|
|
30
|
+
private getArgs(args: TBase[]): TBase[] {
|
|
31
|
+
return [...args];
|
|
12
32
|
}
|
|
13
|
-
|
|
14
|
-
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Sets resolver targets
|
|
36
|
+
* @param updaters Array of resolver targets
|
|
37
|
+
*/
|
|
38
|
+
public set(updaters: TBase[]): void {
|
|
39
|
+
this.updaters = updaters;
|
|
15
40
|
}
|
|
16
|
-
|
|
17
|
-
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Sets resolver targets (variadic version)
|
|
44
|
+
* @param args Resolver targets
|
|
45
|
+
*/
|
|
46
|
+
public setUpdaters(...args: TBase[]): void {
|
|
47
|
+
this.set(this.getArgs(args));
|
|
18
48
|
}
|
|
19
|
-
|
|
20
|
-
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Adds a resolver target
|
|
52
|
+
* @param updater Resolver target to add
|
|
53
|
+
*/
|
|
54
|
+
public addUpdater(updater: TBase): void {
|
|
55
|
+
this.updaters.push(updater);
|
|
21
56
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Resolves a resolver target for the specified type
|
|
60
|
+
* @param type Type to resolve
|
|
61
|
+
* @returns Resolved resolver target
|
|
62
|
+
* @throws {Error} When no resolver targets are registered
|
|
63
|
+
* @throws {Error} When no resolver target supporting the specified type is found
|
|
64
|
+
*/
|
|
65
|
+
public resolve(type: TType): TBase {
|
|
66
|
+
if (this.updaters.length < 1) {
|
|
67
|
+
throw new Error('Unasigned resolve target.');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const target = this.updaters.find(updater => updater.supports(type));
|
|
71
|
+
|
|
72
|
+
if (!target) {
|
|
73
|
+
throw new Error(`Unsupported type: ${type}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return target;
|
|
27
77
|
}
|
|
28
78
|
}
|
|
29
|
-
|
|
79
|
+
|
|
80
|
+
export default Resolver;
|
package/package.json
CHANGED
|
@@ -1,23 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "class-resolver",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Simple class resolver.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
6
7
|
"scripts": {
|
|
7
8
|
"build": "tsc",
|
|
8
9
|
"test": "jest",
|
|
9
10
|
"test:watch": "jest --watch",
|
|
10
|
-
"test:dev": "jest --watch --silent=false --verbose false --coverage"
|
|
11
|
+
"test:dev": "jest --watch --silent=false --verbose false --coverage",
|
|
12
|
+
"prepublishOnly": "npm run build"
|
|
11
13
|
},
|
|
12
|
-
"keywords": [
|
|
14
|
+
"keywords": [
|
|
15
|
+
"resolver",
|
|
16
|
+
"chain-of-responsibility",
|
|
17
|
+
"typescript"
|
|
18
|
+
],
|
|
13
19
|
"author": "Hidetaka Okamoto <info@wp-kyoto.net> (https://wp-kyoto.net)",
|
|
14
20
|
"license": "MIT",
|
|
15
21
|
"devDependencies": {
|
|
16
|
-
"@types/jest": "^
|
|
17
|
-
"@types/node": "^
|
|
18
|
-
"jest": "^
|
|
19
|
-
"ts-jest": "^
|
|
20
|
-
"typescript": "^
|
|
22
|
+
"@types/jest": "^29.5.0",
|
|
23
|
+
"@types/node": "^20.0.0",
|
|
24
|
+
"jest": "^29.5.0",
|
|
25
|
+
"ts-jest": "^29.1.0",
|
|
26
|
+
"typescript": "^5.0.0"
|
|
21
27
|
},
|
|
22
28
|
"jest": {
|
|
23
29
|
"moduleFileExtensions": [
|
|
@@ -26,15 +32,22 @@
|
|
|
26
32
|
"js"
|
|
27
33
|
],
|
|
28
34
|
"transform": {
|
|
29
|
-
"^.+\\.(ts|tsx)$":
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
"^.+\\.(ts|tsx)$": [
|
|
36
|
+
"ts-jest",
|
|
37
|
+
{
|
|
38
|
+
"tsconfig": "tsconfig.json"
|
|
39
|
+
}
|
|
40
|
+
]
|
|
35
41
|
},
|
|
36
42
|
"testMatch": [
|
|
37
43
|
"**/__tests__/*.+(ts|tsx|js)"
|
|
38
44
|
]
|
|
45
|
+
},
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "https://github.com/hideokamoto/class-resolver.git"
|
|
49
|
+
},
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=14.0.0"
|
|
39
52
|
}
|
|
40
53
|
}
|
package/readme-ja.md
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
# Simple Class resolver
|
|
2
|
+
|
|
3
|
+
クラスベースのリゾルバーを使用して責任連鎖パターンを実装するための軽量なTypeScript/JavaScriptライブラリです。
|
|
4
|
+
|
|
5
|
+
## 特徴
|
|
6
|
+
|
|
7
|
+
- さまざまなタイプのリクエストを処理するためのシンプルで直感的なAPI
|
|
8
|
+
- TypeScriptによる型安全な実装
|
|
9
|
+
- 柔軟なリゾルバー登録(コンストラクタ、setUpdaters、addUpdater)
|
|
10
|
+
- 異なる処理ロジックを持つ複数のリゾルバーのサポート
|
|
11
|
+
- サポートされていないタイプに対する明確なエラー処理
|
|
12
|
+
- より良い型安全性のためのジェネリック型サポート
|
|
13
|
+
|
|
14
|
+
## インストール
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install class-resolver
|
|
18
|
+
# または
|
|
19
|
+
yarn add class-resolver
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## 基本的な使い方
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
const Resolver = require('class-resolver')
|
|
26
|
+
|
|
27
|
+
class ExampleClass {
|
|
28
|
+
supports(type) {
|
|
29
|
+
return type === 'hoge'
|
|
30
|
+
}
|
|
31
|
+
handle() {
|
|
32
|
+
return 'hoge'
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
class ExampleClass2 {
|
|
36
|
+
supports(type) {
|
|
37
|
+
return type === 'fuga'
|
|
38
|
+
}
|
|
39
|
+
handle() {
|
|
40
|
+
return 'fuga'
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const resolver = new Resolver(new ExampleClass(), new ExampleClass2())
|
|
45
|
+
const c = resolver.resolve('hoge')
|
|
46
|
+
console.log(c.handle()) // 出力: hoge
|
|
47
|
+
|
|
48
|
+
const c2 = resolver.resolve('fuga')
|
|
49
|
+
console.log(c2.handle()) // 出力: fuga
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
resolver.resolve('xxx') // これはエラーをスローします
|
|
53
|
+
} catch (e) {
|
|
54
|
+
console.log(e) // Error: Unsupported type: xxx
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## 高度な使い方
|
|
59
|
+
|
|
60
|
+
### TypeScriptとパラメータの使用
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import Resolver from 'class-resolver';
|
|
64
|
+
import { ResolveTarget } from 'class-resolver';
|
|
65
|
+
|
|
66
|
+
// より良い型安全性のためにジェネリクスを使用
|
|
67
|
+
class MessageFormatter implements ResolveTarget<[string, number], string> {
|
|
68
|
+
supports(type: string): boolean {
|
|
69
|
+
return type === 'greeting'
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
handle(name: string, count: number): string {
|
|
73
|
+
return `Hello ${name}, this is message #${count}!`
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
class ErrorFormatter implements ResolveTarget<[string, number], string> {
|
|
78
|
+
supports(type: string): boolean {
|
|
79
|
+
return type === 'error'
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
handle(message: string, code: number): string {
|
|
83
|
+
return `Error ${code}: ${message}`
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// より良い型安全性のためにジェネリック型を指定
|
|
88
|
+
const resolver = new Resolver<ResolveTarget<[string, number], string>>(
|
|
89
|
+
new MessageFormatter(),
|
|
90
|
+
new ErrorFormatter()
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
// グリーティングフォーマッターの使用
|
|
94
|
+
const greeting = resolver.resolve('greeting')
|
|
95
|
+
console.log(greeting.handle('John', 1)) // 出力: Hello John, this is message #1!
|
|
96
|
+
|
|
97
|
+
// エラーフォーマッターの使用
|
|
98
|
+
const error = resolver.resolve('error')
|
|
99
|
+
console.log(error.handle('Not Found', 404)) // 出力: Error 404: Not Found
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 動的リゾルバー登録
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
// より良い型安全性のためにジェネリック型を指定
|
|
106
|
+
const resolver = new Resolver<ResolveTarget<[string, number], string>>()
|
|
107
|
+
|
|
108
|
+
// 初期化後にリゾルバーを追加
|
|
109
|
+
resolver.setUpdaters(new MessageFormatter(), new ErrorFormatter())
|
|
110
|
+
|
|
111
|
+
// または一つずつ追加
|
|
112
|
+
resolver.addUpdater(new MessageFormatter())
|
|
113
|
+
resolver.addUpdater(new ErrorFormatter())
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## ジェネリック型サポート
|
|
117
|
+
|
|
118
|
+
バージョン2.0.0から、class-resolverはより良い型安全性のためにジェネリック型をサポートしています:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
// ジェネリクスを使用したインターフェースの定義
|
|
122
|
+
interface ResolveTarget<TArgs extends any[] = any[], TReturn = any> {
|
|
123
|
+
supports(type: string): boolean;
|
|
124
|
+
handle(...args: TArgs): TReturn;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// 特定の型でインターフェースを実装するクラスを定義
|
|
128
|
+
class StringFormatter implements ResolveTarget<[string], string> {
|
|
129
|
+
supports(type: string): boolean {
|
|
130
|
+
return type === 'string-format';
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
handle(input: string): string {
|
|
134
|
+
return input.toUpperCase();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// 特定の型でリゾルバーを作成
|
|
139
|
+
const resolver = new Resolver<ResolveTarget<[string], string>>(new StringFormatter());
|
|
140
|
+
const formatter = resolver.resolve('string-format');
|
|
141
|
+
const result = formatter.handle('hello'); // resultはstring型として型付けされます
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## ユースケース
|
|
145
|
+
|
|
146
|
+
1. **コマンドパターンの実装**: 特定のハンドラーで異なるタイプのコマンドを処理
|
|
147
|
+
2. **フォーマット変換**: タイプに基づいてデータを異なるフォーマット間で変換
|
|
148
|
+
3. **リクエスト処理**: 専用のハンドラーで異なるタイプのリクエストを処理
|
|
149
|
+
4. **プラグインシステム**: 異なるプラグインが特定のタイプの操作を処理するプラグインシステムを実装
|
|
150
|
+
5. **メッセージフォーマット**: 特定のフォーマッターで異なるタイプのメッセージをフォーマット
|
|
151
|
+
|
|
152
|
+
## エラー処理
|
|
153
|
+
|
|
154
|
+
リゾルバーは以下の場合にエラーをスローします:
|
|
155
|
+
- リゾルバーが登録されていない場合: `"Unasigned resolve target."`
|
|
156
|
+
- サポートされていないタイプを解決しようとした場合: `"Unsupported type: xxx"`
|
|
157
|
+
|
|
158
|
+
## アップグレードガイド
|
|
159
|
+
|
|
160
|
+
### 1.xから2.0.0へのアップグレード
|
|
161
|
+
|
|
162
|
+
バージョン2.0.0では、より良い型安全性のためにジェネリック型サポートが導入されました。この変更はJavaScriptユーザーにとって後方互換性がありますが、TypeScriptユーザーはコードを更新する必要があるかもしれません。
|
|
163
|
+
|
|
164
|
+
#### TypeScriptユーザーの変更点
|
|
165
|
+
|
|
166
|
+
1. `ResolveTarget`インターフェースがジェネリクスをサポートするようになりました:
|
|
167
|
+
```typescript
|
|
168
|
+
// 以前 (1.x)
|
|
169
|
+
interface ResolveTarget {
|
|
170
|
+
supports(type: string): boolean;
|
|
171
|
+
handle(...args: any[]): any;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// 以後 (2.0.0)
|
|
175
|
+
interface ResolveTarget<TArgs extends any[] = any[], TReturn = any> {
|
|
176
|
+
supports(type: string): boolean;
|
|
177
|
+
handle(...args: TArgs): TReturn;
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
2. `Resolver`クラスがジェネリクスをサポートするようになりました:
|
|
182
|
+
```typescript
|
|
183
|
+
// 以前 (1.x)
|
|
184
|
+
class Resolver {
|
|
185
|
+
// ...
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// 以後 (2.0.0)
|
|
189
|
+
class Resolver<TBase extends ResolveTarget = ResolveTarget> {
|
|
190
|
+
// ...
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
#### 移行手順
|
|
195
|
+
|
|
196
|
+
1. デフォルトの`any`型を使用してTypeScriptを使用している場合、コードは変更なしで引き続き動作するはずです。
|
|
197
|
+
|
|
198
|
+
2. 改善された型安全性を活用するには、クラスの実装を更新してください:
|
|
199
|
+
```typescript
|
|
200
|
+
// 以前 (1.x)
|
|
201
|
+
class MyHandler implements ResolveTarget {
|
|
202
|
+
supports(type: string): boolean {
|
|
203
|
+
return type === 'my-type';
|
|
204
|
+
}
|
|
205
|
+
handle(name: string): string {
|
|
206
|
+
return `Hello ${name}`;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// 以後 (2.0.0)
|
|
211
|
+
class MyHandler implements ResolveTarget<[string], string> {
|
|
212
|
+
supports(type: string): boolean {
|
|
213
|
+
return type === 'my-type';
|
|
214
|
+
}
|
|
215
|
+
handle(name: string): string {
|
|
216
|
+
return `Hello ${name}`;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
3. 新しいResolverを作成する際に、ジェネリック型を指定してください:
|
|
222
|
+
```typescript
|
|
223
|
+
// 以前 (1.x)
|
|
224
|
+
const resolver = new Resolver(new MyHandler());
|
|
225
|
+
|
|
226
|
+
// 以後 (2.0.0)
|
|
227
|
+
const resolver = new Resolver<ResolveTarget<[string], string>>(new MyHandler());
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
4. 混合ハンドラータイプがある場合は、ユニオン型を使用するか、デフォルトの`any`型を引き続き使用できます:
|
|
231
|
+
```typescript
|
|
232
|
+
// ユニオン型の使用
|
|
233
|
+
type MyHandlers = ResolveTarget<[string], string> | ResolveTarget<[number], boolean>;
|
|
234
|
+
const resolver = new Resolver<MyHandlers>(new StringHandler(), new NumberHandler());
|
|
235
|
+
|
|
236
|
+
// またはデフォルトのany型を引き続き使用
|
|
237
|
+
const resolver = new Resolver(new StringHandler(), new NumberHandler());
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## 貢献
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
$ npm install
|
|
244
|
+
$ git checkout -b YOUR_TOPIC_BRANCH
|
|
245
|
+
$ npm test
|
|
246
|
+
$ npm run build
|
|
247
|
+
$ git add ./
|
|
248
|
+
$ git commit -m "YOUR UPDATE DESCRIPTION"
|
|
249
|
+
$ git push YOUR_ORIGIN YOUR_TOPIC_BRANCH
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## サンプル
|
|
253
|
+
|
|
254
|
+
このライブラリには、使用方法を示すサンプルが含まれています。サンプルを実行するには:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
# サンプルディレクトリに移動
|
|
258
|
+
cd example
|
|
259
|
+
|
|
260
|
+
# 依存関係をインストール
|
|
261
|
+
npm install
|
|
262
|
+
|
|
263
|
+
# ビルドを実行
|
|
264
|
+
npm run build
|
|
265
|
+
|
|
266
|
+
# サンプルを実行
|
|
267
|
+
npm test
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### JavaScriptサンプル
|
|
271
|
+
|
|
272
|
+
JavaScriptでの基本的な使用例は`index.js`ファイルにあります:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
node index.js
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### TypeScriptサンプル
|
|
279
|
+
|
|
280
|
+
TypeScriptでの使用例は`libs/index.ts`ファイルにあります。v2.0.0からはジェネリクスをサポートしており、型安全性が向上しています:
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
import Resolver, { ResolveTarget } from 'class-resolver';
|
|
284
|
+
|
|
285
|
+
// ジェネリクスを使用して引数と戻り値の型を指定
|
|
286
|
+
class StringFormatter implements ResolveTarget<[string], string> {
|
|
287
|
+
supports(type: string): boolean {
|
|
288
|
+
return type === 'string-format';
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
handle(input: string): string {
|
|
292
|
+
return input.toUpperCase();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Resolverにも型パラメータを指定
|
|
297
|
+
const resolver = new Resolver<ResolveTarget<[string], string>>(new StringFormatter());
|
|
298
|
+
const formatter = resolver.resolve('string-format');
|
|
299
|
+
const result = formatter.handle('hello'); // resultはstring型として型付けされます
|
|
300
|
+
console.log(result); // "HELLO"
|
|
301
|
+
```
|
package/dist/libs/interface.js
DELETED
package/dist/libs/resolver.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
class Resolver {
|
|
4
|
-
constructor(...args) {
|
|
5
|
-
this.updater = [];
|
|
6
|
-
this.set(this.getArgs(args));
|
|
7
|
-
}
|
|
8
|
-
getArgs(arg) {
|
|
9
|
-
return Array.prototype.slice.call(arg, 0);
|
|
10
|
-
}
|
|
11
|
-
set(updaters) {
|
|
12
|
-
this.updater = updaters;
|
|
13
|
-
}
|
|
14
|
-
setUpdaters(...args) {
|
|
15
|
-
this.set(this.getArgs(args));
|
|
16
|
-
}
|
|
17
|
-
addUpdater(updater) {
|
|
18
|
-
this.updater.push(updater);
|
|
19
|
-
}
|
|
20
|
-
resolve(type) {
|
|
21
|
-
if (this.updater.length < 1)
|
|
22
|
-
throw new Error('Unasigned resolve target.');
|
|
23
|
-
const target = this.updater.filter(updater => updater.supports(type));
|
|
24
|
-
if (target.length < 1)
|
|
25
|
-
throw new Error(`Unsupported type: ${type}`);
|
|
26
|
-
return target[0];
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
exports.default = Resolver;
|