jopi-toolkit 3.0.5 → 3.0.10

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 (114) hide show
  1. package/README.md +1 -1
  2. package/dist/jk_crypto/jBundler_ifServer.d.ts +2 -2
  3. package/dist/jk_crypto/jBundler_ifServer.js +8 -8
  4. package/dist/jk_crypto/jBundler_ifServer.js.map +1 -1
  5. package/dist/jk_events/index.d.ts +5 -5
  6. package/dist/jk_events/index.js +20 -10
  7. package/dist/jk_events/index.js.map +1 -1
  8. package/dist/jk_fs/jBundler_ifBrowser.d.ts +2 -2
  9. package/dist/jk_fs/jBundler_ifBrowser.js +2 -2
  10. package/dist/jk_fs/jBundler_ifServer.d.ts +39 -3
  11. package/dist/jk_fs/jBundler_ifServer.js +152 -3
  12. package/dist/jk_fs/jBundler_ifServer.js.map +1 -1
  13. package/dist/jk_logs/index.d.ts +54 -0
  14. package/dist/jk_logs/index.js +316 -0
  15. package/dist/jk_logs/index.js.map +1 -0
  16. package/dist/jk_logs/jBundler_ifBrowser.js.map +1 -0
  17. package/dist/jk_logs/jBundler_ifServer.d.ts +2 -0
  18. package/dist/jk_logs/jBundler_ifServer.js +25 -0
  19. package/dist/jk_logs/jBundler_ifServer.js.map +1 -0
  20. package/dist/jk_schemas/index.js +2 -0
  21. package/dist/jk_schemas/index.js.map +1 -1
  22. package/dist/jk_timer/index.js +9 -4
  23. package/dist/jk_timer/index.js.map +1 -1
  24. package/dist/jk_tools/common.d.ts +29 -0
  25. package/dist/jk_tools/common.js +89 -0
  26. package/dist/jk_tools/common.js.map +1 -0
  27. package/dist/jk_tools/index.d.ts +1 -20
  28. package/dist/jk_tools/index.js +1 -71
  29. package/dist/jk_tools/index.js.map +1 -1
  30. package/dist/jk_tools/jBundler_ifBrowser.d.ts +1 -0
  31. package/dist/jk_tools/jBundler_ifBrowser.js +2 -0
  32. package/dist/jk_tools/jBundler_ifBrowser.js.map +1 -0
  33. package/dist/jk_tools/jBundler_ifServer.d.ts +22 -0
  34. package/dist/jk_tools/jBundler_ifServer.js +75 -0
  35. package/dist/jk_tools/jBundler_ifServer.js.map +1 -0
  36. package/package.json +11 -4
  37. package/src/jk_crypto/jBundler_ifServer.ts +8 -8
  38. package/src/jk_events/index.js +17 -7
  39. package/src/jk_events/index.ts +24 -3
  40. package/src/jk_fs/jBundler_ifBrowser.ts +2 -2
  41. package/src/jk_fs/jBundler_ifServer.js +552 -0
  42. package/src/jk_fs/jBundler_ifServer.ts +171 -4
  43. package/src/jk_logs/index.ts +444 -0
  44. package/src/jk_logs/jBundler_ifBrowser.ts +2 -0
  45. package/src/jk_logs/jBundler_ifServer.ts +27 -0
  46. package/src/jk_thread/common.js +7 -0
  47. package/src/jk_tools/common.js +101 -0
  48. package/src/jk_tools/common.ts +99 -0
  49. package/src/jk_tools/index.js +1 -82
  50. package/src/jk_tools/index.ts +1 -82
  51. package/src/jk_tools/jBundler_ifBrowser.ts +1 -0
  52. package/src/jk_tools/jBundler_ifServer.js +167 -0
  53. package/src/jk_tools/jBundler_ifServer.ts +109 -0
  54. package/src/jk_what/jBundler_ifServer.js +5 -0
  55. package/dist/jk_appResolver/common.d.ts +0 -40
  56. package/dist/jk_appResolver/common.js +0 -306
  57. package/dist/jk_appResolver/common.js.map +0 -1
  58. package/dist/jk_appResolver/index.d.ts +0 -30
  59. package/dist/jk_appResolver/index.js +0 -276
  60. package/dist/jk_appResolver/index.js.map +0 -1
  61. package/dist/jk_appResolver/jBundler_ifBrowser.js.map +0 -1
  62. package/dist/jk_appResolver/jBundler_ifServer.d.ts +0 -1
  63. package/dist/jk_appResolver/jBundler_ifServer.js +0 -9
  64. package/dist/jk_appResolver/jBundler_ifServer.js.map +0 -1
  65. package/dist/jk_linker/TypeComposite.d.ts +0 -12
  66. package/dist/jk_linker/TypeComposite.js +0 -112
  67. package/dist/jk_linker/TypeComposite.js.map +0 -1
  68. package/dist/jk_linker/arobaseType_List.d.ts +0 -44
  69. package/dist/jk_linker/arobaseType_List.js +0 -183
  70. package/dist/jk_linker/arobaseType_List.js.map +0 -1
  71. package/dist/jk_linker/arobaseTypes.d.ts +0 -45
  72. package/dist/jk_linker/arobaseTypes.js +0 -181
  73. package/dist/jk_linker/arobaseTypes.js.map +0 -1
  74. package/dist/jk_linker/binding.d.ts +0 -1
  75. package/dist/jk_linker/binding.js +0 -13
  76. package/dist/jk_linker/binding.js.map +0 -1
  77. package/dist/jk_linker/engine.d.ts +0 -119
  78. package/dist/jk_linker/engine.js +0 -553
  79. package/dist/jk_linker/engine.js.map +0 -1
  80. package/dist/jk_linker/index.d.ts +0 -1
  81. package/dist/jk_linker/index.js +0 -2
  82. package/dist/jk_linker/index.js.map +0 -1
  83. package/dist/jk_linker/install.d.ts +0 -4
  84. package/dist/jk_linker/install.js +0 -44
  85. package/dist/jk_linker/install.js.map +0 -1
  86. package/dist/jk_linker/jBundler_ifServer.d.ts +0 -3
  87. package/dist/jk_linker/jBundler_ifServer.js +0 -4
  88. package/dist/jk_linker/jBundler_ifServer.js.map +0 -1
  89. package/dist/jk_linker/modulesInitProcessor.d.ts +0 -7
  90. package/dist/jk_linker/modulesInitProcessor.js +0 -36
  91. package/dist/jk_linker/modulesInitProcessor.js.map +0 -1
  92. package/dist/jk_linker/typeChunks.d.ts +0 -15
  93. package/dist/jk_linker/typeChunks.js +0 -42
  94. package/dist/jk_linker/typeChunks.js.map +0 -1
  95. package/dist/jk_linker/typeComposites.d.ts +0 -13
  96. package/dist/jk_linker/typeComposites.js +0 -121
  97. package/dist/jk_linker/typeComposites.js.map +0 -1
  98. package/dist/jk_linker/typeEvents.d.ts +0 -5
  99. package/dist/jk_linker/typeEvents.js +0 -29
  100. package/dist/jk_linker/typeEvents.js.map +0 -1
  101. package/dist/jk_linker/typeList.d.ts +0 -30
  102. package/dist/jk_linker/typeList.js +0 -144
  103. package/dist/jk_linker/typeList.js.map +0 -1
  104. package/dist/jk_linker/typeListeners.d.ts +0 -21
  105. package/dist/jk_linker/typeListeners.js +0 -188
  106. package/dist/jk_linker/typeListeners.js.map +0 -1
  107. package/dist/jk_linker/typeReplaces.d.ts +0 -8
  108. package/dist/jk_linker/typeReplaces.js +0 -41
  109. package/dist/jk_linker/typeReplaces.js.map +0 -1
  110. package/dist/jk_registry/index.d.ts +0 -11
  111. package/dist/jk_registry/index.js +0 -36
  112. package/dist/jk_registry/index.js.map +0 -1
  113. /package/dist/{jk_appResolver → jk_logs}/jBundler_ifBrowser.d.ts +0 -0
  114. /package/dist/{jk_appResolver → jk_logs}/jBundler_ifBrowser.js +0 -0
