@idlebox/common 1.5.21 → 1.5.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/lib/autoindex.generated.d.ts +0 -2
  2. package/lib/autoindex.generated.d.ts.map +1 -1
  3. package/lib/autoindex.generated.js +1 -8
  4. package/lib/autoindex.generated.js.map +1 -1
  5. package/lib/debugging/inspect.d.ts.map +1 -1
  6. package/lib/debugging/inspect.js +2 -1
  7. package/lib/debugging/inspect.js.map +1 -1
  8. package/lib/error/pretty.nodejs.d.ts.map +1 -1
  9. package/lib/error/pretty.nodejs.js +4 -1
  10. package/lib/error/pretty.nodejs.js.map +1 -1
  11. package/lib/error/stack-parser.v8.js +2 -2
  12. package/lib/error/stack-parser.v8.js.map +1 -1
  13. package/lib/lifecycle/dispose/disposable.d.ts +4 -1
  14. package/lib/lifecycle/dispose/disposable.d.ts.map +1 -1
  15. package/lib/lifecycle/dispose/disposable.js +58 -27
  16. package/lib/lifecycle/dispose/disposable.js.map +1 -1
  17. package/lib/lifecycle/event/event.d.ts +26 -3
  18. package/lib/lifecycle/event/event.d.ts.map +1 -1
  19. package/lib/lifecycle/event/event.js +83 -34
  20. package/lib/lifecycle/event/event.js.map +1 -1
  21. package/lib/map-and-set/required-map.d.ts.map +1 -1
  22. package/lib/map-and-set/required-map.js +8 -0
  23. package/lib/map-and-set/required-map.js.map +1 -1
  24. package/lib/promise/deferred-promise.d.ts +1 -0
  25. package/lib/promise/deferred-promise.d.ts.map +1 -1
  26. package/lib/promise/deferred-promise.js +5 -5
  27. package/lib/promise/deferred-promise.js.map +1 -1
  28. package/lib/re-export.d.ts.map +1 -1
  29. package/lib/re-export.js +0 -1
  30. package/lib/re-export.js.map +1 -1
  31. package/lib/schedule/extendable-timer.d.ts +1 -1
  32. package/lib/schedule/extendable-timer.d.ts.map +1 -1
  33. package/lib/schedule/extendable-timer.js.map +1 -1
  34. package/lib/schedule/timeout.d.ts +1 -1
  35. package/lib/schedule/timeout.d.ts.map +1 -1
  36. package/lib/schedule/timeout.js +6 -9
  37. package/lib/schedule/timeout.js.map +1 -1
  38. package/package.json +9 -12
  39. package/src/autoindex.generated.ts +1 -12
  40. package/src/debugging/inspect.ts +2 -1
  41. package/src/error/pretty.nodejs.ts +5 -1
  42. package/src/error/stack-parser.v8.ts +2 -2
  43. package/src/lifecycle/dispose/disposable.ts +75 -29
  44. package/src/lifecycle/event/event.ts +81 -34
  45. package/src/map-and-set/required-map.ts +10 -0
  46. package/src/promise/deferred-promise.ts +5 -6
  47. package/src/re-export.ts +0 -1
  48. package/src/schedule/extendable-timer.ts +1 -2
  49. package/src/schedule/timeout.ts +8 -4
  50. package/lib/schedule/local-type.d.ts +0 -3
  51. package/lib/schedule/local-type.d.ts.map +0 -1
  52. package/lib/schedule/local-type.js +0 -2
  53. package/lib/schedule/local-type.js.map +0 -1
  54. package/src/schedule/local-type.ts +0 -2
  55. package/src/string/concatType.generator.ts +0 -31
@@ -1,7 +1,8 @@
1
1
  import { defineInspectMethod } from '../../debugging/inspect.js';
2
2
  import type { MaybeNamed } from '../../debugging/object-with-name.js';
3
+ import { convertCaughtError } from '../../error/convert-unknown.js';
4
+ import { prettyPrintError } from '../../error/pretty.nodejs.js';
3
5
  import { createStackTraceHolder, type StackTraceHolder } from '../../error/stack-trace.js';
4
- import { definePublicConstant } from '../../object/definePublicConstant.js';
5
6
  import { isPromiseLike } from '../../promise/is-promise.js';
6
7
  import { Emitter } from '../event/event.js';
