@aidc-toolkit/core 1.0.23-beta → 1.0.25-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.d.ts CHANGED
@@ -1,18 +1,230 @@
1
- /*!
2
- * Copyright © 2024-2025 Dolphin Data Development Ltd. and AIDC Toolkit
3
- * contributors
1
+ import { Logger } from 'tslog';
2
+ import { i18n, Resource } from 'i18next';
3
+
4
+ /**
5
+ * Typed function, applicable to any function, stricter than {@linkcode Function}.
4
6
  *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
7
+ * @template TFunction
8
+ * Function type.
9
+ */
10
+ type TypedFunction<TFunction extends (...args: Parameters<TFunction>) => ReturnType<TFunction>> = (...args: Parameters<TFunction>) => ReturnType<TFunction>;
11
+ /**
12
+ * Typed synchronous function, applicable to any function that doesn't return a {@linkcode Promise}.
13
+ *
14
+ * @template TFunction
15
+ * Function type.
16
+ */
17
+ type TypedSyncFunction<TFunction extends TypedFunction<TFunction>> = [ReturnType<TFunction>] extends [PromiseLike<unknown>] ? never : TypedFunction<TFunction>;
18
+ /**
19
+ * Determine the fundamental promised type. This is stricter than `Awaited<Type>` in that it requires a {@linkcode
20
+ * Promise}.
21
+ *
22
+ * @template T
23
+ * Promised type.
24
+ */
25
+ type PromisedType<T> = [T] extends [PromiseLike<infer TPromised>] ? TPromised : never;
26
+ /**
27
+ * Typed asynchronous function, applicable to any function that returns a {@linkcode Promise}.
28
+ *
29
+ * @template TFunction
30
+ * Function type.
31
+ */
32
+ type TypedAsyncFunction<TMethod extends (...args: Parameters<TMethod>) => PromiseLike<PromisedType<ReturnType<TMethod>>>> = (...args: Parameters<TMethod>) => Promise<PromisedType<ReturnType<TMethod>>>;
33
+ /**
34
+ * Nullishable type. Extends a type by allowing `null` and `undefined`.
35
+ *
36
+ * @template T
37
+ * Type.
38
+ */
39
+ type Nullishable<T> = T | null | undefined;
40
+ /**
41
+ * Non-nullishable type. If T is an object type, it is spread and attributes within it are made non-nullishable.
42
+ * Equivalent to a deep `Required<T>` for an object and `NonNullable<T>` for any other type.
43
+ *
44
+ * @template T
45
+ * Type.
46
+ */
47
+ type NonNullishable<T> = T extends object ? {
48
+ [P in keyof T]-?: NonNullishable<T[P]>;
49
+ } : NonNullable<T>;
50
+ /**
51
+ * Make some keys within a type optional.
52
+ *
53
+ * @template T
54
+ * Object type.
55
+ *
56
+ * @template K
57
+ * Object key type.
58
+ */
59
+ type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
60
+ /**
61
+ * Type to restrict property keys to those that are strings and that support a specified type.
62
+ *
63
+ * @template T
64
+ * Object type.
65
+ *
66
+ * @template P
67
+ * Object property type.
68
+ */
69
+ type PropertyKeys<T, P> = {
70
+ [K in keyof T]: K extends string ? T[K] extends P ? K : never : never;
71
+ }[keyof T];
72
+
73
+ /**
74
+ * Create an object with omitted entries.
75
+ *
76
+ * @template T
77
+ * Object type.
78
+ *
79
+ * @template K
80
+ * Object key type.
81
+ *
82
+ * @param o
83
+ * Object.
84
+ *
85
+ * @param keys
86
+ * Keys to omit.
87
+ *
88
+ * @returns
89
+ * Edited object.
90
+ */
91
+ declare function omit<T extends object, K extends keyof T>(o: T, ...keys: K[]): Omit<T, K>;
92
+ /**
93
+ * Create an object with picked entries.
94
+ *
95
+ * @template T
96
+ * Object type.
97
+ *
98
+ * @template K
99
+ * Object key type.
100
+ *
101
+ * @param o
102
+ * Object.
103
+ *
104
+ * @param keys
105
+ * Keys to pick.
106
+ *
107
+ * @returns
108
+ * Edited object.
109
+ */
110
+ declare function pick<T extends object, K extends keyof T>(o: T, ...keys: K[]): Pick<T, K>;
111
+ /**
112
+ * Cast a property as a more narrow type.
113
+ *
114
+ * @template T
115
+ * Object type.
116
+ *
117
+ * @template K
118
+ * Object key type.
119
+ *
120
+ * @template TAsType
121
+ * Desired type.
122
+ *
123
+ * @param o
124
+ * Object.
125
+ *
126
+ * @param key
127
+ * Key of property to cast.
128
+ *
129
+ * @returns
130
+ * Single-key object with property cast as desired type.
131
+ */
132
+ declare function propertyAs<T extends object, K extends keyof T, TAsType extends T[K]>(o: T, key: K): Readonly<Omit<T, K> extends T ? Partial<Record<K, TAsType>> : Record<K, TAsType>>;
133
+ /**
134
+ * Determine if argument is nullish. Application extension may pass `null` or `undefined` to missing parameters.
135
+ *
136
+ * @param argument
137
+ * Argument.
138
+ *
139
+ * @returns
140
+ * True if argument is undefined or null.
141
+ */
142
+ declare function isNullish(argument: unknown): argument is null | undefined;
143
+
144
+ /**
145
+ * Log levels.
146
+ */
147
+ declare const LogLevels: {
148
+ readonly Silly: 0;
149
+ readonly Trace: 1;
150
+ readonly Debug: 2;
151
+ readonly Info: 3;
152
+ readonly Warn: 4;
153
+ readonly Error: 5;
154
+ readonly Fatal: 6;
155
+ };
156
+ /**
157
+ * Log level key.
158
+ */
159
+ type LogLevelKey = keyof typeof LogLevels;
160
+ /**
161
+ * Log level.
162
+ */
163
+ type LogLevel = typeof LogLevels[LogLevelKey];
164
+ /**
165
+ * Get a simple logger with an optional log level.
166
+ *
167
+ * @param logLevel
168
+ * Log level as enumeration value or string.
169
+ *
170
+ * @returns
171
+ * Logger.
172
+ */
173
+ declare function getLogger(logLevel?: string | number): Logger<unknown>;
174
+
175
+ /**
176
+ * Locale strings type for generic manipulation.
177
+ */
178
+ interface LocaleResources {
179
+ [key: string]: LocaleResources | string;
180
+ }
181
+ /**
182
+ * Internationalization operating environments.
183
+ */
184
+ declare const I18nEnvironments: {
185
+ /**
186
+ * Command-line interface (e.g., unit tests).
187
+ */
188
+ readonly CLI: 0;
189
+ /**
190
+ * Web server.
191
+ */
192
+ readonly Server: 1;
193
+ /**
194
+ * Web browser.
195
+ */
196
+ readonly Browser: 2;
197
+ };
198
+ /**
199
+ * Internationalization operating environment key.
200
+ */
201
+ type I18nEnvironmentKey = keyof typeof I18nEnvironments;
202
+ /**
203
+ * Internationalization operating environment.
204
+ */
205
+ type I18nEnvironment = typeof I18nEnvironments[I18nEnvironmentKey];
206
+ /**
207
+ * Initialize internationalization.
208
+ *
209
+ * @param i18next
210
+ * Internationalization object. As multiple objects exists, this parameter represents the one for the module for which
211
+ * internationalization is being initialized.
212
+ *
213
+ * @param environment
214
+ * Environment in which the application is running.
215
+ *
216
+ * @param debug
217
+ * Debug setting.
218
+ *
219
+ * @param defaultNS
220
+ * Default namespace.
8
221
  *
9
- * https://www.apache.org/licenses/LICENSE-2.0
222
+ * @param resources
223
+ * Resources.
10
224
  *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
225
+ * @returns
226
+ * Void promise.
16
227
  */
