@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.
- package/dist/index.cjs +1 -3709
- package/dist/index.d.cts +607 -333
- package/dist/index.d.ts +607 -333
- package/dist/index.js +1 -3683
- package/package.json +12 -13
- package/src/app-extension.ts +141 -93
- package/src/app-helper-proxy.ts +326 -0
- package/src/descriptor.ts +75 -7
- package/src/generator/generator.ts +118 -96
- package/src/generator/locale-resources-generator.ts +56 -42
- package/src/gs1/character-set-proxy.ts +8 -8
- package/src/gs1/check-proxy.ts +26 -25
- package/src/gs1/gtin-creator-proxy.ts +14 -28
- package/src/gs1/gtin-descriptor.ts +2 -23
- package/src/gs1/gtin-validator-proxy.ts +45 -48
- package/src/gs1/identifier-creator-proxy.ts +63 -53
- package/src/gs1/identifier-descriptor.ts +15 -0
- package/src/gs1/identifier-type.ts +37 -0
- package/src/gs1/identifier-validator-proxy.ts +59 -27
- package/src/gs1/index.ts +8 -0
- package/src/gs1/non-gtin-creator-proxy.ts +22 -33
- package/src/gs1/non-gtin-validator-proxy.ts +22 -33
- package/src/gs1/prefix-definition-descriptor.ts +2 -2
- package/src/gs1/prefix-manager-proxy.ts +164 -9
- package/src/gs1/service-proxy.ts +57 -0
- package/src/gs1/variable-measure-proxy.ts +62 -0
- package/src/index.ts +6 -1
- package/src/lib-proxy.ts +112 -70
- package/src/locale/en/locale-resources.ts +173 -47
- package/src/locale/fr/locale-resources.ts +173 -47
- package/src/locale/i18n.ts +8 -10
- package/src/locale/i18next.d.ts +2 -0
- package/src/proxy.ts +140 -140
- package/src/streaming.ts +13 -0
- package/src/type.ts +8 -7
- package/src/utility/character-set-descriptor.ts +2 -2
- package/src/utility/character-set-proxy.ts +39 -38
- package/src/utility/reg-exp-proxy.ts +12 -11
- package/src/utility/string-descriptor.ts +2 -2
- package/src/utility/string-proxy.ts +7 -7
- package/src/utility/transformer-descriptor.ts +5 -5
- package/src/utility/transformer-proxy.ts +25 -18
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/src/app-utility-proxy.ts +0 -273
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aidc-toolkit/app-extension",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.33-beta",
|
|
4
4
|
"description": "Application extension framework for AIDC Toolkit",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
|
-
"homepage": "https://aidc-toolkit.com
|
|
7
|
+
"homepage": "https://aidc-toolkit.com",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
10
|
"url": "git+https://github.com/aidc-toolkit/app-extension.git"
|
|
@@ -19,21 +19,20 @@
|
|
|
19
19
|
"url": "https://www.linkedin.com/in/kdean"
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
|
22
|
-
"locale-resources-generator": "tsx src/generator/locale-resources-generator.ts",
|
|
23
22
|
"lint": "eslint",
|
|
24
|
-
"
|
|
25
|
-
"build:
|
|
26
|
-
"build:
|
|
27
|
-
"build:
|
|
28
|
-
"build:doc": "npm run build:
|
|
23
|
+
"build:base": "tsc --project tsconfig-src.json --noEmit && tsup",
|
|
24
|
+
"build:alpha": "npm run build:base -- --define.mode=alpha",
|
|
25
|
+
"build:beta": "npm run build:base -- --define.mode=beta",
|
|
26
|
+
"build:prod": "npm run build:base",
|
|
27
|
+
"build:doc": "npm run build:alpha",
|
|
28
|
+
"generate-locale-resources": "tsx src/generator/locale-resources-generator.ts"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@aidc-toolkit/dev": "1.0.
|
|
31
|
+
"@aidc-toolkit/dev": "1.0.33-beta"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@aidc-toolkit/core": "1.0.
|
|
35
|
-
"@aidc-toolkit/gs1": "1.0.
|
|
36
|
-
"@aidc-toolkit/utility": "1.0.
|
|
37
|
-
"i18next": "^25.7.2"
|
|
34
|
+
"@aidc-toolkit/core": "1.0.33-beta",
|
|
35
|
+
"@aidc-toolkit/gs1": "1.0.33-beta",
|
|
36
|
+
"@aidc-toolkit/utility": "1.0.33-beta"
|
|
38
37
|
}
|
|
39
38
|
}
|
package/src/app-extension.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
type AppDataStorage,
|
|
3
|
+
getLogger,
|
|
4
|
+
type Hyperlink,
|
|
5
|
+
LogLevels,
|
|
6
|
+
MemoryTransport,
|
|
7
|
+
type Promisable
|
|
8
|
+
} from "@aidc-toolkit/core";
|
|
9
|
+
import type { Logger } from "tslog";
|
|
2
10
|
import { i18nextAppExtension } from "./locale/i18n.js";
|
|
3
|
-
import type {
|
|
11
|
+
import type { StreamingCancelledCallback, StreamingConsumerCallback } from "./streaming.js";
|
|
12
|
+
import type { ErrorExtends, MatrixResult, SheetAddress, SheetRange, SingletonResult } from "./type.js";
|
|
4
13
|
|
|
5
14
|
/**
|
|
6
15
|
* Application extension.
|
|
@@ -14,10 +23,33 @@ import type { ErrorExtends, ResultError, SheetAddress, SheetRange } from "./type
|
|
|
14
23
|
* @template TInvocationContext
|
|
15
24
|
* Application-specific invocation context type.
|
|
16
25
|
*
|
|
26
|
+
* @template TStreamingInvocationContext
|
|
27
|
+
* Application-specific streaming invocation context type.
|
|
28
|
+
*
|
|
17
29
|
* @template TBigInt
|
|
18
30
|
* Type to which big integer is mapped.
|
|
19
31
|
*/
|
|
20
|
-
export abstract class AppExtension<ThrowError extends boolean, TError extends ErrorExtends<ThrowError>, TInvocationContext, TBigInt> {
|
|
32
|
+
export abstract class AppExtension<ThrowError extends boolean, TError extends ErrorExtends<ThrowError>, TInvocationContext, TStreamingInvocationContext, TBigInt> {
|
|
33
|
+
/**
|
|
34
|
+
* Application name.
|
|
35
|
+
*/
|
|
36
|
+
static readonly APPLICATION_NAME = "AIDCToolkit";
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Version property name.
|
|
40
|
+
*/
|
|
41
|
+
static readonly VERSION_NAME = `${AppExtension.APPLICATION_NAME}.version`;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Maximum logger messages length.
|
|
45
|
+
*/
|
|
46
|
+
static readonly #MAXIMUM_LOGGER_MESSAGES_LENGTH = 120;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Truncate logger messages length.
|
|
50
|
+
*/
|
|
51
|
+
static readonly #TRUNCATE_LOGGER_MESSAGES_LENGTH = 100;
|
|
52
|
+
|
|
21
53
|
/**
|
|
22
54
|
* Application version.
|
|
23
55
|
*/
|
|
@@ -34,14 +66,14 @@ export abstract class AppExtension<ThrowError extends boolean, TError extends Er
|
|
|
34
66
|
readonly #throwError: ThrowError;
|
|
35
67
|
|
|
36
68
|
/**
|
|
37
|
-
*
|
|
69
|
+
* Logger.
|
|
38
70
|
*/
|
|
39
|
-
#
|
|
71
|
+
readonly #logger: Logger<object>;
|
|
40
72
|
|
|
41
73
|
/**
|
|
42
|
-
*
|
|
74
|
+
* Logger memory transport.
|
|
43
75
|
*/
|
|
44
|
-
#
|
|
76
|
+
readonly #memoryTransport: MemoryTransport<object>;
|
|
45
77
|
|
|
46
78
|
/**
|
|
47
79
|
* Constructor.
|
|
@@ -55,10 +87,30 @@ export abstract class AppExtension<ThrowError extends boolean, TError extends Er
|
|
|
55
87
|
* @param throwError
|
|
56
88
|
* If true, errors are reported through the throw/catch mechanism.
|
|
57
89
|
*/
|
|
58
|
-
constructor(version: string, maximumSequenceCount: number, throwError: ThrowError) {
|
|
90
|
+
protected constructor(version: string, maximumSequenceCount: number, throwError: ThrowError) {
|
|
59
91
|
this.#version = version;
|
|
60
92
|
this.#maximumSequenceCount = maximumSequenceCount;
|
|
61
93
|
this.#throwError = throwError;
|
|
94
|
+
|
|
95
|
+
// Running in production if version doesn't include a pre-release identifier.
|
|
96
|
+
const isProduction = !version.includes("-");
|
|
97
|
+
|
|
98
|
+
this.#logger = getLogger(isProduction ? LogLevels.Info : LogLevels.Debug, {
|
|
99
|
+
type: isProduction ? "hidden" : "pretty"
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
this.#memoryTransport = new MemoryTransport(this.#logger, AppExtension.#MAXIMUM_LOGGER_MESSAGES_LENGTH, AppExtension.#TRUNCATE_LOGGER_MESSAGES_LENGTH);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Initialize the application extension.
|
|
107
|
+
*/
|
|
108
|
+
async initialize(): Promise<void> {
|
|
109
|
+
const fileVersion = await this.getDocumentProperty(AppExtension.VERSION_NAME);
|
|
110
|
+
|
|
111
|
+
if (fileVersion !== this.#version) {
|
|
112
|
+
await this.setDocumentProperty(AppExtension.VERSION_NAME, this.#version);
|
|
113
|
+
}
|
|
62
114
|
}
|
|
63
115
|
|
|
64
116
|
/**
|
|
@@ -79,44 +131,28 @@ export abstract class AppExtension<ThrowError extends boolean, TError extends Er
|
|
|
79
131
|
}
|
|
80
132
|
|
|
81
133
|
/**
|
|
82
|
-
* Get the
|
|
83
|
-
*
|
|
84
|
-
* @returns
|
|
85
|
-
* Maximum width supported by the application.
|
|
134
|
+
* Get the logger.
|
|
86
135
|
*/
|
|
87
|
-
|
|
88
|
-
this.#
|
|
89
|
-
|
|
90
|
-
return this.#maximumWidth;
|
|
136
|
+
get logger(): Logger<object> {
|
|
137
|
+
return this.#logger;
|
|
91
138
|
}
|
|
92
139
|
|
|
93
140
|
/**
|
|
94
|
-
* Get the
|
|
95
|
-
*
|
|
96
|
-
* @returns
|
|
97
|
-
* Maximum width supported by the application.
|
|
141
|
+
* Get the logger memory transport.
|
|
98
142
|
*/
|
|
99
|
-
|
|
143
|
+
get memoryTransport(): MemoryTransport<object> {
|
|
144
|
+
return this.#memoryTransport;
|
|
145
|
+
}
|
|
100
146
|
|
|
101
147
|
/**
|
|
102
|
-
* Get the maximum
|
|
103
|
-
*
|
|
104
|
-
* @returns
|
|
105
|
-
* Maximum height supported by the application.
|
|
148
|
+
* Get the maximum width supported by the application.
|
|
106
149
|
*/
|
|
107
|
-
|
|
108
|
-
this.#maximumHeight ??= await this.getMaximumHeight();
|
|
109
|
-
|
|
110
|
-
return this.#maximumHeight;
|
|
111
|
-
}
|
|
150
|
+
abstract get maximumWidth(): number;
|
|
112
151
|
|
|
113
152
|
/**
|
|
114
153
|
* Get the maximum height supported by the application.
|
|
115
|
-
*
|
|
116
|
-
* @returns
|
|
117
|
-
* Maximum height supported by the application.
|
|
118
154
|
*/
|
|
119
|
-
|
|
155
|
+
abstract get maximumHeight(): number;
|
|
120
156
|
|
|
121
157
|
/**
|
|
122
158
|
* Get the sheet address from an invocation context.
|
|
@@ -127,7 +163,7 @@ export abstract class AppExtension<ThrowError extends boolean, TError extends Er
|
|
|
127
163
|
* @returns
|
|
128
164
|
* Sheet address.
|
|
129
165
|
*/
|
|
130
|
-
abstract getSheetAddress(invocationContext: TInvocationContext):
|
|
166
|
+
abstract getSheetAddress(invocationContext: TInvocationContext): Promisable<SheetAddress>;
|
|
131
167
|
|
|
132
168
|
/**
|
|
133
169
|
* Get a parameter range from an invocation context.
|
|
@@ -141,7 +177,61 @@ export abstract class AppExtension<ThrowError extends boolean, TError extends Er
|
|
|
141
177
|
* @returns
|
|
142
178
|
* Sheet range or null if parameter is not a range.
|
|
143
179
|
*/
|
|
144
|
-
abstract getParameterSheetRange(invocationContext: TInvocationContext, parameterNumber: number):
|
|
180
|
+
abstract getParameterSheetRange(invocationContext: TInvocationContext, parameterNumber: number): Promisable<SheetRange | null>;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Set up streaming for a streaming function.
|
|
184
|
+
*
|
|
185
|
+
* @param streamingInvocationContext
|
|
186
|
+
* Streaming invocation context.
|
|
187
|
+
*
|
|
188
|
+
* @param streamingCancelledCallback
|
|
189
|
+
* Streaming cancelled callback, called when streaming is cancelled.
|
|
190
|
+
*
|
|
191
|
+
* @returns
|
|
192
|
+
* Streaming consumer callback, called when stream contents updated.
|
|
193
|
+
*/
|
|
194
|
+
abstract setUpStreaming<TResult>(streamingInvocationContext: TStreamingInvocationContext, streamingCancelledCallback: StreamingCancelledCallback): StreamingConsumerCallback<TResult, ThrowError, TError>;
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Get a property stored within the active document.
|
|
198
|
+
*
|
|
199
|
+
* @param name
|
|
200
|
+
* Property name.
|
|
201
|
+
*
|
|
202
|
+
* @returns
|
|
203
|
+
* Property value or undefined if no value is stored under the given name.
|
|
204
|
+
*/
|
|
205
|
+
abstract getDocumentProperty(name: string): Promisable<string | undefined>;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Set a property to be stored within the active document.
|
|
209
|
+
*
|
|
210
|
+
* @param name
|
|
211
|
+
* Property name.
|
|
212
|
+
*
|
|
213
|
+
* @param value
|
|
214
|
+
* Property value.
|
|
215
|
+
*/
|
|
216
|
+
abstract setDocumentProperty(name: string, value: string): Promisable<void>;
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Delete a property from the active document.
|
|
220
|
+
*
|
|
221
|
+
* @param name
|
|
222
|
+
* Property name.
|
|
223
|
+
*/
|
|
224
|
+
abstract deleteDocumentProperty(name: string): Promisable<void>;
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Get application data storage for the current document.
|
|
228
|
+
*/
|
|
229
|
+
abstract get documentAppDataStorage(): AppDataStorage<boolean>;
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Get application data storage shared across multiple documents.
|
|
233
|
+
*/
|
|
234
|
+
abstract get sharedAppDataStorage(): AppDataStorage<boolean>;
|
|
145
235
|
|
|
146
236
|
/**
|
|
147
237
|
* Validate a sequence count against the maximum supported by application.
|
|
@@ -169,7 +259,21 @@ export abstract class AppExtension<ThrowError extends boolean, TError extends Er
|
|
|
169
259
|
* @returns
|
|
170
260
|
* Mapped big integer value.
|
|
171
261
|
*/
|
|
172
|
-
abstract mapBigInt(value: bigint):
|
|
262
|
+
abstract mapBigInt(value: bigint): SingletonResult<TBigInt, ThrowError, TError>;
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Map hyperlink results to a form suitable for the application.
|
|
266
|
+
*
|
|
267
|
+
* @param invocationContext
|
|
268
|
+
* Invocation context.
|
|
269
|
+
*
|
|
270
|
+
* @param matrixHyperlinkResults
|
|
271
|
+
* Matrix of hyperlink results from function call.
|
|
272
|
+
*
|
|
273
|
+
* @returns
|
|
274
|
+
* Matrix of results in a form suitable for the application.
|
|
275
|
+
*/
|
|
276
|
+
abstract mapHyperlinkResults(invocationContext: TInvocationContext, matrixHyperlinkResults: MatrixResult<Hyperlink, ThrowError, TError>): Promisable<MatrixResult<unknown, ThrowError, TError>>;
|
|
173
277
|
|
|
174
278
|
/**
|
|
175
279
|
* Map a range error (thrown by the library) to an application-specific error. If errors are reported through the
|
|
@@ -187,60 +291,4 @@ export abstract class AppExtension<ThrowError extends boolean, TError extends Er
|
|
|
187
291
|
* Message to include in the error.
|
|
188
292
|
*/
|
|
189
293
|
abstract handleError(message: string): never;
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Bind a synchronous method and wrap it in a try/catch for comprehensive error handling.
|
|
193
|
-
*
|
|
194
|
-
* @template TMethod
|
|
195
|
-
* Method type.
|
|
196
|
-
*
|
|
197
|
-
* @param thisArg
|
|
198
|
-
* The value to be passed as the `this` parameter to the method.
|
|
199
|
-
*
|
|
200
|
-
* @param method
|
|
201
|
-
* Method to call.
|
|
202
|
-
*
|
|
203
|
-
* @returns
|
|
204
|
-
* Function wrapped around the method.
|
|
205
|
-
*/
|
|
206
|
-
bindSync<TMethod extends TypedSyncFunction<TMethod>>(thisArg: ThisParameterType<TMethod>, method: TMethod): TypedFunction<TMethod> {
|
|
207
|
-
const boundMethod = method.bind(thisArg);
|
|
208
|
-
|
|
209
|
-
return (...args: Parameters<TMethod>): ReturnType<TMethod> => {
|
|
210
|
-
try {
|
|
211
|
-
return boundMethod(...args);
|
|
212
|
-
} catch (e: unknown) {
|
|
213
|
-
// eslint-disable-next-line no-console -- Necessary for diagnostics.
|
|
214
|
-
console.error(e);
|
|
215
|
-
|
|
216
|
-
this.handleError(e instanceof Error ? e.message : String(e));
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Bind an asynchronous method and wrap it in a try/catch for comprehensive error handling.
|
|
223
|
-
*
|
|
224
|
-
* @template TMethod
|
|
225
|
-
* Method type.
|
|
226
|
-
*
|
|
227
|
-
* @param thisArg
|
|
228
|
-
* The value to be passed as the `this` parameter to the method.
|
|
229
|
-
*
|
|
230
|
-
* @param method
|
|
231
|
-
* Method to call.
|
|
232
|
-
*
|
|
233
|
-
* @returns
|
|
234
|
-
* Function wrapped around the method.
|
|
235
|
-
*/
|
|
236
|
-
bindAsync<TMethod extends TypedAsyncFunction<TMethod>>(thisArg: ThisParameterType<TMethod>, method: TMethod): TypedAsyncFunction<TMethod> {
|
|
237
|
-
const boundMethod = method.bind(thisArg);
|
|
238
|
-
|
|
239
|
-
return async (...args: Parameters<TMethod>) => await boundMethod(...args).catch((e: unknown) => {
|
|
240
|
-
// eslint-disable-next-line no-console -- Necessary for diagnostics.
|
|
241
|
-
console.error(e);
|
|
242
|
-
|
|
243
|
-
this.handleError(e instanceof Error ? e.message : String(e));
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
294
|
}
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import { isNullish, type LogLevel, logLevelOf, type NonNullishable, type Nullishable } from "@aidc-toolkit/core";
|
|
2
|
+
import { type ExtendsParameterDescriptor, Multiplicities, type ParameterDescriptor, Types } from "./descriptor.js";
|
|
3
|
+
import { LibProxy } from "./lib-proxy.js";
|
|
4
|
+
import { i18nextAppExtension } from "./locale/i18n.js";
|
|
5
|
+
import { proxy } from "./proxy.js";
|
|
6
|
+
import type { ErrorExtends, Matrix, MatrixResult } from "./type.js";
|
|
7
|
+
|
|
8
|
+
const spillArrayParameterDescriptor: ParameterDescriptor = {
|
|
9
|
+
name: "spillArray",
|
|
10
|
+
type: Types.Any,
|
|
11
|
+
multiplicity: Multiplicities.Array,
|
|
12
|
+
isRequired: true
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const spillMaximumParameterDescriptor: ParameterDescriptor = {
|
|
16
|
+
name: "spillMaximum",
|
|
17
|
+
type: Types.Number,
|
|
18
|
+
multiplicity: Multiplicities.Singleton,
|
|
19
|
+
isRequired: false
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const spillMaximumWidthParameterDescriptor: ExtendsParameterDescriptor = {
|
|
23
|
+
extendsDescriptor: spillMaximumParameterDescriptor,
|
|
24
|
+
sortOrder: 0,
|
|
25
|
+
name: "spillMaximumWidth"
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const spillMaximumHeightParameterDescriptor: ExtendsParameterDescriptor = {
|
|
29
|
+
extendsDescriptor: spillMaximumParameterDescriptor,
|
|
30
|
+
sortOrder: 1,
|
|
31
|
+
name: "spillMaximumHeight"
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Maximum dimensions.
|
|
36
|
+
*/
|
|
37
|
+
interface MaximumDimensions {
|
|
38
|
+
/**
|
|
39
|
+
* Optional maximum width.
|
|
40
|
+
*/
|
|
41
|
+
width: Nullishable<number>;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Optional maximum height.
|
|
45
|
+
*/
|
|
46
|
+
height: Nullishable<number>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Application utilities.
|
|
51
|
+
*
|
|
52
|
+
* @template ThrowError
|
|
53
|
+
* If true, errors are reported through the throw/catch mechanism.
|
|
54
|
+
*
|
|
55
|
+
* @template TError
|
|
56
|
+
* Error type.
|
|
57
|
+
*
|
|
58
|
+
* @template TInvocationContext
|
|
59
|
+
* Application-specific invocation context type.
|
|
60
|
+
*
|
|
61
|
+
* @template TStreamingInvocationContext
|
|
62
|
+
* Application-specific streaming invocation context type.
|
|
63
|
+
*
|
|
64
|
+
* @template TBigInt
|
|
65
|
+
* Type to which big integer is mapped.
|
|
66
|
+
*/
|
|
67
|
+
@proxy.describeClass(false, {
|
|
68
|
+
category: "helper"
|
|
69
|
+
})
|
|
70
|
+
export class AppHelperProxy<ThrowError extends boolean, TError extends ErrorExtends<ThrowError>, TInvocationContext, TStreamingInvocationContext, TBigInt> extends LibProxy<ThrowError, TError, TInvocationContext, TStreamingInvocationContext, TBigInt> {
|
|
71
|
+
/**
|
|
72
|
+
* Get the version.
|
|
73
|
+
*
|
|
74
|
+
* @returns
|
|
75
|
+
* Version.
|
|
76
|
+
*/
|
|
77
|
+
@proxy.describeMethod({
|
|
78
|
+
type: Types.String,
|
|
79
|
+
multiplicity: Multiplicities.Singleton,
|
|
80
|
+
parameterDescriptors: []
|
|
81
|
+
})
|
|
82
|
+
version(): string {
|
|
83
|
+
return this.appExtension.version;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Provide default values for maximum width and height if required.
|
|
88
|
+
*
|
|
89
|
+
* @param maximumDimensions
|
|
90
|
+
* Maximum dimensions provided to function.
|
|
91
|
+
*
|
|
92
|
+
* @param invocationContext
|
|
93
|
+
* Invocation context.
|
|
94
|
+
*
|
|
95
|
+
* @returns
|
|
96
|
+
* Array of maximum width and maximum height.
|
|
97
|
+
*/
|
|
98
|
+
async #defaultMaximums(maximumDimensions: MaximumDimensions, invocationContext: Nullishable<TInvocationContext>): Promise<NonNullishable<MaximumDimensions>> {
|
|
99
|
+
if (isNullish(invocationContext)) {
|
|
100
|
+
// Application error; no localization necessary.
|
|
101
|
+
throw new Error("Invocation context not provided by application");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const maximumWidth = maximumDimensions.width;
|
|
105
|
+
const maximumHeight = maximumDimensions.height;
|
|
106
|
+
|
|
107
|
+
let definedMaximumWidth: number;
|
|
108
|
+
let definedMaximumHeight: number;
|
|
109
|
+
|
|
110
|
+
// Skip any extra work if both values are provided.
|
|
111
|
+
if (isNullish(maximumWidth) || isNullish(maximumHeight)) {
|
|
112
|
+
const sheetAddress = await this.appExtension.getSheetAddress(invocationContext);
|
|
113
|
+
|
|
114
|
+
definedMaximumWidth = maximumWidth ?? this.appExtension.maximumWidth - sheetAddress.columnIndex;
|
|
115
|
+
definedMaximumHeight = maximumHeight ?? this.appExtension.maximumHeight - sheetAddress.rowIndex;
|
|
116
|
+
} else {
|
|
117
|
+
definedMaximumWidth = maximumWidth;
|
|
118
|
+
definedMaximumHeight = maximumHeight;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
width: definedMaximumWidth,
|
|
123
|
+
height: definedMaximumHeight
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Spill a one-dimensional matrix to fit a rectangle within a given maximum height and width.
|
|
129
|
+
*
|
|
130
|
+
* @param arrayValues
|
|
131
|
+
* Matrix values. Matrix is length 1 or contains arrays of length 1 with the values.
|
|
132
|
+
*
|
|
133
|
+
* @param maximumHeight
|
|
134
|
+
* Maximum height.
|
|
135
|
+
*
|
|
136
|
+
* @param maximumWidth
|
|
137
|
+
* Maximum width.
|
|
138
|
+
*
|
|
139
|
+
* @param invocationContext
|
|
140
|
+
* Invocation context.
|
|
141
|
+
*
|
|
142
|
+
* @returns
|
|
143
|
+
* Matrix spilled within maximum height and maximum width.
|
|
144
|
+
*/
|
|
145
|
+
@proxy.describeMethod({
|
|
146
|
+
requiresContext: true,
|
|
147
|
+
type: Types.Any,
|
|
148
|
+
multiplicity: Multiplicities.Matrix,
|
|
149
|
+
parameterDescriptors: [spillArrayParameterDescriptor, spillMaximumHeightParameterDescriptor, spillMaximumWidthParameterDescriptor]
|
|
150
|
+
})
|
|
151
|
+
async spill(arrayValues: Matrix<unknown>, maximumHeight: Nullishable<number>, maximumWidth: Nullishable<number>, invocationContext: Nullishable<TInvocationContext>): Promise<MatrixResult<unknown, ThrowError, TError>> {
|
|
152
|
+
let result: MatrixResult<unknown, ThrowError, TError>;
|
|
153
|
+
|
|
154
|
+
// Assume matrix is uniformly two-dimensional.
|
|
155
|
+
const height = arrayValues.length;
|
|
156
|
+
const width = height !== 0 ? arrayValues[0].length : 0;
|
|
157
|
+
|
|
158
|
+
const isArrayOrError = this.singletonResult(() => {
|
|
159
|
+
if (height > 1 && width > 1) {
|
|
160
|
+
throw new RangeError(i18nextAppExtension.t("Proxy.matrixMustBeArray"));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return true;
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
if (isArrayOrError === true) {
|
|
167
|
+
const maximumDimensions = await this.#defaultMaximums({
|
|
168
|
+
width: maximumWidth,
|
|
169
|
+
height: maximumHeight
|
|
170
|
+
}, invocationContext);
|
|
171
|
+
|
|
172
|
+
const isHorizontal = height === 1;
|
|
173
|
+
const length = isHorizontal ? width : height;
|
|
174
|
+
const maximumParallel = isHorizontal ? maximumDimensions.width : maximumDimensions.height;
|
|
175
|
+
const maximumPerpendicular = isHorizontal ? maximumDimensions.height : maximumDimensions.width;
|
|
176
|
+
const maximumArea = maximumParallel * maximumPerpendicular;
|
|
177
|
+
|
|
178
|
+
// Lengths 0 and 1 are valid and require no special processing.
|
|
179
|
+
if (length > 1 && length <= maximumArea) {
|
|
180
|
+
const lengthSquareRoot = Math.sqrt(length);
|
|
181
|
+
|
|
182
|
+
let spillParallel: number | undefined = undefined;
|
|
183
|
+
|
|
184
|
+
// Array that has a length of a power of 10 is treated specially.
|
|
185
|
+
if (Number.isInteger(Math.log10(length))) {
|
|
186
|
+
// Try spill that is a power of 10, favouring the parallel direction.
|
|
187
|
+
let spillParallel10 = 10 ** Math.ceil(Math.log10(lengthSquareRoot));
|
|
188
|
+
|
|
189
|
+
// Favour the perpendicular direction if not enough parallel space.
|
|
190
|
+
if (spillParallel10 > maximumParallel) {
|
|
191
|
+
spillParallel10 /= 10;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Take result as the spill parallel if it fits.
|
|
195
|
+
if (spillParallel10 <= maximumParallel && length / spillParallel10 <= maximumPerpendicular) {
|
|
196
|
+
spillParallel = spillParallel10;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Make spill as square as possible, favouring the parallel direction.
|
|
201
|
+
spillParallel ??= Math.max(Math.min(Math.ceil(lengthSquareRoot), maximumParallel), Math.floor(length / maximumPerpendicular));
|
|
202
|
+
|
|
203
|
+
const spillPerpendicular = Math.ceil(length / spillParallel);
|
|
204
|
+
|
|
205
|
+
result = [];
|
|
206
|
+
|
|
207
|
+
if (isHorizontal) {
|
|
208
|
+
let startIndex = 0;
|
|
209
|
+
|
|
210
|
+
do {
|
|
211
|
+
const endIndex = startIndex + spillParallel;
|
|
212
|
+
|
|
213
|
+
// Each row is a slice of the original single row.
|
|
214
|
+
const row = arrayValues[0].slice(startIndex, endIndex);
|
|
215
|
+
|
|
216
|
+
// Row length will be anywhere from 1 to spillParallel.
|
|
217
|
+
if (row.length < spillParallel) {
|
|
218
|
+
const rowLength = row.length;
|
|
219
|
+
|
|
220
|
+
row.length = spillParallel;
|
|
221
|
+
|
|
222
|
+
// Fill empty cells with empty string.
|
|
223
|
+
row.fill("", rowLength, spillParallel);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
result.push(row);
|
|
227
|
+
|
|
228
|
+
startIndex = endIndex;
|
|
229
|
+
} while (startIndex < length);
|
|
230
|
+
} else {
|
|
231
|
+
for (let rowIndex = 0; rowIndex < spillParallel; rowIndex++) {
|
|
232
|
+
const row: unknown[] = [];
|
|
233
|
+
|
|
234
|
+
// Each column is a slice of the original single column.
|
|
235
|
+
for (let valueIndex = rowIndex; valueIndex < length; valueIndex += spillParallel) {
|
|
236
|
+
row.push(arrayValues[valueIndex][0]);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Row length will always be spillPerpendicular or spillPerpendicular - 1.
|
|
240
|
+
if (row.length < spillPerpendicular) {
|
|
241
|
+
row[spillPerpendicular - 1] = "";
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
result.push(row);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
} else {
|
|
248
|
+
// Return matrix unmodified and let application handle spill error if any.
|
|
249
|
+
result = arrayValues;
|
|
250
|
+
}
|
|
251
|
+
} else {
|
|
252
|
+
// Return error as only element in matrix.
|
|
253
|
+
result = [[isArrayOrError]];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return result;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Get the logger messages as a stream.
|
|
261
|
+
*
|
|
262
|
+
* @param logLevelString
|
|
263
|
+
* Log level as string.
|
|
264
|
+
*
|
|
265
|
+
* @param streamingInvocationContext
|
|
266
|
+
* Streaming invocation context.
|
|
267
|
+
*/
|
|
268
|
+
@proxy.describeMethod({
|
|
269
|
+
type: Types.String,
|
|
270
|
+
isHidden: true,
|
|
271
|
+
isStream: true,
|
|
272
|
+
multiplicity: Multiplicities.Array,
|
|
273
|
+
parameterDescriptors: [{
|
|
274
|
+
name: "logLevel",
|
|
275
|
+
type: Types.String,
|
|
276
|
+
multiplicity: Multiplicities.Singleton,
|
|
277
|
+
isRequired: false
|
|
278
|
+
}]
|
|
279
|
+
})
|
|
280
|
+
loggerMessages(logLevelString: Nullishable<string>, streamingInvocationContext: Nullishable<TStreamingInvocationContext>): void {
|
|
281
|
+
if (isNullish(streamingInvocationContext)) {
|
|
282
|
+
// Application error; no localization necessary.
|
|
283
|
+
throw new Error("Streaming invocation context not provided by application");
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const appExtension = this.appExtension;
|
|
287
|
+
|
|
288
|
+
let notificationCallbackAdded = false;
|
|
289
|
+
let previousLogLevel: number | undefined = undefined;
|
|
290
|
+
|
|
291
|
+
const streamingConsumerCallback = appExtension.setUpStreaming<string>(streamingInvocationContext, () => {
|
|
292
|
+
if (notificationCallbackAdded) {
|
|
293
|
+
appExtension.memoryTransport.removeNotificationCallback("loggerMessages");
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (previousLogLevel !== undefined) {
|
|
297
|
+
appExtension.logger.settings.minLevel = previousLogLevel;
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
if (appExtension.memoryTransport.addNotificationCallback("loggerMessages", (_message, messages) => {
|
|
302
|
+
streamingConsumerCallback(this.iterableResult(() => messages));
|
|
303
|
+
})) {
|
|
304
|
+
notificationCallbackAdded = true;
|
|
305
|
+
|
|
306
|
+
let logLevel: LogLevel | undefined = undefined;
|
|
307
|
+
|
|
308
|
+
if (!isNullish(logLevelString)) {
|
|
309
|
+
try {
|
|
310
|
+
logLevel = logLevelOf(logLevelString);
|
|
311
|
+
} catch {
|
|
312
|
+
// Ignore error.
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Set log level if required.
|
|
317
|
+
if (logLevel !== undefined) {
|
|
318
|
+
previousLogLevel = appExtension.logger.settings.minLevel;
|
|
319
|
+
appExtension.logger.settings.minLevel = logLevel;
|
|
320
|
+
}
|
|
321
|
+
} else {
|
|
322
|
+
// Diagnostic tool; localization not required.
|
|
323
|
+
streamingConsumerCallback([["Only one logger messages call allowable per workbook"]]);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|