class-resolver 1.1.1 → 2.0.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 CHANGED
@@ -1,13 +1,27 @@
1
1
  # Simple Class resolver
2
2
 
3
- ## Getting started
3
+ A lightweight TypeScript/JavaScript library for implementing the Chain of Responsibility pattern with class-based resolvers.
4
4
 
5
- ```
6
- $ npm i -S class-resolver
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
13
+
14
+ ## Installation
8
15
 
9
- ## Example code
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,206 @@ class ExampleClass2 {
26
40
  return 'fuga'
27
41
  }
28
42
  }
29
- console.log(Resolver)
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
- Execute result
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
+ }
44
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!
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
- $ node index.js
47
- hoge
48
- fuga
49
- Error: Unsupported type: xxx
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
- ## Contributing
116
+ ## Generic Type Support
117
+
118
+ From version 2.0.0, class-resolver supports generic types for better type safety:
53
119
 
120
+ ```typescript
121
+ // Define the interface with generics
122
+ interface ResolveTarget<TArgs extends any[] = any[], TReturn = any> {
123
+ supports(type: string): 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
+ }
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
+ ## Use Cases
145
+
146
+ 1. **Command Pattern Implementation**: Handle different types of commands with specific handlers
147
+ 2. **Format Conversion**: Convert data between different formats based on type
148
+ 3. **Request Processing**: Process different types of requests with dedicated handlers
149
+ 4. **Plugin System**: Implement a plugin system where different plugins handle specific types of operations
150
+ 5. **Message Formatting**: Format different types of messages with specific formatters
151
+
152
+ ## Error Handling
153
+
154
+ The resolver will throw errors in the following cases:
155
+ - When no resolvers are registered: `"Unasigned resolve target."`
156
+ - When trying to resolve an unsupported type: `"Unsupported type: xxx"`
157
+
158
+ ## Upgrade Guide
159
+
160
+ ### Upgrading from 1.x to 2.0.0
161
+
162
+ 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.
163
+
164
+ #### Changes for TypeScript Users
165
+
166
+ 1. The `ResolveTarget` interface now supports generics:
167
+ ```typescript
168
+ // Before (1.x)
169
+ interface ResolveTarget {
170
+ supports(type: string): boolean;
171
+ handle(...args: any[]): any;
172
+ }
173
+
174
+ // After (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. The `Resolver` class now supports generics:
182
+ ```typescript
183
+ // Before (1.x)
184
+ class Resolver {
185
+ // ...
186
+ }
187
+
188
+ // After (2.0.0)
189
+ class Resolver<TBase extends ResolveTarget = ResolveTarget> {
190
+ // ...
191
+ }
192
+ ```
193
+
194
+ #### Migration Steps
195
+
196
+ 1. If you're using TypeScript with default `any` types, your code should continue to work without changes.
197
+
198
+ 2. To take advantage of the improved type safety, update your class implementations:
199
+ ```typescript
200
+ // Before (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
+ // After (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. When creating a new Resolver, specify the generic type:
222
+ ```typescript
223
+ // Before (1.x)
224
+ const resolver = new Resolver(new MyHandler());
225
+
226
+ // After (2.0.0)
227
+ const resolver = new Resolver<ResolveTarget<[string], string>>(new MyHandler());
228
+ ```
229
+
230
+ 4. If you have mixed handler types, you can use a union type or keep using the default `any` type:
231
+ ```typescript
232
+ // Using union type
233
+ type MyHandlers = ResolveTarget<[string], string> | ResolveTarget<[number], boolean>;
234
+ const resolver = new Resolver<MyHandlers>(new StringHandler(), new NumberHandler());
235
+
236
+ // Or keep using the default any type
237
+ const resolver = new Resolver(new StringHandler(), new NumberHandler());
238
+ ```
239
+
240
+ ## Contributing
241
+
242
+ ```bash
55
243
  $ npm install
56
244
  $ git checkout -b YOUR_TOPIC_BRANCH
57
245
  $ npm test
@@ -59,4 +247,8 @@ $ npm run build
59
247
  $ git add ./
60
248
  $ git commit -m "YOUR UPDATE DESCRIPTION"
61
249
  $ git push YOUR_ORIGIN YOUR_TOPIC_BRANCH
62
- ```
250
+ ```
251
+
252
+ ## License
253
+
254
+ 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"}
@@ -1,10 +1,23 @@
1
- export interface ResolveTarget {
1
+ /**
2
+ * Interface that classes which are targets for the resolver should implement
3
+ */
4
+ export interface ResolveTarget<TArgs extends any[] = any[], TReturn = any> {
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
+ */
2
10
  supports(type: string): boolean;
3
- handle(...args: any): any;
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 {
19
+ interface ResolveTarget<TArgs extends any[] = any[], TReturn = any> {
7
20
  supports(type: string): boolean;
8
- handle(...args: any): any;
21
+ handle(...args: TArgs): TReturn;
9
22
  }
10
23
  }
package/dist/interface.js CHANGED
@@ -1,2 +1,3 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.js","sourceRoot":"","sources":["../libs/interface.ts"],"names":[],"mappings":""}
@@ -1,12 +1,48 @@
1
- import { interfaces } from './interface';
2
- import ResolveTarget = interfaces.ResolveTarget;
3
- declare class Resolver {
4
- private updater;
5
- constructor(...args: ResolveTarget[]);
6
- getArgs(arg: ResolveTarget[]): ResolveTarget[];
7
- set(updaters: ResolveTarget[]): void;
8
- setUpdaters(...args: ResolveTarget[]): void;
9
- addUpdater(updater: ResolveTarget): void;
10
- resolve(type: string): ResolveTarget;
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 = ResolveTarget> {
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: string): 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
- this.updater = [];
6
- this.set(this.getArgs(args));
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
- getArgs(arg) {
9
- return Array.prototype.slice.call(arg, 0);
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.updater = updaters;
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.updater.push(updater);
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.updater.length < 1)
60
+ if (this.updaters.length < 1) {
22
61
  throw new Error('Unasigned resolve target.');
23
- const target = this.updater.filter(updater => updater.supports(type));
24
- if (target.length < 1)
62
+ }
63
+ const target = this.updaters.find(updater => updater.supports(type));
64
+ if (!target) {
25
65
  throw new Error(`Unsupported type: ${type}`);
26
- return target[0];
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,IAAY;QACzB,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
@@ -1,3 +1,5 @@
1
- const Resolver = require('./libs/resolver')
1
+ 'use strict';
2
2
 
3
- module.exports = Resolver.default || Resolver
3
+ const Resolver = require('./dist/index');
4
+
5
+ module.exports = Resolver.default || Resolver;
package/libs/index.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export * from './interface'
2
2
  import Resolver from './resolver'
3
3
  export default Resolver
4
+ // Export for CommonJS compatibility
5
+ // @ts-ignore
4
6
  module.exports = Resolver
package/libs/interface.ts CHANGED
@@ -1,10 +1,26 @@
1
- export interface ResolveTarget {
1
+ /**
2
+ * Interface that classes which are targets for the resolver should implement
3
+ */
4
+ export interface ResolveTarget<TArgs extends any[] = any[], TReturn = any> {
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
+ */
2
10
  supports(type: string): boolean
3
- handle(...args:any): any
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 {
22
+ export interface ResolveTarget<TArgs extends any[] = any[], TReturn = any> {
7
23
  supports(type: string): boolean
8
- handle(...args:any): any
24
+ handle(...args: TArgs): TReturn
9
25
  }
10
26
  }
package/libs/resolver.ts CHANGED
@@ -1,29 +1,80 @@
1
- import { interfaces } from './interface'
2
- import ResolveTarget = interfaces.ResolveTarget
3
-
4
- class Resolver {
5
- private updater: ResolveTarget[]
6
- constructor (...args: ResolveTarget[]) {
7
- this.updater = []
8
- this.set(this.getArgs(args))
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 = ResolveTarget> {
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
- getArgs (arg: ResolveTarget[]): ResolveTarget[] {
11
- return Array.prototype.slice.call(arg, 0)
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
- set (updaters: ResolveTarget[]) {
14
- this.updater = updaters
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
- setUpdaters (...args: ResolveTarget[]) {
17
- this.set(this.getArgs(args))
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
- addUpdater (updater: ResolveTarget) {
20
- this.updater.push(updater)
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
- resolve (type: string): ResolveTarget {
23
- if (this.updater.length < 1) throw new Error('Unasigned resolve target.')
24
- const target = this.updater.filter(updater => updater.supports(type))
25
- if (target.length < 1) throw new Error(`Unsupported type: ${type}`)
26
- return target[0]
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: string): 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
- export default Resolver
79
+
80
+ export default Resolver;
package/package.json CHANGED
@@ -1,23 +1,29 @@
1
1
  {
2
2
  "name": "class-resolver",
3
- "version": "1.1.1",
3
+ "version": "2.0.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": "^23.3.10",
17
- "@types/node": "^11.10.4",
18
- "jest": "^24.8.0",
19
- "ts-jest": "^23.10.5",
20
- "typescript": "^3.2.2"
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,17 @@
26
32
  "js"
27
33
  ],
28
34
  "transform": {
29
- "^.+\\.(ts|tsx)$": "ts-jest"
30
- },
31
- "globals": {
32
- "ts-jest": {
33
- "tsConfigFile": "tsconfig.json"
34
- }
35
+ "^.+\\.(ts|tsx)$": ["ts-jest", { "tsconfig": "tsconfig.json" }]
35
36
  },
36
37
  "testMatch": [
37
38
  "**/__tests__/*.+(ts|tsx|js)"
38
39
  ]
40
+ },
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "https://github.com/hideokamoto/class-resolver.git"
44
+ },
45
+ "engines": {
46
+ "node": ">=14.0.0"
39
47
  }
40
48
  }
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
+ ```
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -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;