17
- export * from "./locale/i18n.js";
18
- //# sourceMappingURL=index.d.ts.map
228
+ declare function i18nCoreInit(i18next: i18n, environment: I18nEnvironment, debug: boolean, defaultNS: string, ...resources: Resource[]): Promise<void>;
229
+
230
+ export { type I18nEnvironment, type I18nEnvironmentKey, I18nEnvironments, type LocaleResources, type LogLevel, type LogLevelKey, LogLevels, type NonNullishable, type Nullishable, type Optional, type PromisedType, type PropertyKeys, type TypedAsyncFunction, type TypedFunction, type TypedSyncFunction, getLogger, i18nCoreInit, isNullish, omit, pick, propertyAs };
package/dist/index.js CHANGED
@@ -1,3 +1,115 @@
1
+ // src/type-helper.ts
2
+ function omitOrPick(omitting, o, ...keys) {
3
+ return Object.fromEntries(Object.entries(o).filter(([key]) => keys.includes(key) !== omitting));
4
+ }
5
+ function omit(o, ...keys) {
6
+ return omitOrPick(true, o, ...keys);
7
+ }
8
+ function pick(o, ...keys) {
9
+ return omitOrPick(false, o, ...keys);
10
+ }
11
+ function propertyAs(o, key) {
12
+ return key in o ? {
13
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Force cast.
14
+ [key]: o[key]
15
+ } : {};
16
+ }
17
+ function isNullish(argument) {
18
+ return argument === null || argument === void 0;
19
+ }
20
+
21
+ // src/logger.ts
22
+ import { Logger } from "tslog";
23
+ var LogLevels = {
24
+ Silly: 0,
25
+ Trace: 1,
26
+ Debug: 2,
27
+ Info: 3,
28
+ Warn: 4,
29
+ Error: 5,
30
+ Fatal: 6
31
+ };
32
+ function getLogger(logLevel) {
33
+ let minLevel;
34
+ if (typeof logLevel === "string") {
35
+ if (logLevel in LogLevels) {
36
+ minLevel = LogLevels[logLevel];
37
+ } else {
38
+ throw new Error(`Unknown log level ${logLevel}`);
39
+ }
40
+ } else {
41
+ minLevel = logLevel ?? LogLevels.Info;
42
+ }
43
+ return new Logger({
44
+ minLevel
45
+ });
46
+ }
47
+
48
+ // src/locale/i18n.ts
49
+ import I18nextBrowserLanguageDetector from "i18next-browser-languagedetector";
50
+ import I18nextCLILanguageDetector from "i18next-cli-language-detector";
51
+ var I18nEnvironments = {
52
+ /**
53
+ * Command-line interface (e.g., unit tests).
54
+ */
55
+ CLI: 0,
56
+ /**
57
+ * Web server.
58
+ */
59
+ Server: 1,
60
+ /**
61
+ * Web browser.
62
+ */
63
+ Browser: 2
64
+ };
65
+ function toLowerCase(s) {
66
+ return s.split(" ").map((word) => /[a-z]/.test(word) ? word.toLowerCase() : word).join(" ");
67
+ }
68
+ async function i18nCoreInit(i18next, environment, debug, defaultNS, ...resources) {
69
+ if (!i18next.isInitialized) {
70
+ const mergedResource = {};
71
+ for (const resource of resources) {
72
+ for (const [language, resourceLanguage] of Object.entries(resource)) {
73
+ if (!(language in mergedResource)) {
74
+ mergedResource[language] = {};
75
+ }
76
+ const mergedResourceLanguage = mergedResource[language];
77
+ for (const [namespace, resourceKey] of Object.entries(resourceLanguage)) {
78
+ mergedResourceLanguage[namespace] = resourceKey;
79
+ }
80
+ }
81
+ }
82
+ let module;
83
+ switch (environment) {
84
+ case I18nEnvironments.CLI:
85
+ module = I18nextCLILanguageDetector;
86
+ break;
87
+ case I18nEnvironments.Browser:
88
+ module = I18nextBrowserLanguageDetector;
89
+ break;
90
+ default:
91
+ throw new Error("Not supported");
92
+ }
93
+ await i18next.use(module).init({
94
+ debug,
95
+ resources: mergedResource,
96
+ fallbackLng: "en",
97
+ defaultNS
98
+ }).then(() => {
99
+ i18next.services.formatter?.add("toLowerCase", (value) => typeof value === "string" ? toLowerCase(value) : String(value));
100
+ });
101
+ }
102
+ }
103
+ export {
104
+ I18nEnvironments,
105
+ LogLevels,
106
+ getLogger,
107
+ i18nCoreInit,
108
+ isNullish,
109
+ omit,
110
+ pick,
111
+ propertyAs
112
+ };
1
113
  /*!
2
114
  * Copyright © 2024-2025 Dolphin Data Development Ltd. and AIDC Toolkit
3
115
  * contributors
@@ -14,5 +126,4 @@
14
126
  * See the License for the specific language governing permissions and
15
127
  * limitations under the License.
16
128
  */
