@aidc-toolkit/core 1.0.32-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 (59) hide show
  1. package/README.md +98 -87
  2. package/dist/app-data-storage.d.ts +118 -0
  3. package/dist/app-data-storage.d.ts.map +1 -0
  4. package/dist/app-data-storage.js +117 -0
  5. package/dist/app-data-storage.js.map +1 -0
  6. package/dist/app-data.d.ts +26 -0
  7. package/dist/app-data.d.ts.map +1 -0
  8. package/dist/app-data.js +79 -0
  9. package/dist/app-data.js.map +1 -0
  10. package/dist/browser-app-data-storage.d.ts +26 -0
  11. package/dist/browser-app-data-storage.d.ts.map +1 -0
  12. package/dist/browser-app-data-storage.js +34 -0
  13. package/dist/browser-app-data-storage.js.map +1 -0
  14. package/dist/file-app-data-storage.d.ts +26 -0
  15. package/dist/file-app-data-storage.d.ts.map +1 -0
  16. package/dist/file-app-data-storage.js +40 -0
  17. package/dist/file-app-data-storage.js.map +1 -0
  18. package/dist/index.d.ts +4 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +4 -0
  21. package/dist/index.js.map +1 -1
  22. package/dist/local-app-data-storage.d.ts +8 -0
  23. package/dist/local-app-data-storage.d.ts.map +1 -0
  24. package/dist/local-app-data-storage.js +11 -0
  25. package/dist/local-app-data-storage.js.map +1 -0
  26. package/dist/locale/en/locale-resources.d.ts +3 -0
  27. package/dist/locale/en/locale-resources.d.ts.map +1 -1
  28. package/dist/locale/en/locale-resources.js +3 -0
  29. package/dist/locale/en/locale-resources.js.map +1 -1
  30. package/dist/locale/fr/locale-resources.d.ts +3 -0
  31. package/dist/locale/fr/locale-resources.d.ts.map +1 -1
  32. package/dist/locale/fr/locale-resources.js +3 -0
  33. package/dist/locale/fr/locale-resources.js.map +1 -1
  34. package/dist/locale/i18n.d.ts +22 -13
  35. package/dist/locale/i18n.d.ts.map +1 -1
  36. package/dist/locale/i18n.js +62 -43
  37. package/dist/locale/i18n.js.map +1 -1
  38. package/dist/logger.d.ts +4 -2
  39. package/dist/logger.d.ts.map +1 -1
  40. package/dist/logger.js +9 -3
  41. package/dist/logger.js.map +1 -1
  42. package/dist/remote-app-data-storage.d.ts +18 -0
  43. package/dist/remote-app-data-storage.d.ts.map +1 -0
  44. package/dist/remote-app-data-storage.js +37 -0
  45. package/dist/remote-app-data-storage.js.map +1 -0
  46. package/dist/type-helper.js.map +1 -1
  47. package/package.json +9 -7
  48. package/src/app-data-storage.ts +166 -0
  49. package/src/app-data.ts +94 -0
  50. package/src/browser-app-data-storage.ts +37 -0
  51. package/src/file-app-data-storage.ts +49 -0
  52. package/src/index.ts +5 -0
  53. package/src/local-app-data-storage.ts +12 -0
  54. package/src/locale/en/locale-resources.ts +3 -0
  55. package/src/locale/fr/locale-resources.ts +3 -0
  56. package/src/locale/i18n.ts +81 -49
  57. package/src/logger.ts +10 -3
  58. package/src/remote-app-data-storage.ts +38 -0
  59. package/src/type-helper.ts +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"type-helper.js","sourceRoot":"","sources":["../src/type-helper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,SAAS,UAAU,CAAgE,QAAkB,EAAE,CAAI,EAAE,GAAG,IAAS;IACrH,yGAAyG;IACzG,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAQ,CAAC,KAAK,QAAQ,CAAC,CAAkD,CAAC;AAC1J,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,IAAI,CAAsC,CAAI,EAAE,GAAG,IAAS;IACxE,OAAO,UAAU,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,IAAI,CAAsC,CAAI,EAAE,GAAG,IAAS;IACxE,OAAO,UAAU,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;AACzC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,OAAO,CAAyE,IAAW,EAAE,MAAe;IACxH,0FAA0F;IAC1F,OAAO,IAAI,CAAC,IAAI,EAAE,GAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAS,CAAC,CAAC;AACvD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,OAAO,CAAyE,IAAW,EAAE,MAAe;IACxH,0FAA0F;IAC1F,OAAO,IAAI,CAAC,IAAI,EAAE,GAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAS,CAAC,CAAC;AACvD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,UAAU,CAA4D,CAAI,EAAE,GAAM;IAC9F,2GAA2G;IAC3G,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;QACd;YACI,sFAAsF;YACtF,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAY;SAC3B,CAAC,CAAC;QACH,EAAE,CAC2C,CAAC;AACtD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,SAAS,CAAC,QAAiB;IACvC,OAAO,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,SAAS,CAAC;AACvD,CAAC"}
