@aidc-toolkit/app-extension 0.9.19-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 (112) hide show
  1. package/LICENSE +174 -0
  2. package/README.md +17 -0
  3. package/app-extension.iml +9 -0
  4. package/dist/app-extension.d.ts +169 -0
  5. package/dist/app-extension.d.ts.map +1 -0
  6. package/dist/app-extension.js +148 -0
  7. package/dist/app-extension.js.map +1 -0
  8. package/dist/app-utility-proxy.d.ts +66 -0
  9. package/dist/app-utility-proxy.d.ts.map +1 -0
  10. package/dist/app-utility-proxy.js +233 -0
  11. package/dist/app-utility-proxy.js.map +1 -0
  12. package/dist/descriptor.d.ts +168 -0
  13. package/dist/descriptor.d.ts.map +1 -0
  14. package/dist/descriptor.js +175 -0
  15. package/dist/descriptor.js.map +1 -0
  16. package/dist/gs1/character-set-proxy.d.ts +10 -0
  17. package/dist/gs1/character-set-proxy.d.ts.map +1 -0
  18. package/dist/gs1/character-set-proxy.js +47 -0
  19. package/dist/gs1/character-set-proxy.js.map +1 -0
  20. package/dist/gs1/check-proxy.d.ts +11 -0
  21. package/dist/gs1/check-proxy.d.ts.map +1 -0
  22. package/dist/gs1/check-proxy.js +120 -0
  23. package/dist/gs1/check-proxy.js.map +1 -0
  24. package/dist/gs1/idkey-proxy.d.ts +135 -0
  25. package/dist/gs1/idkey-proxy.d.ts.map +1 -0
  26. package/dist/gs1/idkey-proxy.js +779 -0
  27. package/dist/gs1/idkey-proxy.js.map +1 -0
  28. package/dist/gs1/index.d.ts +4 -0
  29. package/dist/gs1/index.d.ts.map +1 -0
  30. package/dist/gs1/index.js +4 -0
  31. package/dist/gs1/index.js.map +1 -0
  32. package/dist/index.d.ts +25 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +25 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/lib-proxy.d.ts +135 -0
  37. package/dist/lib-proxy.d.ts.map +1 -0
  38. package/dist/lib-proxy.js +235 -0
  39. package/dist/lib-proxy.js.map +1 -0
  40. package/dist/locale/en/locale-strings.d.ts +616 -0
  41. package/dist/locale/en/locale-strings.d.ts.map +1 -0
  42. package/dist/locale/en/locale-strings.js +616 -0
  43. package/dist/locale/en/locale-strings.js.map +1 -0
  44. package/dist/locale/fr/locale-strings.d.ts +616 -0
  45. package/dist/locale/fr/locale-strings.d.ts.map +1 -0
  46. package/dist/locale/fr/locale-strings.js +616 -0
  47. package/dist/locale/fr/locale-strings.js.map +1 -0
  48. package/dist/locale/i18n.d.ts +27 -0
  49. package/dist/locale/i18n.d.ts.map +1 -0
  50. package/dist/locale/i18n.js +39 -0
  51. package/dist/locale/i18n.js.map +1 -0
  52. package/dist/types.d.ts +127 -0
  53. package/dist/types.d.ts.map +1 -0
  54. package/dist/types.js +13 -0
  55. package/dist/types.js.map +1 -0
  56. package/dist/utility/character-set-descriptor.d.ts +6 -0
  57. package/dist/utility/character-set-descriptor.d.ts.map +1 -0
  58. package/dist/utility/character-set-descriptor.js +28 -0
  59. package/dist/utility/character-set-descriptor.js.map +1 -0
  60. package/dist/utility/character-set-proxy.d.ts +26 -0
  61. package/dist/utility/character-set-proxy.d.ts.map +1 -0
  62. package/dist/utility/character-set-proxy.js +167 -0
  63. package/dist/utility/character-set-proxy.js.map +1 -0
  64. package/dist/utility/index.d.ts +4 -0
  65. package/dist/utility/index.d.ts.map +1 -0
  66. package/dist/utility/index.js +4 -0
  67. package/dist/utility/index.js.map +1 -0
  68. package/dist/utility/reg-exp-proxy.d.ts +7 -0
  69. package/dist/utility/reg-exp-proxy.d.ts.map +1 -0
  70. package/dist/utility/reg-exp-proxy.js +61 -0
  71. package/dist/utility/reg-exp-proxy.js.map +1 -0
  72. package/dist/utility/string-descriptor.d.ts +4 -0
  73. package/dist/utility/string-descriptor.d.ts.map +1 -0
  74. package/dist/utility/string-descriptor.js +12 -0
  75. package/dist/utility/string-descriptor.js.map +1 -0
  76. package/dist/utility/string-proxy.d.ts +8 -0
  77. package/dist/utility/string-proxy.d.ts.map +1 -0
  78. package/dist/utility/string-proxy.js +12 -0
  79. package/dist/utility/string-proxy.js.map +1 -0
  80. package/dist/utility/transformer-descriptor.d.ts +6 -0
  81. package/dist/utility/transformer-descriptor.d.ts.map +1 -0
  82. package/dist/utility/transformer-descriptor.js +24 -0
  83. package/dist/utility/transformer-descriptor.js.map +1 -0
  84. package/dist/utility/transformer-proxy.d.ts +8 -0
  85. package/dist/utility/transformer-proxy.d.ts.map +1 -0
  86. package/dist/utility/transformer-proxy.js +74 -0
  87. package/dist/utility/transformer-proxy.js.map +1 -0
  88. package/eslint.config.ts +21 -0
  89. package/package.json +37 -0
  90. package/src/app-extension.ts +244 -0
  91. package/src/app-utility-proxy.ts +266 -0
  92. package/src/descriptor.ts +314 -0
  93. package/src/gs1/character-set-proxy.ts +41 -0
  94. package/src/gs1/check-proxy.ts +122 -0
  95. package/src/gs1/idkey-proxy.ts +815 -0
  96. package/src/gs1/index.ts +3 -0
  97. package/src/index.ts +24 -0
  98. package/src/lib-proxy.ts +256 -0
  99. package/src/locale/en/locale-strings.ts +615 -0
  100. package/src/locale/fr/locale-strings.ts +615 -0
  101. package/src/locale/i18n.ts +48 -0
  102. package/src/locale/i18next.d.ts +20 -0
  103. package/src/types.ts +144 -0
  104. package/src/utility/character-set-descriptor.ts +32 -0
  105. package/src/utility/character-set-proxy.ts +185 -0
  106. package/src/utility/index.ts +3 -0
  107. package/src/utility/reg-exp-proxy.ts +51 -0
  108. package/src/utility/string-descriptor.ts +13 -0
  109. package/src/utility/string-proxy.ts +15 -0
  110. package/src/utility/transformer-descriptor.ts +27 -0
  111. package/src/utility/transformer-proxy.ts +72 -0
  112. package/tsconfig.json +6 -0