17
- export * from "./locale/i18n.js";
18
129
  //# sourceMappingURL=index.js.map
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"}
1
+ {"version":3,"sources":["../src/type-helper.ts","../src/logger.ts","../src/locale/i18n.ts"],"sourcesContent":["/**\n * Create an object with omitted or picked entries.\n *\n * @template Omitting\n * Type representation of `omitting` parameter for return type determination.\n *\n * @template T\n * Object type.\n *\n * @template K\n * Object key type.\n *\n * @param omitting\n * True if omitting.\n *\n * @param o\n * Object.\n *\n * @param keys\n * Keys to omit or pick.\n *\n * @returns\n * Edited object.\n */\nfunction omitOrPick<Omitting extends boolean, T extends object, K extends keyof T>(omitting: Omitting, o: T, ...keys: K[]): Omitting extends true ? Omit<T, K> : Pick<T, K> {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Key and value types are known.\n return Object.fromEntries(Object.entries(o).filter(([key]) => keys.includes(key as K) !== omitting)) as ReturnType<typeof omitOrPick<Omitting, T, K>>;\n}\n\n/**\n * Create an object with omitted entries.\n *\n * @template T\n * Object type.\n *\n * @template K\n * Object key type.\n *\n * @param o\n * Object.\n *\n * @param keys\n * Keys to omit.\n *\n * @returns\n * Edited object.\n */\nexport function omit<T extends object, K extends keyof T>(o: T, ...keys: K[]): Omit<T, K> {\n return omitOrPick(true, o, ...keys);\n}\n\n/**\n * Create an object with picked entries.\n *\n * @template T\n * Object type.\n *\n * @template K\n * Object key type.\n *\n * @param o\n * Object.\n *\n * @param keys\n * Keys to pick.\n *\n * @returns\n * Edited object.\n */\nexport function pick<T extends object, K extends keyof T>(o: T, ...keys: K[]): Pick<T, K> {\n return omitOrPick(false, o, ...keys);\n}\n\n/**\n * Cast a property as a more narrow type.\n *\n * @template T\n * Object type.\n *\n * @template K\n * Object key type.\n *\n * @template TAsType\n * Desired type.\n *\n * @param o\n * Object.\n *\n * @param key\n * Key of property to cast.\n *\n * @returns\n * Single-key object with property cast as desired type.\n */\nexport function propertyAs<T extends object, K extends keyof T, TAsType extends T[K]>(o: T, key: K): Readonly<Omit<T, K> extends T ? Partial<Record<K, TAsType>> : Record<K, TAsType>> {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Type is determined by condition.\n return (key in o ?\n {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Force cast.\n [key]: o[key] as TAsType\n } :\n {}\n ) as ReturnType<typeof propertyAs<T, K, TAsType>>;\n}\n\n/**\n * Determine if argument is nullish. Application extension may pass `null` or `undefined` to missing parameters.\n *\n * @param argument\n * Argument.\n *\n * @returns\n * True if argument is undefined or null.\n */\nexport function isNullish(argument: unknown): argument is null | undefined {\n return argument === null || argument === undefined;\n}\n","import { Logger } from \"tslog\";\n\n/**\n * Log levels.\n */\nexport const LogLevels = {\n Silly: 0,\n Trace: 1,\n Debug: 2,\n Info: 3,\n Warn: 4,\n Error: 5,\n Fatal: 6\n} as const;\n\n/**\n * Log level key.\n */\nexport type LogLevelKey = keyof typeof LogLevels;\n\n/**\n * Log level.\n */\nexport type LogLevel = typeof LogLevels[LogLevelKey];\n\n/**\n * Get a simple logger with an optional log level.\n *\n * @param logLevel\n * Log level as enumeration value or string.\n *\n * @returns\n * Logger.\n */\nexport function getLogger(logLevel?: string | number): Logger<unknown> {\n let minLevel: number;\n\n if (typeof logLevel === \"string\") {\n if (logLevel in LogLevels) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- String exists as a key.\n minLevel = LogLevels[logLevel as LogLevelKey];\n } else {\n throw new Error(`Unknown log level ${logLevel}`);\n }\n } else {\n minLevel = logLevel ?? LogLevels.Info;\n }\n\n return new Logger({\n minLevel\n });\n}\n","import type { i18n, LanguageDetectorModule, Resource } from \"i18next\";\nimport I18nextBrowserLanguageDetector from \"i18next-browser-languagedetector\";\nimport I18nextCLILanguageDetector from \"i18next-cli-language-detector\";\n\n/**\n * Locale strings type for generic manipulation.\n */\nexport interface LocaleResources {\n [key: string]: LocaleResources | string;\n}\n\n/**\n * Internationalization operating environments.\n */\nexport const I18nEnvironments = {\n /**\n * Command-line interface (e.g., unit tests).\n */\n CLI: 0,\n\n /**\n * Web server.\n */\n Server: 1,\n\n /**\n * Web browser.\n */\n Browser: 2\n} as const;\n\n/**\n * Internationalization operating environment key.\n */\nexport type I18nEnvironmentKey = keyof typeof I18nEnvironments;\n\n/**\n * Internationalization operating environment.\n */\nexport type I18nEnvironment = typeof I18nEnvironments[I18nEnvironmentKey];\n\n/**\n * Convert a string to lower case, skipping words that are all upper case.\n *\n * @param s\n * String.\n *\n * @returns\n * Lower case string.\n */\nfunction toLowerCase(s: string): string {\n // Words with no lower case letters are preserved as they are likely mnemonics.\n return s.split(\" \").map(word => /[a-z]/.test(word) ? word.toLowerCase() : word).join(\" \");\n}\n\n/**\n * Initialize internationalization.\n *\n * @param i18next\n * Internationalization object. As multiple objects exists, this parameter represents the one for the module for which\n * internationalization is being initialized.\n *\n * @param environment\n * Environment in which the application is running.\n *\n * @param debug\n * Debug setting.\n *\n * @param defaultNS\n * Default namespace.\n *\n * @param resources\n * Resources.\n *\n * @returns\n * Void promise.\n */\nexport async function i18nCoreInit(i18next: i18n, environment: I18nEnvironment, debug: boolean, defaultNS: string, ...resources: Resource[]): Promise<void> {\n // Initialization may be called more than once.\n if (!i18next.isInitialized) {\n const mergedResource: Resource = {};\n\n // Merge resources.\n for (const resource of resources) {\n // Merge languages.\n for (const [language, resourceLanguage] of Object.entries(resource)) {\n if (!(language in mergedResource)) {\n mergedResource[language] = {};\n }\n\n const mergedResourceLanguage = mergedResource[language];\n\n // Merge namespaces.\n for (const [namespace, resourceKey] of Object.entries(resourceLanguage)) {\n mergedResourceLanguage[namespace] = resourceKey;\n }\n }\n }\n\n let module: Parameters<typeof i18next.use>[0];\n\n switch (environment) {\n case I18nEnvironments.CLI:\n // TODO Refactor when https://github.com/neet/i18next-cli-language-detector/issues/281 resolved.\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Per above.\n module = I18nextCLILanguageDetector as unknown as LanguageDetectorModule;\n break;\n\n case I18nEnvironments.Browser:\n module = I18nextBrowserLanguageDetector;\n break;\n\n default:\n throw new Error(\"Not supported\");\n }\n\n await i18next.use(module).init({\n debug,\n resources: mergedResource,\n fallbackLng: \"en\",\n defaultNS\n }).then(() => {\n // Add toLowerCase function.\n i18next.services.formatter?.add(\"toLowerCase\", value => typeof value === \"string\" ? toLowerCase(value) : String(value));\n });\n }\n}\n"],"mappings":";AAwBA,SAAS,WAA0E,UAAoB,MAAS,MAA4D;AAExK,SAAO,OAAO,YAAY,OAAO,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,KAAK,SAAS,GAAQ,MAAM,QAAQ,CAAC;AACvG;AAoBO,SAAS,KAA0C,MAAS,MAAuB;AACtF,SAAO,WAAW,MAAM,GAAG,GAAG,IAAI;AACtC;AAoBO,SAAS,KAA0C,MAAS,MAAuB;AACtF,SAAO,WAAW,OAAO,GAAG,GAAG,IAAI;AACvC;AAuBO,SAAS,WAAsE,GAAM,KAA2F;AAEnL,SAAQ,OAAO,IACX;AAAA;AAAA,IAEI,CAAC,GAAG,GAAG,EAAE,GAAG;AAAA,EAChB,IACA,CAAC;AAET;AAWO,SAAS,UAAU,UAAiD;AACvE,SAAO,aAAa,QAAQ,aAAa;AAC7C;;;ACpHA,SAAS,cAAc;AAKhB,IAAM,YAAY;AAAA,EACrB,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,OAAO;AACX;AAqBO,SAAS,UAAU,UAA6C;AACnE,MAAI;AAEJ,MAAI,OAAO,aAAa,UAAU;AAC9B,QAAI,YAAY,WAAW;AAEvB,iBAAW,UAAU,QAAuB;AAAA,IAChD,OAAO;AACH,YAAM,IAAI,MAAM,qBAAqB,QAAQ,EAAE;AAAA,IACnD;AAAA,EACJ,OAAO;AACH,eAAW,YAAY,UAAU;AAAA,EACrC;AAEA,SAAO,IAAI,OAAO;AAAA,IACd;AAAA,EACJ,CAAC;AACL;;;AClDA,OAAO,oCAAoC;AAC3C,OAAO,gCAAgC;AAYhC,IAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA,EAI5B,KAAK;AAAA;AAAA;AAAA;AAAA,EAKL,QAAQ;AAAA;AAAA;AAAA;AAAA,EAKR,SAAS;AACb;AAqBA,SAAS,YAAY,GAAmB;AAEpC,SAAO,EAAE,MAAM,GAAG,EAAE,IAAI,UAAQ,QAAQ,KAAK,IAAI,IAAI,KAAK,YAAY,IAAI,IAAI,EAAE,KAAK,GAAG;AAC5F;AAwBA,eAAsB,aAAa,SAAe,aAA8B,OAAgB,cAAsB,WAAsC;AAExJ,MAAI,CAAC,QAAQ,eAAe;AACxB,UAAM,iBAA2B,CAAC;AAGlC,eAAW,YAAY,WAAW;AAE9B,iBAAW,CAAC,UAAU,gBAAgB,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACjE,YAAI,EAAE,YAAY,iBAAiB;AAC/B,yBAAe,QAAQ,IAAI,CAAC;AAAA,QAChC;AAEA,cAAM,yBAAyB,eAAe,QAAQ;AAGtD,mBAAW,CAAC,WAAW,WAAW,KAAK,OAAO,QAAQ,gBAAgB,GAAG;AACrE,iCAAuB,SAAS,IAAI;AAAA,QACxC;AAAA,MACJ;AAAA,IACJ;AAEA,QAAI;AAEJ,YAAQ,aAAa;AAAA,MACjB,KAAK,iBAAiB;AAGlB,iBAAS;AACT;AAAA,MAEJ,KAAK,iBAAiB;AAClB,iBAAS;AACT;AAAA,MAEJ;AACI,cAAM,IAAI,MAAM,eAAe;AAAA,IACvC;AAEA,UAAM,QAAQ,IAAI,MAAM,EAAE,KAAK;AAAA,MAC3B;AAAA,MACA,WAAW;AAAA,MACX,aAAa;AAAA,MACb;AAAA,IACJ,CAAC,EAAE,KAAK,MAAM;AAEV,cAAQ,SAAS,WAAW,IAAI,eAAe,WAAS,OAAO,UAAU,WAAW,YAAY,KAAK,IAAI,OAAO,KAAK,CAAC;AAAA,IAC1H,CAAC;AAAA,EACL;AACJ;","names":[]}
package/package.json CHANGED
@@ -1,14 +1,11 @@
1
1
  {
2
2
  "name": "@aidc-toolkit/core",
3
- "version": "1.0.23-beta",
3
+ "version": "1.0.25-beta",
4
4
  "description": "Core functionality for AIDC Toolkit",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "homepage": "https://aidc-toolkit.com/",
8
- "repository": {
9
- "type": "git",
10
- "url": "git+https://github.com/aidc-toolkit/core.git"
11
- },
8
+ "repository": "aidc-toolkit/core",
12
9
  "bugs": {
13
10
  "url": "https://github.com/aidc-toolkit/core/issues"
14
11
  },
@@ -20,17 +17,17 @@
20
17
  },