1
+ {"version":3,"file":"type-helper.js","sourceRoot":"","sources":["../src/type-helper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,SAAS,UAAU,CAAgE,QAAkB,EAAE,CAAI,EAAE,GAAG,IAAS;IACrH,yGAAyG;IACzG,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAQ,CAAC,KAAK,QAAQ,CAAC,CAAkD,CAAC;AAC1J,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,IAAI,CAAsC,CAAI,EAAE,GAAG,IAAS;IACxE,OAAO,UAAU,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,IAAI,CAAsC,CAAI,EAAE,GAAG,IAAS;IACxE,OAAO,UAAU,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;AACzC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,OAAO,CAAyE,IAAW,EAAE,MAAe;IACxH,0FAA0F;IAC1F,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAQ,CAAC,CAAC;AACrD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,OAAO,CAAyE,IAAW,EAAE,MAAe;IACxH,0FAA0F;IAC1F,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAQ,CAAC,CAAC;AACrD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,UAAU,CAA4D,CAAI,EAAE,GAAM;IAC9F,2GAA2G;IAC3G,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;QACd;YACI,sFAAsF;YACtF,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAY;SAC3B,CAAC,CAAC;QACH,EAAE,CAC2C,CAAC;AACtD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,SAAS,CAAC,QAAiB;IACvC,OAAO,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,SAAS,CAAC;AACvD,CAAC"}
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@aidc-toolkit/core",
3
- "version": "1.0.32-beta",
3
+ "version": "1.0.33-beta",
4
4
  "description": "Core functionality 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/core.git"
@@ -20,15 +20,17 @@
20
20
  },
21
21
  "scripts": {
22
22
  "lint": "eslint",
23
- "tsc:core": "tsc --project tsconfig-src.json",
24
- "build:dev": "rimraf dist && npm run tsc:core -- --declarationMap --sourceMap",
25
- "build:release": "npm run tsc:core -- --noEmit && tsup",
26
- "build:doc": "npm run build:dev"
23
+ "tsc-src": "tsc --project tsconfig-src.json",
24
+ "build:alpha": "rimraf dist && npm run tsc-src -- --declarationMap --sourceMap",
25
+ "build:beta": "npm run build:alpha",
26
+ "build:prod": "npm run tsc-src -- --noEmit && tsup",
27
+ "build:doc": "npm run build:alpha"
27
28
  },
28
29
  "devDependencies": {
29
- "@aidc-toolkit/dev": "1.0.32-beta"
30
+ "@aidc-toolkit/dev": "1.0.33-beta"
30
31
  },