@@ -0,0 +1,266 @@
1
+ import { type ParameterDescriptor, ProxyClass, ProxyMethod, ProxyParameter, Type } from "./descriptor.js";
2
+ import { LibProxy } from "./lib-proxy.js";
3
+ import { i18nextAppExtension } from "./locale/i18n.js";
4
+ import { type ErrorExtends, isNullish, type Matrix, type NonNullishable, type Nullishable } from "./types.js";
5
+
6
+ const spillMatrix: ParameterDescriptor = {
7
+ name: "spillMatrix",
8
+ type: Type.Any,
9
+ isMatrix: true,
10
+ isRequired: true
11
+ };
12
+
13
+ const spillMaximumParameterDescriptor: ParameterDescriptor = {
14
+ name: "spillMaximum",
15
+ type: Type.Number,
16
+ isMatrix: false,
17
+ isRequired: false
18
+ };
19
+
20
+ const spillMaximumWidthParameterDescriptor: ParameterDescriptor = {
21
+ extendsDescriptor: spillMaximumParameterDescriptor,
22
+ sortOrder: 0,
23
+ name: "spillMaximumWidth"
24
+ };
25
+
26
+ const spillMaximumHeightParameterDescriptor: ParameterDescriptor = {
27
+ extendsDescriptor: spillMaximumParameterDescriptor,
28
+ sortOrder: 1,
29
+ name: "spillMaximumHeight"
30
+ };
31
+
32
+ /**
33
+ * Maximum dimensions.
34
+ */
35
+ interface MaximumDimensions {
36
+ /**
37
+ * Optional maximum width.
38
+ */
39
+ width: Nullishable<number>;
40
+
41
+ /**
42
+ * Optional maximum height.
43
+ */
44
+ height: Nullishable<number>;
45
+ }
46
+
47
+ /**
48
+ * Application utilities.
49
+ */
50
+ @ProxyClass()
51
+ export class AppUtilityProxy<ThrowError extends boolean, TError extends ErrorExtends<ThrowError>, TInvocationContext, TBigInt> extends LibProxy<ThrowError, TError, TInvocationContext, TBigInt> {
52
+ /**
53
+ * Get the version.
54
+ *
55
+ * @returns
56
+ * Version.
57
+ */
58
+ @ProxyMethod({
59
+ type: Type.String,
60
+ isMatrix: false
61
+ })
62
+ version(): string {
63
+ return this.appExtension.version;
64
+ }
65
+
66
+ /**
67
+ * Provide default values for maximum width and height if required.
68
+ *
69
+ * @param maximumDimensions
70
+ * Maximum dimensions provided to function.
71
+ *
72
+ * @param invocationContext
73
+ * Invocation context.
74
+ *
75
+ * @returns
76
+ * Array of maximum width and maximum height.
77
+ */
78
+ private async defaultMaximums(maximumDimensions: MaximumDimensions, invocationContext: Nullishable<TInvocationContext>): Promise<NonNullishable<MaximumDimensions>> {
79
+ if (isNullish(invocationContext)) {
80
+ // Application error; no localization necessary.
81
+ throw new Error("Invocation context not provided by application");
82
+ }
83
+
84
+ const maximumWidth = maximumDimensions.width;
85
+ const maximumHeight = maximumDimensions.height;
86
+
87
+ let definedMaximumWidth: number;
88
+ let definedMaximumHeight: number;
89
+
90
+ // Skip any extra work if both values are provided.
91
+ if (isNullish(maximumWidth) || isNullish(maximumHeight)) {
92
+ const sheetAddress = await this.appExtension.getSheetAddress(invocationContext);
93
+
94
+ definedMaximumWidth = maximumWidth ?? await this.appExtension.maximumWidth() - sheetAddress.columnIndex;
95
+ definedMaximumHeight = maximumHeight ?? await this.appExtension.maximumHeight() - sheetAddress.rowIndex;
96
+ } else {
97
+ definedMaximumWidth = maximumWidth;
98
+ definedMaximumHeight = maximumHeight;
99
+ }
100
+
101
+ return {
102
+ width: definedMaximumWidth,
103
+ height: definedMaximumHeight
104
+ };
105
+ }
106
+
107
+ /**
108
+ * Spill a horizontal matrix vertically to fit within a maximum width and height.
109
+ *
110
+ * @param hMatrixValues
111
+ * Horizontal matrix values. Matrix has length 1 and contains a single array with the values.
112
+ *
113
+ * @param maximumWidth
114
+ * Maximum width.
115
+ *
116
+ * @param maximumHeight
117
+ * Maximum height.
118
+ *
119
+ * @param invocationContext
120
+ * Invocation context.
121
+ *
122
+ * @returns
123
+ * Matrix spilled within maximum width and maximum height.
124
+ */
125
+ @ProxyMethod({
126
+ requiresContext: true,
127
+ type: Type.Any,
128
+ isMatrix: true
129
+ })
130
+ async vSpill(
131
+ @ProxyParameter(spillMatrix) hMatrixValues: Matrix<unknown>,
132
+ @ProxyParameter(spillMaximumWidthParameterDescriptor) maximumWidth: Nullishable<number>,
133
+ @ProxyParameter(spillMaximumHeightParameterDescriptor) maximumHeight: Nullishable<number>,
134
+ invocationContext: Nullishable<TInvocationContext>
135
+ ): Promise<Matrix<unknown>> {
136
+ let result: Matrix<unknown>;
137
+
138
+ if (hMatrixValues.length !== 1) {
139
+ throw new RangeError(i18nextAppExtension.t("Proxy.vSpillMustBeHorizontalArray"));
140
+ }
141
+
142
+ const maximumDimensions = await this.defaultMaximums({
143
+ width: maximumWidth,
144
+ height: maximumHeight
145
+ }, invocationContext);
146
+
147
+ const hArrayValues = hMatrixValues[0];
148
+ const hLength = hArrayValues.length;
149
+ const maximumArea = maximumDimensions.width * maximumDimensions.height;
150
+
151
+ // Lengths 0 and 1 are valid and require no special processing.
152
+ if (hLength > 1 && hLength <= maximumArea) {
153
+ // Make spill as square as possible.
154
+ let spillWidth = Math.min(Math.ceil(Math.sqrt(maximumArea)), maximumDimensions.width);
155
+
156
+ // Array that has a length of a power of 10 is treated specially.
157
+ if (Number.isInteger(Math.log10(hLength))) {
158
+ // Try spill width that is a power of 10.
159
+ const spillWidth10 = Math.pow(10, Math.floor(Math.log10(spillWidth)));
160
+
161
+ // Keep default if not enough space for power of 10 matrix.
162
+ if (hLength / spillWidth10 <= maximumDimensions.height) {
163
+ spillWidth = spillWidth10;
164
+ }
165
+ }
166
+
167
+ result = [];
168
+
169
+ let hStartIndex = 0;
170
+
171
+ do {
172
+ const hEndIndex = hStartIndex + spillWidth;
173
+
174
+ result.push(hArrayValues.slice(hStartIndex, hEndIndex));
175
+
176
+ hStartIndex = hEndIndex;
177
+ } while (hStartIndex < hLength);
178
+ } else {
179
+ // Return matrix unmodified and let application handle spill error if any.
180
+ result = hMatrixValues;
181
+ }
182
+
183
+ return result;
184
+ }
185
+
186
+ /**
187
+ * Spill a vertical matrix horizontally to fit within a maximum width and height.
188
+ *
189
+ * @param vMatrixValues
190
+ * Vertical matrix values. Matrix contains arrays of length 1 with the values.
191
+ *
192
+ * @param maximumHeight
193
+ * Maximum height.
194
+ *
195
+ * @param maximumWidth
196
+ * Maximum width.
197
+ *
198
+ * @param invocationContext
199
+ * Invocation context.
200
+ *
201
+ * @returns
202
+ * Matrix spilled within maximum height and maximum width.
203
+ */
204
+ @ProxyMethod({
205
+ requiresContext: true,
206
+ type: Type.Any,
207
+ isMatrix: true
208
+ })
209
+ async hSpill(
210
+ @ProxyParameter(spillMatrix) vMatrixValues: Matrix<unknown>,
211
+ @ProxyParameter(spillMaximumHeightParameterDescriptor) maximumHeight: Nullishable<number>,
212
+ @ProxyParameter(spillMaximumWidthParameterDescriptor) maximumWidth: Nullishable<number>,
213
+ invocationContext: Nullishable<TInvocationContext>
214
+ ): Promise<Matrix<unknown>> {
215
+ let result: Matrix<unknown>;
216
+
217
+ for (const hArrayValues of vMatrixValues) {
218
+ // This test should be necessary only once but account for zero-size matrix and misuse of method.
219
+ if (hArrayValues.length !== 1) {
220
+ throw new RangeError(i18nextAppExtension.t("Proxy.hSpillMustBeVerticalArray"));
221
+ }
222
+ }
223
+
224
+ const maximumDimensions = await this.defaultMaximums({
225
+ width: maximumWidth,
226
+ height: maximumHeight
227
+ }, invocationContext);
228
+
229
+ const vLength = vMatrixValues.length;
230
+ const maximumArea = maximumDimensions.width * maximumDimensions.height;
231
+
232
+ // Lengths 0 and 1 are valid and require no special processing.
233
+ if (vLength > 1 && vLength <= maximumArea) {
234
+ // Make spill as square as possible.
235
+ let spillHeight = Math.min(Math.ceil(Math.sqrt(maximumArea)), maximumDimensions.height);
236
+
237
+ // Array that has a length of a power of 10 is treated specially.
238
+ if (Number.isInteger(Math.log10(vLength))) {
239
+ // Try spill height that is a power of 10.
240
+ const spillHeight10 = Math.pow(10, Math.floor(Math.log10(spillHeight)));
241
+
242
+ // Keep default if not enough space for power of 10 matrix.
243
+ if (vLength / spillHeight10 <= maximumDimensions.width) {
244
+ spillHeight = spillHeight10;
245
+ }
246
+ }
247
+
248
+ result = [];
249
+
250
+ for (let rowIndex = 0; rowIndex < spillHeight; rowIndex++) {
251
+ const row = new Array<unknown>();
252
+
253
+ for (let cellIndex = rowIndex; cellIndex < vLength; cellIndex++) {
254
+ row.push(vMatrixValues[cellIndex][0]);
255
+ }
256
+
257
+ result.push(row);
258
+ }
259
+ } else {
260
+ // Return matrix unmodified and let application handle spill error if any.
261
+ result = vMatrixValues;
262
+ }
263
+
264
+ return result;
265
+ }
266
+ }
@@ -0,0 +1,314 @@
1
+ import type { AppExtension } from "./app-extension.js";
2
+ import { LibProxy } from "./lib-proxy.js";
3
+ import type { ErrorExtends, TypedFunction } from "./types.js";
4
+
5
+ /**
6
+ * Core descriptor.
7
+ */
8
+ interface Descriptor {
9
+ readonly name: string;
10
+ }
11
+
12
+ /**
13
+ * Types supported by proxy methods.
14
+ */
15
+ export enum Type {
16
+ /**
17
+ * String.
18
+ */
19
+ String,
20
+
21
+ /**
22
+ * Number or enumeration.
23
+ */
24
+ Number,
25
+
26
+ /**
27
+ * Boolean.
28
+ */
29
+ Boolean,
30
+
31
+ /**
32
+ * Any.
33
+ */
34
+ Any
35
+ }
36
+
37
+ /**
38
+ * Type descriptor.
39
+ */
40
+ interface TypeDescriptor extends Descriptor {
41
+ /**
42
+ * Type.
43
+ */
44
+ readonly type: Type;
45
+
46
+ /**
47
+ * True if type is a matrix (method accepts or returns a two-dimensional array).
48
+ */
49
+ readonly isMatrix: boolean;
50
+ }
51
+
52
+ /**
53
+ * Base parameter descriptor; all attributes required.
54
+ */
55
+ export interface BaseParameterDescriptor extends TypeDescriptor {
56
+ /**
57
+ * True if required.
58
+ */
59
+ readonly isRequired: boolean;
60
+ }
61
+
62
+ /**
63
+ * Extends parameter descriptor; extends a parameter descriptor and overrides select attributes.
64
+ */
65
+ export interface ExtendsParameterDescriptor extends Partial<BaseParameterDescriptor> {
66
+ /**
67
+ * Base parameter descriptor that this one extends.
68
+ */
69
+ readonly extendsDescriptor: ParameterDescriptor;
70
+
71
+ /**
72
+ * Sort order within base parameter descriptor if applicable.
73
+ */
74
+ readonly sortOrder?: number;
75
+ }
76
+
77
+ /**
78
+ * Parameter descriptor, either base or extends.
79
+ */
80
+ export type ParameterDescriptor = BaseParameterDescriptor | ExtendsParameterDescriptor;
81
+
82
+ /**
83
+ * Expand a parameter descriptor to its full form with all required attributes.
84
+ *
85
+ * @param parameterDescriptor
86
+ * Parameter descriptor.
87
+ *
88
+ * @returns
89
+ * Parameter descriptor in its full form.
90
+ */
91
+ export function expandParameterDescriptor(parameterDescriptor: ParameterDescriptor): BaseParameterDescriptor {
92
+ return !("extendsDescriptor" in parameterDescriptor) ?
93
+ parameterDescriptor :
94
+ {
95
+ ...expandParameterDescriptor(parameterDescriptor.extendsDescriptor),
96
+ ...parameterDescriptor
97
+ };
98
+ }
99
+
100
+ /**
101
+ * Method descriptor.
102
+ */
103
+ export interface MethodDescriptor extends TypeDescriptor {
104
+ /**
105
+ * If true, application-specific invocation context is required.
106
+ */
107
+ readonly requiresContext?: boolean;
108
+
109
+ /**
110
+ * If true, method infix is ignored.
111
+ */
112
+ readonly ignoreInfix?: boolean;
113
+
114
+ /**
115
+ * String before which method infix appears. If undefined, infix is appended to the method name. Ignored if
116
+ * `ignoreInfix` is true.
117
+ */
118
+ readonly infixBefore?: string;
119
+
120
+ /**
121
+ * Parameter descriptors.
122
+ */
123
+ readonly parameterDescriptors: readonly ParameterDescriptor[];
124
+ }
125
+
126
+ /**
127
+ * Class descriptor.
128
+ */
129
+ export interface ClassDescriptor extends Descriptor {
130
+ /**
131
+ * Class namespace. If not provided, class is at the top level.
132
+ */
133
+ readonly namespace?: string;
134
+
135
+ /**
136
+ * Method infix. If undefined, method name is generated verbatim.
137
+ */
138
+ readonly methodInfix?: string;
139
+
140
+ /**
141
+ * Replace parameter descriptors for class hierarchies where enumeration parameter descriptors can change.
142
+ */
143
+ readonly replaceParameterDescriptors?: ReadonlyArray<{
144
+ readonly name: string;
145
+ readonly replacement: ParameterDescriptor;
146
+ }>;
147
+
148
+ /**
149
+ * Method descriptors.
150
+ */
151
+ readonly methodDescriptors: readonly MethodDescriptor[];
152
+ }
153
+
154
+ /**
155
+ * Proxy class type with fixed constructor.
156
+ */
157
+ type ProxyClassType<ThrowError extends boolean, TError extends ErrorExtends<ThrowError>, TInvocationContext, TBigInt, T extends LibProxy<ThrowError, TError, TInvocationContext, TBigInt>> = (new(appExtension: AppExtension<ThrowError, TError, TInvocationContext, TBigInt>) => T) & typeof LibProxy;
158
+
159
+ /**
160
+ * Pending parameter descriptors, consumed and reset when method is described.
161
+ */
162
+ let pendingParameterDescriptors: ParameterDescriptor[] = [];
163
+
164
+ /**
165
+ * Class method descriptors, keyed on declaration class name and method name.
166
+ */
167
+ const classMethodsDescriptorsMap = new Map<string, MethodDescriptor[]>();
168
+
169
+ /**
170
+ * Class descriptors, keyed on declaration class name.
171
+ */
172
+ const classDescriptorsMap = new Map<string, ClassDescriptor>();
173
+
174
+ /**
175
+ * Proxy parameter decorator.
176
+ *
177
+ * @param parameterDescriptor
178
+ * Parameter descriptor.
179
+ *
180
+ * @returns
181
+ * Function defining metadata for the parameter.
182
+ */
183
+ export function ProxyParameter<ThrowError extends boolean, TError extends ErrorExtends<ThrowError>, TInvocationContext, TBigInt, T extends LibProxy<ThrowError, TError, TInvocationContext, TBigInt>>(parameterDescriptor: ParameterDescriptor): ((target: T, propertyKey: string, parameterIndex: number) => void) {
184
+ return (_target: T, _propertyKey: string, parameterIndex: number) => {
185
+ pendingParameterDescriptors[parameterIndex] = parameterDescriptor;
186
+ };
187
+ }
188
+
189
+ /**
190
+ * Proxy method decorator.
191
+ *
192
+ * @param methodDescriptor
193
+ * Method descriptor.
194
+ *
195
+ * @returns
196
+ * Function defining metadata for the method.
197
+ */
198
+ export function ProxyMethod<ThrowError extends boolean, TError extends ErrorExtends<ThrowError>, TInvocationContext, TBigInt, T extends LibProxy<ThrowError, TError, TInvocationContext, TBigInt>>(methodDescriptor: Omit<MethodDescriptor, "name" | "parameterDescriptors">): ((target: T, propertyKey: string, propertyDescriptor: PropertyDescriptor) => void) {
199
+ return (target: T, propertyKey: string, propertyDescriptor: PropertyDescriptor) => {
200
+ const declarationClassName = target.constructor.name;
201
+
202
+ // Validate that method descriptor is applied to a function.
203
+ if (typeof propertyDescriptor.value !== "function") {
204
+ throw new Error(`${declarationClassName}.${propertyKey} is not a method`);
205
+ }
206
+
207
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Known to be a method.
208
+ const parameterCount = (propertyDescriptor.value as TypedFunction<(...args: unknown[]) => unknown>).length - (!(methodDescriptor.requiresContext ?? false) ? 0 : 1);
209
+
210
+ let anyOptional = false;
211
+
212
+ // Validate that all parameters have descriptors.
213
+ for (let index = 0; index < parameterCount; index++) {
214
+ const parameterDescriptor = expandParameterDescriptor(pendingParameterDescriptors[index]);
215
+
216
+ if (typeof parameterDescriptor === "undefined") {
217
+ throw new Error(`Missing parameter descriptor at index ${index} of ${declarationClassName}.${propertyKey}`);
218
+ }
219
+
220
+ if (!parameterDescriptor.isRequired) {
221
+ anyOptional = true;
222
+ } else if (anyOptional) {
223
+ throw new Error(`Parameter descriptor ${parameterDescriptor.name} at index ${index} of ${declarationClassName}.${propertyKey} is required but prior parameter descriptor ${pendingParameterDescriptors[index - 1].name} is optional`);
224
+ }
225
+ }
226
+
227
+ let methodDescriptors = classMethodsDescriptorsMap.get(declarationClassName);
228
+ if (methodDescriptors === undefined) {
229
+ methodDescriptors = [];
230
+ classMethodsDescriptorsMap.set(declarationClassName, methodDescriptors);
231
+ }
232
+
233
+ // Method descriptors array is constructed in reverse order so that final result is in the correct order.
234
+ methodDescriptors.push({
235
+ name: propertyKey,
236
+ ...methodDescriptor,
237
+ parameterDescriptors: pendingParameterDescriptors
238
+ });
239
+
240
+ pendingParameterDescriptors = [];
241
+ };
242
+ }
243
+
244
+ /**
245
+ * Proxy class decorator.
246
+ *
247
+ * @param classDescriptor
248
+ * Class descriptor.
249
+ *
250
+ * @returns
251
+ * Function defining metadata for the class.
252
+ */
253
+ export function ProxyClass<ThrowError extends boolean, TError extends ErrorExtends<ThrowError>, TInvocationContext, TBigInt, T extends LibProxy<ThrowError, TError, TInvocationContext, TBigInt>>(classDescriptor: Omit<ClassDescriptor, "name" | "methodDescriptors"> = {}): ((classType: ProxyClassType<ThrowError, TError, TInvocationContext, TBigInt, T>) => void) {
254
+ return (classType: ProxyClassType<ThrowError, TError, TInvocationContext, TBigInt, T>) => {
255
+ const methodDescriptorsMap = new Map<string, MethodDescriptor>();
256
+
257
+ /**
258
+ * Build method descriptors map from every class in hierarchy until LibProxy class is reached.
259
+ *
260
+ * @param classType
261
+ * Class type.
262
+ */
263
+ function buildMethodDescriptorsMap(classType: typeof LibProxy): void {
264
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Class hierarchy is known.
265
+ const baseClassType = Object.getPrototypeOf(classType) as typeof LibProxy;
266
+
267
+ // Start with class furthest up the hierarchy.
268
+ if (baseClassType !== LibProxy) {
269
+ buildMethodDescriptorsMap(baseClassType);
270
+ }
271
+
272
+ const classMethodDescriptors = classMethodsDescriptorsMap.get(classType.name);
273
+
274
+ if (classMethodDescriptors !== undefined) {
275
+ for (const classMethodDescriptor of classMethodDescriptors) {
276
+ // If any class overrides a base class method, it will appear in the same position as the base class method.
277
+ methodDescriptorsMap.set(classMethodDescriptor.name, classMethodDescriptor);
278
+ }
279
+ }
280
+ }
281
+
282
+ buildMethodDescriptorsMap(classType);
283
+
284
+ let methodDescriptors: MethodDescriptor[];
285
+
286
+ if (classDescriptor.replaceParameterDescriptors !== undefined) {
287
+ const replacementParameterDescriptorsMap = new Map(classDescriptor.replaceParameterDescriptors.map(replaceParameterDescriptor => [replaceParameterDescriptor.name, replaceParameterDescriptor.replacement]));
288
+
289
+ // Method descriptors for class have to be built as copies due to possible mutation of parameter descriptors.
290
+ methodDescriptors = Array.from(methodDescriptorsMap.values()).map(methodDescriptor => ({
291
+ ...methodDescriptor,
292
+ parameterDescriptors: methodDescriptor.parameterDescriptors.map(parameterDescriptor => replacementParameterDescriptorsMap.get(expandParameterDescriptor(parameterDescriptor).name) ?? parameterDescriptor)
293
+ }));
294
+ } else {
295
+ methodDescriptors = Array.from(methodDescriptorsMap.values());
296
+ }
297
+
298
+ classDescriptorsMap.set(classType.name, {
299
+ name: classType.name,
300
+ ...classDescriptor,
301
+ methodDescriptors
302
+ });
303
+ };
304
+ }
305
+
306
+ /**
307
+ * Get class descriptors.
308
+ *
309
+ * @returns
310
+ * Class descriptors.
311
+ */
312
+ export function getClassDescriptors(): ReadonlyMap<string, ClassDescriptor> {
313
+ return classDescriptorsMap;
314
+ }
@@ -0,0 +1,41 @@
1
+ import { AI39_CREATOR, AI82_CREATOR } from "@aidc-toolkit/gs1";
2
+ import type { AppExtension } from "../app-extension.js";
3
+ import { expandParameterDescriptor, ProxyClass } from "../descriptor.js";
4
+ import type { ErrorExtends } from "../types.js";
5
+ import {
6
+ exclusionAllNumericParameterDescriptor,
7
+ exclusionNoneParameterDescriptor
8
+ } from "../utility/character-set-descriptor.js";
9
+ import { CharacterSetProxy } from "../utility/character-set-proxy.js";
10
+
11
+ @ProxyClass({
12
+ namespace: "GS1",
13
+ methodInfix: "AI82",
14
+ replaceParameterDescriptors: [
15
+ {
16
+ name: expandParameterDescriptor(exclusionNoneParameterDescriptor).name,
17
+ replacement: exclusionAllNumericParameterDescriptor
18
+ }
19
+ ]
20
+ })
21
+ export class AI82Proxy<ThrowError extends boolean, TError extends ErrorExtends<ThrowError>, TInvocationContext, TBigInt> extends CharacterSetProxy<ThrowError, TError, TInvocationContext, TBigInt> {
22
+ constructor(appExtension: AppExtension<ThrowError, TError, TInvocationContext, TBigInt>) {
23
+ super(appExtension, AI82_CREATOR);
24
+ }
25
+ }
26
+
27
+ @ProxyClass({
28
+ namespace: "GS1",
29
+ methodInfix: "AI39",
30
+ replaceParameterDescriptors: [
31
+ {
32
+ name: expandParameterDescriptor(exclusionNoneParameterDescriptor).name,
33
+ replacement: exclusionAllNumericParameterDescriptor
34
+ }
35
+ ]
36
+ })
37
+ export class AI39Proxy<ThrowError extends boolean, TError extends ErrorExtends<ThrowError>, TInvocationContext, TBigInt> extends CharacterSetProxy<ThrowError, TError, TInvocationContext, TBigInt> {
38
+ constructor(appExtension: AppExtension<ThrowError, TError, TInvocationContext, TBigInt>) {
39
+ super(appExtension, AI39_CREATOR);
40
+ }
41
+ }