21
18
  "scripts": {
22
19
  "lint": "eslint",
23
- "build:core": "rimraf dist && tsc --project",
24
- "build:dev": "npm run build:core -- node_modules/@aidc-toolkit/dev/tsconfig-build-dev.json",
25
- "build:release": "npm run build:core -- node_modules/@aidc-toolkit/dev/tsconfig-build.json",
20
+ "build:dev": "tsup --define.mode=dev",
21
+ "build:release": "tsup",
26
22
  "build:doc": "npm run build:dev"
27
23
  },
28
24
  "devDependencies": {
29
- "@aidc-toolkit/dev": "beta"
25
+ "@aidc-toolkit/dev": "1.0.25-beta"
30
26
  },
31
27
  "dependencies": {
32
- "i18next": "^25.6.3",
28
+ "i18next": "^25.7.1",
33
29
  "i18next-browser-languagedetector": "^8.2.0",
34
- "i18next-cli-language-detector": "^1.1.8"
30
+ "i18next-cli-language-detector": "^1.1.8",
31
+ "tslog": "^4.10.2"
35
32
  }
36
33
  }
package/src/index.ts CHANGED
@@ -14,4 +14,7 @@
14
14
  * See the License for the specific language governing permissions and
15
15
  * limitations under the License.
16
16
  */
