@aidc-toolkit/app-extension 0.9.19-beta → 0.9.20-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/README.md +1 -1
- package/dist/generator/descriptor.d.ts +107 -0
- package/dist/generator/descriptor.d.ts.map +1 -0
- package/dist/generator/descriptor.js +2 -0
- package/dist/generator/descriptor.js.map +1 -0
- package/dist/generator/generator.d.ts +120 -0
- package/dist/generator/generator.d.ts.map +1 -0
- package/dist/generator/generator.js +213 -0
- package/dist/generator/generator.js.map +1 -0
- package/dist/generator/index.d.ts +3 -0
- package/dist/generator/index.d.ts.map +1 -0
- package/dist/generator/index.js +2 -0
- package/dist/generator/index.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/generator/descriptor.ts +122 -0
- package/src/generator/generator.ts +287 -0
- package/src/generator/index.ts +2 -0
- package/src/generator/locale-strings-generator.ts +358 -0
- package/src/generator/logger.ts +34 -0
- package/src/index.ts +1 -0
package/README.md
CHANGED
|
@@ -14,4 +14,4 @@ Unless required by applicable law or agreed to in writing, software distributed
|
|
|
14
14
|
>
|
|
15
15
|
> **This software is in beta**, with production release is scheduled for 2025Q4. To follow the status of this and other projects, go to the AIDC Toolkit [projects](https://github.com/orgs/aidc-toolkit/projects) page.
|
|
16
16
|
|
|
17
|
-
The AIDC Toolkit `app-extension` package is the bridge between the AIDC Toolkit and applications such
|
|
17
|
+
The AIDC Toolkit `app-extension` package is the bridge between the AIDC Toolkit and applications such as Microsoft Excel and Google Sheets. It does so by flattening the object model, replacing stateful object construction and method calls with stateless functions.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { BaseParameterDescriptor, ClassDescriptor, MethodDescriptor } from "../descriptor.js";
|
|
2
|
+
/**
|
|
3
|
+
* Localization.
|
|
4
|
+
*/
|
|
5
|
+
export interface Localization {
|
|
6
|
+
/**
|
|
7
|
+
* Name.
|
|
8
|
+
*/
|
|
9
|
+
name: string;
|
|
10
|
+
/**
|
|
11
|
+
* Description.
|
|
12
|
+
*/
|
|
13
|
+
description: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Function localization.
|
|
17
|
+
*/
|
|
18
|
+
export interface FunctionLocalization extends Localization {
|
|
19
|
+
/**
|
|
20
|
+
* Documentation URL.
|
|
21
|
+
*/
|
|
22
|
+
documentationURL: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Parameter localization.
|
|
26
|
+
*/
|
|
27
|
+
export interface ParameterLocalization extends Localization {
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Localization descriptor.
|
|
31
|
+
*/
|
|
32
|
+
export interface LocalizationDescriptor<T extends Localization> {
|
|
33
|
+
/**
|
|
34
|
+
* Localizations map by locale.
|
|
35
|
+
*/
|
|
36
|
+
readonly localizationsMap: ReadonlyMap<string, T>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Proxy namespace descriptor.
|
|
40
|
+
*/
|
|
41
|
+
export interface ProxyNamespaceDescriptor {
|
|
42
|
+
/**
|
|
43
|
+
* Namespace if any.
|
|
44
|
+
*/
|
|
45
|
+
readonly namespace: string | undefined;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Proxy class descriptor.
|
|
49
|
+
*/
|
|
50
|
+
export interface ProxyClassDescriptor extends ProxyNamespaceDescriptor {
|
|
51
|
+
/**
|
|
52
|
+
* Class name.
|
|
53
|
+
*/
|
|
54
|
+
readonly className: string;
|
|
55
|
+
/**
|
|
56
|
+
* Namespace-qualified class name.
|
|
57
|
+
*/
|
|
58
|
+
readonly namespaceClassName: string;
|
|
59
|
+
/**
|
|
60
|
+
* Class descriptor.
|
|
61
|
+
*/
|
|
62
|
+
readonly classDescriptor: ClassDescriptor;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Proxy object descriptor.
|
|
66
|
+
*/
|
|
67
|
+
export interface ProxyObjectDescriptor extends ProxyClassDescriptor {
|
|
68
|
+
/**
|
|
69
|
+
* Object name.
|
|
70
|
+
*/
|
|
71
|
+
readonly objectName: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Proxy parameter descriptor.
|
|
75
|
+
*/
|
|
76
|
+
export interface ProxyParameterDescriptor extends ProxyNamespaceDescriptor, LocalizationDescriptor<ParameterLocalization> {
|
|
77
|
+
/**
|
|
78
|
+
* Function name.
|
|
79
|
+
*/
|
|
80
|
+
readonly parameterName: string;
|
|
81
|
+
/**
|
|
82
|
+
* Parameter descriptor.
|
|
83
|
+
*/
|
|
84
|
+
readonly parameterDescriptor: BaseParameterDescriptor;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Proxy function descriptor.
|
|
88
|
+
*/
|
|
89
|
+
export interface ProxyFunctionDescriptor extends ProxyObjectDescriptor, LocalizationDescriptor<FunctionLocalization> {
|
|
90
|
+
/**
|
|
91
|
+
* Function name.
|
|
92
|
+
*/
|
|
93
|
+
readonly functionName: string;
|
|
94
|
+
/**
|
|
95
|
+
* Namespace-qualified function name.
|
|
96
|
+
*/
|
|
97
|
+
readonly namespaceFunctionName: string;
|
|
98
|
+
/**
|
|
99
|
+
* Proxy parameter descriptors
|
|
100
|
+
*/
|
|
101
|
+
readonly proxyParameterDescriptors: ProxyParameterDescriptor[];
|
|
102
|
+
/**
|
|
103
|
+
* Method descriptor.
|
|
104
|
+
*/
|
|
105
|
+
readonly methodDescriptor: MethodDescriptor;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=descriptor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"descriptor.d.ts","sourceRoot":"","sources":["../../src/generator/descriptor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEnG;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,YAAY;IACtD;;OAEG;IACH,gBAAgB,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,qBAAsB,SAAQ,YAAY;CAC1D;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB,CAAC,CAAC,SAAS,YAAY;IAC1D;;OAEG;IACH,QAAQ,CAAC,gBAAgB,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;CACrD;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACrC;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1C;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,wBAAwB;IAClE;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IAEpC;;OAEG;IACH,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;CAC7C;AAED;;GAEG;AACH,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB;IAC/D;;OAEG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,wBAAyB,SAAQ,wBAAwB,EAAE,sBAAsB,CAAC,qBAAqB,CAAC;IACrH;;OAEG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAE/B;;OAEG;IACH,QAAQ,CAAC,mBAAmB,EAAE,uBAAuB,CAAC;CACzD;AAED;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,qBAAqB,EAAE,sBAAsB,CAAC,oBAAoB,CAAC;IAChH;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAE9B;;OAEG;IACH,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAC;IAEvC;;OAEG;IACH,QAAQ,CAAC,yBAAyB,EAAE,wBAAwB,EAAE,CAAC;IAE/D;;OAEG;IACH,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;CAC/C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"descriptor.js","sourceRoot":"","sources":["../../src/generator/descriptor.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { FunctionLocalization, ParameterLocalization, ProxyFunctionDescriptor, ProxyObjectDescriptor } from "./descriptor.js";
|
|
2
|
+
/**
|
|
3
|
+
* Abstract generator.
|
|
4
|
+
*/
|
|
5
|
+
export declare abstract class Generator {
|
|
6
|
+
/**
|
|
7
|
+
* Documentation base URL.
|
|
8
|
+
*/
|
|
9
|
+
private static readonly DOCUMENTATION_BASE_URL;
|
|
10
|
+
/**
|
|
11
|
+
* Documentation path, optionally preceded by locale.
|
|
12
|
+
*/
|
|
13
|
+
private static readonly DOCUMENTATION_PATH;
|
|
14
|
+
/**
|
|
15
|
+
* Locales.
|
|
16
|
+
*/
|
|
17
|
+
private readonly _locales;
|
|
18
|
+
/**
|
|
19
|
+
* Default locale.
|
|
20
|
+
*/
|
|
21
|
+
private readonly _defaultLocale;
|
|
22
|
+
/**
|
|
23
|
+
* Map of function localizations maps by namespace function name.
|
|
24
|
+
*/
|
|
25
|
+
private readonly _functionLocalizationsMapsMap;
|
|
26
|
+
/**
|
|
27
|
+
* Map of parameter localizations maps by namespace function parameter name.
|
|
28
|
+
*/
|
|
29
|
+
private readonly _parameterLocalizationsMapsMap;
|
|
30
|
+
/**
|
|
31
|
+
*
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* Constructor.
|
|
35
|
+
*
|
|
36
|
+
* @param includeLocalizations
|
|
37
|
+
* Include localizations if true.
|
|
38
|
+
*/
|
|
39
|
+
constructor(includeLocalizations?: boolean);
|
|
40
|
+
/**
|
|
41
|
+
* Get the locales.
|
|
42
|
+
*/
|
|
43
|
+
protected get locales(): readonly string[];
|
|
44
|
+
/**
|
|
45
|
+
* Get the default locale.
|
|
46
|
+
*/
|
|
47
|
+
protected get defaultLocale(): string;
|
|
48
|
+
/**
|
|
49
|
+
* Get function localization.
|
|
50
|
+
*
|
|
51
|
+
* @param namespaceFunctionName
|
|
52
|
+
* Namespace function name.
|
|
53
|
+
*
|
|
54
|
+
* @param locale
|
|
55
|
+
* Locale.
|
|
56
|
+
*
|
|
57
|
+
* @returns
|
|
58
|
+
* Function localization.
|
|
59
|
+
*/
|
|
60
|
+
protected getFunctionLocalization(namespaceFunctionName: string, locale: string): FunctionLocalization;
|
|
61
|
+
/**
|
|
62
|
+
* Get parameter localization.
|
|
63
|
+
*
|
|
64
|
+
* @param namespaceFunctionName
|
|
65
|
+
* Namespace function name.
|
|
66
|
+
*
|
|
67
|
+
* @param parameterName
|
|
68
|
+
* Parameter name.
|
|
69
|
+
*
|
|
70
|
+
* @param locale
|
|
71
|
+
* Locale.
|
|
72
|
+
*
|
|
73
|
+
* @returns
|
|
74
|
+
* Function localization.
|
|
75
|
+
*/
|
|
76
|
+
protected getParameterLocalization(namespaceFunctionName: string, parameterName: string, locale: string): ParameterLocalization;
|
|
77
|
+
/**
|
|
78
|
+
* Initialize the generation of the output.
|
|
79
|
+
*/
|
|
80
|
+
protected abstract initialize(): void;
|
|
81
|
+
/**
|
|
82
|
+
* Create a proxy object.
|
|
83
|
+
*
|
|
84
|
+
* @param proxyObjectDescriptor
|
|
85
|
+
* Proxy object descriptor.
|
|
86
|
+
*/
|
|
87
|
+
protected abstract createProxyObject(proxyObjectDescriptor: ProxyObjectDescriptor): void;
|
|
88
|
+
/**
|
|
89
|
+
* Create a proxy function.
|
|
90
|
+
*
|
|
91
|
+
* @param proxyFunctionDescriptor
|
|
92
|
+
* Proxy function descriptor.
|
|
93
|
+
*/
|
|
94
|
+
protected abstract createProxyFunction(proxyFunctionDescriptor: ProxyFunctionDescriptor): void;
|
|
95
|
+
/**
|
|
96
|
+
* Finalize the generation of the output.
|
|
97
|
+
*
|
|
98
|
+
* @param success
|
|
99
|
+
* True if successful.
|
|
100
|
+
*/
|
|
101
|
+
protected abstract finalize(success: boolean): void | Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Generate localizations map.
|
|
104
|
+
*
|
|
105
|
+
* @param localizedKeyPrefix
|
|
106
|
+
* Localized key prefix.
|
|
107
|
+
*
|
|
108
|
+
* @param localizationCallback
|
|
109
|
+
* Callback to finalize localization.
|
|
110
|
+
*
|
|
111
|
+
* @returns
|
|
112
|
+
* Localization map.
|
|
113
|
+
*/
|
|
114
|
+
private generateLocalizationsMap;
|
|
115
|
+
/**
|
|
116
|
+
* Generate by processing individual imports.
|
|
117
|
+
*/
|
|
118
|
+
generate(): Promise<void>;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/generator/generator.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACR,oBAAoB,EAEpB,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,EACxB,MAAM,iBAAiB,CAAC;AAEzB;;GAEG;AACH,8BAAsB,SAAS;IAC3B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAA+B;IAE7E;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAoB;IAE9D;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAE7C;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IAExC;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,6BAA6B,CAAgE;IAE9G;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,8BAA8B,CAAiE;IAEhH;;OAEG;IAEH;;;;;OAKG;gBACS,oBAAoB,UAAO;IAKvC;;OAEG;IACH,SAAS,KAAK,OAAO,IAAI,SAAS,MAAM,EAAE,CAEzC;IAED;;OAEG;IACH,SAAS,KAAK,aAAa,IAAI,MAAM,CAEpC;IAED;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,uBAAuB,CAAC,qBAAqB,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,oBAAoB;IAUtG;;;;;;;;;;;;;;OAcG;IACH,SAAS,CAAC,wBAAwB,CAAC,qBAAqB,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,qBAAqB;IAU/H;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,UAAU,IAAI,IAAI;IAErC;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,qBAAqB,GAAG,IAAI;IAExF;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,CAAC,mBAAmB,CAAC,uBAAuB,EAAE,uBAAuB,GAAG,IAAI;IAE9F;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAEnE;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,wBAAwB;IAehC;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAyGlC"}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { I18nEnvironment } from "@aidc-toolkit/core";
|
|
2
|
+
import { expandParameterDescriptor, getClassDescriptors } from "../descriptor.js";
|
|
3
|
+
import { appExtensionResources, i18nAppExtensionInit, i18nextAppExtension } from "../locale/i18n.js";
|
|
4
|
+
/**
|
|
5
|
+
* Abstract generator.
|
|
6
|
+
*/
|
|
7
|
+
export class Generator {
|
|
8
|
+
/**
|
|
9
|
+
* Documentation base URL.
|
|
10
|
+
*/
|
|
11
|
+
static DOCUMENTATION_BASE_URL = "https://aidc-toolkit.com/";
|
|
12
|
+
/**
|
|
13
|
+
* Documentation path, optionally preceded by locale.
|
|
14
|
+
*/
|
|
15
|
+
static DOCUMENTATION_PATH = "app-extension/";
|
|
16
|
+
/**
|
|
17
|
+
* Locales.
|
|
18
|
+
*/
|
|
19
|
+
_locales;
|
|
20
|
+
/**
|
|
21
|
+
* Default locale.
|
|
22
|
+
*/
|
|
23
|
+
_defaultLocale;
|
|
24
|
+
/**
|
|
25
|
+
* Map of function localizations maps by namespace function name.
|
|
26
|
+
*/
|
|
27
|
+
_functionLocalizationsMapsMap = new Map();
|
|
28
|
+
/**
|
|
29
|
+
* Map of parameter localizations maps by namespace function parameter name.
|
|
30
|
+
*/
|
|
31
|
+
_parameterLocalizationsMapsMap = new Map();
|
|
32
|
+
/**
|
|
33
|
+
*
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* Constructor.
|
|
37
|
+
*
|
|
38
|
+
* @param includeLocalizations
|
|
39
|
+
* Include localizations if true.
|
|
40
|
+
*/
|
|
41
|
+
constructor(includeLocalizations = true) {
|
|
42
|
+
this._locales = includeLocalizations ? Object.keys(appExtensionResources) : [];
|
|
43
|
+
this._defaultLocale = this._locales[0] ?? "";
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get the locales.
|
|
47
|
+
*/
|
|
48
|
+
get locales() {
|
|
49
|
+
return this._locales;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get the default locale.
|
|
53
|
+
*/
|
|
54
|
+
get defaultLocale() {
|
|
55
|
+
return this._defaultLocale;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get function localization.
|
|
59
|
+
*
|
|
60
|
+
* @param namespaceFunctionName
|
|
61
|
+
* Namespace function name.
|
|
62
|
+
*
|
|
63
|
+
* @param locale
|
|
64
|
+
* Locale.
|
|
65
|
+
*
|
|
66
|
+
* @returns
|
|
67
|
+
* Function localization.
|
|
68
|
+
*/
|
|
69
|
+
getFunctionLocalization(namespaceFunctionName, locale) {
|
|
70
|
+
const functionLocalization = this._functionLocalizationsMapsMap.get(namespaceFunctionName)?.get(locale);
|
|
71
|
+
if (functionLocalization === undefined) {
|
|
72
|
+
throw new Error(`Localization for function "${namespaceFunctionName}", locale "${locale}" not found`);
|
|
73
|
+
}
|
|
74
|
+
return functionLocalization;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get parameter localization.
|
|
78
|
+
*
|
|
79
|
+
* @param namespaceFunctionName
|
|
80
|
+
* Namespace function name.
|
|
81
|
+
*
|
|
82
|
+
* @param parameterName
|
|
83
|
+
* Parameter name.
|
|
84
|
+
*
|
|
85
|
+
* @param locale
|
|
86
|
+
* Locale.
|
|
87
|
+
*
|
|
88
|
+
* @returns
|
|
89
|
+
* Function localization.
|
|
90
|
+
*/
|
|
91
|
+
getParameterLocalization(namespaceFunctionName, parameterName, locale) {
|
|
92
|
+
const parameterLocalization = this._parameterLocalizationsMapsMap.get(`${namespaceFunctionName}.${parameterName}`)?.get(locale);
|
|
93
|
+
if (parameterLocalization === undefined) {
|
|
94
|
+
throw new Error(`Localization for function "${namespaceFunctionName}", parameter "${parameterName}", locale "${locale}" not found`);
|
|
95
|
+
}
|
|
96
|
+
return parameterLocalization;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Generate localizations map.
|
|
100
|
+
*
|
|
101
|
+
* @param localizedKeyPrefix
|
|
102
|
+
* Localized key prefix.
|
|
103
|
+
*
|
|
104
|
+
* @param localizationCallback
|
|
105
|
+
* Callback to finalize localization.
|
|
106
|
+
*
|
|
107
|
+
* @returns
|
|
108
|
+
* Localization map.
|
|
109
|
+
*/
|
|
110
|
+
generateLocalizationsMap(localizedKeyPrefix, localizationCallback) {
|
|
111
|
+
return new Map(this._locales.map((locale) => {
|
|
112
|
+
const lngOption = {
|
|
113
|
+
lng: locale
|
|
114
|
+
};
|
|
115
|
+
return [locale, localizationCallback(locale, {
|
|
116
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Localized key exists.
|
|
117
|
+
name: i18nextAppExtension.t(`${localizedKeyPrefix}name`, lngOption),
|
|
118
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Localized key exists.
|
|
119
|
+
description: i18nextAppExtension.t(`${localizedKeyPrefix}description`, lngOption)
|
|
120
|
+
})];
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Generate by processing individual imports.
|
|
125
|
+
*/
|
|
126
|
+
async generate() {
|
|
127
|
+
let success = false;
|
|
128
|
+
await i18nAppExtensionInit(I18nEnvironment.CLI);
|
|
129
|
+
this.initialize();
|
|
130
|
+
try {
|
|
131
|
+
for (const classDescriptor of getClassDescriptors().values()) {
|
|
132
|
+
const namespace = classDescriptor.namespace;
|
|
133
|
+
const namespacePrefix = namespace === undefined ? "" : `${namespace}.`;
|
|
134
|
+
const className = classDescriptor.name;
|
|
135
|
+
const methodInfix = classDescriptor.methodInfix;
|
|
136
|
+
// Namespace-qualified class name is used to construct object name.
|
|
137
|
+
const namespaceClassName = `${namespacePrefix}${className}`;
|
|
138
|
+
// First capture group is:
|
|
139
|
+
// - one or more uppercase letters followed by zero or more numbers; or
|
|
140
|
+
// - single uppercase letter followed by zero or more characters except uppercase letters or period.
|
|
141
|
+
// Second capture group is:
|
|
142
|
+
// - single uppercase letter followed by zero or more characters except period; or
|
|
143
|
+
// - zero characters (empty string).
|
|
144
|
+
// Third capture group, separated by optional period, is:
|
|
145
|
+
// - single uppercase letter followed by zero or more characters (remainder of string); or
|
|
146
|
+
// - zero characters (empty string).
|
|
147
|
+
const classNameMatch = /^([A-Z]+[0-9]*|[A-Z][^A-Z.]*)([A-Z][^.]*|)\.?([A-Z].*|)$/.exec(namespaceClassName);
|
|
148
|
+
if (classNameMatch === null) {
|
|
149
|
+
throw new Error(`${namespaceClassName} is not a valid namespace-qualified class name`);
|
|
150
|
+
}
|
|
151
|
+
const proxyObjectDescriptor = {
|
|
152
|
+
namespace,
|
|
153
|
+
className,
|
|
154
|
+
namespaceClassName,
|
|
155
|
+
classDescriptor,
|
|
156
|
+
objectName: `${classNameMatch[1].toLowerCase()}${classNameMatch[2]}${classNameMatch[3]}`
|
|
157
|
+
};
|
|
158
|
+
this.createProxyObject(proxyObjectDescriptor);
|
|
159
|
+
for (const methodDescriptor of classDescriptor.methodDescriptors) {
|
|
160
|
+
const methodName = methodDescriptor.name;
|
|
161
|
+
const infixBefore = methodDescriptor.infixBefore;
|
|
162
|
+
let functionName;
|
|
163
|
+
if (methodInfix === undefined || methodDescriptor.ignoreInfix === true) {
|
|
164
|
+
// No other classes in the hierarchy or no infix required.
|
|
165
|
+
functionName = methodName;
|
|
166
|
+
}
|
|
167
|
+
else if (infixBefore === undefined) {
|
|
168
|
+
// Other classes in the hierarchy and infix is postfix.
|
|
169
|
+
functionName = `${methodName}${methodInfix}`;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
const insertIndex = methodName.indexOf(infixBefore);
|
|
173
|
+
if (insertIndex === -1) {
|
|
174
|
+
throw new Error(`Cannot find "${infixBefore}" in method name ${methodName}`);
|
|
175
|
+
}
|
|
176
|
+
// Other classes in the hierarchy and infix is in the middle of the string.
|
|
177
|
+
functionName = `${methodName.substring(0, insertIndex)}${methodInfix}${methodName.substring(insertIndex)}`;
|
|
178
|
+
}
|
|
179
|
+
const namespaceFunctionName = `${namespacePrefix}${functionName}`;
|
|
180
|
+
const functionLocalizationsMap = this.generateLocalizationsMap(`Functions.${namespaceFunctionName}.`, (locale, localization) => ({
|
|
181
|
+
...localization,
|
|
182
|
+
documentationURL: `${Generator.DOCUMENTATION_BASE_URL}${locale === this.defaultLocale ? "" : `${locale}/`}${Generator.DOCUMENTATION_PATH}${namespace === undefined ? "" : `${namespace}/`}${localization.name}.html`
|
|
183
|
+
}));
|
|
184
|
+
this._functionLocalizationsMapsMap.set(namespaceFunctionName, functionLocalizationsMap);
|
|
185
|
+
this.createProxyFunction({
|
|
186
|
+
...proxyObjectDescriptor,
|
|
187
|
+
functionName,
|
|
188
|
+
namespaceFunctionName,
|
|
189
|
+
localizationsMap: functionLocalizationsMap,
|
|
190
|
+
proxyParameterDescriptors: methodDescriptor.parameterDescriptors.map((parameterDescriptor) => {
|
|
191
|
+
const expandedParameterDescriptor = expandParameterDescriptor(parameterDescriptor);
|
|
192
|
+
const parameterName = expandedParameterDescriptor.name;
|
|
193
|
+
const parameterLocalizationsMap = this.generateLocalizationsMap(`Parameters.${parameterName}.`, (_locale, localization) => localization);
|
|
194
|
+
this._parameterLocalizationsMapsMap.set(`${namespaceFunctionName}.${parameterName}`, parameterLocalizationsMap);
|
|
195
|
+
return {
|
|
196
|
+
namespace,
|
|
197
|
+
parameterName,
|
|
198
|
+
localizationsMap: parameterLocalizationsMap,
|
|
199
|
+
parameterDescriptor: expandedParameterDescriptor
|
|
200
|
+
};
|
|
201
|
+
}),
|
|
202
|
+
methodDescriptor
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
success = true;
|
|
207
|
+
}
|
|
208
|
+
finally {
|
|
209
|
+
await this.finalize(success);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../src/generator/generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generator/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,iBAAiB,CAAC;AACrC,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/generator/index.ts"],"names":[],"mappings":"AACA,cAAc,gBAAgB,CAAC"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,cAAc,sBAAsB,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,OAAO,KAAK,GAAG,MAAM,gBAAgB,CAAC;AACtC,cAAc,sBAAsB,CAAC"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { BaseParameterDescriptor, ClassDescriptor, MethodDescriptor } from "../descriptor.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Localization.
|
|
5
|
+
*/
|
|
6
|
+
export interface Localization {
|
|
7
|
+
/**
|
|
8
|
+
* Name.
|
|
9
|
+
*/
|
|
10
|
+
name: string;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Description.
|
|
14
|
+
*/
|
|
15
|
+
description: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Function localization.
|
|
20
|
+
*/
|
|
21
|
+
export interface FunctionLocalization extends Localization {
|
|
22
|
+
/**
|
|
23
|
+
* Documentation URL.
|
|
24
|
+
*/
|
|
25
|
+
documentationURL: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Parameter localization.
|
|
30
|
+
*/
|
|
31
|
+
export interface ParameterLocalization extends Localization {
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Localization descriptor.
|
|
36
|
+
*/
|
|
37
|
+
export interface LocalizationDescriptor<T extends Localization> {
|
|
38
|
+
/**
|
|
39
|
+
* Localizations map by locale.
|
|
40
|
+
*/
|
|
41
|
+
readonly localizationsMap: ReadonlyMap<string, T>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Proxy namespace descriptor.
|
|
46
|
+
*/
|
|
47
|
+
export interface ProxyNamespaceDescriptor {
|
|
48
|
+
/**
|
|
49
|
+
* Namespace if any.
|
|
50
|
+
*/
|
|
51
|
+
readonly namespace: string | undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Proxy class descriptor.
|
|
56
|
+
*/
|
|
57
|
+
export interface ProxyClassDescriptor extends ProxyNamespaceDescriptor {
|
|
58
|
+
/**
|
|
59
|
+
* Class name.
|
|
60
|
+
*/
|
|
61
|
+
readonly className: string;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Namespace-qualified class name.
|
|
65
|
+
*/
|
|
66
|
+
readonly namespaceClassName: string;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Class descriptor.
|
|
70
|
+
*/
|
|
71
|
+
readonly classDescriptor: ClassDescriptor;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Proxy object descriptor.
|
|
76
|
+
*/
|
|
77
|
+
export interface ProxyObjectDescriptor extends ProxyClassDescriptor {
|
|
78
|
+
/**
|
|
79
|
+
* Object name.
|
|
80
|
+
*/
|
|
81
|
+
readonly objectName: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Proxy parameter descriptor.
|
|
86
|
+
*/
|
|
87
|
+
export interface ProxyParameterDescriptor extends ProxyNamespaceDescriptor, LocalizationDescriptor<ParameterLocalization> {
|
|
88
|
+
/**
|
|
89
|
+
* Function name.
|
|
90
|
+
*/
|
|
91
|
+
readonly parameterName: string;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Parameter descriptor.
|
|
95
|
+
*/
|
|
96
|
+
readonly parameterDescriptor: BaseParameterDescriptor;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Proxy function descriptor.
|
|
101
|
+
*/
|
|
102
|
+
export interface ProxyFunctionDescriptor extends ProxyObjectDescriptor, LocalizationDescriptor<FunctionLocalization> {
|
|
103
|
+
/**
|
|
104
|
+
* Function name.
|
|
105
|
+
*/
|
|
106
|
+
readonly functionName: string;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Namespace-qualified function name.
|
|
110
|
+
*/
|
|
111
|
+
readonly namespaceFunctionName: string;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Proxy parameter descriptors
|
|
115
|
+
*/
|
|
116
|
+
readonly proxyParameterDescriptors: ProxyParameterDescriptor[];
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Method descriptor.
|
|
120
|
+
*/
|
|
121
|
+
readonly methodDescriptor: MethodDescriptor;
|
|
122
|
+
}
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { I18nEnvironment } from "@aidc-toolkit/core";
|
|
2
|
+
import type { ParseKeys } from "i18next";
|
|
3
|
+
import { expandParameterDescriptor, getClassDescriptors } from "../descriptor.js";
|
|
4
|
+
import { appExtensionResources, i18nAppExtensionInit, i18nextAppExtension } from "../locale/i18n.js";
|
|
5
|
+
import type {
|
|
6
|
+
FunctionLocalization,
|
|
7
|
+
Localization,
|
|
8
|
+
ParameterLocalization,
|
|
9
|
+
ProxyFunctionDescriptor,
|
|
10
|
+
ProxyObjectDescriptor
|
|
11
|
+
} from "./descriptor.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Abstract generator.
|
|
15
|
+
*/
|
|
16
|
+
export abstract class Generator {
|
|
17
|
+
/**
|
|
18
|
+
* Documentation base URL.
|
|
19
|
+
*/
|
|
20
|
+
private static readonly DOCUMENTATION_BASE_URL = "https://aidc-toolkit.com/";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Documentation path, optionally preceded by locale.
|
|
24
|
+
*/
|
|
25
|
+
private static readonly DOCUMENTATION_PATH = "app-extension/";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Locales.
|
|
29
|
+
*/
|
|
30
|
+
private readonly _locales: readonly string[];
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Default locale.
|
|
34
|
+
*/
|
|
35
|
+
private readonly _defaultLocale: string;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Map of function localizations maps by namespace function name.
|
|
39
|
+
*/
|
|
40
|
+
private readonly _functionLocalizationsMapsMap = new Map<string, ReadonlyMap<string, FunctionLocalization>>();
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Map of parameter localizations maps by namespace function parameter name.
|
|
44
|
+
*/
|
|
45
|
+
private readonly _parameterLocalizationsMapsMap = new Map<string, ReadonlyMap<string, ParameterLocalization>>();
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
*
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Constructor.
|
|
53
|
+
*
|
|
54
|
+
* @param includeLocalizations
|
|
55
|
+
* Include localizations if true.
|
|
56
|
+
*/
|
|
57
|
+
constructor(includeLocalizations = true) {
|
|
58
|
+
this._locales = includeLocalizations ? Object.keys(appExtensionResources) : [];
|
|
59
|
+
this._defaultLocale = this._locales[0] ?? "";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get the locales.
|
|
64
|
+
*/
|
|
65
|
+
protected get locales(): readonly string[] {
|
|
66
|
+
return this._locales;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Get the default locale.
|
|
71
|
+
*/
|
|
72
|
+
protected get defaultLocale(): string {
|
|
73
|
+
return this._defaultLocale;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Get function localization.
|
|
78
|
+
*
|
|
79
|
+
* @param namespaceFunctionName
|
|
80
|
+
* Namespace function name.
|
|
81
|
+
*
|
|
82
|
+
* @param locale
|
|
83
|
+
* Locale.
|
|
84
|
+
*
|
|
85
|
+
* @returns
|
|
86
|
+
* Function localization.
|
|
87
|
+
*/
|
|
88
|
+
protected getFunctionLocalization(namespaceFunctionName: string, locale: string): FunctionLocalization {
|
|
89
|
+
const functionLocalization = this._functionLocalizationsMapsMap.get(namespaceFunctionName)?.get(locale);
|
|
90
|
+
|
|
91
|
+
if (functionLocalization === undefined) {
|
|
92
|
+
throw new Error(`Localization for function "${namespaceFunctionName}", locale "${locale}" not found`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return functionLocalization;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Get parameter localization.
|
|
100
|
+
*
|
|
101
|
+
* @param namespaceFunctionName
|
|
102
|
+
* Namespace function name.
|
|
103
|
+
*
|
|
104
|
+
* @param parameterName
|
|
105
|
+
* Parameter name.
|
|
106
|
+
*
|
|
107
|
+
* @param locale
|
|
108
|
+
* Locale.
|
|
109
|
+
*
|
|
110
|
+
* @returns
|
|
111
|
+
* Function localization.
|
|
112
|
+
*/
|
|
113
|
+
protected getParameterLocalization(namespaceFunctionName: string, parameterName: string, locale: string): ParameterLocalization {
|
|
114
|
+
const parameterLocalization = this._parameterLocalizationsMapsMap.get(`${namespaceFunctionName}.${parameterName}`)?.get(locale);
|
|
115
|
+
|
|
116
|
+
if (parameterLocalization === undefined) {
|
|
117
|
+
throw new Error(`Localization for function "${namespaceFunctionName}", parameter "${parameterName}", locale "${locale}" not found`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return parameterLocalization;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Initialize the generation of the output.
|
|
125
|
+
*/
|
|
126
|
+
protected abstract initialize(): void;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Create a proxy object.
|
|
130
|
+
*
|
|
131
|
+
* @param proxyObjectDescriptor
|
|
132
|
+
* Proxy object descriptor.
|
|
133
|
+
*/
|
|
134
|
+
protected abstract createProxyObject(proxyObjectDescriptor: ProxyObjectDescriptor): void;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Create a proxy function.
|
|
138
|
+
*
|
|
139
|
+
* @param proxyFunctionDescriptor
|
|
140
|
+
* Proxy function descriptor.
|
|
141
|
+
*/
|
|
142
|
+
protected abstract createProxyFunction(proxyFunctionDescriptor: ProxyFunctionDescriptor): void;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Finalize the generation of the output.
|
|
146
|
+
*
|
|
147
|
+
* @param success
|
|
148
|
+
* True if successful.
|
|
149
|
+
*/
|
|
150
|
+
protected abstract finalize(success: boolean): void | Promise<void>;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Generate localizations map.
|
|
154
|
+
*
|
|
155
|
+
* @param localizedKeyPrefix
|
|
156
|
+
* Localized key prefix.
|
|
157
|
+
*
|
|
158
|
+
* @param localizationCallback
|
|
159
|
+
* Callback to finalize localization.
|
|
160
|
+
*
|
|
161
|
+
* @returns
|
|
162
|
+
* Localization map.
|
|
163
|
+
*/
|
|
164
|
+
private generateLocalizationsMap<T extends Localization>(localizedKeyPrefix: string, localizationCallback: (locale: string, localization: Localization) => T): ReadonlyMap<string, T> {
|
|
165
|
+
return new Map(this._locales.map((locale) => {
|
|
166
|
+
const lngOption = {
|
|
167
|
+
lng: locale
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
return [locale, localizationCallback(locale, {
|
|
171
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Localized key exists.
|
|
172
|
+
name: i18nextAppExtension.t(`${localizedKeyPrefix}name` as ParseKeys, lngOption),
|
|
173
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Localized key exists.
|
|
174
|
+
description: i18nextAppExtension.t(`${localizedKeyPrefix}description` as ParseKeys, lngOption)
|
|
175
|
+
})];
|
|
176
|
+
}));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Generate by processing individual imports.
|
|
181
|
+
*/
|
|
182
|
+
async generate(): Promise<void> {
|
|
183
|
+
let success = false;
|
|
184
|
+
|
|
185
|
+
await i18nAppExtensionInit(I18nEnvironment.CLI);
|
|
186
|
+
|
|
187
|
+
this.initialize();
|
|
188
|
+
|
|
189
|
+
try {
|
|
190
|
+
for (const classDescriptor of getClassDescriptors().values()) {
|
|
191
|
+
const namespace = classDescriptor.namespace;
|
|
192
|
+
const namespacePrefix = namespace === undefined ? "" : `${namespace}.`;
|
|
193
|
+
const className = classDescriptor.name;
|
|
194
|
+
const methodInfix = classDescriptor.methodInfix;
|
|
195
|
+
|
|
196
|
+
// Namespace-qualified class name is used to construct object name.
|
|
197
|
+
const namespaceClassName = `${namespacePrefix}${className}`;
|
|
198
|
+
|
|
199
|
+
// First capture group is:
|
|
200
|
+
// - one or more uppercase letters followed by zero or more numbers; or
|
|
201
|
+
// - single uppercase letter followed by zero or more characters except uppercase letters or period.
|
|
202
|
+
// Second capture group is:
|
|
203
|
+
// - single uppercase letter followed by zero or more characters except period; or
|
|
204
|
+
// - zero characters (empty string).
|
|
205
|
+
// Third capture group, separated by optional period, is:
|
|
206
|
+
// - single uppercase letter followed by zero or more characters (remainder of string); or
|
|
207
|
+
// - zero characters (empty string).
|
|
208
|
+
const classNameMatch = /^([A-Z]+[0-9]*|[A-Z][^A-Z.]*)([A-Z][^.]*|)\.?([A-Z].*|)$/.exec(namespaceClassName);
|
|
209
|
+
|
|
210
|
+
if (classNameMatch === null) {
|
|
211
|
+
throw new Error(`${namespaceClassName} is not a valid namespace-qualified class name`);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const proxyObjectDescriptor: ProxyObjectDescriptor = {
|
|
215
|
+
namespace,
|
|
216
|
+
className,
|
|
217
|
+
namespaceClassName,
|
|
218
|
+
classDescriptor,
|
|
219
|
+
objectName: `${classNameMatch[1].toLowerCase()}${classNameMatch[2]}${classNameMatch[3]}`
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
this.createProxyObject(proxyObjectDescriptor);
|
|
223
|
+
|
|
224
|
+
for (const methodDescriptor of classDescriptor.methodDescriptors) {
|
|
225
|
+
const methodName = methodDescriptor.name;
|
|
226
|
+
const infixBefore = methodDescriptor.infixBefore;
|
|
227
|
+
|
|
228
|
+
let functionName: string;
|
|
229
|
+
|
|
230
|
+
if (methodInfix === undefined || methodDescriptor.ignoreInfix === true) {
|
|
231
|
+
// No other classes in the hierarchy or no infix required.
|
|
232
|
+
functionName = methodName;
|
|
233
|
+
} else if (infixBefore === undefined) {
|
|
234
|
+
// Other classes in the hierarchy and infix is postfix.
|
|
235
|
+
functionName = `${methodName}${methodInfix}`;
|
|
236
|
+
} else {
|
|
237
|
+
const insertIndex = methodName.indexOf(infixBefore);
|
|
238
|
+
|
|
239
|
+
if (insertIndex === -1) {
|
|
240
|
+
throw new Error(`Cannot find "${infixBefore}" in method name ${methodName}`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Other classes in the hierarchy and infix is in the middle of the string.
|
|
244
|
+
functionName = `${methodName.substring(0, insertIndex)}${methodInfix}${methodName.substring(insertIndex)}`;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const namespaceFunctionName = `${namespacePrefix}${functionName}`;
|
|
248
|
+
|
|
249
|
+
const functionLocalizationsMap = this.generateLocalizationsMap<FunctionLocalization>(`Functions.${namespaceFunctionName}.`, (locale, localization) => ({
|
|
250
|
+
...localization,
|
|
251
|
+
documentationURL: `${Generator.DOCUMENTATION_BASE_URL}${locale === this.defaultLocale ? "" : `${locale}/`}${Generator.DOCUMENTATION_PATH}${namespace === undefined ? "" : `${namespace}/`}${localization.name}.html`
|
|
252
|
+
}));
|
|
253
|
+
|
|
254
|
+
this._functionLocalizationsMapsMap.set(namespaceFunctionName, functionLocalizationsMap);
|
|
255
|
+
|
|
256
|
+
this.createProxyFunction({
|
|
257
|
+
...proxyObjectDescriptor,
|
|
258
|
+
functionName,
|
|
259
|
+
namespaceFunctionName,
|
|
260
|
+
localizationsMap: functionLocalizationsMap,
|
|
261
|
+
proxyParameterDescriptors: methodDescriptor.parameterDescriptors.map((parameterDescriptor) => {
|
|
262
|
+
const expandedParameterDescriptor = expandParameterDescriptor(parameterDescriptor);
|
|
263
|
+
|
|
264
|
+
const parameterName = expandedParameterDescriptor.name;
|
|
265
|
+
|
|
266
|
+
const parameterLocalizationsMap = this.generateLocalizationsMap(`Parameters.${parameterName}.`, (_locale, localization) => localization);
|
|
267
|
+
|
|
268
|
+
this._parameterLocalizationsMapsMap.set(`${namespaceFunctionName}.${parameterName}`, parameterLocalizationsMap);
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
namespace,
|
|
272
|
+
parameterName,
|
|
273
|
+
localizationsMap: parameterLocalizationsMap,
|
|
274
|
+
parameterDescriptor: expandedParameterDescriptor
|
|
275
|
+
};
|
|
276
|
+
}),
|
|
277
|
+
methodDescriptor
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
success = true;
|
|
283
|
+
} finally {
|
|
284
|
+
await this.finalize(success);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import type { LocaleStrings } from "@aidc-toolkit/core";
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { expandParameterDescriptor, type ParameterDescriptor } from "../descriptor.js";
|
|
5
|
+
import type { ProxyFunctionDescriptor } from "./descriptor.js";
|
|
6
|
+
import { Generator } from "./generator.js";
|
|
7
|
+
import { logger } from "./logger.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Parameters sequencer entry.
|
|
11
|
+
*/
|
|
12
|
+
interface ParametersSequencerEntry {
|
|
13
|
+
/**
|
|
14
|
+
* Parameters sequence or null if automatic.
|
|
15
|
+
*/
|
|
16
|
+
parametersSequencerOrNull: ParametersSequencer | null;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Parameter descriptor.
|
|
20
|
+
*/
|
|
21
|
+
parameterDescriptor: ParameterDescriptor;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* True if parameter is actually used and not just a base.
|
|
25
|
+
*/
|
|
26
|
+
isUsed: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Parameters sequencer for keeping similar (extended) parameters together.
|
|
31
|
+
*/
|
|
32
|
+
type ParametersSequencer = Record<string, ParametersSequencerEntry>;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Format of locale strings module.
|
|
36
|
+
*/
|
|
37
|
+
interface LocaleStringsModule {
|
|
38
|
+
/**
|
|
39
|
+
* Locale strings.
|
|
40
|
+
*/
|
|
41
|
+
localeStrings: LocaleStrings;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Locale strings generator.
|
|
46
|
+
*/
|
|
47
|
+
class LocaleStringsGenerator extends Generator {
|
|
48
|
+
/**
|
|
49
|
+
* Locale strings import path.
|
|
50
|
+
*/
|
|
51
|
+
private static readonly IMPORT_PATH = "../app-extension/src/locale";
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Parameters sequencer.
|
|
55
|
+
*/
|
|
56
|
+
private readonly _parametersSequencer: ParametersSequencer = {};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Parameters locale strings.
|
|
60
|
+
*/
|
|
61
|
+
private readonly _parametersLocaleStrings: LocaleStrings = {};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Functions locale strings.
|
|
65
|
+
*/
|
|
66
|
+
private readonly _functionsLocaleStrings: LocaleStrings = {};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Locale strings.
|
|
70
|
+
*/
|
|
71
|
+
private readonly _localeStrings: LocaleStrings = {
|
|
72
|
+
Parameters: this._parametersLocaleStrings,
|
|
73
|
+
Functions: this._functionsLocaleStrings
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Constructor.
|
|
78
|
+
*/
|
|
79
|
+
constructor() {
|
|
80
|
+
super(false);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @inheritDoc
|
|
85
|
+
*/
|
|
86
|
+
protected initialize(): void {
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @inheritDoc
|
|
91
|
+
*/
|
|
92
|
+
protected createProxyObject(): void {
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Save a parameter descriptor in the appropriate spot in the sequence.
|
|
97
|
+
*
|
|
98
|
+
* @param parameterDescriptor
|
|
99
|
+
* Parameter descriptor.
|
|
100
|
+
*
|
|
101
|
+
* @param isUsed
|
|
102
|
+
* True if parameter descriptor is actually used and not just a base.
|
|
103
|
+
*
|
|
104
|
+
* @returns
|
|
105
|
+
* Parameters sequencer entry.
|
|
106
|
+
*/
|
|
107
|
+
private saveParameterSequence(parameterDescriptor: ParameterDescriptor, isUsed: boolean): ParametersSequencerEntry {
|
|
108
|
+
let parametersSequencerEntry: ParametersSequencerEntry;
|
|
109
|
+
|
|
110
|
+
if (!("extendsDescriptor" in parameterDescriptor)) {
|
|
111
|
+
const parameterName = parameterDescriptor.name;
|
|
112
|
+
|
|
113
|
+
// Create entry if it doesn't exist, otherwise pick up where last call left off.
|
|
114
|
+
if (!(parameterName in this._parametersSequencer)) {
|
|
115
|
+
parametersSequencerEntry = {
|
|
116
|
+
parametersSequencerOrNull: null,
|
|
117
|
+
parameterDescriptor,
|
|
118
|
+
isUsed
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
this._parametersSequencer[parameterName] = parametersSequencerEntry;
|
|
122
|
+
} else {
|
|
123
|
+
parametersSequencerEntry = this._parametersSequencer[parameterName];
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
const baseParametersSequencerEntry = this.saveParameterSequence(parameterDescriptor.extendsDescriptor, false);
|
|
127
|
+
|
|
128
|
+
const expandedParameterDescriptor = expandParameterDescriptor(parameterDescriptor);
|
|
129
|
+
const parameterName = expandedParameterDescriptor.name;
|
|
130
|
+
|
|
131
|
+
if (parameterName !== expandParameterDescriptor(parameterDescriptor.extendsDescriptor).name) {
|
|
132
|
+
// Make sure that base parameters sequencer entry refers to a record type.
|
|
133
|
+
baseParametersSequencerEntry.parametersSequencerOrNull ??= {};
|
|
134
|
+
|
|
135
|
+
if (!(parameterName in baseParametersSequencerEntry.parametersSequencerOrNull)) {
|
|
136
|
+
parametersSequencerEntry = {
|
|
137
|
+
parametersSequencerOrNull: null,
|
|
138
|
+
parameterDescriptor,
|
|
139
|
+
isUsed
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
baseParametersSequencerEntry.parametersSequencerOrNull[parameterName] = parametersSequencerEntry;
|
|
143
|
+
} else {
|
|
144
|
+
parametersSequencerEntry = baseParametersSequencerEntry.parametersSequencerOrNull[parameterName];
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
// If name is the same, which means that parameter descriptor modified type information only.
|
|
148
|
+
parametersSequencerEntry = baseParametersSequencerEntry;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return parametersSequencerEntry;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* @inheritDoc
|
|
157
|
+
*/
|
|
158
|
+
protected createProxyFunction(proxyFunctionDescriptor: ProxyFunctionDescriptor): void {
|
|
159
|
+
const {
|
|
160
|
+
namespace,
|
|
161
|
+
functionName,
|
|
162
|
+
methodDescriptor
|
|
163
|
+
} = proxyFunctionDescriptor;
|
|
164
|
+
|
|
165
|
+
// Add any parameters that are not already known.
|
|
166
|
+
for (const parameterDescriptor of methodDescriptor.parameterDescriptors) {
|
|
167
|
+
this.saveParameterSequence(parameterDescriptor, true);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
let functionsLocaleStrings = this._functionsLocaleStrings;
|
|
171
|
+
|
|
172
|
+
if (namespace !== undefined) {
|
|
173
|
+
if (!(namespace in functionsLocaleStrings)) {
|
|
174
|
+
const namespaceFunctionsLocaleStrings: LocaleStrings = {};
|
|
175
|
+
|
|
176
|
+
// Add namespace and navigate to it.
|
|
177
|
+
functionsLocaleStrings[namespace] = namespaceFunctionsLocaleStrings;
|
|
178
|
+
functionsLocaleStrings = namespaceFunctionsLocaleStrings;
|
|
179
|
+
} else {
|
|
180
|
+
// Navigate to namespace.
|
|
181
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Entry is never a string.
|
|
182
|
+
functionsLocaleStrings = functionsLocaleStrings[namespace] as LocaleStrings;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (functionName in functionsLocaleStrings) {
|
|
187
|
+
throw new Error(`Duplicate function "${functionName}"`);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Add function.
|
|
191
|
+
functionsLocaleStrings[functionName] = {
|
|
192
|
+
name: functionName,
|
|
193
|
+
description: "*** LOCALIZATION REQUIRED ***"
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Merge source locale strings into existing destination locale strings.
|
|
199
|
+
*
|
|
200
|
+
* @param logChanges
|
|
201
|
+
* If true, changes are logged. Limits output when processing multiple sources.
|
|
202
|
+
*
|
|
203
|
+
* @param parentKey
|
|
204
|
+
* Parent key for logging purposes.
|
|
205
|
+
*
|
|
206
|
+
* @param sourceLocaleStrings
|
|
207
|
+
* Source locale strings.
|
|
208
|
+
*
|
|
209
|
+
* @param destinationLocaleStrings
|
|
210
|
+
* Destination locale strings.
|
|
211
|
+
*
|
|
212
|
+
* @param addMissing
|
|
213
|
+
* Add missing if true; applies to locale strings that are not regional.
|
|
214
|
+
*
|
|
215
|
+
* @returns
|
|
216
|
+
* Merged locale strings.
|
|
217
|
+
*/
|
|
218
|
+
private static merge(logChanges: boolean, parentKey: string, sourceLocaleStrings: LocaleStrings, destinationLocaleStrings: LocaleStrings, addMissing: boolean): LocaleStrings {
|
|
219
|
+
// Some entries at the top are not part of the generator output.
|
|
220
|
+
const deleteMissing = parentKey.length !== 0;
|
|
221
|
+
|
|
222
|
+
const newDestinationLocaleStrings: LocaleStrings = {};
|
|
223
|
+
|
|
224
|
+
// Copy over or delete any destination keys that are not in source.
|
|
225
|
+
for (const [key, destinationValue] of Object.entries(destinationLocaleStrings)) {
|
|
226
|
+
if (!(key in sourceLocaleStrings)) {
|
|
227
|
+
if (!deleteMissing) {
|
|
228
|
+
newDestinationLocaleStrings[key] = destinationValue;
|
|
229
|
+
} else if (logChanges) {
|
|
230
|
+
logger.info(`Deleting ${parentKey}${key}...`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
for (const [key, sourceValue] of Object.entries(sourceLocaleStrings)) {
|
|
236
|
+
if (!(key in destinationLocaleStrings)) {
|
|
237
|
+
if (addMissing) {
|
|
238
|
+
if (logChanges) {
|
|
239
|
+
logger.info(`Adding ${parentKey}${key}...`);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
newDestinationLocaleStrings[key] = sourceValue;
|
|
243
|
+
}
|
|
244
|
+
} else {
|
|
245
|
+
const destinationValue = destinationLocaleStrings[key];
|
|
246
|
+
|
|
247
|
+
if (typeof sourceValue === "object" && typeof destinationValue === "object") {
|
|
248
|
+
newDestinationLocaleStrings[key] = LocaleStringsGenerator.merge(logChanges, `${parentKey}${key}.`, sourceValue, destinationValue, addMissing);
|
|
249
|
+
} else if (typeof sourceValue === "string" && typeof destinationValue === "string") {
|
|
250
|
+
newDestinationLocaleStrings[key] = destinationValue;
|
|
251
|
+
} else {
|
|
252
|
+
throw new Error(`Mismatched types at ${parentKey}${key}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return newDestinationLocaleStrings;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Build parameters locale strings by going through parameters sequencer.
|
|
262
|
+
*
|
|
263
|
+
* @param parametersSequencer
|
|
264
|
+
* Parameters sequencer.
|
|
265
|
+
*/
|
|
266
|
+
private buildParametersLocaleStrings(parametersSequencer: ParametersSequencer): void {
|
|
267
|
+
const entries = Object.entries(parametersSequencer);
|
|
268
|
+
|
|
269
|
+
// Sort the entries as defined by the descriptors.
|
|
270
|
+
entries.sort((entry1, entry2) => {
|
|
271
|
+
let result: number;
|
|
272
|
+
|
|
273
|
+
const parameterDescriptor1 = entry1[1].parameterDescriptor;
|
|
274
|
+
const parameterDescriptor2 = entry2[1].parameterDescriptor;
|
|
275
|
+
|
|
276
|
+
if ("sortOrder" in parameterDescriptor1) {
|
|
277
|
+
if ("sortOrder" in parameterDescriptor2) {
|
|
278
|
+
result = parameterDescriptor1.sortOrder - parameterDescriptor2.sortOrder;
|
|
279
|
+
} else {
|
|
280
|
+
// Parameter descriptors with undefined sort order to go the end.
|
|
281
|
+
result = -parameterDescriptor1.sortOrder;
|
|
282
|
+
}
|
|
283
|
+
} else {
|
|
284
|
+
// eslint-disable-next-line no-lonely-if -- Matches structure in "then" clause.
|
|
285
|
+
if ("sortOrder" in parameterDescriptor2) {
|
|
286
|
+
// Parameter descriptors with undefined sort order to go the end.
|
|
287
|
+
result = parameterDescriptor2.sortOrder;
|
|
288
|
+
} else {
|
|
289
|
+
result = 0;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return result;
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
for (const [parameterName, parametersSequencerEntry] of entries) {
|
|
297
|
+
if (parametersSequencerEntry.isUsed) {
|
|
298
|
+
this._parametersLocaleStrings[parameterName] = {
|
|
299
|
+
name: parameterName,
|
|
300
|
+
description: ""
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (parametersSequencerEntry.parametersSequencerOrNull !== null) {
|
|
305
|
+
this.buildParametersLocaleStrings(parametersSequencerEntry.parametersSequencerOrNull);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Build output to be written back to source file.
|
|
312
|
+
*
|
|
313
|
+
* @param prefix
|
|
314
|
+
* Line prefix.
|
|
315
|
+
*
|
|
316
|
+
* @param value
|
|
317
|
+
* Line value.
|
|
318
|
+
*
|
|
319
|
+
* @param indentLevel
|
|
320
|
+
* Indent level.
|
|
321
|
+
*
|
|
322
|
+
* @returns
|
|
323
|
+
* Output string.
|
|
324
|
+
*/
|
|
325
|
+
private static buildOutput(prefix: string, value: LocaleStrings | string, indentLevel: number): string {
|
|
326
|
+
return `${" ".repeat(indentLevel)}${prefix} ${typeof value === "object" ?
|
|
327
|
+
`{\n${
|
|
328
|
+
Object.entries(value).map(entry => LocaleStringsGenerator.buildOutput(`${entry[0]}:`, entry[1], indentLevel + 1)).join(",\n")
|
|
329
|
+
}\n${" ".repeat(indentLevel)}}` :
|
|
330
|
+
// JSON.stringify() will apply quotes as appropriate.
|
|
331
|
+
JSON.stringify(value)
|
|
332
|
+
}`;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* @inheritDoc
|
|
337
|
+
*/
|
|
338
|
+
protected async finalize(success: boolean): Promise<void> {
|
|
339
|
+
if (success) {
|
|
340
|
+
this.buildParametersLocaleStrings(this._parametersSequencer);
|
|
341
|
+
|
|
342
|
+
await Promise.all(fs.readdirSync(LocaleStringsGenerator.IMPORT_PATH, {
|
|
343
|
+
withFileTypes: true
|
|
344
|
+
}).filter(entry => entry.isDirectory()).map(async (entry) => {
|
|
345
|
+
const localeStringsSource = path.resolve(LocaleStringsGenerator.IMPORT_PATH, entry.name, "locale-strings.ts");
|
|
346
|
+
|
|
347
|
+
await import(localeStringsSource).then((module) => {
|
|
348
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Module format is known.
|
|
349
|
+
const localeStrings = LocaleStringsGenerator.merge(entry.name === "en", "", this._localeStrings, (module as LocaleStringsModule).localeStrings, !entry.name.includes("-"));
|
|
350
|
+
|
|
351
|
+
fs.writeFileSync(localeStringsSource, `${LocaleStringsGenerator.buildOutput("export const localeStrings =", localeStrings, 0)};\n`);
|
|
352
|
+
});
|
|
353
|
+
}));
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
await new LocaleStringsGenerator().generate();
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Logger } from "tslog";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Log level.
|
|
5
|
+
*/
|
|
6
|
+
enum LogLevel {
|
|
7
|
+
Silly, Trace, Debug, Info, Warn, Error, Fatal
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Logger with a default minimum level of Info.
|
|
12
|
+
*/
|
|
13
|
+
export const logger = new Logger({
|
|
14
|
+
minLevel: LogLevel.Info
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Set the log level.
|
|
19
|
+
*
|
|
20
|
+
* @param logLevel
|
|
21
|
+
* Log level as enumeration value or string.
|
|
22
|
+
*/
|
|
23
|
+
export function setLogLevel(logLevel: LogLevel | string): void {
|
|
24
|
+
if (typeof logLevel === "string") {
|
|
25
|
+
if (logLevel in LogLevel) {
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- String exists as a key.
|
|
27
|
+
logger.settings.minLevel = LogLevel[logLevel as keyof typeof LogLevel];
|
|
28
|
+
} else {
|
|
29
|
+
logger.error(`Unknown log level ${logLevel}`);
|
|
30
|
+
}
|
|
31
|
+
} else {
|
|
32
|
+
logger.settings.minLevel = logLevel;
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/index.ts
CHANGED