@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/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@aidc-toolkit/app-extension",
3
- "version": "1.0.31-beta",
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
- "tsc:core": "tsc --project tsconfig-src.json",
25
- "build:devx": "rimraf dist && npm run tsc:core -- --declarationMap --sourceMap",
26
- "build:dev": "tsup --define.mode=dev",
27
- "build:release": "npm run tsc:core -- --noEmit && tsup",
28
- "build:doc": "npm run build:dev"
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-beta"
31
+ "@aidc-toolkit/dev": "1.0.33-beta"
32
32
  },
33
33
  "dependencies": {
34
- "@aidc-toolkit/core": "1.0.31-beta",
35
- "@aidc-toolkit/gs1": "1.0.31-beta",
36
- "@aidc-toolkit/utility": "1.0.31-beta",
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
  }
@@ -1,6 +1,15 @@
1
- import type { TypedAsyncFunction, TypedFunction, TypedSyncFunction } from "@aidc-toolkit/core";
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 { ErrorExtends, ResultError, SheetAddress, SheetRange } from "./type.js";
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
- * Maximum width supported by application.
69
+ * Logger.
38
70
  */
39
- #maximumWidth?: number;
71
+ readonly #logger: Logger<object>;
40
72
 
41
73
  /**
42
- * Maximum height supported by application.
74
+ * Logger memory transport.
43
75
  */
44
- #maximumHeight?: number;
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 maximum width supported by the application.
83
- *
84
- * @returns
85
- * Maximum width supported by the application.
134
+ * Get the logger.
86
135
  */
87
- async maximumWidth(): Promise<number> {
88
- this.#maximumWidth ??= await this.getMaximumWidth();
89
-
90
- return this.#maximumWidth;
136
+ get logger(): Logger<object> {
137
+ return this.#logger;
91
138
  }
92
139
 
93
140
  /**
94
- * Get the maximum width supported by the application.
95
- *
96
- * @returns
97
- * Maximum width supported by the application.
141
+ * Get the logger memory transport.
98
142
  */
99
- protected abstract getMaximumWidth(): number | Promise<number>;
143
+ get memoryTransport(): MemoryTransport<object> {
144
+ return this.#memoryTransport;
145
+ }
100
146
 
101
147
  /**
102
- * Get the maximum height supported by the application.
103
- *
104
- * @returns
105
- * Maximum height supported by the application.
148
+ * Get the maximum width supported by the application.
106
149
  */
107
- async maximumHeight(): Promise<number> {
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
- protected abstract getMaximumHeight(): number | Promise<number>;
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): SheetAddress | Promise<SheetAddress>;
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): SheetRange | null | Promise<SheetRange | null>;
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): ResultError<TBigInt, ThrowError, TError>;
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
+ }