17
- export * from "./locale/i18n.js";
17
+ export type * from "./type";
18
+ export * from "./type-helper";
19
+ export * from "./logger";
20
+ export * from "./locale/i18n";
@@ -30,100 +30,14 @@ export const I18nEnvironments = {
30
30
  } as const;
31
31
 
32
32
  /**
33
- * Internationalization operating environment.
33
+ * Internationalization operating environment key.
34
34
  */
35
- export type I18nEnvironment = typeof I18nEnvironments[keyof typeof I18nEnvironments];
35
+ export type I18nEnvironmentKey = keyof typeof I18nEnvironments;
36
36
 
37
37
  /**
38
- * Parse parameter names in a resource string.
39
- *
40
- * @param s
41
- * Resource string.
42
- *
43
- * @returns
44
- * Array of parameter names.
45
- */
46
- function parseParameterNames(s: string): string[] {
47
- const parameterRegExp = /\{\{.+?}}/g;
48
-
49
- const parameterNames: string[] = [];
50
-
51
- let match: RegExpExecArray | null;
52
-
53
- while ((match = parameterRegExp.exec(s)) !== null) {
54
- parameterNames.push(match[1]);
55
- }
56
-
57
- return parameterNames;
58
- }
59
-
60
- /**
61
- * Assert that language resources are a type match for English (default) resources.
62
- *
63
- * @param enResources
64
- * English resources.
65
- *
66
- * @param lng
67
- * Language.
68
- *
69
- * @param lngResources
70
- * Language resources.
71
- *
72
- * @param parent
73
- * Parent key name (set recursively).
38
+ * Internationalization operating environment.
74
39
  */
