@aidc-toolkit/app-extension 1.0.31-beta → 1.0.33-beta

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 (45) hide show
  1. package/dist/index.cjs +1 -3709
  2. package/dist/index.d.cts +607 -333
  3. package/dist/index.d.ts +607 -333
  4. package/dist/index.js +1 -3683
  5. package/package.json +12 -13
  6. package/src/app-extension.ts +141 -93
  7. package/src/app-helper-proxy.ts +326 -0
  8. package/src/descriptor.ts +75 -7
  9. package/src/generator/generator.ts +118 -96
  10. package/src/generator/locale-resources-generator.ts +56 -42
  11. package/src/gs1/character-set-proxy.ts +8 -8
  12. package/src/gs1/check-proxy.ts +26 -25
  13. package/src/gs1/gtin-creator-proxy.ts +14 -28
  14. package/src/gs1/gtin-descriptor.ts +2 -23
  15. package/src/gs1/gtin-validator-proxy.ts +45 -48
  16. package/src/gs1/identifier-creator-proxy.ts +63 -53
  17. package/src/gs1/identifier-descriptor.ts +15 -0
  18. package/src/gs1/identifier-type.ts +37 -0
  19. package/src/gs1/identifier-validator-proxy.ts +59 -27
  20. package/src/gs1/index.ts +8 -0
  21. package/src/gs1/non-gtin-creator-proxy.ts +22 -33
  22. package/src/gs1/non-gtin-validator-proxy.ts +22 -33
  23. package/src/gs1/prefix-definition-descriptor.ts +2 -2
  24. package/src/gs1/prefix-manager-proxy.ts +164 -9
  25. package/src/gs1/service-proxy.ts +57 -0
  26. package/src/gs1/variable-measure-proxy.ts +62 -0
  27. package/src/index.ts +6 -1
  28. package/src/lib-proxy.ts +112 -70
  29. package/src/locale/en/locale-resources.ts +173 -47
  30. package/src/locale/fr/locale-resources.ts +173 -47
  31. package/src/locale/i18n.ts +8 -10
  32. package/src/locale/i18next.d.ts +2 -0
  33. package/src/proxy.ts +140 -140
  34. package/src/streaming.ts +13 -0
  35. package/src/type.ts +8 -7
  36. package/src/utility/character-set-descriptor.ts +2 -2
  37. package/src/utility/character-set-proxy.ts +39 -38
  38. package/src/utility/reg-exp-proxy.ts +12 -11
  39. package/src/utility/string-descriptor.ts +2 -2
  40. package/src/utility/string-proxy.ts +7 -7
  41. package/src/utility/transformer-descriptor.ts +5 -5
  42. package/src/utility/transformer-proxy.ts +25 -18
  43. package/dist/index.cjs.map +0 -1
  44. package/dist/index.js.map +0 -1
  45. package/src/app-utility-proxy.ts +0 -273
package/src/proxy.ts CHANGED
@@ -1,19 +1,19 @@
1
1
  import {
2
2
  type AbstractConstructor,
3
3
  type Constructor,
4
- getLogger,
5
- type LogLevel,
6
- LogLevels,
4
+ loggableValue,
7
5
  omit,
8
6
  type TypedAbstractConstructor
9
7
  } from "@aidc-toolkit/core";
10
8
  import type { Logger } from "tslog";
11
9
  import type { AppExtension } from "./app-extension.js";