@@ -1,13 +1,15 @@
1
1
  // noinspection JSUnusedGlobalSymbols
2
2
 
3
3
  import fs from "node:fs/promises";
4
- import fss, {createReadStream} from "node:fs";
4
+ import fss, {createReadStream, createWriteStream} from "node:fs";
5
5
  import {fileURLToPath as n_fileURLToPath, pathToFileURL as n_pathToFileURL } from "node:url";
6
6
  import {lookup} from "mime-types";
7
7
  import {Readable} from "node:stream";
8
8
  import path from "node:path";
9
+ import {createHash} from "node:crypto";
9
10
  import {isBunJS} from "jopi-toolkit/jk_what";
10
11
  import type {DirItem, FileState} from "./common.ts";
12
+ import AdmZip from 'adm-zip';
11
13
 
12
14
  class WebToNodeReadableStreamAdapter extends Readable {
13
15
  private webStreamReader: ReadableStreamDefaultReader<any>;
@@ -170,7 +172,7 @@ export async function writeTextToFile(filePath: string, text: string, createDir:
170
172
  await fs.writeFile(filePath, text, {encoding: 'utf8', flag: 'w'});
171
173
  }
172
174
 
173
- export function writeTextSyncToFile(filePath: string, text: string, createDir: boolean = true): void {
175
+ export function writeTextToFileSync(filePath: string, text: string, createDir: boolean = true): void {
174
176
  if (createDir) {
175
177
  try {
176
178
  fss.mkdirSync(path.dirname(filePath), {recursive: true});
@@ -183,7 +185,12 @@ export function readTextFromFile(filePath: string): Promise<string> {
183
185
  return fs.readFile(filePath, 'utf8');
184
186
  }
185
187
 
186
- export function readTextSyncFromFile(filePath: string): string {
188
+ export async function readJsonFromFile<T = any>(filePath: string): Promise<T> {
189
+ let txt = await fs.readFile(filePath, 'utf8');
190
+ return JSON.parse(txt) as T;
191
+ }
192
+
193
+ export function readTextFromFileSync(filePath: string): string {
187
194
  return fss.readFileSync(filePath, 'utf8');
188
195
  }
189
196
 
@@ -287,6 +294,56 @@ export async function listDir(dirPath: string): Promise<DirItem[]> {
287
294
  return result;
288
295
  }
289
296
 
297
+ const MEGA = 1024 * 1024;
298
+
299
+ async function calcFileHash_bun(filePath: string): Promise<string|undefined> {
300
+ const file = Bun.file(filePath);
301
+ if (!await file.exists()) return undefined;
302
+
303
+ if (file.size>10 * MEGA) {
304
+ return calcFileHash_bun_streamed(file)
305
+ }
306
+
307
+ return Bun.hash(await file.arrayBuffer(), 12346).toString();
308
+ }
309
+
310
+ async function calcFileHash_bun_streamed(file: Bun.BunFile): Promise<string|undefined> {
311
+ const stream = file.stream();
312
+ const reader = stream.getReader();
313
+ const hasher = new Bun.CryptoHasher("sha256");
314
+
315
+ try {
316
+ while (true) {
317
+ const { done, value } = await reader.read();
318
+ if (done) break;
319
+ hasher.update(value);
320
+ }
321
+
322
+ return hasher.digest("hex");
323
+ } finally {
324
+ reader.releaseLock();
325
+ }
326
+ }
327
+
328
+ function calcFileHash_node(filePath: string): Promise<string|undefined> {
329
+ if (!isFile(filePath)) return Promise.resolve(undefined);
330
+
331
+ return new Promise((resolve, reject) => {
332
+ const hash = createHash('sha256');
333
+ const stream = createReadStream(filePath);
334
+ stream.on('data', (data) => hash.update(data));
335
+ stream.on('end', () => resolve(hash.digest('hex')));
336
+ stream.on('error', (error) => reject(error));
337
+ });
338
+ }
339
+
340
+ /**
341
+ * Calculate the hash of a file.
342
+ * Allows using it for HTTP ETag or another change proof.
343
+ * This version is optimized to use streams and avoid loading the whole file in memory.
344
+ */
345
+ export const calcFileHash = isBunJS ? calcFileHash_bun : calcFileHash_node;
346
+
290
347
  /**
291
348
  * Convert a simple win32 path to a linux path.
292
349
  */
@@ -294,6 +351,114 @@ export function win32ToLinuxPath(filePath: string): string {
294
351
  return filePath.replace(/\\/g, '/');
295
352
  }
296
353
 
354
+ /**
355
+ * Copy a directory recursively.
356
+ * Is optimized for large files.
357
+ */
358
+ export async function copyDirectory(srcDir: string, destDir: string): Promise<void> {
359
+ if (!await isDirectory(srcDir)) {
360
+ throw new Error(`Directory doesn't exist : ${srcDir}`);
361
+ }
362
+
363
+ await mkDir(destDir);
364
+ const entries = await fs.readdir(srcDir, { withFileTypes: true });
365
+
366
+ await Promise.all(entries.map(async (entry) => {
367
+ const srcPath = path.join(srcDir, entry.name);
368
+ const destPath = path.join(destDir, entry.name);
369
+
370
+ if (entry.isDirectory()) {
371
+ await copyDirectory(srcPath, destPath);
372
+ } else {
373
+ try {
374
+ await copyFile(srcPath, destPath);
375
+ } catch {
376
+ console.warn(`jk_fs.copyDirectory - Failed to copy file ${srcPath}`);
377
+ }
378
+ }
379
+ }));
380
+ }
381
+
382
+ /**
383
+ * Copy of a file.
384
+ * Is optimized for large files.
385
+ */
386
+ export async function copyFile(srcPath: string, destPath: string): Promise<void> {
387
+ let stat = await getFileStat(srcPath);
388
+ if (!stat) return;
389
+
390
+ // Assert the symlink exist.
391
+ if (stat.isSymbolicLink()) {
392
+ const symStat = await fs.lstat(srcPath);
393
+ if (!symStat) return;
394
+ if (!symStat.isFile()) return;
395
+ }
396
+
397
+ return new Promise<void>((resolve, reject) => {
398
+ const readStream = createReadStream(srcPath);
399
+ const writeStream = createWriteStream(destPath);
400
+
401
+ readStream.on('error', reject);
402
+ writeStream.on('error', reject);
403
+ writeStream.on('finish', resolve);
404
+
405
+ readStream.pipe(writeStream);
406
+ });
407
+ }
408
+
409
+ /**
410
+ * Unzip a .zip file in an optimized way.
411
+ * Note was using : "@types/unzipper": "^0.10.11"
412
+ * which has some bug, files/folders was forgottens.
413
+ * import * as unzipper from "unzipper";
414
+ */
415
+ /*export async function unzipFile_old(zipFilePath: string, outputDir: string): Promise<void> {
416
+ if (!await isFile(zipFilePath)) {
417
+ throw new Error(`File doesn't exist : ${zipFilePath}`);
418
+ }
419
+
420
+ if (!await isDirectory(outputDir)) {
421
+ await mkDir(outputDir);
422
+ }
423
+
424
+ await createReadStream(zipFilePath)
425
+ .pipe(unzipper.Extract({path: outputDir}))
426
+ .promise();
427
+ }*/
428
+
429
+ /**
430
+ * Unzip a .zip file in an optimized way.
431
+ */
432
+ export async function unzipFile(zipFilePath: string, outputDir: string): Promise<void> {
433
+ if (!await isFile(zipFilePath)) {
434
+ throw new Error(`File doesn't exist : ${zipFilePath}`);
435
+ }
436
+
437
+ if (!await isDirectory(outputDir)) {
438
+ await mkDir(outputDir);
439
+ }
440
+
441
+ const zip = new AdmZip(zipFilePath);
442
+ zip.extractAllTo(outputDir, true);
443
+ }
444
+
445
+ /**
446
+ * Create a temporary directory.
447
+ * Return an object containing the directory path and a cleanup function.
448
+ */
449
+ export async function createTempDir(prefix: string): Promise<{path: string, remove: ()=>Promise<void>}> {
450
+ const dirPath = await fs.mkdtemp(prefix);
451
+
452
+ return {
453
+ path: dirPath,
454
+ remove: async () => {
455
+ return fs.rm(dirPath, {recursive: true, force: true});
456
+ }
457
+ }
458
+ }
459
+
460
+ //region Node.js functions
461
+
297
462
  export const join = path.join;
298
463
  export const resolve = path.resolve;
299
464
  export const dirname = path.dirname;
@@ -305,4 +470,6 @@ export const normalize = path.normalize;
305
470
  export const basename = path.basename;
306
471
 
307
472
  export const symlink = fs.symlink;
308
- export const rename = fs.rename;
473
+ export const rename = fs.rename;
474
+
475
+ //endregion
@@ -0,0 +1,444 @@
1
+ // noinspection JSUnusedGlobalSymbols
2
+
3
+ import * as jk_terms from "jopi-toolkit/jk_term";
4
+ import {init} from "./jBundler_ifServer.ts";
5
+
6
+ //region Common
7
+
8
+ export interface LogEntry {
9
+ level: LogLevel;
10
+ logger: string;
11
+
12
+ date: number;
13
+ title?: string;
14
+ data?: any;
15
+
16
+ timeDif?: number;
17
+ }
18
+
19
+ export type LogEntryFormater = (entry: LogEntry) => string;
20
+
21
+ export enum LogLevel {
22
+ SPAM = 1,
23
+ INFO = 2,
24
+ WARN = 3,
25
+ ERROR = 4,
26
+ NONE = 10
27
+ }
28
+
29
+ export type LogCall = string | ((w: LogLevelHandler)=>void);
30
+
31
+ //endregion
32
+
33
+ //region Formater
34
+
35
+ const RED = jk_terms.C_RED;
36
+ const ORANGE = jk_terms.C_ORANGE;
37
+ const GREY = jk_terms.C_GREY;
38
+ const LIGHT_BLUE = jk_terms.C_LIGHT_BLUE;
39
+ const RESET = jk_terms.T_RESET;
40
+
41
+ export function formatDate1(timeStamp: number): string {
42
+ const date = new Date(timeStamp);
43
+ return date.toISOString();
44
+ }
45
+
46
+ export const formater_simpleJson: LogEntryFormater = (entry: LogEntry) => {
47
+ return JSON.stringify(entry);
48
+ };
49
+
50
+ export const formater_dateTypeTitleSourceData: LogEntryFormater = (entry: LogEntry) => {
51
+ const date = formatDate1(entry.date);
52
+
53
+ let json = entry.data ? JSON.stringify(entry.data) : "";
54
+ const title = (entry.title || "").padEnd(50, " ");
55
+
56
+ json = entry.logger + " |>" + json;
57
+
58
+ switch (entry.level) {
59
+ case LogLevel.ERROR:
60
+ return `${date} - ERROR - ${title}${json}`;
61
+ case LogLevel.WARN:
62
+ return `${date} - WARN - ${title}${json}`;
63
+ case LogLevel.INFO:
64
+ return `${date} - INFO - ${title}${json}`;
65
+ case LogLevel.SPAM:
66
+ return `${date} - SPAM - ${title}${json}`;
67
+ default:
68
+ return "";
69
+ }
70
+ }
71
+
72
+ export const formater_typeTitleSourceData_colored: LogEntryFormater = (entry: LogEntry) => {
73
+ let json = entry.data ? JSON.stringify(entry.data) : "";
74
+ const title = (entry.title || "").padEnd(50, " ");
75
+
76
+ json = entry.timeDif === undefined
77
+ ? `${entry.logger} ${json}` : `${entry.logger} (${entry.timeDif} ms) ${json}`;
78
+
79
+ switch (entry.level) {
80
+ case LogLevel.ERROR:
81
+ return `${RED}error${RESET} - ${title}${GREY}${json}${RESET}`;
82
+ case LogLevel.WARN:
83
+ return `${ORANGE}warn ${RESET} - ${title}${GREY}${json}${RESET}`;
84
+ case LogLevel.INFO:
85
+ return `${LIGHT_BLUE}info ${RESET} - ${title}${GREY}${json}${RESET}`;
86
+ case LogLevel.SPAM:
87
+ return `${GREY}spam ${RESET} - ${title}${GREY}${json}${RESET}`;
88
+ default:
89
+ return "";
90
+ }
91
+ }
92
+
93
+ //endregion
94
+
95
+ //region LogWriter
96
+
97
+ export interface LogWriter {
98
+ addEntry(entry: LogEntry): void;
99
+ addBatch(entries: LogEntry[]): void;
100
+ }
101
+
102
+ class ConsoleLogWriter implements LogWriter {
103
+ constructor(private readonly formater: LogEntryFormater = gDefaultFormater) {
104
+ }
105
+
106
+ addEntry(entry: LogEntry): void {
107
+ console.log(this.formater(entry));
108
+ }
109
+
110
+ addBatch(entries: LogEntry[]) {
111
+ entries.forEach(e => this.addEntry(e));
112
+ }
113
+ }
114
+
115
+ export class VoidLogWriter implements LogWriter {
116
+ addBatch(_entries: LogEntry[]): void {
117
+ }
118
+
119
+ addEntry(_entry: LogEntry): void {
120
+ }
121
+ }
122
+
123
+ export function setDefaultWriter(writer: LogWriter) {
124
+ gDefaultWriter = writer;
125
+ }
126
+
127
+ export function getDefaultWriter(): LogWriter {
128
+ return gDefaultWriter;
129
+ }
130
+
131
+ export function setDefaultFormater(formater: LogEntryFormater) {
132
+ gDefaultFormater = formater;
133
+ }
134
+
135
+ export function getDefaultFormater(): LogEntryFormater {
136
+ return gDefaultFormater;
137
+ }
138
+
139
+ let gDefaultFormater: LogEntryFormater = formater_typeTitleSourceData_colored;
140
+ let gDefaultWriter: LogWriter = new ConsoleLogWriter();
141
+
142
+ //endregion
143
+
144
+ //region JopiLogger
145
+
146
+ export interface Logger {
147
+ get fullName(): string;
148
+
149
+ spam(_l?: LogCall): boolean;
150
+ info(_l?: LogCall): boolean;
151
+ warn(_l?: LogCall): boolean;
152
+ error(_l?: LogCall): boolean
153
+
154
+ beginSpam(l: LogCall): LoggerGroupCallback;
155
+ beginInfo(l: LogCall): LoggerGroupCallback;
156
+ }
157
+
158
+ export function getLogger(name: string, parent?: Logger): Logger {
159
+ let fullName = name;
160
+ if (parent) fullName = parent.fullName + '.' + name;
161
+
162
+ let level = getLogLevelFor(fullName);
163
+
164
+ switch (level) {
165
+ case LogLevel.SPAM:
166
+ return new Logger_Spam(parent as JopiLogger, name);
167
+ case LogLevel.INFO:
168
+ return new Logger_Info(parent as JopiLogger, name);
169
+ case LogLevel.WARN:
170
+ return new Logger_Warn(parent as JopiLogger, name);
171
+ case LogLevel.ERROR:
172
+ return new Logger_Error(parent as JopiLogger, name);
173
+ }
174
+
175
+ return new Logger_None(parent as JopiLogger, name);
176
+ }
177
+
178
+ abstract class JopiLogger implements Logger {
179
+ public readonly fullName: string;
180
+ private _onLog: LogWriter = gDefaultWriter;
181
+
182
+ protected readonly hSpam: LogLevelHandler;
183
+ protected readonly hInfo: LogLevelHandler;
184
+ protected readonly hWarn: LogLevelHandler;
185
+ protected readonly hError: LogLevelHandler;
186
+
187
+ private timeDif?: number;
188
+ private extraData?: any;
189
+
190
+ constructor(parent: JopiLogger|null, public readonly name: string) {
191
+ this.fullName = parent ? parent.fullName + '.' + name : name;
192
+
193
+ if (parent) {
194
+ this._onLog = parent._onLog;
195
+ }
196
+
197
+ const me = this;
198
+
199
+ this.hSpam = (title?: string, data?: any) => {
200
+ let td = this.timeDif;
201
+ this.timeDif = undefined;
202
+ data = this.mergeData(data);
203
+
204
+ me._onLog.addEntry({
205
+ level: LogLevel.SPAM,
206
+ logger: me.fullName, date: Date.now(), title, data, timeDif: td });
207
+ };
208
+
209
+ this.hInfo = (title?: string, data?: any) => {
210
+ let td = this.timeDif;
211
+ this.timeDif = undefined;
212
+ data = this.mergeData(data);
213
+
214
+ me._onLog.addEntry({
215
+ level: LogLevel.INFO,
216
+ logger: me.fullName, date: Date.now(), title, data, timeDif: td });
217
+ };
218
+
219
+ this.hWarn = (title?: string, data?: any) => {
220
+ let td = this.timeDif;
221
+ this.timeDif = undefined;
222
+ data = this.mergeData(data);
223
+
224
+ me._onLog.addEntry({
225
+ level: LogLevel.WARN,
226
+ logger: me.fullName, date: Date.now(), title, data, timeDif: td });
227
+ };
228
+
229
+ this.hError = (title?: string, data?: any) => {
230
+ let td = this.timeDif;
231
+ this.timeDif = undefined;
232
+ data = this.mergeData(data);
233
+
234
+ me._onLog.addEntry({
235
+ level: LogLevel.ERROR,
236
+ logger: me.fullName, date: Date.now(), title, data, timeDif: td });
237
+ };
238
+ }
239
+
240
+ private mergeData(data?: any): any|undefined {
241
+ if (!this.extraData) return data;
242
+ const extraData = this.extraData;
243
+ this.extraData = undefined;
244
+
245
+ if (!data) return extraData;
246
+ for (let p in extraData) data[p] = extraData[p];
247
+
248
+ return data;
249
+ }
250
+
251
+ setLogWriter(callback: LogWriter) {
252
+ if (!callback) callback = gDefaultWriter;
253
+ this._onLog = callback;
254
+ }
255
+
256
+ spam(_l?: (w: LogLevelHandler)=>void): boolean {
257
+ return false;
258
+ }
259
+
260
+ info(_l?: (w: LogLevelHandler)=>void): boolean {
261
+ return false;
262
+ }
263
+
264
+ warn(_l?: (w: LogLevelHandler)=>void) {
265
+ return false;
266
+ }
267
+
268
+ error(_l?: (w: LogLevelHandler)=>void) {
269
+ return false;
270
+ }
271
+
272
+ beginSpam(l: (w: LogLevelHandler)=>void): LoggerGroupCallback {
273
+ return gVoidLoggerGroupCallback;
274
+ }
275
+
276
+ beginInfo(l: (w: LogLevelHandler)=>void): LoggerGroupCallback {
277
+ return gVoidLoggerGroupCallback;
278
+ }
279
+
280
+ protected doBegin(l: LogCall, w: LogLevelHandler): LoggerGroupCallback {
281
+ const startTime = Date.now();
282
+
283
+ return (data?: any) => {
284
+ this.timeDif = Date.now() - startTime;
285
+ this.doCall(l, w, data);
286
+ }
287
+ }
288
+
289
+ protected doCall(l: LogCall|undefined, w: LogLevelHandler, data?: any) {
290
+ this.extraData = data;
291
+
292
+ if (l) {
293
+ if (l instanceof Function) {
294
+ l(w);
295
+ }
296
+ else {
297
+ w(l as string);
298
+ }
299
+ }
300
+
301
+ return true;
302
+ }
303
+ }
304
+
305
+ class Logger_None extends JopiLogger {
306
+ }
307
+
308
+ class Logger_Spam extends JopiLogger {
309
+ override spam(l?: LogCall) {
310
+ return this.doCall(l, this.hSpam);
311
+ }
312
+
313
+ override info(l?: LogCall) {
314
+ return this.doCall(l, this.hInfo);
315
+ }
316
+
317
+ override warn(l?: LogCall) {
318
+ return this.doCall(l, this.hWarn);
319
+ }
320
+
321
+ override error(l?: LogCall) {
322
+ return this.doCall(l, this.hError);
323
+ }
324
+
325
+ override beginSpam(l: LogCall) {
326
+ return this.doBegin(l, this.hSpam);
327
+ }
328
+
329
+ override beginInfo(l: LogCall): LoggerGroupCallback {
330
+ return this.doBegin(l, this.hInfo);
331
+ }
332
+ }
333
+
334
+ class Logger_Info extends JopiLogger {
335
+ override info(l?: LogCall) {
336
+ return this.doCall(l, this.hInfo);
337
+ }
338
+
339
+ override warn(l?: LogCall) {
340
+ return this.doCall(l, this.hWarn);
341
+ }
342
+
343
+ override error(l?: LogCall) {
344
+ return this.doCall(l, this.hError);
345
+ }
346
+
347
+ override beginInfo(l: LogCall): LoggerGroupCallback {
348
+ return this.doBegin(l, this.hInfo);
349
+ }
350
+ }
351
+
352
+ class Logger_Warn extends JopiLogger {
353
+ override warn(l?: LogCall) {
354
+ return this.doCall(l, this.hWarn);
355
+ }
356
+
357
+ override error(l?: LogCall) {
358
+ return this.doCall(l, this.hError);
359
+ }
360
+ }
361
+
362
+ class Logger_Error extends JopiLogger {
363
+ override error(l?: LogCall) {
364
+ return this.doCall(l, this.hError);
365
+ }
366
+ }
367
+
368
+ export type LoggerGroupCallback = (data?: any) => void;
369
+ const gVoidLoggerGroupCallback = () => {};
370
+
371
+ //endregion
372
+
373
+ //region Log levels
374
+
375
+ type LogLevelHandler = (title?: string, data?: any|undefined)=>void;
376
+
377
+ function getLogLevelName(level: LogLevel) {
378
+ switch (level) {
379
+ case LogLevel.SPAM:
380
+ return "SPAM";
381
+ case LogLevel.ERROR:
382
+ return "ERROR";
383
+ case LogLevel.INFO:
384
+ return "INFO";
385
+ case LogLevel.WARN:
386
+ return "WARN";
387
+ case LogLevel.NONE:
388
+ return "NONE";
389
+ }
390
+ }
391
+
392
+ function getLogLevelByName(name: string): LogLevel | undefined {
393
+ switch (name) {
394
+ case "NONE": return LogLevel.NONE;
395
+ case "SPAM": return LogLevel.SPAM;
396
+ case "INFO": return LogLevel.INFO;
397
+ case "WARN": return LogLevel.WARN;
398
+ case "ERROR": return LogLevel.ERROR;
399
+ }
400
+
401
+ return undefined;
402
+ }
403
+
404
+ //endregion
405
+
406
+ //region Registry
407
+
408
+ export interface LogConfig {
409
+ level?: string;
410
+ writer?: string;
411
+ formater?: string;
412
+ }
413
+
414
+ export interface LogInitializer {
415
+ setLogLevel(name: string, config: LogConfig): void;
416
+ }
417
+
418
+ class Initializer implements LogInitializer {
419
+ setLogLevel(name: string, config: LogConfig): void {
420
+ let logLevel = getLogLevelByName(config.level || "NONE");
421
+ if (!logLevel) logLevel = LogLevel.NONE;
422
+ gRegistry[name] = logLevel;
423
+ }
424
+ }
425
+
426
+ function getLogLevelFor(name: string) {
427
+ let entry = gRegistry[name];
428
+ if (entry!==undefined) return entry;
429
+
430
+ for (let prefix in gRegistry) {
431
+ if (name.startsWith(prefix + ".")) {
432
+ return gRegistry[prefix];
433
+ }
434
+ }
435
+
436
+ return gDefaultLogLevel;
437
+ }
438
+
439
+ const gDefaultLogLevel: LogLevel = LogLevel.WARN;
440
+ const gRegistry: Record<string, LogLevel> = {};
441
+
442
+ //endregion
443
+
444
+ init(new Initializer());
@@ -0,0 +1,2 @@
1
+ export function init() {
2
+ }
@@ -0,0 +1,27 @@
1
+ import * as jk_app from "jopi-toolkit/jk_app";
2
+ import * as jk_fs from "jopi-toolkit/jk_fs";
3
+ import type {LogInitializer} from "./index.ts";
4
+
5
+ export function init(init: LogInitializer) {
6
+ const mainDir = jk_app.findPackageJsonDir();
7
+ const filePath = jk_fs.join(mainDir, "logConfig.json");
8
+
9
+ if (!jk_fs.isFileSync(filePath)) return;
10
+ let text = jk_fs.readTextFromFileSync(jk_fs.join(mainDir, "logConfig.json"));
11
+
12
+ if (!text) return;
13
+ let logJson = JSON.parse(text)
14
+ if (!logJson.config) return;
15
+
16
+ for (let logName in logJson.config) {
17
+ let logConfig = logJson.config[logName];
18
+
19
+ if (typeof(logConfig)==="string") {
20
+ logConfig = {level: logConfig.toUpperCase().trim()};
21
+ } else if (!logConfig) {
22
+ logConfig = {level: "none" };
23
+ }
24
+
25
+ init.setLogLevel(logName, logConfig);
26
+ }
27
+ }
@@ -0,0 +1,7 @@
1
+ export var gIsUsingWorkers = false;
2
+ export function declareUsingWorker() {
3
+ gIsUsingWorkers = true;
4
+ }
5
+ export function isUsingWorker() {
6
+ return gIsUsingWorkers;
7
+ }