31
32
  "dependencies": {
33
+ "base64-js": "^1.5.1",
32
34
  "i18next": "^25.7.4",
33
35
  "i18next-browser-languagedetector": "^8.2.0",
34
36
  "i18next-cli-language-detector": "^1.1.8",
@@ -0,0 +1,166 @@
1
+ import { type AppData, decodeAppData, encodeAppData } from "./app-data.js";
2
+ import type { Promisable } from "./type.js";
3
+
4
+ /**
5
+ * Generic read-only application data storage.
6
+ */
7
+ export abstract class ReadOnlyAppDataStorage<SupportsBinary extends boolean> {
8
+ /**
9
+ * Extension to identify binary data.
10
+ */
11
+ protected static readonly BINARY_EXTENSION = ".bin";
12
+
13
+ /**
14
+ * Extension to identify JSON data.
15
+ */
16
+ protected static readonly JSON_EXTENSION = ".json";
17
+
18
+ /**
19
+ * True if binary data is supported natively.
20
+ */
21
+ readonly #supportsBinary: SupportsBinary;
22
+
23
+ /**
24
+ * Storage path prepended to each key.
25
+ */
26
+ readonly #path: string;
27
+
28
+ /**
29
+ * Constructor.
30
+ *
31
+ * @param supportsBinary
32
+ * True if binary data is supported.
33
+ *
34
+ * @param path
35
+ * Storage path prepended to each key along with '/' if defined, empty string if not.
36
+ */
37
+ protected constructor(supportsBinary: SupportsBinary, path?: string) {
38
+ this.#supportsBinary = supportsBinary;
39
+ this.#path = path !== undefined ? `${path}/` : "";
40
+ }
41
+
42
+ /**
43
+ * Determine if binary data is supported.
44
+ */
45
+ get supportsBinary(): SupportsBinary {
46
+ return this.#supportsBinary;
47
+ }
48
+
49
+ /**
50
+ * Get the storage path, prepended to each key.
51
+ */
52
+ get path(): string {
53
+ return this.#path;
54
+ }
55
+
56
+ /**
57
+ * Build the full storage key.
58
+ *
59
+ * @param pathKey
60
+ * Key relative to path.
61
+ *
62
+ * @param isBinary
63
+ * True if key is to binary data, false or undefined if to string data. Ignored if binary data is not supported.
64
+ *
65
+ * @returns
66
+ * Full storage key.
67
+ */
68
+ protected fullKey(pathKey: string, isBinary: boolean): string {
69
+ const keyNoExtension = `${this.path}${pathKey}`;
70
+
71
+ // Add extension to key if binary data is supported.
72
+ return this.supportsBinary ?
73
+ `${keyNoExtension}${isBinary ? ReadOnlyAppDataStorage.BINARY_EXTENSION : ReadOnlyAppDataStorage.JSON_EXTENSION}` :
74
+ keyNoExtension;
75
+ }
76
+
77
+ /**
78
+ * Read a string or binary data from persistent storage.
79
+ *
80
+ * @param key
81
+ * Storage key (file path in Node.js, key in localStorage).
82
+ *
83
+ * @param asBinary
84
+ * True if binary data is requested, false or undefined if string data is requested. Ignored if binary data is not
85
+ * supported.
86
+ *
87
+ * @returns
88
+ * String or binary data or undefined if not found.
89
+ */
90
+ protected abstract doRead(key: string, asBinary: boolean | undefined): Promisable<(SupportsBinary extends true ? string | Uint8Array : string) | undefined>;
91
+
92
+ /**
93
+ * Read application data from storage.
94
+ *
95
+ * @param pathKey
96
+ * Key relative to path.
97
+ *
98
+ * @param asBinary
99
+ * True if binary data is requested, false or undefined if string data is requested. Ignored if binary data is not
100
+ * supported.
101
+ *
102
+ * @returns
103
+ * Application data or undefined if not found.
104
+ */
105
+ async read(pathKey: string, asBinary?: boolean): Promise<AppData | undefined> {
106
+ const data = await this.doRead(this.fullKey(pathKey, asBinary === true), asBinary);
107
+
108
+ return typeof data === "string" ? decodeAppData(data) : data;
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Generic read/write application data storage.
114
+ */
115
+ export abstract class AppDataStorage<SupportsBinary extends boolean> extends ReadOnlyAppDataStorage<SupportsBinary> {
116
+ /**
117
+ * Write a string or binary data in persistent storage.
118
+ *
119
+ * @param key
120
+ * Storage key (file path in Node.js, key in localStorage).
121
+ *
122
+ * @param data
123
+ * String or binary data.
124
+ */
125
+ protected abstract doWrite(key: string, data: SupportsBinary extends true ? string | Uint8Array : string): Promisable<void>;
126
+
127
+ /**
128
+ * Write application data to storage.
129
+ *
130
+ * @param pathKey
131
+ * Key relative to path.
132
+ *
133
+ * @param appData
134
+ * Application data to write.
135
+ */
136
+ async write(pathKey: string, appData: AppData): Promise<void> {
137
+ const isBinary = appData instanceof Uint8Array;
138
+
139
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Type is determined by supports binary flag.
140
+ await this.doWrite(this.fullKey(pathKey, isBinary), (this.supportsBinary && isBinary ?
141
+ appData :
142
+ encodeAppData(appData)
143
+ ) as Parameters<typeof this.doWrite>[1]);
144
+ }
145
+
146
+ /**
147
+ * Delete from persistent storage.
148
+ *
149
+ * @param key
150
+ * Storage key (file path in Node.js, key in localStorage).
151
+ */
152
+ protected abstract doDelete(key: string): Promisable<void>;
153
+
154
+ /**
155
+ * Delete application data from persistent storage.
156
+ *
157
+ * @param pathKey
158
+ * Key relative to path.
159
+ *
160
+ * @param asBinary
161
+ * True if key is to binary data, false or undefined if to string data. Ignored if binary data is not supported.
162
+ */
163
+ async delete(pathKey: string, asBinary?: boolean): Promise<void> {
164
+ await this.doDelete(this.fullKey(pathKey, asBinary === true));
165
+ }
166
+ }
@@ -0,0 +1,94 @@
1
+ import { fromByteArray, toByteArray } from "base64-js";
2
+
3
+ /**
4
+ * Application data.
5
+ */
6
+ export type AppData = string | number | boolean | object;
7
+
8
+ /**
9
+ * Decode application data from an encoded string.
10
+ *
11
+ * @param stringData
12
+ * String data.
13
+ *
14
+ * @returns
15
+ * Decoded application data.
16
+ */
17
+ export function decodeAppData(stringData: string): AppData | undefined {
18
+ let decodedAppData: AppData | undefined;
19
+
20
+ try {
21
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Mapping is expected to be correct.
22
+ decodedAppData = JSON.parse(stringData, (_key, value: unknown) => {
23
+ let replacementValue = value;
24
+
25
+ // Decode string representing date/time and binary array and pass through other values unmodified.
26
+ if (typeof value === "string") {
27
+ // First capture group is type, second is data; simple split at ':' character.
28
+ const stringDataGroups = /^(?<type>\w+):(?<data>.*)$/u.exec(value)?.groups;
29
+
30
+ if (stringDataGroups !== undefined) {
31
+ const type = stringDataGroups["type"];
32
+ const data = stringDataGroups["data"];
33
+
34
+ switch (type) {
35
+ case "dateTime":
36
+ replacementValue = new Date(data);
37
+ break;
38
+
39
+ case "binary":
40
+ replacementValue = toByteArray(data);
41
+ break;
42
+ }
43
+ }
44
+ }
45
+
46
+ return replacementValue;
47
+ }) as AppData;
48
+ } catch {
49
+ // String data is not valid JSON; discard it.
50
+ decodedAppData = undefined;
51
+ }
52
+
53
+ return decodedAppData;
54
+ }
55
+
56
+ /**
57
+ * Encode an object to a format suitable for storage.
58
+ *
59
+ * @param o
60
+ * Object.
61
+ *
62
+ * @returns
63
+ * Object suitable for storage with date/time and binary types encoded as strings.
64
+ */
65
+ function encodeObject(o: object): object | string {
66
+ let mappedData: object | string;
67
+
68
+ // Encode date/time and binary array as string and pass through other values unmodified.
69
+ if (o instanceof Date) {
70
+ mappedData = `dateTime:${o.toISOString()}`;
71
+ } else if (o instanceof Uint8Array) {
72
+ mappedData = `binary:${fromByteArray(o)}`;
73
+ } else {
74
+ mappedData = Object.fromEntries(Object.entries(o).map(([key, value]: [string, unknown]) =>
75
+ [key, typeof value === "object" && value !== null ? encodeObject(value) : value]
76
+ ));
77
+ }
78
+
79
+ return mappedData;
80
+ }
81
+
82
+ /**
83
+ * Encode application data as a string for storage. Encoded string is in JSON format with date/time and binary data
84
+ * converted to identifiable strings for decoding.
85
+ *
86
+ * @param appData
87
+ * Application data.
88
+ *
89
+ * @returns
90
+ * Encoded application data.
91
+ */
92
+ export function encodeAppData(appData: AppData): string {
93
+ return JSON.stringify(typeof appData !== "object" ? appData : encodeObject(appData));
94
+ }
@@ -0,0 +1,37 @@
1
+ import { AppDataStorage } from "./app-data-storage.js";
2
+
3
+ /**
4
+ * Application data storage using the browser local storage.
5
+ */
6
+ export class BrowserAppDataStorage extends AppDataStorage<false> {
7
+ /**
8
+ * Constructor.
9
+ *
10
+ * @param path
11
+ * Storage path prepended to each key along with '/' if defined, empty string if not.
12
+ */
13
+ constructor(path?: string) {
14
+ super(false, path);
15
+ }
16
+
17
+ /**
18
+ * @inheritDoc
19
+ */
20
+ protected override doRead(key: string): string | undefined {
21
+ return localStorage.getItem(key) ?? undefined;
22
+ }
23
+
24
+ /**
25
+ * @inheritDoc
26
+ */
27
+ protected override doWrite(key: string, s: string): void {
28
+ localStorage.setItem(key, s);
29
+ }
30
+
31
+ /**
32
+ * @inheritDoc
33
+ */
34
+ protected override doDelete(key: string): void {
35
+ localStorage.removeItem(key);
36
+ }
37
+ }
@@ -0,0 +1,49 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { AppDataStorage } from "./app-data-storage.js";
4
+
5
+ /**
6
+ * Application data storage using the file system.
7
+ */
8
+ export class FileAppDataStorage extends AppDataStorage<true> {
9
+ /**
10
+ * Constructor.
11
+ *
12
+ * @param path
13
+ * Storage path prepended to each key along with '/' if defined, empty string if not.
14
+ */
15
+ constructor(path?: string) {
16
+ super(true, path);
17
+ }
18
+
19
+ /**
20
+ * @inheritDoc
21
+ */
22
+ protected override async doRead(key: string, asBinary: boolean | undefined): Promise<string | Uint8Array | undefined> {
23
+ return fs.promises.readFile(key).then(buffer =>
24
+ asBinary === true ? buffer : buffer.toString()
25
+ ).catch(() =>
26
+ undefined
27
+ );
28
+ }
29
+
30
+ /**
31
+ * @inheritDoc
32
+ */
33
+ protected override async doWrite(key: string, data: string | Uint8Array): Promise<void> {
34
+ return fs.promises.mkdir(path.dirname(key), {
35
+ recursive: true
36
+ }).then(async () =>
37
+ fs.promises.writeFile(key, data)
38
+ );
39
+ }
40
+
41
+ /**
42
+ * @inheritDoc
43
+ */
44
+ protected override async doDelete(key: string): Promise<void> {
45
+ return fs.promises.rm(key, {
46
+ force: true
47
+ });
48
+ }
49
+ }
package/src/index.ts CHANGED
@@ -19,7 +19,12 @@ export * from "./type-helper.js";
19
19
 
20
20
  export * from "./logger.js";
21
21
 
22
+ export * from "./app-data.js";
23
+ export * from "./app-data-storage.js";
24
+ export * from "./local-app-data-storage.js";
25
+ export * from "./remote-app-data-storage.js";
22
26
  export * from "./cache.js";
27
+
23
28
  export type * from "./hyperlink.js";
24
29
 
25
30
  export * from "./locale/i18n.js";
@@ -0,0 +1,12 @@
1
+ import type { AppDataStorage } from "./app-data-storage.js";
2
+
3
+ /**
4
+ * Local application data storage class for the current environment. This is a variable representing a `Promise` as the
5
+ * implementing class is loaded dynamically to prevent the inclusion of unnecessary node dependencies in a browser
6
+ * environment.
7
+ */
8
+ export const LocalAppDataStorage: Promise<new (path?: string) => AppDataStorage<boolean>> =
9
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- localStorage is undefined when running under Node.js.
10
+ globalThis.localStorage === undefined ?
11
+ import("./file-app-data-storage.js").then(module => module.FileAppDataStorage) :
12
+ import("./browser-app-data-storage.js").then(module => module.BrowserAppDataStorage);
@@ -1,5 +1,8 @@
1
1
  export default {
2
2
  Logger: {
3
3
  unknownLogLevel: "Unknown log level \"{{logLevel}}\""
4
+ },
5
+ RemoteAppDataStorage: {
6
+ httpError: "HTTP error {{status, number}} retrieving file"
4
7
  }
5
8
  };
@@ -1,5 +1,8 @@
1
1
  export default {
2
2
  Logger: {
3
3
  unknownLogLevel: "Niveau de journalisation inconnu «{{logLevel}}»"
4
+ },
5
+ RemoteAppDataStorage: {
6
+ httpError: "Erreur HTTP {{status, number}} lors de la récupération du fichier"
4
7
  }
5
8
  };
@@ -1,4 +1,11 @@
1
- import i18next, { type i18n, type LanguageDetectorModule, type Resource } from "i18next";
1
+ import i18next, {
2
+ type i18n,
3
+ type LanguageDetectorModule,
4
+ type Module,
5
+ type Newable,
6
+ type NewableModule,
7
+ type Resource
8
+ } from "i18next";
2
9
  import I18nextBrowserLanguageDetector from "i18next-browser-languagedetector";
3
10
  import I18nextCLILanguageDetector from "i18next-cli-language-detector";
4
11
  import enLocaleResources from "./en/locale-resources.js";
@@ -63,9 +70,9 @@ export const coreNS = "aidct_core";
63
70
  export type CoreLocaleResources = typeof enLocaleResources;
64
71
 
65
72
  /**
66
- * Core resources.
73
+ * Core resource bundle.
67
74
  */
68
- export const coreResources: Resource = {
75
+ export const coreResourceBundle: Resource = {
69
76
  en: {
70
77
  aidct_core: enLocaleResources
71
78
  },
@@ -77,24 +84,11 @@ export const coreResources: Resource = {
77
84
  // Explicit type is necessary because type can't be inferred without additional references.
78
85
  export const i18nextCore: i18n = i18next.createInstance();
79
86
 
80
- /**
81
- * Initialize internationalization.
82
- *
83
- * @param environment
84
- * Environment in which the application is running.
85
- *
86
- * @param debug
87
- * Debug setting.
88
- */
89
- export async function i18nCoreInit(environment: I18nEnvironment, debug = false): Promise<void> {
90
- await i18nFinalizeInit(i18nextCore, environment, debug, coreNS, coreResources);
91
- }
92
-
93
87
  /**
94
88
  * Initialize internationalization.
95
89
  *
96
90
  * @param i18next
97
- * Internationalization object. As multiple objects exists, this parameter represents the one for the module for which
91
+ * Internationalization object. As multiple objects exist, this parameter represents the one for the module for which
98
92
  * internationalization is being initialized.
99
93
  *
100
94
  * @param environment
@@ -106,56 +100,94 @@ export async function i18nCoreInit(environment: I18nEnvironment, debug = false):
106
100
  * @param defaultNS
107
101
  * Default namespace.
108
102
  *
109
- * @param resources
110
- * Resources.
103
+ * @param defaultResourceBundle
104
+ * Default resource bundle.
105
+ *
106
+ * @param i18nDependencyInits
107
+ * Dependency internationalization initialization functions.
108
+ *
109
+ * @returns
110
+ * Default resource bundle.
111
111
  */
112
- export async function i18nFinalizeInit(i18next: i18n, environment: I18nEnvironment, debug: boolean, defaultNS: string, ...resources: Resource[]): Promise<void> {
112
+ export async function i18nInit(i18next: i18n, environment: I18nEnvironment, debug: boolean, defaultNS: string, defaultResourceBundle: Resource, ...i18nDependencyInits: Array<(environment: I18nEnvironment, debug: boolean) => Promise<Resource>>): Promise<Resource> {
113
113
  // Initialization may be called more than once.
114
114
  if (!i18next.isInitialized) {
115
- const mergedResource: Resource = {};
116
-
117
- // Merge resources.
118
- for (const resource of resources) {
115
+ const mergedResourceBundle: Resource = {};
116
+
117
+ /**
118
+ * Merge a package resource bundle into the merged resource bundle.
119
+ *
120
+ * @param resourceBundle
121
+ * Package resource bundle.
122
+ */
123
+ function mergeResourceBundle(resourceBundle: Resource): void {
119
124
  // Merge languages.
120
- for (const [language, resourceLanguage] of Object.entries(resource)) {
121
- if (!(language in mergedResource)) {
122
- mergedResource[language] = {};
125
+ for (const [language, languageResourceBundle] of Object.entries(resourceBundle)) {
126
+ if (!(language in mergedResourceBundle)) {
127
+ mergedResourceBundle[language] = {};
123
128
  }
124
129
 
125
- const mergedResourceLanguage = mergedResource[language];
130
+ const mergedLanguageResourceBundle = mergedResourceBundle[language];
126
131
 
127
132
  // Merge namespaces.
128
- for (const [namespace, resourceKey] of Object.entries(resourceLanguage)) {
129
- mergedResourceLanguage[namespace] = resourceKey;
133
+ for (const [namespace, resourceKey] of Object.entries(languageResourceBundle)) {
134
+ mergedLanguageResourceBundle[namespace] = resourceKey;
130
135
  }
131
136
  }
132
137
  }
133
138
 
134
- let module: Parameters<typeof i18next.use>[0];
139
+ mergeResourceBundle(defaultResourceBundle);
135
140
 
136
- switch (environment) {
137
- case I18nEnvironments.CLI:
138
- // TODO Refactor when https://github.com/neet/i18next-cli-language-detector/issues/281 resolved.
139
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Per above.
140
- module = I18nextCLILanguageDetector as unknown as LanguageDetectorModule;
141
- break;
141
+ // Initialize dependencies and merge their resource bundles.
142
+ await Promise.all(i18nDependencyInits.map(async i18nDependencyInit =>
143
+ i18nDependencyInit(environment, debug).then(mergeResourceBundle))
144
+ ).then(() => {
145
+ let module: Module | Newable<Module> | NewableModule<Module>;
142
146
 
143
- case I18nEnvironments.Browser:
144
- module = I18nextBrowserLanguageDetector;
145
- break;
147
+ switch (environment) {
148
+ case I18nEnvironments.CLI:
149
+ // TODO Refactor when https://github.com/neet/i18next-cli-language-detector/issues/281 resolved.
150
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Per above.
151
+ module = I18nextCLILanguageDetector as unknown as LanguageDetectorModule;
152
+ break;
146
153
 
147
- default:
148
- throw new Error("Not supported");
149
- }
154
+ case I18nEnvironments.Browser:
155
+ module = I18nextBrowserLanguageDetector;
156
+ break;
150
157
 
151
- await i18next.use(module).init({
152
- debug,
153
- resources: mergedResource,
154
- fallbackLng: "en",
155
- defaultNS
156
- }).then(() => {
158
+ default:
159
+ throw new Error("Not supported");
160
+ }
161
+
162
+ return module;
163
+ }).then(async module =>
164
+ i18next.use(module).init({
165
+ debug,
166
+ resources: mergedResourceBundle,
167
+ fallbackLng: "en",
168
+ defaultNS
169
+ })
170
+ ).then(() => {
157
171
  // Add toLowerCase function.
158
172
  i18next.services.formatter?.add("toLowerCase", value => typeof value === "string" ? toLowerCase(value) : String(value));
159
173
  });
160
174
  }
175
+
176
+ return defaultResourceBundle;
177
+ }
178
+
179
+ /**
180
+ * Initialize internationalization.
181
+ *
182
+ * @param environment
183
+ * Environment in which the application is running.
184
+ *
185
+ * @param debug
186
+ * Debug setting.
187
+ *
188
+ * @returns
189
+ * Core resource bundle.
190
+ */
191
+ export async function i18nCoreInit(environment: I18nEnvironment, debug = false): Promise<Resource> {
192
+ return i18nInit(i18nextCore, environment, debug, coreNS, coreResourceBundle);
161
193
  }
package/src/logger.ts CHANGED
@@ -67,10 +67,12 @@ export function logLevelOf(untypedLogLevel?: string | number): LogLevel {
67
67
  * [`tslog`](https://tslog.js.org/).
68
68
  *
69
69
  * @param logLevel
70
- * Log level as enumeration value or string. Mapped to `minLevel` in settings.
70
+ * Log level as enumeration value or string. Mapped to `minLevel` and sets `hideLogPositionForProduction` to true in
71
+ * settings if at {@linkcode LogLevels.Info} or higher. Default is {@linkcode LogLevels.Info}.
71
72
  *
72
73
  * @param settings
73
- * Detailed settings. See [`tslog`](https://tslog.js.org/#/?id=settings) documentation for details.
74
+ * Detailed settings. See [`tslog`](https://tslog.js.org/#/?id=settings) documentation for details. The `minLevel` is
75
+ * ignored in favour of `logLevel` but `hideLogPositionForProduction` will override the default logic.
74
76
  *
75
77
  * @param logObj
76
78
  * Default log object. See [`tslog`](https://tslog.js.org/#/?id=defining-and-accessing-logobj) documentation for
@@ -83,9 +85,14 @@ export function logLevelOf(untypedLogLevel?: string | number): LogLevel {
83
85
  * Log object type.
84
86
  */
85
87
  export function getLogger<T extends object = object>(logLevel?: string | number, settings?: ISettingsParam<T>, logObj?: T): Logger<T> {
88
+ const minLevel = logLevelOf(logLevel);
89
+
86
90
  return new Logger({
91
+ // Hiding log position for production can be overridden in settings parameter.
92
+ hideLogPositionForProduction: minLevel >= LogLevels.Info,
87
93
  ...settings ?? {},
88
- minLevel: logLevelOf(logLevel)
94
+ // Minimum log level overrides settings parameter.
95
+ minLevel
89
96
  }, logObj);
90
97
  }
91
98