7
8
  import type { EventRegister } from '../event/type.js';
@@ -39,6 +40,22 @@ export interface IAsyncDisposable extends MaybeNamed {
39
40
  type _Type<Async extends boolean> = Async extends true ? IAsyncDisposable : IDisposable;
40
41
  type _RType<Async extends boolean> = Async extends true ? Promise<void> : void;
41
42
 
43
+ interface IDisposeState<Async extends boolean> {
44
+ /**
45
+ * 存在stack说明dispose已经开始(可能已经完成)
46
+ */
47
+ trace?: StackTraceHolder;
48
+ finished: boolean;
49
+ /**
50
+ * 同步的是undefined,异步的是Promise
51
+ */
52
+ result?: _RType<Async>;
53
+ /**
54
+ * 只有同步的用到,每次调用始终抛出相同错误,异步通过promise保存状态
55
+ */
56
+ error?: Error;
57
+ }
58
+
42
59
  /**
43
60
  * 增强型Disposable
44
61
  */
@@ -74,11 +91,11 @@ export abstract class AbstractEnhancedDisposable<Async extends boolean> implemen
74
91
  return `[Function debug]`;
75
92
  });
76
93
 
77
- this._onDisposeError = new Emitter<Error>(`${this.displayName}:errorEvent`);
94
+ this._onDisposeError = new Emitter<Error>(`${this.displayName}:errorEvent`, Emitter.EAction.PrintIgnore);
78
95
  this.onDisposeError = this._onDisposeError.register;
79
- this._onBeforeDispose = new Emitter<void>(`${this.displayName}:beforeEvent`);
96
+ this._onBeforeDispose = new Emitter<void>(`${this.displayName}:beforeEvent`, Emitter.EAction.PrintIgnore);
80
97
  this.onBeforeDispose = this._onBeforeDispose.register;
81
- this._onPostDispose = new Emitter<void>(`${this.displayName}:postEvent`);
98
+ this._onPostDispose = new Emitter<void>(`${this.displayName}:postEvent`, Emitter.EAction.PrintIgnore);
82
99
  this.onPostDispose = this._onPostDispose.register;
83
100
  }
84
101
 
@@ -86,8 +103,8 @@ export abstract class AbstractEnhancedDisposable<Async extends boolean> implemen
86
103
  * @throws if already disposed
87
104
  */
88
105
  public assertNotDisposed() {
89
- if (this._disposed) {
90
- throw new DuplicateDisposedError(this, this._disposed.trace);
106
+ if (this.__dispose_state.trace) {
107
+ throw new DuplicateDisposedError(this, this.__dispose_state.trace);
91
108
  }
92
109
  }
93
110
 
@@ -103,6 +120,7 @@ export abstract class AbstractEnhancedDisposable<Async extends boolean> implemen
103
120
  this._disposables.unshift(fromNativeDisposable(d));
104
121
  if (autoDereference) {
105
122
  (d as IBackReferenceDisposableEvent).onBeforeDispose(() => {
123
+ if (this.disposing || this.disposed) return;
106
124
  this._unregister(d);
107
125
  });
108
126
  }
@@ -122,60 +140,88 @@ export abstract class AbstractEnhancedDisposable<Async extends boolean> implemen
122
140
  return rmOk;
123
141
  }
124
142
 
125
- private _disposed?: {
126
- trace: StackTraceHolder;
127
- result: _RType<Async>;
128
- };
143
+ private __dispose_state: IDisposeState<Async> = { finished: false };
129
144
  public get disposed() {
130
- return !!this._disposed;
145
+ return this.__dispose_state.finished;
131
146
  }
132
147
 
148
+ /**
149
+ * 正在dispose中(已开始但未完成)
150
+ */
133
151
  public get disposing() {
134
- return this._onBeforeDispose.disposed && !this._disposed;
152
+ return !this.__dispose_state.finished && !!this.__dispose_state.trace;
135
153
  }
136
154
 
137
155
  /**
138
156
  * 释放相关资源
139
157
  */