75
- export function i18nAssertValidResources(enResources: object, lng: string, lngResources: object, parent?: string): void {
76
- const enResourcesMap = new Map<string, object>(Object.entries(enResources));
77
- const lngResourcesMap = new Map<string, object>(Object.entries(lngResources));
78
-
79
- const isLocale = lng.includes("-");
80
-
81
- for (const [enKey, enValue] of enResourcesMap) {
82
- const enFullKey = `${parent === undefined ? "" : `${parent}.`}${enKey}`;
83
-
84
- const lngValue = lngResourcesMap.get(enKey);
85
-
86
- if (lngValue !== undefined) {
87
- const enValueType = typeof enValue;
88
- const lngValueType = typeof lngValue;
89
-
90
- if (lngValueType !== enValueType) {
91
- throw new Error(`Mismatched value type ${lngValueType} for key ${enFullKey} in ${lng} resources (expected ${enValueType})`);
92
- }
93
-
94
- if (enValueType === "string") {
95
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Value is known to be string.
96
- const enParameterNames = parseParameterNames(enValue as unknown as string);
97
-
98
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Value is known to be string.
99
- const lngParameterNames = parseParameterNames(lngValue as unknown as string);
100
-
101
- for (const enParameterName of enParameterNames) {
102
- if (!lngParameterNames.includes(enParameterName)) {
103
- throw new Error(`Missing parameter ${enParameterName} for key ${enFullKey} in ${lng} resources`);
104
- }
105
- }
106
-
107
- for (const lngParameterName of lngParameterNames) {
108
- if (!enParameterNames.includes(lngParameterName)) {
109
- throw new Error(`Extraneous parameter ${lngParameterName} for key ${enFullKey} in ${lng} resources`);
110
- }
111
- }
112
- } else if (enValueType === "object") {
113
- i18nAssertValidResources(enValue, lng, lngValue, `${parent === undefined ? "" : `${parent}.`}${enKey}`);
114
- }
115
- // Locale falls back to raw language so ignore if missing.
116
- } else if (!isLocale) {
117
- throw new Error(`Missing key ${enFullKey} in ${lng} resources`);
118
- }
119
- }
120
-
121
- for (const [lngKey] of lngResourcesMap) {
122
- if (!enResourcesMap.has(lngKey)) {
123
- throw new Error(`Extraneous key ${parent === undefined ? "" : `${parent}.`}${lngKey} in ${lng} resources`);
124
- }
125
- }
126
- }
40
+ export type I18nEnvironment = typeof I18nEnvironments[I18nEnvironmentKey];
127
41
 