12
- import type {
13
- ClassDescriptor,
14
- ExtendsParameterDescriptor,
15
- MethodDescriptor,
16
- ParameterDescriptor
10
+ import {
11
+ type ClassDescriptor,
12
+ type ExtendsParameterDescriptor,
13
+ type MethodDescriptor,
14
+ Multiplicities,
15
+ type ParameterDescriptor,
16
+ type ReplacementParameterDescriptor
17
17
  } from "./descriptor.js";
18
18
  import { LibProxy } from "./lib-proxy.js";
19
19
  import type { ErrorExtends } from "./type.js";
@@ -21,7 +21,7 @@ import type { ErrorExtends } from "./type.js";
21
21
  /**
22
22
  * Remaining parameters past first parameter in constructor.
23
23
  */
24
- type RemainingParameters<TConstructor extends TypedAbstractConstructor<TConstructor>> =
24
+ type RemainingConstructorParameters<TConstructor extends TypedAbstractConstructor<TConstructor>> =
25
25
  TConstructor extends abstract new (arg0: infer _P0, ...args: infer P) => InstanceType<TConstructor> ? P : never;
26
26
 
27
27
  /**
@@ -38,13 +38,13 @@ type RemainingParameters<TConstructor extends TypedAbstractConstructor<TConstruc
38
38
  * Proxy class constructor type.
39
39
  */
40
40
  type ProxyClassConstructor<
41
- ThrowError extends boolean, TError extends ErrorExtends<ThrowError>, TInvocationContext, TBigInt,
42
- T extends LibProxy<ThrowError, TError, TInvocationContext, TBigInt>,
41
+ ThrowError extends boolean, TError extends ErrorExtends<ThrowError>, TInvocationContext, TStreamingInvocationContext, TBigInt,
42
+ T extends LibProxy<ThrowError, TError, TInvocationContext, TStreamingInvocationContext, TBigInt>,
43
43
  IsAbstract extends boolean,
44
44
  TConstructor extends TypedAbstractConstructor<TConstructor>
45
45
  > = IsAbstract extends true ?
46
- AbstractConstructor<[appExtension: AppExtension<ThrowError, TError, TInvocationContext, TBigInt>, ...args: RemainingParameters<TConstructor>], T> :
47
- Constructor<[appExtension: AppExtension<ThrowError, TError, TInvocationContext, TBigInt>], T>;
46
+ AbstractConstructor<[appExtension: AppExtension<ThrowError, TError, TInvocationContext, TStreamingInvocationContext, TBigInt>, ...args: RemainingConstructorParameters<TConstructor>], T> :
47
+ Constructor<[appExtension: AppExtension<ThrowError, TError, TInvocationContext, TStreamingInvocationContext, TBigInt>], T>;
48
48
 
49
49
  /**
50
50
  * Class decorator type. Defines the parameters passed to a class decorator function and the return type as identical to
@@ -63,11 +63,11 @@ type ProxyClassConstructor<
63
63
  * Narrowed proxy class constructor type.
64
64
  */
65
65
  type ClassDecorator<
66
- ThrowError extends boolean, TError extends ErrorExtends<ThrowError>, TInvocationContext, TBigInt,
67
- T extends LibProxy<ThrowError, TError, TInvocationContext, TBigInt>,
66
+ ThrowError extends boolean, TError extends ErrorExtends<ThrowError>, TInvocationContext, TStreamingInvocationContext, TBigInt,
67
+ T extends LibProxy<ThrowError, TError, TInvocationContext, TStreamingInvocationContext, TBigInt>,
68
68
  IsAbstract extends boolean,
69
69
  TConstructor extends TypedAbstractConstructor<TConstructor>,
70
- TProxyClassConstructor extends ProxyClassConstructor<ThrowError, TError, TInvocationContext, TBigInt, T, IsAbstract, TConstructor>
70
+ TProxyClassConstructor extends ProxyClassConstructor<ThrowError, TError, TInvocationContext, TStreamingInvocationContext, TBigInt, T, IsAbstract, TConstructor>
71
71
  > = (Target: TProxyClassConstructor, context: ClassDecoratorContext<TProxyClassConstructor>) => TProxyClassConstructor;
72
72
 
73
73
  /**
@@ -88,21 +88,22 @@ type InterimMethodDescriptor = Omit<MethodDescriptor, "functionName" | "namespac
88
88
  /**
89
89
  * Subset of method descriptor used in call to decorator.
90
90
  */
91
- type DecoratorMethodDescriptor = Omit<InterimMethodDescriptor, "name" | "parameterDescriptors"> & {
91
+ interface DecoratorMethodDescriptor extends Omit<InterimMethodDescriptor, "name" | "parameterDescriptors"> {
92
92
  parameterDescriptors: Array<ParameterDescriptor | ExtendsParameterDescriptor>;
93
- };
93
+ }
94
94
 
95
95
  /**
96
96
  * Subset of class descriptor used during decoration process.
97
97
  */
98
- type InterimClassDescriptor =
99
- Omit<ClassDescriptor, "name" | "namespaceClassName" | "objectName" | "methodDescriptors">;
98
+ interface InterimClassDescriptor extends Omit<ClassDescriptor, "name" | "category" | "namespaceClassName" | "objectName" | "methodDescriptors"> {
99
+ readonly category?: string;
100
+ }
100
101
 
101
102
  /**
102
103
  * Subset of class descriptor used in call to decorator.
103
104
  */
104
- interface DecoratorClassDescriptor extends Omit<InterimClassDescriptor, "replaceParameterDescriptors"> {
105
- readonly replaceParameterDescriptors?: ReadonlyArray<Omit<Required<ClassDescriptor>["replaceParameterDescriptors"][number], "replacement"> & {
105
+ interface DecoratorClassDescriptor extends Omit<InterimClassDescriptor, "replacementParameterDescriptors"> {
106
+ readonly replacementParameterDescriptors?: ReadonlyArray<Omit<ReplacementParameterDescriptor, "replacement"> & {
106
107
  readonly replacement: ParameterDescriptor | ExtendsParameterDescriptor;
107
108
  }>;
108
109
  }
@@ -145,10 +146,12 @@ interface Interim {
145
146
  */
146
147
  interface TargetLogger {
147
148
  /**
148
- * Log a method call.
149
- *
150
- * @param logLevel
151
- * Log level.
149
+ * Logger.
150
+ */
151
+ readonly logger: Logger<object>;
152
+
153
+ /**
154
+ * Build a function that returns a loggable value for a method call.
152
155
  *
153
156
  * @param methodName
154
157
  * Method name.
@@ -159,7 +162,7 @@ interface TargetLogger {
159
162
  * @param result
160
163
  * Output result.
161
164
  */
162
- log: (logLevel: LogLevel, methodName: string, args: unknown[], result: unknown) => void;
165
+ callBuilder: (methodName: string, args: unknown[], result: unknown) => () => unknown;
163
166
  }
164
167
 
165
168
  /**
@@ -167,71 +170,26 @@ interface TargetLogger {
167
170
  */
168
171
  export class Proxy {
169
172
  /**
170
- * Logger.
173
+ * Abstract class descriptors map, keyed on declaration class. Abstract classes are not used directly by target
174
+ * applications.
171
175
  */
172
- // TODO Add configuration parameter to output JSON.
173
- // TODO Change this to LogLevels.Trace when configuration available.
174
- readonly #logger: Logger<unknown> = getLogger(LogLevels.Info);
176
+ readonly #abstractClassDescriptorsMap = new Map<typeof LibProxy, ClassDescriptor>();
175
177
 
176
178
  /**
177
- * Abstract class descriptors map, keyed on declaration class name. Abstract classes are not used directly by target
178
- * applications.
179
+ * Concrete class descriptors map, keyed on declaration class.
179
180
  */
180
- readonly #abstractClassDescriptorsMap = new Map<string, ClassDescriptor>();
181
+ readonly #concreteClassDescriptorsMap = new Map<typeof LibProxy, ClassDescriptor>();
181
182
 
182
183
  /**
183
- * Concrete class descriptors map, keyed on declaration class name.
184
+ * Namespace class names set for duplicate detection.
184
185
  */
185
- readonly #concreteClassDescriptorsMap = new Map<string, ClassDescriptor>();
186
+ readonly #namespaceClassNamesSet = new Set<string>();
186
187
 
187
188
  /**
188
189
  * Interim object.
189
190
  */
190
191
  #interim: Interim | undefined = undefined;
191
192
 
192
- /**
193
- * Get the proper JSON representation of a value.
194
- *
195
- * @param value
196
- * Value.
197
- *
198
- * @returns
199
- * Replacement value.
200
- */
201
- static #jsonValue(value: unknown): unknown {
202
- let replacementValue: unknown;
203
-
204
- switch (typeof value) {
205
- case "string":
206
- case "number":
207
- case "boolean":
208
- case "undefined":
209
- replacementValue = value;
210
- break;
211
-
212
- case "bigint":
213
- // Big integers not supported in JSON.
214
- replacementValue = value >= Number.MIN_SAFE_INTEGER && value <= Number.MAX_SAFE_INTEGER ? Number(value) : value.toString(10);
215
- break;
216
-
217
- case "object":
218
- if (value === null) {
219
- replacementValue = value;
220
- } else if (Array.isArray(value)) {
221
- replacementValue = value.map(entry => Proxy.#jsonValue(entry));
222
- } else {
223
- replacementValue = Object.fromEntries(Object.entries(value).map(([k, v]) => [k, Proxy.#jsonValue(v)]));
224
- }
225
- break;
226
-
227
- case "symbol":
228
- case "function":
229
- throw new Error(`Unsupported ${typeof value} value type`);
230
- }
231
-
232
- return replacementValue;
233
- }
234
-
235
193
  /**
236
194
  * Describe a proxy class.
237
195
  *
@@ -257,17 +215,17 @@ export class Proxy {
257
215
  * Function with which to decorate the class.
258
216
  */
259
217
  describeClass<
260
- ThrowError extends boolean, TError extends ErrorExtends<ThrowError>, TInvocationContext, TBigInt,
261
- T extends LibProxy<ThrowError, TError, TInvocationContext, TBigInt>,
218
+ ThrowError extends boolean, TError extends ErrorExtends<ThrowError>, TInvocationContext, TStreamingInvocationContext, TBigInt,
219
+ T extends LibProxy<ThrowError, TError, TInvocationContext, TStreamingInvocationContext, TBigInt>,
262
220
  IsAbstract extends boolean,
263
221
  TConstructor extends TypedAbstractConstructor<TConstructor>,
264
- TProxyClassConstructor extends ProxyClassConstructor<ThrowError, TError, TInvocationContext, TBigInt, T, IsAbstract, TConstructor>
265
- >(isAbstract: IsAbstract, decoratorClassDescriptor: DecoratorClassDescriptor = {}): ClassDecorator<ThrowError, TError, TInvocationContext, TBigInt, T, IsAbstract, TConstructor, TProxyClassConstructor> {
266
- const interimClassDescriptor: InterimClassDescriptor = decoratorClassDescriptor.replaceParameterDescriptors === undefined ?
267
- omit(decoratorClassDescriptor, "replaceParameterDescriptors") :
222
+ TProxyClassConstructor extends ProxyClassConstructor<ThrowError, TError, TInvocationContext, TStreamingInvocationContext, TBigInt, T, IsAbstract, TConstructor>
223
+ >(isAbstract: IsAbstract, decoratorClassDescriptor: DecoratorClassDescriptor = {}): ClassDecorator<ThrowError, TError, TInvocationContext, TStreamingInvocationContext, TBigInt, T, IsAbstract, TConstructor, TProxyClassConstructor> {
224
+ const interimClassDescriptor: InterimClassDescriptor = decoratorClassDescriptor.replacementParameterDescriptors === undefined ?
225
+ omit(decoratorClassDescriptor, "replacementParameterDescriptors") :
268
226
  {
269
227
  ...decoratorClassDescriptor,
270
- replaceParameterDescriptors: decoratorClassDescriptor.replaceParameterDescriptors.map(replaceParameterDescriptor => ({
228
+ replacementParameterDescriptors: decoratorClassDescriptor.replacementParameterDescriptors.map(replaceParameterDescriptor => ({
271
229
  ...replaceParameterDescriptor,
272
230
  replacement: expandParameterDescriptor(replaceParameterDescriptor.replacement)
273
231
  }))
@@ -281,44 +239,41 @@ export class Proxy {
281
239
  this.#interim = interim;
282
240
 
283
241
  return (Target: TProxyClassConstructor, context: ClassDecoratorContext<TProxyClassConstructor>) => {
284
- const name = context.name;
242
+ const className = context.name;
285
243
 
286
244
  // Validate that class descriptor is applied within an appropriate class.
287
- if (typeof name !== "string") {
288
- throw new Error(`${String(name)} has an invalid name`);
245
+ if (className === undefined) {
246
+ throw new Error("Class has no name");
289
247
  }
290
248
 
291
- const namespacePrefix = decoratorClassDescriptor.namespace === undefined ? "" : `${decoratorClassDescriptor.namespace}.`;
292
- const namespaceClassName = `${namespacePrefix}${name}`;
293
-
294
249
  const abstractClassDescriptorsMap = this.#abstractClassDescriptorsMap;
295
250
  const concreteClassDescriptorsMap = this.#concreteClassDescriptorsMap;
296
251
 
297
- if (abstractClassDescriptorsMap.has(namespaceClassName) || concreteClassDescriptorsMap.has(namespaceClassName)) {
298
- throw new Error(`Duplicate class ${namespaceClassName}`);
299
- }
300
-
301
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Class hierarchy is known.
302
- let baseClassType: typeof LibProxy = Target as unknown as typeof LibProxy;
252
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Target is known to be of type LibProxy.
253
+ const targetClassType = Target as unknown as typeof LibProxy;
254
+ let baseClassType = targetClassType;
303
255
  let baseClassDescriptor: ClassDescriptor | undefined;
304
256
 
305
257
  do {
306
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Class hierarchy is known.
258
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Class hierarchy is known to stop at LibProxy.
307
259
  baseClassType = Object.getPrototypeOf(baseClassType) as typeof LibProxy;
308
260
 
309
- const namespaceBaseClassName = `${namespacePrefix}${baseClassType.name}`;
310
-
311
- // Look first within the namespace and then in no namespace, in both abstract class descriptors map and concrete class descriptors map.
312
- baseClassDescriptor =
313
- abstractClassDescriptorsMap.get(namespaceBaseClassName) ?? abstractClassDescriptorsMap.get(baseClassType.name) ??
314
- concreteClassDescriptorsMap.get(namespaceBaseClassName) ?? concreteClassDescriptorsMap.get(baseClassType.name);
261
+ // Look in both abstract class descriptors map and concrete class descriptors map.
262
+ baseClassDescriptor = abstractClassDescriptorsMap.get(baseClassType) ?? concreteClassDescriptorsMap.get(baseClassType);
315
263
  } while (baseClassType !== LibProxy && baseClassDescriptor === undefined);
316
264
 
265
+ let namespace = interimClassDescriptor.namespace;
266
+ let category = interimClassDescriptor.category;
267
+
317
268
  let interimMethodDescriptors: InterimMethodDescriptor[];
318
269
 
319
270
  if (baseClassDescriptor !== undefined) {
271
+ // Inherit namespace and category from base class if not explicitly defined.
272
+ namespace ??= baseClassDescriptor.namespace;
273
+ category ??= baseClassDescriptor.category;
274
+
320
275
  const baseClassMethodDescriptors = baseClassDescriptor.methodDescriptors;
321
- const replaceParameterDescriptors = decoratorClassDescriptor.replaceParameterDescriptors;
276
+ const replaceParameterDescriptors = decoratorClassDescriptor.replacementParameterDescriptors;
322
277
 
323
278
  if (replaceParameterDescriptors !== undefined) {
324
279
  const replacementParameterDescriptorsMap = new Map(replaceParameterDescriptors.map(replaceParameterDescriptor => [replaceParameterDescriptor.name, expandParameterDescriptor(replaceParameterDescriptor.replacement)]));
@@ -335,6 +290,19 @@ export class Proxy {
335
290
  interimMethodDescriptors = [];
336
291
  }
337
292
 
293
+ const namespacePrefix = namespace === undefined ? "" : `${namespace}.`;
294
+ const namespaceClassName = `${namespacePrefix}${className}`;
295
+
296
+ if (this.#namespaceClassNamesSet.has(namespaceClassName)) {
297
+ throw new Error(`Duplicate class ${namespaceClassName}`);
298
+ }
299
+
300
+ if (category === undefined) {
301
+ throw new Error(`Missing category for ${namespaceClassName}`);
302
+ }
303
+
304
+ this.#namespaceClassNamesSet.add(namespaceClassName);
305
+
338
306
  // Replace base class method descriptors with matching names or append new method descriptor.
339
307
  for (const classInterimMethodDescriptor of interim.methodDescriptors) {
340
308
  const existingIndex = interimMethodDescriptors.findIndex(interimMethodDescriptor => interimMethodDescriptor.name === classInterimMethodDescriptor.name);
@@ -395,21 +363,23 @@ export class Proxy {
395
363
  // Third capture group, separated by optional period, is:
396
364
  // - single uppercase letter followed by zero or more characters (remainder of string); or
397
365
  // - zero characters (empty string).
398
- const objectNameGroups = /^(?<namespaceFirstWord>[A-Z]+[0-9]*|[A-Z][^A-Z.]*)(?<namespaceRemaining>[A-Z][^.]*|)\.?(?<className>[A-Z].*|)$/.exec(namespaceClassName)?.groups;
366
+ const objectNameGroups = /^(?<namespaceFirstWord>[A-Z]+[0-9]*|[A-Z][^A-Z.]*)(?<namespaceRemaining>[A-Z][^.]*|)\.?(?<className>[A-Z].*|)$/u.exec(namespaceClassName)?.groups;
399
367
 
400
368
  if (objectNameGroups === undefined) {
401
369
  throw new Error(`${namespaceClassName} is not a valid namespace-qualified class name`);
402
370
  }
403
371
 
404
372
  const classDescriptor: ClassDescriptor = {
405
- name,
406
373
  ...interimClassDescriptor,
374
+ name: className,
375
+ namespace,
376
+ category,
407
377
  namespaceClassName,
408
378
  objectName: `${objectNameGroups["namespaceFirstWord"].toLowerCase()}${objectNameGroups["namespaceRemaining"]}${objectNameGroups["className"]}`,
409
379
  methodDescriptors
410
380
  };
411
381
 
412
- (isAbstract ? abstractClassDescriptorsMap : concreteClassDescriptorsMap).set(namespaceClassName, classDescriptor);
382
+ (isAbstract ? abstractClassDescriptorsMap : concreteClassDescriptorsMap).set(targetClassType, classDescriptor);
413
383
 
414
384
  const methodDescriptorsMap = new Map<string, MethodDescriptor>();
415
385
 
@@ -419,30 +389,35 @@ export class Proxy {
419
389
 
420
390
  this.#interim = undefined;
421
391
 
422
- const logger = this.#logger;
423
-
424
392
  return class extends Target implements TargetLogger {
393
+ /**
394
+ * Get the logger.
395
+ */
396
+ get logger(): Logger<object> {
397
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Type hierarchy is known.
398
+ return (this as unknown as T).appExtension.logger;
399
+ }
400
+
425
401
  /**
426
402
  * @inheritDoc
427
403
  */
428
- log(logLevel: LogLevel, methodName: string, args: unknown[], result: unknown): void {
429
- // // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Type hierarchy is known.
430
- // const appExtension = (this as unknown as T).appExtension;
431
-
432
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Method name is known to be valid at this point.
433
- const methodDescriptor = methodDescriptorsMap.get(methodName)!;
434
-
435
- logger.log(logLevel, "", JSON.stringify({
436
- namespace: decoratorClassDescriptor.namespace,
437
- className: name,
438
- methodName,
439
- functionName: methodDescriptor.functionName,
440
- parameters: methodDescriptor.parameterDescriptors.map((parameterDescriptor, index) => ({
441
- name: parameterDescriptor.name,
442
- value: args[index]
443
- })),
444
- result: Proxy.#jsonValue(result)
445
- }, null, 2));
404
+ callBuilder(methodName: string, args: unknown[], result: unknown): () => unknown {
405
+ return () => {
406
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Method name is known to be valid at this point.
407
+ const methodDescriptor = methodDescriptorsMap.get(methodName)!;
408
+
409
+ return {
410
+ namespace,
411
+ className,
412
+ methodName,
413
+ functionName: methodDescriptor.functionName,
414
+ parameters: methodDescriptor.parameterDescriptors.map((parameterDescriptor, index) => ({
415
+ name: parameterDescriptor.name,
416
+ value: loggableValue(args[index])
417
+ })),
418
+ result: loggableValue(result)
419
+ };
420
+ };
446
421
  }
447
422
  };
448
423
  };
@@ -464,9 +439,14 @@ export class Proxy {
464
439
  return (target: (this: TThis, ...args: TArguments) => TReturn, context: ClassMethodDecoratorContext<TThis>): (this: TThis, ...args: TArguments) => TReturn => {
465
440
  const name = context.name;
466
441
 
467
- // Validate that method descriptor is applied within an appropriate class and has a valid name.
468
- if (this.#interim === undefined || typeof name !== "string" || context.static || context.private) {
469
- throw new Error(`${String(name)} is not defined within a supported class, has an invalid name, is static, or is private`);
442
+ // Validate that method descriptor is applied within an appropriate class.
443
+ if (this.#interim === undefined) {
444
+ throw new Error(`Class for method ${String(name)} does not have a descriptor`);
445
+ }
446
+
447
+ // Validate that method descriptor has a valid name and is neither static nor private.
448
+ if (typeof name !== "string" || context.static || context.private) {
449
+ throw new Error(`Method ${String(name)} has an invalid name, is static, or is private`);
470
450
  }
471
451
 
472
452
  let anyOptional = false;
@@ -474,19 +454,24 @@ export class Proxy {
474
454
  // Expand all parameter descriptors.
475
455
  const parameterDescriptors = decoratorMethodDescriptor.parameterDescriptors.map((decoratorParameterDescriptor) => {
476
456
  const parameterDescriptor = expandParameterDescriptor(decoratorParameterDescriptor);
457
+ const parameterName = parameterDescriptor.name;
477
458
 
478
459
  if (!parameterDescriptor.isRequired) {
479
460
  anyOptional = true;
480
461
  } else if (anyOptional) {
481
- throw new Error(`Parameter ${parameterDescriptor.name} descriptor of method ${name} is required but prior parameter descriptor is optional`);
462
+ throw new Error(`Parameter ${parameterName} descriptor of method ${name} is required but prior parameter descriptor is optional`);
463
+ }
464
+
465
+ if ((parameterDescriptor.multiplicity === Multiplicities.Array || parameterDescriptor.multiplicity === Multiplicities.Matrix) && decoratorMethodDescriptor.multiplicity !== Multiplicities.Matrix) {
466
+ throw new Error(`Parameter ${parameterName} descriptor of method ${name} is array or matrix but method descriptor is not matrix`);
482
467
  }
483
468
 
484
469
  return parameterDescriptor;
485
470
  });
486
471
 
487
472
  this.#interim.methodDescriptors.push({
488
- name,
489
473
  ...decoratorMethodDescriptor,
474
+ name,
490
475
  parameterDescriptors
491
476
  });
492
477
 
@@ -499,10 +484,25 @@ export class Proxy {
499
484
  try {
500
485
  result = target.call(this, ...args);
501
486
 
502
- // TODO Change this to LogLevels.Trace when configuration available.
503
- targetLogger.log(LogLevels.Info, name, args, result);
487
+ // Stream methods are responsible for their own logging.
488
+ if (decoratorMethodDescriptor.isStream !== true) {
489
+ if (!(result instanceof Promise)) {
490
+ targetLogger.logger.trace(targetLogger.callBuilder(name, args, result));
491
+ } else {
492
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Promise interception pattern.
493
+ result = result.then((promisedResult: unknown) => {
494
+ targetLogger.logger.trace(targetLogger.callBuilder(name, args, promisedResult));
495
+
496
+ return promisedResult;
497
+ }).catch((e: unknown) => {
498
+ targetLogger.logger.error(targetLogger.callBuilder(name, args, e));
499
+
500
+ throw e;
501
+ }) as TReturn;
502
+ }
503
+ }
504
504
  } catch (e: unknown) {
505
- targetLogger.log(LogLevels.Error, name, args, e instanceof Error ? `${e.name}: ${e.message}` : `Unknown exception: ${String(e)}`);
505
+ targetLogger.logger.error(targetLogger.callBuilder(name, args, e));
506
506
 
507
507
  throw e;
508
508
  }
@@ -513,10 +513,10 @@ export class Proxy {
513
513
  }
514
514
 
515
515
  /**
516
- * Get the class descriptors map.
516
+ * Get the class descriptors.
517
517
  */
518
- get classDescriptorsMap(): Map<string, ClassDescriptor> {
519
- return this.#concreteClassDescriptorsMap;
518
+ get classDescriptors(): MapIterator<ClassDescriptor> {
519
+ return this.#concreteClassDescriptorsMap.values();
520
520
  }
521
521
  }
522
522
 
@@ -0,0 +1,13 @@
1
+ import type { ErrorExtends, MatrixResult } from "./type.js";
2
+
3
+ /**
4
+ * Streaming consumer callback, returned by application extension implementation.
5
+ */
6
+ export type StreamingConsumerCallback<TResult, ThrowError extends boolean, TError extends ErrorExtends<ThrowError>> =
7
+ (result: MatrixResult<TResult, ThrowError, TError>) => void;
8
+
9
+ /**
10
+ * Streaming cancelled callback, passed to application extension implementation.
11
+ */
12
+ export type StreamingCancelledCallback =
13
+ () => void;
package/src/type.ts CHANGED
@@ -68,8 +68,9 @@ export interface SheetRange extends Sheet, Range {
68
68
  export type Matrix<T> = T[][];
69
69
 
70
70
  /**
71
- * Function result, possibly including an error result. If the application framework reports errors through the return
72
- * value, the result is the union of the result type and the error type; otherwise, it's just the result type.
71
+ * Function singleton return, possibly including an error return. If the application extension reports errors through
72
+ * the return value, the result is the union of the return type and the error type; otherwise, it's just the return
73
+ * type.
73
74
  *
74
75
  * @template TResult
75
76
  * Result type.
@@ -80,12 +81,12 @@ export type Matrix<T> = T[][];
80
81
  * @template TError
81
82
  * Error type.
82
83
  */
83
- export type ResultError<TResult, ThrowError extends boolean, TError extends ErrorExtends<ThrowError>> = ThrowError extends false ? TResult | TError : TResult;
84
+ export type SingletonResult<TResult, ThrowError extends boolean, TError extends ErrorExtends<ThrowError>> = ThrowError extends false ? TResult | TError : TResult;
84
85
 
85
86
  /**
86
- * Function result as matrix, possibly including an error result in each element. If the application framework reports
87
- * errors through the return value, the individual element result is the union of the result type and the error type;
88
- * otherwise, it's just the result type.
87
+ * Function matrix return, possibly including an error return in each element. If the application extension reports
88
+ * errors through the return value, the individual element result is the union of the return type and the error type;
89
+ * otherwise, it's just the return type.
89
90
  *
90
91
  * @template TResult
91
92
  * Result type.
@@ -96,4 +97,4 @@ export type ResultError<TResult, ThrowError extends boolean, TError extends Erro
96
97
  * @template TError
97
98
  * Error type.
98
99
  */
99
- export type MatrixResultError<TResult, ThrowError extends boolean, TError extends ErrorExtends<ThrowError>> = Matrix<ResultError<TResult, ThrowError, TError>>;
100
+ export type MatrixResult<TResult, ThrowError extends boolean, TError extends ErrorExtends<ThrowError>> = Matrix<SingletonResult<TResult, ThrowError, TError>>;
@@ -1,9 +1,9 @@
1
- import { type ExtendsParameterDescriptor, type ParameterDescriptor, Types } from "../descriptor.js";
1
+ import { type ExtendsParameterDescriptor, Multiplicities, type ParameterDescriptor, Types } from "../descriptor.js";
2
2
 
3
3
  const exclusionParameterDescriptor: ParameterDescriptor = {
4
4
  name: "exclusion",
5
5
  type: Types.Number,
6
- isMatrix: false,
6
+ multiplicity: Multiplicities.Singleton,
7
7
  isRequired: false
8
8
  };
9
9