@jeffchi/logger 1.0.1 → 1.0.5
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/lib/cache.d.ts +19 -0
- package/lib/cache.js +84 -0
- package/lib/consts/defOptions.d.ts +2 -0
- package/lib/consts/defOptions.js +8 -0
- package/lib/index.d.ts +2 -2
- package/lib/index.js +29 -22
- package/lib/interface.d.ts +51 -1
- package/lib/interface.js +12 -1
- package/lib/utils/buildLogPreffix.d.ts +2 -0
- package/lib/utils/buildLogPreffix.js +27 -0
- package/lib/utils/checkLogMode.d.ts +2 -0
- package/lib/utils/checkLogMode.js +5 -0
- package/lib/utils/checkPlateform.d.ts +6 -0
- package/lib/utils/checkPlateform.js +46 -0
- package/lib/utils/noop.d.ts +2 -0
- package/lib/utils/noop.js +3 -0
- package/lib/utils/type.d.ts +3 -0
- package/lib/utils/type.js +9 -0
- package/lib/utils/writeFile.d.ts +2 -0
- package/lib/utils/writeFile.js +10 -0
- package/package.json +7 -2
package/lib/cache.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/// <reference types="lodash" />
|
|
2
|
+
export interface LogContent {
|
|
3
|
+
prefix?: string[];
|
|
4
|
+
data: any[];
|
|
5
|
+
timestamp: number;
|
|
6
|
+
}
|
|
7
|
+
/** 单例模式的缓存对像 */
|
|
8
|
+
export declare class LogCache {
|
|
9
|
+
#private;
|
|
10
|
+
lastWrite: number;
|
|
11
|
+
static get cache(): LogCache;
|
|
12
|
+
get defaultLogFile(): string;
|
|
13
|
+
private constructor();
|
|
14
|
+
push(data: LogContent, file?: string): void;
|
|
15
|
+
/** 立即写入并清空缓存 */
|
|
16
|
+
flush(file?: string): void;
|
|
17
|
+
/** 延迟写入并清空缓存 */
|
|
18
|
+
write: import("lodash").DebouncedFunc<(file: any) => void>;
|
|
19
|
+
}
|
package/lib/cache.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.LogCache = void 0;
|
|
7
|
+
const checkPlateform_1 = require("./utils/checkPlateform");
|
|
8
|
+
const date_fns_1 = require("date-fns");
|
|
9
|
+
const lodash_1 = require("lodash");
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const noop_1 = __importDefault(require("./utils/noop"));
|
|
12
|
+
const type_1 = require("./utils/type");
|
|
13
|
+
/** 单例模式的缓存对像 */
|
|
14
|
+
class LogCache {
|
|
15
|
+
static #cache = new LogCache();
|
|
16
|
+
lastWrite = Date.now();
|
|
17
|
+
#map;
|
|
18
|
+
#fs;
|
|
19
|
+
static get cache() {
|
|
20
|
+
return LogCache.#cache;
|
|
21
|
+
}
|
|
22
|
+
get defaultLogFile() {
|
|
23
|
+
return `logs/${(0, date_fns_1.format)(Date.now(), 'yyyy-MM-dd')}.log`;
|
|
24
|
+
}
|
|
25
|
+
constructor() {
|
|
26
|
+
this.#map = new Map();
|
|
27
|
+
(0, checkPlateform_1.checkPlatform)().then((fs) => {
|
|
28
|
+
this.#fs = fs;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
push(data, file) {
|
|
32
|
+
file = file || this.defaultLogFile;
|
|
33
|
+
let set = this.#map.get(file);
|
|
34
|
+
if (!set) {
|
|
35
|
+
set = new Set();
|
|
36
|
+
this.#map.set(file, set);
|
|
37
|
+
}
|
|
38
|
+
const now = Date.now();
|
|
39
|
+
if (set.add(data).size > 1000 || now - this.lastWrite > 30000) {
|
|
40
|
+
this.flush(file);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
this.write(file);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** 立即写入并清空缓存 */
|
|
47
|
+
flush(file) {
|
|
48
|
+
if (!this.#fs)
|
|
49
|
+
return;
|
|
50
|
+
this.#map.forEach((set, key) => {
|
|
51
|
+
if (!set)
|
|
52
|
+
return;
|
|
53
|
+
if ((file === null && key === this.defaultLogFile) || !file || key === file) {
|
|
54
|
+
const list = Array.from(set);
|
|
55
|
+
set.clear();
|
|
56
|
+
this.#writeLogFile(key, list);
|
|
57
|
+
this.lastWrite = Date.now();
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
/** 延迟写入并清空缓存 */
|
|
62
|
+
write = (0, lodash_1.debounce)((file) => this.flush(file), 1000);
|
|
63
|
+
/** 检查日志文件的路径,如果目录不存在,则创建,最好返回有效的日志文件,如果文件已存在,则追加日志数据 */
|
|
64
|
+
#checkFolder(output) {
|
|
65
|
+
const paths = path_1.default.dirname(output || this.defaultLogFile);
|
|
66
|
+
const { existsSync, mkdirSync } = this.#fs || {};
|
|
67
|
+
if (!existsSync?.(paths)) {
|
|
68
|
+
mkdirSync?.(paths);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
#writeLogFile(outputFile, content) {
|
|
72
|
+
if (!(0, type_1.isArray)(content)) {
|
|
73
|
+
content = [content];
|
|
74
|
+
}
|
|
75
|
+
outputFile = outputFile || this.defaultLogFile;
|
|
76
|
+
this.#checkFolder(outputFile);
|
|
77
|
+
const { writeFile } = this.#fs || {};
|
|
78
|
+
if (outputFile && writeFile) {
|
|
79
|
+
const list = content.reduce((o, { prefix = [], data }) => [...o, [...prefix, ...data.map(JSON.stringify), '\n'].join(' ')], []);
|
|
80
|
+
writeFile?.(outputFile, list.join(''), { flag: 'a' }, noop_1.default);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.LogCache = LogCache;
|
package/lib/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { ILogger, ILogOptions } from './interface';
|
|
2
|
-
export declare const loggerWithTags: (tags:
|
|
1
|
+
import { ILogger, ILogOptions, LogTags } from './interface';
|
|
2
|
+
export declare const loggerWithTags: (tags: LogTags, options?: ILogOptions) => ILogger;
|
package/lib/index.js
CHANGED
|
@@ -1,40 +1,47 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.loggerWithTags = void 0;
|
|
4
|
-
const
|
|
4
|
+
const cache_1 = require("./cache");
|
|
5
|
+
const defOptions_1 = require("./consts/defOptions");
|
|
5
6
|
const interface_1 = require("./interface");
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
env: interface_1.LogMode.ALL,
|
|
10
|
-
};
|
|
7
|
+
const buildLogPreffix_1 = require("./utils/buildLogPreffix");
|
|
8
|
+
const checkLogMode_1 = require("./utils/checkLogMode");
|
|
9
|
+
const type_1 = require("./utils/type");
|
|
11
10
|
const loggerWithTags = (tags, options) => {
|
|
12
|
-
if (!
|
|
11
|
+
if (!(0, type_1.isArray)(tags)) {
|
|
13
12
|
tags = [tags];
|
|
14
13
|
}
|
|
15
|
-
const { env, ...mergedOptions } = { ...defOptions, ...(options || {}) };
|
|
14
|
+
const { env, outputFile, ...mergedOptions } = { ...defOptions_1.defOptions, ...(options || {}) };
|
|
16
15
|
const debug = (...rest) => {
|
|
17
|
-
const prefix = (0,
|
|
18
|
-
(0,
|
|
16
|
+
const prefix = (0, buildLogPreffix_1.buildLogPreffix)(tags, { level: interface_1.LogLevel.DEBUG, ...mergedOptions });
|
|
17
|
+
(0, checkLogMode_1.checkLogMode)(env || interface_1.LogMode.ALL) && console.debug([...prefix, ...rest]);
|
|
18
|
+
cache_1.LogCache.cache.push({ prefix, timestamp: Date.now(), data: [...rest] }, outputFile);
|
|
19
19
|
};
|
|
20
20
|
const info = (...rest) => {
|
|
21
|
-
const prefix = (0,
|
|
22
|
-
(0,
|
|
21
|
+
const prefix = (0, buildLogPreffix_1.buildLogPreffix)(tags, { level: interface_1.LogLevel.INFO, ...mergedOptions });
|
|
22
|
+
(0, checkLogMode_1.checkLogMode)(env || interface_1.LogMode.ALL) && console.info([...prefix, ...rest]);
|
|
23
|
+
cache_1.LogCache.cache.push({ prefix, timestamp: Date.now(), data: [...rest] }, outputFile);
|
|
23
24
|
};
|
|
24
25
|
const log = (...rest) => {
|
|
25
|
-
const prefix = (0,
|
|
26
|
-
(0,
|
|
27
|
-
|
|
26
|
+
const prefix = (0, buildLogPreffix_1.buildLogPreffix)(tags, mergedOptions);
|
|
27
|
+
(0, checkLogMode_1.checkLogMode)(env || interface_1.LogMode.ALL) && console.log([...prefix, ...rest]);
|
|
28
|
+
cache_1.LogCache.cache.push({ prefix, timestamp: Date.now(), data: [...rest] }, outputFile);
|
|
28
29
|
};
|
|
29
30
|
const warn = (...rest) => {
|
|
30
|
-
const prefix = (0,
|
|
31
|
-
|
|
31
|
+
const prefix = (0, buildLogPreffix_1.buildLogPreffix)(tags, { level: interface_1.LogLevel.WARN, ...mergedOptions });
|
|
32
|
+
const { disableError } = mergedOptions;
|
|
33
|
+
const out = disableError ? console.debug : console.warn;
|
|
34
|
+
(0, checkLogMode_1.checkLogMode)(env || interface_1.LogMode.ALL) && out([...prefix, ...rest]);
|
|
35
|
+
cache_1.LogCache.cache.push({ prefix, timestamp: Date.now(), data: [...rest] }, outputFile);
|
|
32
36
|
};
|
|
33
|
-
const error = (msg) => {
|
|
34
|
-
const prefix = (0,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
const error = (msg, cause) => {
|
|
38
|
+
const prefix = (0, buildLogPreffix_1.buildLogPreffix)(tags, { level: interface_1.LogLevel.ERROR, ...mergedOptions });
|
|
39
|
+
const { ignoreThrow, disableError } = mergedOptions;
|
|
40
|
+
const out = disableError ? console.debug : console.error;
|
|
41
|
+
(0, checkLogMode_1.checkLogMode)(env || interface_1.LogMode.ALL) && out([...prefix, msg]);
|
|
42
|
+
cache_1.LogCache.cache.push({ prefix, timestamp: Date.now(), data: [msg] }, outputFile);
|
|
43
|
+
if (!ignoreThrow) {
|
|
44
|
+
throw new Error(msg, { cause });
|
|
38
45
|
}
|
|
39
46
|
};
|
|
40
47
|
return { debug, info, log, warn, error };
|
package/lib/interface.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
export type PathLike = string | Buffer | URL;
|
|
1
3
|
/**
|
|
2
4
|
* 日志输出打印的模式
|
|
3
5
|
* @default LogMode.ALL
|
|
@@ -8,13 +10,28 @@ export declare enum LogMode {
|
|
|
8
10
|
DEVELOPMENET = "development",
|
|
9
11
|
NONE = "none"
|
|
10
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* 日志级别
|
|
15
|
+
*/
|
|
16
|
+
export declare enum LogLevel {
|
|
17
|
+
LOG = "LOG",
|
|
18
|
+
WARN = "WARN",
|
|
19
|
+
INFO = "INFO",
|
|
20
|
+
ERROR = "ERROR",
|
|
21
|
+
DEBUG = "DEBUG"
|
|
22
|
+
}
|
|
23
|
+
export type LogTags = string | string[];
|
|
11
24
|
/** 日志输入配置选项 */
|
|
12
25
|
export interface ILogOptions {
|
|
26
|
+
/** 日志级别
|
|
27
|
+
* @default LogLevel.LOG
|
|
28
|
+
*/
|
|
29
|
+
level?: LogLevel;
|
|
13
30
|
/**
|
|
14
31
|
* 是否支持输出时间戳及时间戳格式
|
|
15
32
|
*
|
|
16
33
|
* 字符串格式参见: https://github.com/date-fns/date-fns/blob/main/src/format/index.ts
|
|
17
|
-
* @default true
|
|
34
|
+
* @default true 开启后默认IOS格式 'yyyy-MM-ddTHH:mm:ss.SSSZ'
|
|
18
35
|
*/
|
|
19
36
|
date?: boolean | string;
|
|
20
37
|
/**
|
|
@@ -22,6 +39,39 @@ export interface ILogOptions {
|
|
|
22
39
|
* @default 'all'
|
|
23
40
|
*/
|
|
24
41
|
env?: LogMode;
|
|
42
|
+
/** 禁用warn输出,避免在测试场景下影响测试结果
|
|
43
|
+
* @default false
|
|
44
|
+
*/
|
|
45
|
+
disableWarn?: boolean;
|
|
46
|
+
/** 禁用error输出,避免在测试场景下打断正常测试流程
|
|
47
|
+
* @default false
|
|
48
|
+
*/
|
|
49
|
+
disableError?: boolean;
|
|
50
|
+
/** 调用error输出错误信息后,禁止继续抛出异常错误
|
|
51
|
+
* @description
|
|
52
|
+
* 调用error输出错误信息后,默认继续抛出异常错误,在测试环境下可以临地禁用,避免影响正常的测试流程
|
|
53
|
+
*/
|
|
54
|
+
ignoreThrow?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* 基于当前工程根目录下的日志输出文件
|
|
57
|
+
*
|
|
58
|
+
* @description
|
|
59
|
+
* 浏览器环境:自动忽略该选项;
|
|
60
|
+
*
|
|
61
|
+
* node环境下默认 logs/xxx.log
|
|
62
|
+
*/
|
|
63
|
+
outputFile?: string;
|
|
64
|
+
}
|
|
65
|
+
export interface IFileHelper {
|
|
66
|
+
existsSync?: (path: PathLike) => boolean;
|
|
67
|
+
mkdirSync?: (path: PathLike, options?: {
|
|
68
|
+
mode?: number | string | undefined;
|
|
69
|
+
recursive: true;
|
|
70
|
+
}) => string | undefined;
|
|
71
|
+
writeFile?: CallableFunction;
|
|
72
|
+
join?: (...paths: string[]) => string;
|
|
73
|
+
sep?: '\\' | '/';
|
|
74
|
+
resolve?: (...paths: string[]) => string;
|
|
25
75
|
}
|
|
26
76
|
export interface ILogger {
|
|
27
77
|
debug: (...rest: any[]) => void;
|
package/lib/interface.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.LogMode = void 0;
|
|
3
|
+
exports.LogLevel = exports.LogMode = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* 日志输出打印的模式
|
|
6
6
|
* @default LogMode.ALL
|
|
@@ -12,3 +12,14 @@ var LogMode;
|
|
|
12
12
|
LogMode["DEVELOPMENET"] = "development";
|
|
13
13
|
LogMode["NONE"] = "none";
|
|
14
14
|
})(LogMode = exports.LogMode || (exports.LogMode = {}));
|
|
15
|
+
/**
|
|
16
|
+
* 日志级别
|
|
17
|
+
*/
|
|
18
|
+
var LogLevel;
|
|
19
|
+
(function (LogLevel) {
|
|
20
|
+
LogLevel["LOG"] = "LOG";
|
|
21
|
+
LogLevel["WARN"] = "WARN";
|
|
22
|
+
LogLevel["INFO"] = "INFO";
|
|
23
|
+
LogLevel["ERROR"] = "ERROR";
|
|
24
|
+
LogLevel["DEBUG"] = "DEBUG";
|
|
25
|
+
})(LogLevel = exports.LogLevel || (exports.LogLevel = {}));
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildLogPreffix = void 0;
|
|
4
|
+
const date_fns_1 = require("date-fns");
|
|
5
|
+
const interface_1 = require("../interface");
|
|
6
|
+
const type_1 = require("./type");
|
|
7
|
+
const buildLogPreffix = (tags, options) => {
|
|
8
|
+
const { level = interface_1.LogLevel.LOG, date } = options;
|
|
9
|
+
const prefix = [];
|
|
10
|
+
if (tags.length) {
|
|
11
|
+
prefix.unshift(tags.map((t) => `[${t.toUpperCase()}]`).join(' '));
|
|
12
|
+
}
|
|
13
|
+
if (date) {
|
|
14
|
+
const now = new Date();
|
|
15
|
+
let dtStr;
|
|
16
|
+
if ((0, type_1.isString)(date)) {
|
|
17
|
+
dtStr = (0, date_fns_1.format)(now, date);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
dtStr = new Date(now).toISOString();
|
|
21
|
+
}
|
|
22
|
+
prefix.unshift(dtStr);
|
|
23
|
+
}
|
|
24
|
+
prefix.unshift(`[${level}]\t`);
|
|
25
|
+
return prefix;
|
|
26
|
+
};
|
|
27
|
+
exports.buildLogPreffix = buildLogPreffix;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.checkPlatform = void 0;
|
|
27
|
+
/**
|
|
28
|
+
* 检查当前运行环境,node环境下返回node的fs模块,浏览器环境返回null
|
|
29
|
+
* @returns fs
|
|
30
|
+
*/
|
|
31
|
+
const checkPlatform = () => Promise.all([Promise.resolve().then(() => __importStar(require('fs'))), Promise.resolve().then(() => __importStar(require('path')))]).then(([fs, path]) => {
|
|
32
|
+
// 如果fs为空则判定当前为浏览器环境
|
|
33
|
+
if (!fs)
|
|
34
|
+
return null;
|
|
35
|
+
const { existsSync, mkdirSync, writeFile } = fs;
|
|
36
|
+
const { sep, resolve, join } = path;
|
|
37
|
+
return {
|
|
38
|
+
existsSync,
|
|
39
|
+
mkdirSync,
|
|
40
|
+
writeFile,
|
|
41
|
+
join,
|
|
42
|
+
sep,
|
|
43
|
+
resolve,
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
exports.checkPlatform = checkPlatform;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isArray = exports.isString = exports.isUndefined = void 0;
|
|
4
|
+
const toString = (v) => Object.prototype.toString.call(v);
|
|
5
|
+
const isUndefined = (v) => v === undefined;
|
|
6
|
+
exports.isUndefined = isUndefined;
|
|
7
|
+
const isString = (v) => typeof v === 'string' || toString(v) === '[object String]';
|
|
8
|
+
exports.isString = isString;
|
|
9
|
+
exports.isArray = Array.isArray;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.writeLogFile = void 0;
|
|
7
|
+
const date_fns_1 = require("date-fns");
|
|
8
|
+
const noop_1 = __importDefault(require("./noop"));
|
|
9
|
+
const writeLogFile = (writer, data) => writer?.(`logs/${(0, date_fns_1.format)(Date.now(), 'yyyy-MM-dd')}.log`, data.map(JSON.stringify).join(' ') + '\n', { flag: 'a' }, noop_1.default);
|
|
10
|
+
exports.writeLogFile = writeLogFile;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jeffchi/logger",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "lib/index.d.ts",
|
|
6
6
|
"description": "A log print output javascript tool library that can be used at the front and back ends",
|
|
@@ -39,12 +39,17 @@
|
|
|
39
39
|
"lib/**/*"
|
|
40
40
|
],
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"date-fns": "^2.29.3"
|
|
42
|
+
"date-fns": "^2.29.3",
|
|
43
|
+
"@types/lodash": "^4.14.191",
|
|
44
|
+
"@types/node": "^18.11.18",
|
|
45
|
+
"lodash": "^4.17.21"
|
|
43
46
|
},
|
|
44
47
|
"devDependencies": {
|
|
45
48
|
"@types/jest": "^29.2.5",
|
|
49
|
+
"@types/lodash": "^4.14.191",
|
|
46
50
|
"@types/node": "^18.11.18",
|
|
47
51
|
"jest": "^29.3.1",
|
|
52
|
+
"lodash": "^4.17.21",
|
|
48
53
|
"prettier": "^2.8.2",
|
|
49
54
|
"ts-jest": "^29.0.5",
|
|
50
55
|
"tslint": "^6.1.3",
|