140
158
  public dispose(): _RType<Async> {
141
- if (this._disposed) {
142
- if (this.duplicateDispose === DuplicateDisposeAction.Allow) return this._disposed.result;
159
+ if (this.__dispose_state.trace) {
160
+ // 释放已开始或已结束
161
+ if (this.duplicateDispose === DuplicateDisposeAction.Allow) {
162
+ if (this.__dispose_state.error) {
163
+ throw this.__dispose_state.error;
164
+ } else {
165
+ /**
166
+ * biome-ignore lint/style/noNonNullAssertion: 完全无需考虑
167
+ *
168
+ * 异步dispose的同步部分,重复调用dispose,会返回undefined而非Promise
169
+ * 但这正好是希望的,否则死锁了
170
+ */
171
+ return this.__dispose_state.result!;
172
+ }
173
+ }
143
174
 
144
- const dupErr = new DuplicateDisposedError(this, this._disposed.trace);
175
+ const dupErr = new DuplicateDisposedError(this, this.__dispose_state.trace);
145
176
  dupErr.consoleWarning();
146
177
  if (this.duplicateDispose === DuplicateDisposeAction.Disable) {
147
178
  throw dupErr;
148
179
  } else {
149
- return this._disposed.result;
180
+ return this.__dispose_state.result as any;
150
181
  }
182
+ // never
151
183
  }
152
- this._onBeforeDispose.fireNoError();
153
- this._onBeforeDispose.dispose();
154
- const trace = createStackTraceHolder('disposed', this.dispose);
155
184
 
156
185
  const cleanup = () => {
157
- definePublicConstant(this, '_disposed', {
158
- // 记录 disposed 状态,顺便也记录调用栈
159
- trace: trace,
160
- result: r,
161
- });
186
+ this.__dispose_state.finished = true;
162
187
 
163
188
  Object.assign(this, { _disposables: null });
164
- this._onPostDispose.fireNoError();
189
+ this._onPostDispose.fire();
165
190
  this._onPostDispose.dispose();
191
+
166
192
  this._onDisposeError.dispose();
167
193
  };
168
194
 
169
- let r: _RType<Async>;
195
+ // 第一时间设置trace
196
+ this.__dispose_state.trace = createStackTraceHolder('disposed', this.dispose);
197
+
198
+ this._onBeforeDispose.fire();
199
+ this._onBeforeDispose.dispose();
200
+
170
201
  try {
171
- r = this._dispose(this._disposables);
202
+ this.__dispose_state.result = this._dispose(this._disposables);
172
203
  } catch (e) {
204
+ // 同步错误处理
205
+ const err = convertCaughtError(e);
206
+ this.__dispose_state.error = err;
207
+ this._onDisposeError.fire(err);
208
+ if (this._onDisposeError.listenerCount() === 0) {
209
+ prettyPrintError('unhandled sync dispose error', err);
210
+ }
173
211
  cleanup();
174
- throw e;
212
+ throw this.__dispose_state.error;
175
213
  }
176
214
 
215
+ const r = this.__dispose_state.result;
177
216
  if (isPromiseLike(r)) {
178
- r.finally(cleanup);
217
+ // 异步错误处理
218
+ r.catch((e) => {
219
+ e = convertCaughtError(e);
220
+ this._onDisposeError.fire(e);
221
+ if (this._onDisposeError.listenerCount() === 0) {
222
+ prettyPrintError('unhandled async dispose error', e);
223
+ }
224
+ }).finally(cleanup);
179
225
  } else {
180
226
  cleanup();
181
227
  }
@@ -1,6 +1,7 @@
1
- import { Exit } from '@idlebox/errors';
2
1
  import { defineInspectMethod, inspectSymbol } from '../../debugging/inspect.js';
3
2
  import { nameObject, objectName } from '../../debugging/object-with-name.js';
3
+ import { convertCaughtError } from '../../error/convert-unknown.js';
4
+ import { prettyPrintError } from '../../error/pretty.nodejs.js';
4
5
  import { createStackTraceHolder } from '../../error/stack-trace.js';
5
6
  import { functionToDisposable } from '../dispose/bridges/function.js';
6
7
  import type { IDisposable } from '../dispose/disposable.js';
@@ -9,15 +10,27 @@ import type { EventHandler, EventRegister, IEventEmitter } from './type.js';
9
10
 
10
11
  const anonymousName = 'AnonymousEmitter';
11
12
 
13
+ enum FireErrorAction {
14
+ Throw = 0,
15
+ Delay = 1,
16
+ Ignore = 2,
17
+ PrintIgnore = 3,
18
+ }
19
+
12
20
  /**
13
21
  * @public
14
22
  */
15
23
  export class Emitter<T = unknown> implements IEventEmitter<T> {
16
- protected _callbacks?: (EventHandler<T> | undefined)[];
24
+ protected readonly _callbacks: (EventHandler<T> | undefined)[] = [];
17
25
  private executing = false;
18
26
  private _something_change_during_call = false;
19
27
 
20
- constructor(public readonly displayName: string = anonymousName) {
28
+ static readonly EAction = FireErrorAction;
29
+
30
+ constructor(
31
+ public readonly displayName: string = anonymousName,
32
+ private readonly onErrorDefault: FireErrorAction = FireErrorAction.Throw,
33
+ ) {
21
34
  this.handle = Object.defineProperties(this.handle.bind(this), {
22
35
  once: {
23
36
  get: () => this.once.bind(this),
@@ -35,17 +48,69 @@ export class Emitter<T = unknown> implements IEventEmitter<T> {
35
48
  }
36
49
 
37
50
  public listenerCount() {
38
- return this._callbacks?.length ?? 0;
51
+ return this._callbacks.length;
52
+ }
53
+
54
+ private __fireThrow(data: T) {
55
+ for (const callback of this._callbacks) {
56
+ callback?.(data);
57
+ }
58
+ }
59
+ private __fireDelay(data: T) {
60
+ const errors: Error[] = [];
61
+ for (const callback of this._callbacks) {
62
+ try {
63
+ callback?.(data);
64
+ } catch (e) {
65
+ errors.push(convertCaughtError(e));
66
+ }
67
+ }
68
+ return errors;
69
+ }
70
+ private __fireIgnore(data: T) {
71
+ for (const callback of this._callbacks) {
72
+ try {
73
+ callback?.(data);
74
+ } catch {}
75
+ }
76
+ }
77
+ private __firePrintIgnore(data: T) {
78
+ for (const callback of this._callbacks) {
79
+ try {
80
+ callback?.(data);
81
+ } catch (e) {
82
+ const ee = convertCaughtError(e);
83
+ prettyPrintError('error while handling event', ee);
84
+ }
85
+ }
39
86
  }
40
87
 
41
- public fire(data: T) {
88
+ /**
89
+ * @param data
90
+ * @param error {Emitter.EAction} 如何处理错误
91
+ * - Throw: 默认行为,遇到错误立即抛出,后续监听器不再被调用
92
+ * - Delay: 等所有监听器都调用完后,如果有错误则抛出AggregateError,包含所有错误
93
+ * - Ignore: 忽略所有错误,继续调用全部监听器
94
+ * - PrintIgnore: 忽略所有错误,但打印错误信息
95
+ * @returns
96
+ */
97
+ public fire(data: T, error = this.onErrorDefault) {
42
98
  this.requireNotExecuting();
43
- if (!this._callbacks) return;
99
+ if (!this._callbacks.length) return;
44
100
 
45
101
  this.executing = true;
46
102
  try {
47
- for (const callback of this._callbacks) {
48
- callback?.(data);
103
+ if (error === FireErrorAction.Throw) {
104
+ this.__fireThrow(data);
105
+ } else if (error === FireErrorAction.Delay) {
106
+ const errors = this.__fireDelay(data);
107
+ if (errors.length) {
108
+ throw new AggregateError(errors, 'multiple errors while handling event');
109
+ }
110
+ } else if (error === FireErrorAction.Ignore) {
111
+ this.__fireIgnore(data);
112
+ } else if (error === FireErrorAction.PrintIgnore) {
113
+ this.__firePrintIgnore(data);
49
114
  }
50
115
  } finally {
51
116
  this.executing = false;
@@ -55,25 +120,9 @@ export class Emitter<T = unknown> implements IEventEmitter<T> {
55
120
  }
56
121
  }
57
122
 
123
+ /** @deprecated use fire(data, Emitter.Error.Ignore) */
58
124
  public fireNoError(data: T) {
59
- this.requireNotExecuting();
60
- if (!this._callbacks) return;
61
-
62
- this.executing = true;
63
- for (const callback of this._callbacks) {
64
- try {
65
- callback?.(data);
66
- } catch (e) {
67
- if (e instanceof Exit) {
68
- break;
69
- }
70
- console.error('Emitter.fireNoError: error ignored: %s', e instanceof Error ? e.stack : e);
71
- }
72
- }
73
- this.executing = false;
74
- if (this._something_change_during_call) {
75
- this.checkDeleted();
76
- }
125
+ this.fire(data, FireErrorAction.Ignore);
77
126
  }
78
127
 
79
128
  get register(): EventRegister<T> {
@@ -91,20 +140,17 @@ export class Emitter<T = unknown> implements IEventEmitter<T> {
91
140
  handle(callback: EventHandler<T>): IDisposable {
92
141
  this.requireNotExecuting();
93
142
 
94
- if (!this._callbacks) this._callbacks = [];
95
-
96
- const callbacks = this._callbacks;
97
- callbacks.unshift(callback);
143
+ this._callbacks.unshift(callback);
98
144
 
99
145
  return functionToDisposable(
100
146
  nameObject(`removeListener(${objectName(callback)})`, () => {
101
- const index = callbacks.indexOf(callback);
147
+ const index = this._callbacks.indexOf(callback);
102
148
  if (index === -1) return;
103
149
  if (this.executing) {
104
150
  this._something_change_during_call = true;
105
- callbacks[index] = undefined;
151
+ this._callbacks[index] = undefined;
106
152
  } else {
107
- callbacks.splice(index, 1);
153
+ this._callbacks.splice(index, 1);
108
154
  }
109
155
  }),
110
156
  );
@@ -159,7 +205,8 @@ export class Emitter<T = unknown> implements IEventEmitter<T> {
159
205
  if (this._disposed) return;
160
206
  this._disposed = true;
161
207
 
162
- this._callbacks = undefined;
208
+ this._callbacks.length = 0;
209
+ Object.assign(this, { _callbacks: null });
163
210
 
164
211
  if (this._waittings) {
165
212
  for (const rej of this._waittings) {
@@ -37,6 +37,10 @@ export class RequiredMap<K, V> extends Map<K, V> {
37
37
  }
38
38
  }
39
39
 
40
+ if (Map.prototype.getOrInsert) {
41
+ RequiredMap.prototype.get = Map.prototype.getOrInsert as any;
42
+ }
43
+
40
44
  /**
41
45
  * A map that holds instances, automatically create new instance
42
46
  */
@@ -56,3 +60,9 @@ export abstract class InstanceMap<K, V> extends Map<K, V> {
56
60
  return nv;
57
61
  }
58
62
  }
63
+
64
+ if (typeof Map.prototype.getOrInsertComputed === 'function') {
65
+ RequiredMap.prototype.get = function (this: InstanceMap<any, any>, id: any): any {
66
+ return this.getOrInsertComputed(id, (k) => this.instance(k));
67
+ };
68
+ }
@@ -1,6 +1,5 @@
1
1
  import { CanceledError, TimeoutError } from '@idlebox/errors';
2
2
  import type { IDisposable } from '../lifecycle/dispose/disposable.js';
3
- import type { TimeoutType } from '../schedule/local-type.js';
4
3
  import { scheduler } from '../schedule/scheduler.js';
5
4
 
6
5
  export type ValueCallback<T = any> = (value: T | Promise<T>) => void;
@@ -143,16 +142,16 @@ export class DeferredPromise<T, PT = any> {
143
142
  };
144
143
  }
145
144
 
146
- #timer?: TimeoutType;
145
+ private timer?: ITimeoutType;
147
146
  #cancel_timeout() {
148
- if (this.#timer) {
149
- clearTimeout(this.#timer);
150
- this.#timer = undefined;
147
+ if (this.timer) {
148
+ clearTimeout(this.timer);
149
+ this.timer = undefined;
151
150
  }
152
151
  }
153
152
  timeout(ms: number) {
154
153
  if (this.settled) throw new Error('no more timeout after settled');
155
- this.#timer = setTimeout(() => {
154
+ this.timer = setTimeout(() => {
156
155
  this.error(new TimeoutError(ms, 'promise not settled'));
157
156
  }, ms);
158
157
 
package/src/re-export.ts CHANGED
@@ -1,4 +1,3 @@
1
- /// <reference types="@idlebox/itypes" />
2
1
  /// <reference types="debug" />
3
2
 
4
3
  export * from '@idlebox/errors';
@@ -1,12 +1,11 @@
1
1
  import { DeferredPromise } from '../promise/deferred-promise.js';
2
- import type { TimeoutType } from './local-type.js';
3
2
 
4
3
  /**
5
4
  * 反复推迟的 setTimeout
6
5
  */
7
6
  export class ExtendableTimer {
8
7
  private readonly dfd = new DeferredPromise<void>();
9
- private tmr?: TimeoutType;
8
+ public tmr?: ITimeoutType;
10
9
 
11
10
  constructor(private readonly durationMs: number) {}
12
11
 
@@ -1,4 +1,5 @@
1
1
  import { TimeoutError } from '@idlebox/errors';
2
+ import { createStackTraceHolder } from '../error/stack-trace.js';
2
3
  import { isNodeJs } from '../platform/os.js';
3
4
 
4
5
  /**
@@ -6,10 +7,13 @@ import { isNodeJs } from '../platform/os.js';
6
7
  * can not set to `true` on other platform (will throw "unref is not function" error).
7
8
  * @returns promise reject with TimeoutError after specific time
8
9
  */
9
- export function timeout(ms: number, error = 'no response', unref = false): Promise<never> {
10
+ export function timeout(ms: number, error?: string, boundary?: Function, unref?: boolean): Promise<never>;
11
+ export function timeout(ms: number, error: string = 'no response', boundary: Function = timeout, unref = false): Promise<never> {
12
+ const s = createStackTraceHolder('', boundary);
13
+
10
14
  return new Promise((_, reject) => {
11
15
  const timer = setTimeout(() => {
12
- reject(new TimeoutError(ms, error));
16
+ reject(new TimeoutError(ms, error, s));
13
17
  }, ms);
14
18
  if (unref) (timer as any).unref();
15
19
  });
@@ -42,8 +46,8 @@ export function raceTimeout<T>(ms: number, message: string, p: PromiseLike<T>):
42
46
  */
43
47
  export function raceTimeout<T>(ms: number, message_or_p: string | PromiseLike<T>, p?: PromiseLike<T>): Promise<T> {
44
48
  if (p) {
45
- return Promise.race([p, timeout(ms, message_or_p as string, isNodeJs)]);
49
+ return Promise.race([p, timeout(ms, message_or_p as string, raceTimeout, isNodeJs)]);
46
50
  } else {
47
- return Promise.race([message_or_p as PromiseLike<T>, timeout(ms, undefined, isNodeJs)]);
51
+ return Promise.race([message_or_p as PromiseLike<T>, timeout(ms, undefined, raceTimeout, isNodeJs)]);
48
52
  }
49
53
  }
@@ -1,3 +0,0 @@
1
- export type TimeoutType = ReturnType<typeof setTimeout>;
2
- export type IntervalType = ReturnType<typeof setInterval>;
3
- //# sourceMappingURL=local-type.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"local-type.d.ts","sourceRoot":"","sources":["../../src/schedule/local-type.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AACxD,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=local-type.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"local-type.js","sourceRoot":"","sources":["../../src/schedule/local-type.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export type TimeoutType = ReturnType<typeof setTimeout>;
2
- export type IntervalType = ReturnType<typeof setInterval>;
@@ -1,31 +0,0 @@
1
- import type { FileBuilder, GenerateContext } from '@build-script/codegen';
2
-
3
- export function concatStringType(a: string[]): string {
4
- return a.join('');
5
- }
6
-
7
- export function generate(context: GenerateContext) {
8
- let builder: FileBuilder;
9
- if (context.file) {
10
- builder = context.file('./concatType');
11
- } else {
12
- // TODO
13
- builder = context as any;
14
- }
15
-
16
- const typeList = [];
17
- const argList = [];
18
- const returnList = [];
19
- for (let i = 0; i < 20; i++) {
20
- typeList.push(`T${i} extends string`);
21
- argList.push(`t${i}: T${i}`);
22
- returnList.push(`\${T${i}}`);
23
-
24
- const type = typeList.join(', ');
25
- const arg = argList.join(', ');
26
- const ret = returnList.join('');
27
- builder.append(`export function concatStringType\n\t<${type}>\n\t\t(${arg}):\n\t\`${ret}\`;`);
28
- }
29
-
30
- builder.copyFunctionDeclare('concatStringType');
31
- }