@zdepot/utils 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,206 @@
1
+ # @zdepot/utils
2
+
3
+ 安全类型转换工具库,提供带兜底值的类型判断与转换方法,确保你的代码永远不会因类型问题而抛异常。
4
+
5
+ ## 特性
6
+
7
+ ✅ **类型安全** - 基于 `Object.prototype.toString` 的精确类型判断
8
+ ✅ **兜底保护** - 所有转换方法都有默认兜底值,避免运行时错误
9
+ ✅ **JSON 解析** - 智能 JSON 解析,自动判断类型
10
+ ✅ **循环引用** - 安全的 JSON 序列化,自动处理循环引用和函数
11
+ ✅ **TypeScript 支持** - 完整的 TypeScript 类型定义
12
+ ✅ **Tree-shaking** - 无副作用,支持打包器优化
13
+
14
+ ## 安装
15
+
16
+ ```bash
17
+ npm install @zdepot/utils
18
+ ```
19
+
20
+ ## 使用
21
+
22
+ ```ts
23
+ import safe from '@zdepot/utils'
24
+
25
+ // 或按需引入
26
+ import { safe } from '@zdepot/utils'
27
+ ```
28
+
29
+ ## API
30
+
31
+ ### isSameType(a, b)
32
+
33
+ 判断两个值是否为相同类型,基于 `Object.prototype.toString` 精确判断。
34
+
35
+ ```ts
36
+ safe.isSameType([], []) // true
37
+ safe.isSameType({}, []) // false
38
+ safe.isSameType(1, '1') // false
39
+ ```
40
+
41
+ ### array(value)
42
+
43
+ 确保返回数组。如果输入是数组则直接返回;如果是 JSON 字符串则自动 parse;否则返回空数组 `[]`。
44
+
45
+ ```ts
46
+ safe.array([1, 2]) // [1, 2]
47
+ safe.array('[1,2]') // [1, 2]
48
+ safe.array('hello') // []
49
+ safe.array(null) // []
50
+ ```
51
+
52
+ ### string(value, fallback?)
53
+
54
+ 确保返回字符串。如果输入是字符串则直接返回,否则返回兜底值(默认 `""`)。
55
+
56
+ ```ts
57
+ safe.string('hello') // 'hello'
58
+ safe.string(123) // ''
59
+ safe.string(123, 'default') // 'default'
60
+ ```
61
+
62
+ ### number(value, fallback?)
63
+
64
+ 确保返回数字。用 `Number()` 转换,如果结果为 NaN 或 Infinity 则返回兜底值(默认 `0`)。
65
+
66
+ ```ts
67
+ safe.number(123) // 123
68
+ safe.number('456') // 456
69
+ safe.number('abc') // 0
70
+ safe.number('abc', -1) // -1
71
+ safe.number(Infinity) // 0
72
+ ```
73
+
74
+ ### jsonParse(value, fallback)
75
+
76
+ 带兜底值的 `JSON.parse`。解析失败或结果类型与兜底值不一致时返回兜底值。
77
+
78
+ ```ts
79
+ safe.jsonParse('{"a":1}', {}) // { a: 1 }
80
+ safe.jsonParse('invalid', {}) // {}
81
+ safe.jsonParse('"hello"', []) // [] (类型不匹配)
82
+ safe.jsonParse(null, {}) // {}
83
+ ```
84
+
85
+ ### jsonParseObj(value, fallback)
86
+
87
+ 增强版 `jsonParse`,只处理以 `[` 或 `{` 开头的字符串(对象/数组),否则直接返回兜底值。内置长度限制防止 DoS 攻击。
88
+
89
+ ```ts
90
+ safe.jsonParseObj('{"a":1}', {}) // { a: 1 }
91
+ safe.jsonParseObj('[1,2]', []) // [1, 2]
92
+ safe.jsonParseObj('"hello"', {}) // {} (不以 [ 或 { 开头)
93
+ safe.jsonParseObj('invalid', {}) // {}
94
+ ```
95
+
96
+ ### split(value, splitStr)
97
+
98
+ 安全的 `String.split`。空字符串返回 `[]` 避免 `['']`,异常也返回 `[]`。
99
+
100
+ ```ts
101
+ safe.split('a,b,c', ',') // ['a', 'b', 'c']
102
+ safe.split('', ',') // []
103
+ safe.split(null, ',') // []
104
+ ```
105
+
106
+ ### boolean(value, fallback?)
107
+
108
+ 确保返回布尔值。支持 `true/false` 字符串(大小写不敏感)和 `0/1` 数字。
109
+
110
+ ```ts
111
+ safe.boolean(true) // true
112
+ safe.boolean('TRUE') // true
113
+ safe.boolean(1) // true
114
+ safe.boolean('false') // false
115
+ safe.boolean(0) // false
116
+ safe.boolean('hello') // false (兜底值)
117
+ ```
118
+
119
+ ### date(value, fallback?)
120
+
121
+ 确保返回日期对象。支持 Date 对象、时间戳和日期字符串。
122
+
123
+ ```ts
124
+ safe.date(new Date()) // 原样返回
125
+ safe.date(1700000000000) // new Date(1700000000000)
126
+ safe.date('2023-01-01') // new Date('2023-01-01')
127
+ safe.date('invalid') // new Date() (当前时间)
128
+ safe.date('invalid', fallback) // fallback
129
+ ```
130
+
131
+ ### function(value, fallback?)
132
+
133
+ 确保返回函数。如果输入是函数则直接返回,否则返回兜底值(默认空函数)。
134
+
135
+ ```ts
136
+ safe.function(fn) // fn
137
+ safe.function(null) // () => undefined
138
+ safe.function(null, () => 'hi') // () => 'hi'
139
+ ```
140
+
141
+ ### nonEmptyString(value, fallback?)
142
+
143
+ 确保返回非空字符串。如果是非空字符串则返回,否则返回兜底值。
144
+
145
+ ```ts
146
+ safe.nonEmptyString('hello') // 'hello'
147
+ safe.nonEmptyString(' ') // '' (纯空白)
148
+ safe.nonEmptyString('') // ''
149
+ safe.nonEmptyString(123, 'N/A') // 'N/A'
150
+ ```
151
+
152
+ ### email(value, fallback?)
153
+
154
+ 确保返回有效的 email 字符串。
155
+
156
+ ```ts
157
+ safe.email('user@example.com') // 'user@example.com'
158
+ safe.email('invalid') // ''
159
+ safe.email('bad', 'a@b.com') // 'a@b.com'
160
+ ```
161
+
162
+ ### timestamp(value, fallback?)
163
+
164
+ 确保返回有效的时间戳。
165
+
166
+ ```ts
167
+ safe.timestamp(1700000000000) // 1700000000000
168
+ safe.timestamp(new Date()) // date.getTime()
169
+ safe.timestamp('2023-01-01') // 1672531200000
170
+ safe.timestamp('invalid', 0) // 0
171
+ ```
172
+
173
+ ### jsonStringify(value, indent?)
174
+
175
+ 安全的 JSON 序列化。自动处理循环引用和函数,避免抛异常。
176
+
177
+ ```ts
178
+ safe.jsonStringify({ a: 1 }) // '{"a":1}'
179
+ safe.jsonStringify({ fn: () => {} }) // '{"fn":"[Function]"}'
180
+
181
+ const obj: any = { name: 'test' }
182
+ obj.self = obj
183
+ safe.jsonStringify(obj) // '{"name":"test","self":"[Circular]"}'
184
+ ```
185
+
186
+ ## 使用场景
187
+
188
+ ```ts
189
+ // API 响应处理
190
+ const data = safe.jsonParse(response.data, defaultValue)
191
+ const items = safe.array(data.items)
192
+
193
+ // 配置文件解析
194
+ const config = safe.jsonParseObj(fs.readFileSync('config.json', 'utf-8'), {})
195
+
196
+ // 用户输入处理
197
+ const username = safe.string(input.username, 'guest')
198
+ const age = safe.number(input.age, 0)
199
+
200
+ // 字符串分割
201
+ const parts = safe.split(input.tags, ',') // 避免 split(',a', ',') 得到 ['', 'a']
202
+ ```
203
+
204
+ ## License
205
+
206
+ MIT
@@ -0,0 +1,103 @@
1
+ interface SafeUtils {
2
+ /**
3
+ * 判断相同类型
4
+ * @param a 第一个值
5
+ * @param b 第二个值
6
+ * @returns 是否为相同类型
7
+ */
8
+ isSameType: (a: unknown, b: unknown) => boolean;
9
+ /**
10
+ * 确保返回数组。如果输入是数组则直接返回;如果是 JSON 字符串则自动 parse;否则返回空数组 `[]`。
11
+ * @param value 输入值
12
+ * @returns 数组或空数组
13
+ */
14
+ array: <T = unknown>(value: T) => T extends readonly unknown[] ? T : [];
15
+ /**
16
+ * 确保返回字符串。如果输入是字符串则直接返回,否则返回兜底值(默认 `""`)。
17
+ * @param value 输入值
18
+ * @param fallback 兜底值
19
+ * @returns 字符串或空字符串
20
+ */
21
+ string: (value: unknown, fallback?: string) => string;
22
+ /**
23
+ * 确保返回数字。用 `Number()` 转换,如果结果为 NaN 则返回兜底值(默认 `0`)。
24
+ * @param value 输入值
25
+ * @param fallback 兜底值
26
+ * @returns 数字或兜底值
27
+ */
28
+ number: (value: unknown, fallback?: number) => number;
29
+ /**
30
+ * 带兜底值的 `JSON.parse`。解析失败或结果类型与兜底值不一致时返回兜底值。
31
+ * @param value 输入值
32
+ * @param fallback 兜底值
33
+ * @returns 解析结果或兜底值
34
+ */
35
+ jsonParse: <T = unknown>(value: unknown, fallback: T) => T;
36
+ /**
37
+ * 增版 `jsonParse`,只处理以 `[` 或 `{` 开头的字符串(对象/数组),否则直接返回兜底值。
38
+ * @param value 输入值
39
+ * @param fallback 兜底值
40
+ * @returns 解析结果或兜底值
41
+ */
42
+ jsonParseObj: <T extends Record<string, unknown> | unknown[]>(value: string, fallback: T) => T;
43
+ /**
44
+ * 安全的 `String.split`。空字符串返回 `[]` 避免 `['']`,异常也返回 `[]`。
45
+ * @param value 输入值
46
+ * @param splitStr 分隔符
47
+ * @returns 分割结果或空数组
48
+ */
49
+ split: (value: string, splitStr: string) => string[];
50
+ /**
51
+ * 确保返回布尔值。真值返回 `true`,其他情况返回兜底值(默认 `false`)。
52
+ * @param value 输入值
53
+ * @param fallback 兜底值
54
+ * @returns 布尔值
55
+ */
56
+ boolean: (value: unknown, fallback?: boolean) => boolean;
57
+ /**
58
+ * 确保返回日期对象。如果是有效的时间戳、日期字符串或 Date 对象,返回对应的 Date,否则返回兜底值。
59
+ * @param value 输入值
60
+ * @param fallback 兜底值
61
+ * @returns 日期对象
62
+ */
63
+ date: (value: unknown, fallback?: Date) => Date;
64
+ /**
65
+ * 确保返回函数。如果输入是函数则直接返回,否则返回空函数。
66
+ * @param value 输入值
67
+ * @param fallback 兜底值
68
+ * @returns 函数
69
+ */
70
+ function: <T extends (...args: any[]) => any>(value: unknown, fallback?: T) => T;
71
+ /**
72
+ * 确保返回非空字符串。如果是非空字符串则返回,否则返回兜底值。
73
+ * @param value 输入值
74
+ * @param fallback 兜底值
75
+ * @returns 非空字符串
76
+ */
77
+ nonEmptyString: (value: unknown, fallback?: string) => string;
78
+ /**
79
+ * 确保返回有效的 email 字符串。如果是有效 email 则返回,否则返回兜底值。
80
+ * @param value 输入值
81
+ * @param fallback 兜底值
82
+ * @returns 有效的 email 字符串
83
+ */
84
+ email: (value: unknown, fallback?: string) => string;
85
+ /**
86
+ * 确保返回有效的时间戳。如果是有效时间戳则返回,否则返回兜底值。
87
+ * @param value 输入值
88
+ * @param fallback 兜底值
89
+ * @returns 有效的时间戳
90
+ */
91
+ timestamp: (value: unknown, fallback?: number) => number;
92
+ /**
93
+ * 安全的 JSON 序列化。处理循环引用和不可序列化的值。
94
+ * @param value 要序列化的值
95
+ * @param indent 缩进
96
+ * @returns 序列化后的字符串
97
+ */
98
+ jsonStringify: (value: unknown, indent?: number) => string;
99
+ }
100
+
101
+ declare const safe: SafeUtils;
102
+
103
+ export { type SafeUtils, safe as default, safe };
@@ -0,0 +1,103 @@
1
+ interface SafeUtils {
2
+ /**
3
+ * 判断相同类型
4
+ * @param a 第一个值
5
+ * @param b 第二个值
6
+ * @returns 是否为相同类型
7
+ */
8
+ isSameType: (a: unknown, b: unknown) => boolean;
9
+ /**
10
+ * 确保返回数组。如果输入是数组则直接返回;如果是 JSON 字符串则自动 parse;否则返回空数组 `[]`。
11
+ * @param value 输入值
12
+ * @returns 数组或空数组
13
+ */
14
+ array: <T = unknown>(value: T) => T extends readonly unknown[] ? T : [];
15
+ /**
16
+ * 确保返回字符串。如果输入是字符串则直接返回,否则返回兜底值(默认 `""`)。
17
+ * @param value 输入值
18
+ * @param fallback 兜底值
19
+ * @returns 字符串或空字符串
20
+ */
21
+ string: (value: unknown, fallback?: string) => string;
22
+ /**
23
+ * 确保返回数字。用 `Number()` 转换,如果结果为 NaN 则返回兜底值(默认 `0`)。
24
+ * @param value 输入值
25
+ * @param fallback 兜底值
26
+ * @returns 数字或兜底值
27
+ */
28
+ number: (value: unknown, fallback?: number) => number;
29
+ /**
30
+ * 带兜底值的 `JSON.parse`。解析失败或结果类型与兜底值不一致时返回兜底值。
31
+ * @param value 输入值
32
+ * @param fallback 兜底值
33
+ * @returns 解析结果或兜底值
34
+ */
35
+ jsonParse: <T = unknown>(value: unknown, fallback: T) => T;
36
+ /**
37
+ * 增版 `jsonParse`,只处理以 `[` 或 `{` 开头的字符串(对象/数组),否则直接返回兜底值。
38
+ * @param value 输入值
39
+ * @param fallback 兜底值
40
+ * @returns 解析结果或兜底值
41
+ */
42
+ jsonParseObj: <T extends Record<string, unknown> | unknown[]>(value: string, fallback: T) => T;
43
+ /**
44
+ * 安全的 `String.split`。空字符串返回 `[]` 避免 `['']`,异常也返回 `[]`。
45
+ * @param value 输入值
46
+ * @param splitStr 分隔符
47
+ * @returns 分割结果或空数组
48
+ */
49
+ split: (value: string, splitStr: string) => string[];
50
+ /**
51
+ * 确保返回布尔值。真值返回 `true`,其他情况返回兜底值(默认 `false`)。
52
+ * @param value 输入值
53
+ * @param fallback 兜底值
54
+ * @returns 布尔值
55
+ */
56
+ boolean: (value: unknown, fallback?: boolean) => boolean;
57
+ /**
58
+ * 确保返回日期对象。如果是有效的时间戳、日期字符串或 Date 对象,返回对应的 Date,否则返回兜底值。
59
+ * @param value 输入值
60
+ * @param fallback 兜底值
61
+ * @returns 日期对象
62
+ */
63
+ date: (value: unknown, fallback?: Date) => Date;
64
+ /**
65
+ * 确保返回函数。如果输入是函数则直接返回,否则返回空函数。
66
+ * @param value 输入值
67
+ * @param fallback 兜底值
68
+ * @returns 函数
69
+ */
70
+ function: <T extends (...args: any[]) => any>(value: unknown, fallback?: T) => T;
71
+ /**
72
+ * 确保返回非空字符串。如果是非空字符串则返回,否则返回兜底值。
73
+ * @param value 输入值
74
+ * @param fallback 兜底值
75
+ * @returns 非空字符串
76
+ */
77
+ nonEmptyString: (value: unknown, fallback?: string) => string;
78
+ /**
79
+ * 确保返回有效的 email 字符串。如果是有效 email 则返回,否则返回兜底值。
80
+ * @param value 输入值
81
+ * @param fallback 兜底值
82
+ * @returns 有效的 email 字符串
83
+ */
84
+ email: (value: unknown, fallback?: string) => string;
85
+ /**
86
+ * 确保返回有效的时间戳。如果是有效时间戳则返回,否则返回兜底值。
87
+ * @param value 输入值
88
+ * @param fallback 兜底值
89
+ * @returns 有效的时间戳
90
+ */
91
+ timestamp: (value: unknown, fallback?: number) => number;
92
+ /**
93
+ * 安全的 JSON 序列化。处理循环引用和不可序列化的值。
94
+ * @param value 要序列化的值
95
+ * @param indent 缩进
96
+ * @returns 序列化后的字符串
97
+ */
98
+ jsonStringify: (value: unknown, indent?: number) => string;
99
+ }
100
+
101
+ declare const safe: SafeUtils;
102
+
103
+ export { type SafeUtils, safe as default, safe };
package/dist/index.js ADDED
@@ -0,0 +1,218 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ default: () => index_default,
24
+ safe: () => safe
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+ var MAX_JSON_LENGTH = 10 * 1024 * 1024;
28
+ var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
29
+ var JSON_OBJ_PREFIX = /^[\[{]/;
30
+ function getTypeTag(value) {
31
+ return Object.prototype.toString.call(value);
32
+ }
33
+ var safe = {
34
+ /**
35
+ * 判断相同类型
36
+ * @param a 第一个值
37
+ * @param b 第二个值
38
+ * @returns 是否为相同类型
39
+ */
40
+ isSameType: function isSameType(a, b) {
41
+ return getTypeTag(a) === getTypeTag(b);
42
+ },
43
+ /**
44
+ * 确保返回数组。如果输入是数组则直接返回;如果是 JSON 字符串则自动 parse;否则返回空数组 `[]`。
45
+ * @param value 输入值
46
+ * @returns 数组或空数组
47
+ */
48
+ array: function array(value) {
49
+ if (this.isSameType(value, [])) return value;
50
+ if (this.isSameType(value, ""))
51
+ return this.jsonParse(value, []);
52
+ return [];
53
+ },
54
+ /**
55
+ * 确保返回字符串。如果输入是字符串则直接返回,否则返回兜底值(默认 `""`)。
56
+ * @param value 输入值
57
+ * @param fallback 兜底值
58
+ * @returns 字符串或空字符串
59
+ */
60
+ string: function string(value, fallback = "") {
61
+ if (typeof value === "string") return value;
62
+ return fallback != null ? fallback : "";
63
+ },
64
+ /**
65
+ * 确保返回数字。用 `Number()` 转换,如果结果为 NaN 则返回兜底值(默认 `0`)。
66
+ * @param value 输入值
67
+ * @param fallback 兜底值
68
+ * @returns 数字或兜底值
69
+ */
70
+ number: function number(value, fallback = 0) {
71
+ const result = Number(value);
72
+ if (!Number.isFinite(result)) return Number.isFinite(fallback) ? fallback : 0;
73
+ return result;
74
+ },
75
+ /**
76
+ * 带兜底值的 `JSON.parse`。解析失败或结果类型与兜底值不一致时返回兜底值。
77
+ * @param value 输入值
78
+ * @param fallback 兜底值
79
+ * @returns 解析结果或兜底值
80
+ */
81
+ jsonParse: function jsonParse(value, fallback) {
82
+ if (value == null) return fallback;
83
+ try {
84
+ const result = JSON.parse(value);
85
+ return this.isSameType(result, fallback) ? result : fallback;
86
+ } catch (error) {
87
+ return fallback;
88
+ }
89
+ },
90
+ /**
91
+ * 增版 `jsonParse`,只处理以 `[` 或 `{` 开头的字符串(对象/数组),否则直接返回兜底值。
92
+ * @param value 输入值
93
+ * @param fallback 兜底值
94
+ * @returns 解析结果或兜底值
95
+ */
96
+ jsonParseObj: function jsonParseObj(value, fallback) {
97
+ if (typeof value !== "string" || value.length > MAX_JSON_LENGTH || value.length < 2) {
98
+ return fallback;
99
+ }
100
+ try {
101
+ if (!JSON_OBJ_PREFIX.test(value)) throw new Error();
102
+ const result = JSON.parse(value);
103
+ return this.isSameType(result, fallback) ? result : fallback;
104
+ } catch (error) {
105
+ return fallback;
106
+ }
107
+ },
108
+ /**
109
+ * 安全的 `String.split`。空字符串返回 `[]` 避免 `['']`,异常也返回 `[]`。
110
+ * @param value 输入值
111
+ * @param splitStr 分隔符
112
+ * @returns 分割结果或空数组
113
+ */
114
+ split: function split(value, splitStr) {
115
+ if (typeof value !== "string" || value === "") return [];
116
+ try {
117
+ return value.split(splitStr);
118
+ } catch (error) {
119
+ return [];
120
+ }
121
+ },
122
+ /**
123
+ * 确保返回布尔值。真值返回 `true`,其他情况返回兜底值(默认 `false`)。
124
+ * @param value 输入值
125
+ * @param fallback 兜底值
126
+ * @returns 布尔值
127
+ */
128
+ boolean: function boolean(value, fallback = false) {
129
+ if (value === true || String(value).toLowerCase() === "true" || value === 1) return true;
130
+ if (value === false || String(value).toLowerCase() === "false" || value === 0) return false;
131
+ return fallback;
132
+ },
133
+ /**
134
+ * 确保返回日期对象。如果是有效的时间戳、日期字符串或 Date 对象,返回对应的 Date,否则返回兜底值。
135
+ * @param value 输入值
136
+ * @param fallback 兜底值
137
+ * @returns 日期对象
138
+ */
139
+ date: function date(value, fallback) {
140
+ const actualFallback = fallback != null ? fallback : /* @__PURE__ */ new Date();
141
+ if (value instanceof Date) return value;
142
+ if (typeof value === "number" || typeof value === "string") {
143
+ const d = new Date(value);
144
+ return isNaN(d.getTime()) ? actualFallback : d;
145
+ }
146
+ return actualFallback;
147
+ },
148
+ /**
149
+ * 确保返回函数。如果输入是函数则直接返回,否则返回空函数。
150
+ * @param value 输入值
151
+ * @param fallback 兜底值
152
+ * @returns 函数
153
+ */
154
+ function: function(value, fallback = (() => void 0)) {
155
+ if (typeof value === "function") return value;
156
+ return fallback;
157
+ },
158
+ /**
159
+ * 确保返回非空字符串。如果是非空字符串则返回,否则返回兜底值。
160
+ * @param value 输入值
161
+ * @param fallback 兜底值
162
+ * @returns 非空字符串
163
+ */
164
+ nonEmptyString: function nonEmptyString(value, fallback = "") {
165
+ const str = this.string(value, fallback);
166
+ return str.trim() !== "" ? str : fallback;
167
+ },
168
+ /**
169
+ * 确保返回有效的 email 字符串。如果是有效 email 则返回,否则返回兜底值。
170
+ * @param value 输入值
171
+ * @param fallback 兜底值
172
+ * @returns 有效的 email 字符串
173
+ */
174
+ email: function email(value, fallback = "") {
175
+ const str = this.string(value, fallback);
176
+ return EMAIL_REGEX.test(str) ? str : fallback;
177
+ },
178
+ /**
179
+ * 确保返回有效的时间戳。如果是有效时间戳则返回,否则返回兜底值。
180
+ * @param value 输入值
181
+ * @param fallback 兜底值
182
+ * @returns 有效的时间戳
183
+ */
184
+ timestamp: function timestamp(value, fallback = Date.now()) {
185
+ const date2 = this.date(value, new Date(fallback));
186
+ return date2.getTime();
187
+ },
188
+ /**
189
+ * 安全的 JSON 序列化。处理循环引用和不可序列化的值。
190
+ * @param value 要序列化的值
191
+ * @param indent 缩进
192
+ * @returns 序列化后的字符串
193
+ */
194
+ jsonStringify: function jsonStringify(value, indent) {
195
+ const seen = /* @__PURE__ */ new WeakSet();
196
+ try {
197
+ return JSON.stringify(
198
+ value,
199
+ (key, val) => {
200
+ if (typeof val === "function") return "[Function]";
201
+ if (typeof val === "object" && val !== null) {
202
+ if (seen.has(val)) return "[Circular]";
203
+ seen.add(val);
204
+ }
205
+ return val;
206
+ },
207
+ indent
208
+ );
209
+ } catch (error) {
210
+ return "{}";
211
+ }
212
+ }
213
+ };
214
+ var index_default = safe;
215
+ // Annotate the CommonJS export names for ESM import in node:
216
+ 0 && (module.exports = {
217
+ safe
218
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,193 @@
1
+ // src/index.ts
2
+ var MAX_JSON_LENGTH = 10 * 1024 * 1024;
3
+ var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
4
+ var JSON_OBJ_PREFIX = /^[\[{]/;
5
+ function getTypeTag(value) {
6
+ return Object.prototype.toString.call(value);
7
+ }
8
+ var safe = {
9
+ /**
10
+ * 判断相同类型
11
+ * @param a 第一个值
12
+ * @param b 第二个值
13
+ * @returns 是否为相同类型
14
+ */
15
+ isSameType: function isSameType(a, b) {
16
+ return getTypeTag(a) === getTypeTag(b);
17
+ },
18
+ /**
19
+ * 确保返回数组。如果输入是数组则直接返回;如果是 JSON 字符串则自动 parse;否则返回空数组 `[]`。
20
+ * @param value 输入值
21
+ * @returns 数组或空数组
22
+ */
23
+ array: function array(value) {
24
+ if (this.isSameType(value, [])) return value;
25
+ if (this.isSameType(value, ""))
26
+ return this.jsonParse(value, []);
27
+ return [];
28
+ },
29
+ /**
30
+ * 确保返回字符串。如果输入是字符串则直接返回,否则返回兜底值(默认 `""`)。
31
+ * @param value 输入值
32
+ * @param fallback 兜底值
33
+ * @returns 字符串或空字符串
34
+ */
35
+ string: function string(value, fallback = "") {
36
+ if (typeof value === "string") return value;
37
+ return fallback != null ? fallback : "";
38
+ },
39
+ /**
40
+ * 确保返回数字。用 `Number()` 转换,如果结果为 NaN 则返回兜底值(默认 `0`)。
41
+ * @param value 输入值
42
+ * @param fallback 兜底值
43
+ * @returns 数字或兜底值
44
+ */
45
+ number: function number(value, fallback = 0) {
46
+ const result = Number(value);
47
+ if (!Number.isFinite(result)) return Number.isFinite(fallback) ? fallback : 0;
48
+ return result;
49
+ },
50
+ /**
51
+ * 带兜底值的 `JSON.parse`。解析失败或结果类型与兜底值不一致时返回兜底值。
52
+ * @param value 输入值
53
+ * @param fallback 兜底值
54
+ * @returns 解析结果或兜底值
55
+ */
56
+ jsonParse: function jsonParse(value, fallback) {
57
+ if (value == null) return fallback;
58
+ try {
59
+ const result = JSON.parse(value);
60
+ return this.isSameType(result, fallback) ? result : fallback;
61
+ } catch (error) {
62
+ return fallback;
63
+ }
64
+ },
65
+ /**
66
+ * 增版 `jsonParse`,只处理以 `[` 或 `{` 开头的字符串(对象/数组),否则直接返回兜底值。
67
+ * @param value 输入值
68
+ * @param fallback 兜底值
69
+ * @returns 解析结果或兜底值
70
+ */
71
+ jsonParseObj: function jsonParseObj(value, fallback) {
72
+ if (typeof value !== "string" || value.length > MAX_JSON_LENGTH || value.length < 2) {
73
+ return fallback;
74
+ }
75
+ try {
76
+ if (!JSON_OBJ_PREFIX.test(value)) throw new Error();
77
+ const result = JSON.parse(value);
78
+ return this.isSameType(result, fallback) ? result : fallback;
79
+ } catch (error) {
80
+ return fallback;
81
+ }
82
+ },
83
+ /**
84
+ * 安全的 `String.split`。空字符串返回 `[]` 避免 `['']`,异常也返回 `[]`。
85
+ * @param value 输入值
86
+ * @param splitStr 分隔符
87
+ * @returns 分割结果或空数组
88
+ */
89
+ split: function split(value, splitStr) {
90
+ if (typeof value !== "string" || value === "") return [];
91
+ try {
92
+ return value.split(splitStr);
93
+ } catch (error) {
94
+ return [];
95
+ }
96
+ },
97
+ /**
98
+ * 确保返回布尔值。真值返回 `true`,其他情况返回兜底值(默认 `false`)。
99
+ * @param value 输入值
100
+ * @param fallback 兜底值
101
+ * @returns 布尔值
102
+ */
103
+ boolean: function boolean(value, fallback = false) {
104
+ if (value === true || String(value).toLowerCase() === "true" || value === 1) return true;
105
+ if (value === false || String(value).toLowerCase() === "false" || value === 0) return false;
106
+ return fallback;
107
+ },
108
+ /**
109
+ * 确保返回日期对象。如果是有效的时间戳、日期字符串或 Date 对象,返回对应的 Date,否则返回兜底值。
110
+ * @param value 输入值
111
+ * @param fallback 兜底值
112
+ * @returns 日期对象
113
+ */
114
+ date: function date(value, fallback) {
115
+ const actualFallback = fallback != null ? fallback : /* @__PURE__ */ new Date();
116
+ if (value instanceof Date) return value;
117
+ if (typeof value === "number" || typeof value === "string") {
118
+ const d = new Date(value);
119
+ return isNaN(d.getTime()) ? actualFallback : d;
120
+ }
121
+ return actualFallback;
122
+ },
123
+ /**
124
+ * 确保返回函数。如果输入是函数则直接返回,否则返回空函数。
125
+ * @param value 输入值
126
+ * @param fallback 兜底值
127
+ * @returns 函数
128
+ */
129
+ function: function(value, fallback = (() => void 0)) {
130
+ if (typeof value === "function") return value;
131
+ return fallback;
132
+ },
133
+ /**
134
+ * 确保返回非空字符串。如果是非空字符串则返回,否则返回兜底值。
135
+ * @param value 输入值
136
+ * @param fallback 兜底值
137
+ * @returns 非空字符串
138
+ */
139
+ nonEmptyString: function nonEmptyString(value, fallback = "") {
140
+ const str = this.string(value, fallback);
141
+ return str.trim() !== "" ? str : fallback;
142
+ },
143
+ /**
144
+ * 确保返回有效的 email 字符串。如果是有效 email 则返回,否则返回兜底值。
145
+ * @param value 输入值
146
+ * @param fallback 兜底值
147
+ * @returns 有效的 email 字符串
148
+ */
149
+ email: function email(value, fallback = "") {
150
+ const str = this.string(value, fallback);
151
+ return EMAIL_REGEX.test(str) ? str : fallback;
152
+ },
153
+ /**
154
+ * 确保返回有效的时间戳。如果是有效时间戳则返回,否则返回兜底值。
155
+ * @param value 输入值
156
+ * @param fallback 兜底值
157
+ * @returns 有效的时间戳
158
+ */
159
+ timestamp: function timestamp(value, fallback = Date.now()) {
160
+ const date2 = this.date(value, new Date(fallback));
161
+ return date2.getTime();
162
+ },
163
+ /**
164
+ * 安全的 JSON 序列化。处理循环引用和不可序列化的值。
165
+ * @param value 要序列化的值
166
+ * @param indent 缩进
167
+ * @returns 序列化后的字符串
168
+ */
169
+ jsonStringify: function jsonStringify(value, indent) {
170
+ const seen = /* @__PURE__ */ new WeakSet();
171
+ try {
172
+ return JSON.stringify(
173
+ value,
174
+ (key, val) => {
175
+ if (typeof val === "function") return "[Function]";
176
+ if (typeof val === "object" && val !== null) {
177
+ if (seen.has(val)) return "[Circular]";
178
+ seen.add(val);
179
+ }
180
+ return val;
181
+ },
182
+ indent
183
+ );
184
+ } catch (error) {
185
+ return "{}";
186
+ }
187
+ }
188
+ };
189
+ var index_default = safe;
190
+ export {
191
+ index_default as default,
192
+ safe
193
+ };
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@zdepot/utils",
3
+ "version": "1.0.0",
4
+ "description": "安全类型转换工具库,提供带兜底值的类型判断与转换方法",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.mjs",
11
+ "require": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "sideEffects": false,
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "scripts": {
23
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean",
24
+ "prepublishOnly": "npm run build",
25
+ "test": "vitest",
26
+ "test:coverage": "vitest run --coverage",
27
+ "test:coverage:report": "vitest run --coverage --reporter=text --reporter=html",
28
+ "lint": "eslint src --ext .ts",
29
+ "lint:fix": "eslint src --ext .ts --fix",
30
+ "format": "prettier --write src/**/*.ts"
31
+ },
32
+ "keywords": [
33
+ "utils",
34
+ "safe",
35
+ "type-check",
36
+ "fallback",
37
+ "json-parse",
38
+ "type-conversion",
39
+ "typescript",
40
+ "ts"
41
+ ],
42
+ "author": "dalongzhu",
43
+ "license": "MIT",
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "https://github.com/dalongzhu/z-tools.git",
47
+ "directory": ""
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^20.0.0",
51
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
52
+ "@typescript-eslint/parser": "^6.0.0",
53
+ "@vitest/coverage-v8": "^1.0.0",
54
+ "eslint": "^8.0.0",
55
+ "jsdom": "^29.1.1",
56
+ "prettier": "^3.0.0",
57
+ "tsup": "^8.0.0",
58
+ "typescript": "^5.4.0",
59
+ "vitest": "^1.0.0"
60
+ },
61
+ "engines": {
62
+ "node": ">=14.0.0"
63
+ }
64
+ }