128
42
  /**
129
43
  * Convert a string to lower case, skipping words that are all upper case.
package/src/logger.ts ADDED
@@ -0,0 +1,52 @@
1
+ import { Logger } from "tslog";
2
+
3
+ /**
4
+ * Log levels.
5
+ */
6
+ export const LogLevels = {
7
+ Silly: 0,
8
+ Trace: 1,
9
+ Debug: 2,
10
+ Info: 3,
11
+ Warn: 4,
12
+ Error: 5,
13
+ Fatal: 6
14
+ } as const;
15
+
16
+ /**
17
+ * Log level key.
18
+ */
19
+ export type LogLevelKey = keyof typeof LogLevels;
20
+
21
+ /**
22
+ * Log level.
23
+ */
24
+ export type LogLevel = typeof LogLevels[LogLevelKey];
25
+
26
+ /**
27
+ * Get a simple logger with an optional log level.
28
+ *
29
+ * @param logLevel
30
+ * Log level as enumeration value or string.
31
+ *
32
+ * @returns
33
+ * Logger.
34
+ */
35
+ export function getLogger(logLevel?: string | number): Logger<unknown> {
36
+ let minLevel: number;
37
+
38
+ if (typeof logLevel === "string") {
39
+ if (logLevel in LogLevels) {
40
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- String exists as a key.
41
+ minLevel = LogLevels[logLevel as LogLevelKey];
42
+ } else {
43
+ throw new Error(`Unknown log level ${logLevel}`);
44
+ }
45
+ } else {
46
+ minLevel = logLevel ?? LogLevels.Info;
47
+ }
48
+
49
+ return new Logger({
50
+ minLevel
51
+ });
52
+ }