@brix-sdk/platform-shared 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.
@@ -0,0 +1,509 @@
1
+ import { init_id } from './chunk-DJX6ASLI.js';
2
+
3
+ // src/utils/debounce.ts
4
+ function debounce(fn, delay2) {
5
+ let timeoutId = null;
6
+ return function(...args) {
7
+ if (timeoutId !== null) {
8
+ clearTimeout(timeoutId);
9
+ }
10
+ const context = this;
11
+ timeoutId = setTimeout(() => {
12
+ fn.apply(context, args);
13
+ timeoutId = null;
14
+ }, delay2);
15
+ };
16
+ }
17
+ function throttle(fn, limit) {
18
+ let inThrottle = false;
19
+ let lastArgs = null;
20
+ let lastContext = null;
21
+ return function(...args) {
22
+ if (!inThrottle) {
23
+ fn.apply(this, args);
24
+ inThrottle = true;
25
+ setTimeout(() => {
26
+ inThrottle = false;
27
+ if (lastArgs !== null && lastContext !== null) {
28
+ fn.apply(lastContext, lastArgs);
29
+ lastArgs = null;
30
+ lastContext = null;
31
+ }
32
+ }, limit);
33
+ } else {
34
+ lastArgs = args;
35
+ lastContext = this;
36
+ }
37
+ };
38
+ }
39
+
40
+ // src/utils/index.ts
41
+ init_id();
42
+
43
+ // src/utils/guards.ts
44
+ function isNullOrUndefined(value) {
45
+ return value === null || value === void 0;
46
+ }
47
+ function isNotNullOrUndefined(value) {
48
+ return value !== null && value !== void 0;
49
+ }
50
+ function isString(value) {
51
+ return typeof value === "string";
52
+ }
53
+ function isNumber(value) {
54
+ return typeof value === "number" && !Number.isNaN(value);
55
+ }
56
+ function isBoolean(value) {
57
+ return typeof value === "boolean";
58
+ }
59
+ function isFunction(value) {
60
+ return typeof value === "function";
61
+ }
62
+ function isObject(value) {
63
+ return typeof value === "object" && value !== null && !Array.isArray(value);
64
+ }
65
+ function isArray(value) {
66
+ return Array.isArray(value);
67
+ }
68
+ function isPromise(value) {
69
+ return value instanceof Promise || isObject(value) && isFunction(value.then) && isFunction(value.catch);
70
+ }
71
+ function assertNotNull(value, message = "Value is null or undefined") {
72
+ if (isNullOrUndefined(value)) {
73
+ throw new Error(message);
74
+ }
75
+ }
76
+ function assert(condition, message = "Assertion failed") {
77
+ if (!condition) {
78
+ throw new Error(message);
79
+ }
80
+ }
81
+
82
+ // src/utils/clone.ts
83
+ function deepClone(obj) {
84
+ if (obj === null || typeof obj !== "object") {
85
+ return obj;
86
+ }
87
+ if (obj instanceof Date) {
88
+ return new Date(obj.getTime());
89
+ }
90
+ if (obj instanceof RegExp) {
91
+ return new RegExp(obj.source, obj.flags);
92
+ }
93
+ if (obj instanceof Map) {
94
+ const clonedMap = /* @__PURE__ */ new Map();
95
+ obj.forEach((value, key) => {
96
+ clonedMap.set(deepClone(key), deepClone(value));
97
+ });
98
+ return clonedMap;
99
+ }
100
+ if (obj instanceof Set) {
101
+ const clonedSet = /* @__PURE__ */ new Set();
102
+ obj.forEach((value) => {
103
+ clonedSet.add(deepClone(value));
104
+ });
105
+ return clonedSet;
106
+ }
107
+ if (Array.isArray(obj)) {
108
+ return obj.map((item) => deepClone(item));
109
+ }
110
+ const clonedObj = {};
111
+ for (const key in obj) {
112
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
113
+ clonedObj[key] = deepClone(obj[key]);
114
+ }
115
+ }
116
+ return clonedObj;
117
+ }
118
+ function deepMerge(target, ...sources) {
119
+ if (!sources.length) {
120
+ return target;
121
+ }
122
+ const source = sources.shift();
123
+ if (source === void 0) {
124
+ return target;
125
+ }
126
+ for (const key in source) {
127
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
128
+ const targetValue = target[key];
129
+ const sourceValue = source[key];
130
+ if (typeof sourceValue === "object" && sourceValue !== null && !Array.isArray(sourceValue) && typeof targetValue === "object" && targetValue !== null && !Array.isArray(targetValue)) {
131
+ target[key] = deepMerge(
132
+ targetValue,
133
+ sourceValue
134
+ );
135
+ } else if (sourceValue !== void 0) {
136
+ target[key] = deepClone(sourceValue);
137
+ }
138
+ }
139
+ }
140
+ return deepMerge(target, ...sources);
141
+ }
142
+
143
+ // src/utils/format.ts
144
+ function formatFileSize(bytes, decimals = 2) {
145
+ if (bytes === 0) return "0 B";
146
+ if (bytes < 0) return "-" + formatFileSize(-bytes, decimals);
147
+ const k = 1024;
148
+ const sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
149
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
150
+ const index = Math.min(i, sizes.length - 1);
151
+ return `${parseFloat((bytes / Math.pow(k, index)).toFixed(decimals))} ${sizes[index]}`;
152
+ }
153
+ function parseFileSize(sizeStr) {
154
+ const units = {
155
+ B: 1,
156
+ KB: 1024,
157
+ MB: 1024 ** 2,
158
+ GB: 1024 ** 3,
159
+ TB: 1024 ** 4,
160
+ PB: 1024 ** 5
161
+ };
162
+ const match = sizeStr.trim().toUpperCase().match(/^([\d.]+)\s*([A-Z]+)$/);
163
+ if (!match) return 0;
164
+ const [, value, unit] = match;
165
+ return parseFloat(value) * (units[unit] || 1);
166
+ }
167
+ function formatDate(date, format = "YYYY-MM-DD HH:mm:ss") {
168
+ const d = new Date(date);
169
+ if (isNaN(d.getTime())) {
170
+ return "Invalid Date";
171
+ }
172
+ const replacements = {
173
+ YYYY: d.getFullYear().toString(),
174
+ YY: d.getFullYear().toString().slice(-2),
175
+ MM: (d.getMonth() + 1).toString().padStart(2, "0"),
176
+ M: (d.getMonth() + 1).toString(),
177
+ DD: d.getDate().toString().padStart(2, "0"),
178
+ D: d.getDate().toString(),
179
+ HH: d.getHours().toString().padStart(2, "0"),
180
+ H: d.getHours().toString(),
181
+ mm: d.getMinutes().toString().padStart(2, "0"),
182
+ m: d.getMinutes().toString(),
183
+ ss: d.getSeconds().toString().padStart(2, "0"),
184
+ s: d.getSeconds().toString(),
185
+ SSS: d.getMilliseconds().toString().padStart(3, "0")
186
+ };
187
+ let result = format;
188
+ const keys = Object.keys(replacements).sort((a, b) => b.length - a.length);
189
+ for (const key of keys) {
190
+ result = result.replace(new RegExp(key, "g"), replacements[key]);
191
+ }
192
+ return result;
193
+ }
194
+ function formatRelativeTime(date, now = Date.now()) {
195
+ const d = new Date(date);
196
+ const diff = now - d.getTime();
197
+ const absDiff = Math.abs(diff);
198
+ const suffix = diff > 0 ? "\u524D" : "\u540E";
199
+ const seconds = Math.floor(absDiff / 1e3);
200
+ const minutes = Math.floor(seconds / 60);
201
+ const hours = Math.floor(minutes / 60);
202
+ const days = Math.floor(hours / 24);
203
+ const months = Math.floor(days / 30);
204
+ const years = Math.floor(days / 365);
205
+ if (seconds < 60) {
206
+ return seconds <= 10 ? "\u521A\u521A" : `${seconds}\u79D2${suffix}`;
207
+ }
208
+ if (minutes < 60) {
209
+ return `${minutes}\u5206\u949F${suffix}`;
210
+ }
211
+ if (hours < 24) {
212
+ return `${hours}\u5C0F\u65F6${suffix}`;
213
+ }
214
+ if (days < 30) {
215
+ return `${days}\u5929${suffix}`;
216
+ }
217
+ if (months < 12) {
218
+ return `${months}\u4E2A\u6708${suffix}`;
219
+ }
220
+ return `${years}\u5E74${suffix}`;
221
+ }
222
+ function formatDuration(ms, options = {}) {
223
+ const { style = "short" } = options;
224
+ const seconds = Math.floor(ms / 1e3 % 60);
225
+ const minutes = Math.floor(ms / (1e3 * 60) % 60);
226
+ const hours = Math.floor(ms / (1e3 * 60 * 60) % 24);
227
+ const days = Math.floor(ms / (1e3 * 60 * 60 * 24));
228
+ if (style === "long") {
229
+ const parts = [];
230
+ if (days > 0) parts.push(`${days}\u5929`);
231
+ if (hours > 0) parts.push(`${hours}\u5C0F\u65F6`);
232
+ if (minutes > 0) parts.push(`${minutes}\u5206\u949F`);
233
+ if (seconds > 0 || parts.length === 0) parts.push(`${seconds}\u79D2`);
234
+ return parts.join("");
235
+ }
236
+ if (days > 0) {
237
+ return `${days}d ${hours}:${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
238
+ }
239
+ if (hours > 0) {
240
+ return `${hours}:${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
241
+ }
242
+ return `${minutes}:${seconds.toString().padStart(2, "0")}`;
243
+ }
244
+ function formatNumber(num, decimals) {
245
+ if (isNaN(num)) return "NaN";
246
+ if (!isFinite(num)) return num > 0 ? "\u221E" : "-\u221E";
247
+ const fixed = decimals !== void 0 ? num.toFixed(decimals) : num.toString();
248
+ const [intPart, decPart] = fixed.split(".");
249
+ const formattedInt = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
250
+ return decPart ? `${formattedInt}.${decPart}` : formattedInt;
251
+ }
252
+ function formatPercent(value, decimals = 2, asRatio = true) {
253
+ const percent = asRatio ? value * 100 : value;
254
+ return `${percent.toFixed(decimals)}%`;
255
+ }
256
+ function formatCurrency(amount, currency = "CNY", locale = "zh-CN") {
257
+ return new Intl.NumberFormat(locale, {
258
+ style: "currency",
259
+ currency
260
+ }).format(amount);
261
+ }
262
+ function truncate(str, maxLength, suffix = "...") {
263
+ if (str.length <= maxLength) return str;
264
+ return str.slice(0, maxLength - suffix.length) + suffix;
265
+ }
266
+ function capitalize(str) {
267
+ return str.charAt(0).toUpperCase() + str.slice(1);
268
+ }
269
+ function kebabCase(str) {
270
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
271
+ }
272
+ function camelCase(str) {
273
+ return str.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
274
+ }
275
+
276
+ // src/utils/timing.ts
277
+ function delay(ms) {
278
+ return new Promise((resolve) => setTimeout(resolve, ms));
279
+ }
280
+ function delayWith(ms, value) {
281
+ return new Promise((resolve) => setTimeout(() => resolve(value), ms));
282
+ }
283
+ function cancelableDelay(ms) {
284
+ let timeoutId;
285
+ let rejectFn;
286
+ const promise = new Promise((resolve, reject) => {
287
+ rejectFn = reject;
288
+ timeoutId = setTimeout(resolve, ms);
289
+ });
290
+ return {
291
+ promise,
292
+ cancel: () => {
293
+ clearTimeout(timeoutId);
294
+ rejectFn(new Error("Delay cancelled"));
295
+ }
296
+ };
297
+ }
298
+ function withTimeout(promise, ms, message = "Operation timed out") {
299
+ let timeoutId;
300
+ const timeoutPromise = new Promise((_, reject) => {
301
+ timeoutId = setTimeout(() => {
302
+ reject(new Error(message));
303
+ }, ms);
304
+ });
305
+ return Promise.race([promise, timeoutPromise]).finally(() => {
306
+ clearTimeout(timeoutId);
307
+ });
308
+ }
309
+ function nextTick(fn) {
310
+ setTimeout(fn, 0);
311
+ }
312
+ function requestIdleCallback(fn, options) {
313
+ if (typeof window !== "undefined" && "requestIdleCallback" in window) {
314
+ return window.requestIdleCallback(fn, options);
315
+ }
316
+ return setTimeout(fn, options?.timeout ?? 1);
317
+ }
318
+
319
+ // src/utils/validators.ts
320
+ function isValidEmail(email) {
321
+ if (!email || typeof email !== "string") return false;
322
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
323
+ return emailRegex.test(email.trim());
324
+ }
325
+ function isValidPhone(phone) {
326
+ if (!phone || typeof phone !== "string") return false;
327
+ const phoneRegex = /^1[3-9]\d{9}$/;
328
+ return phoneRegex.test(phone.trim());
329
+ }
330
+ function isValidUrl(url) {
331
+ if (!url || typeof url !== "string") return false;
332
+ try {
333
+ const parsed = new URL(url);
334
+ return ["http:", "https:"].includes(parsed.protocol);
335
+ } catch {
336
+ return false;
337
+ }
338
+ }
339
+ function isValidIPv4(ip) {
340
+ if (!ip || typeof ip !== "string") return false;
341
+ const parts = ip.split(".");
342
+ if (parts.length !== 4) return false;
343
+ return parts.every((part) => {
344
+ const num = parseInt(part, 10);
345
+ return num >= 0 && num <= 255 && part === num.toString();
346
+ });
347
+ }
348
+ function isValidJSON(str) {
349
+ try {
350
+ JSON.parse(str);
351
+ return true;
352
+ } catch {
353
+ return false;
354
+ }
355
+ }
356
+ function isValidIdCard(idCard) {
357
+ if (!idCard || typeof idCard !== "string") return false;
358
+ const id = idCard.trim().toUpperCase();
359
+ if (id.length === 18) {
360
+ if (!/^\d{17}[\dX]$/.test(id)) return false;
361
+ const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
362
+ const checkCodes = ["1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"];
363
+ let sum = 0;
364
+ for (let i = 0; i < 17; i++) {
365
+ sum += parseInt(id[i], 10) * weights[i];
366
+ }
367
+ return id[17] === checkCodes[sum % 11];
368
+ }
369
+ if (id.length === 15) {
370
+ return /^\d{15}$/.test(id);
371
+ }
372
+ return false;
373
+ }
374
+ function isValidUnifiedCreditCode(code) {
375
+ if (!code || typeof code !== "string") return false;
376
+ const regex = /^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$/;
377
+ return regex.test(code.trim().toUpperCase());
378
+ }
379
+ function isValidBankCard(cardNumber) {
380
+ if (!cardNumber || typeof cardNumber !== "string") return false;
381
+ const cleaned = cardNumber.replace(/\s/g, "");
382
+ if (!/^\d{13,19}$/.test(cleaned)) return false;
383
+ let sum = 0;
384
+ let isEven = false;
385
+ for (let i = cleaned.length - 1; i >= 0; i--) {
386
+ let digit = parseInt(cleaned[i], 10);
387
+ if (isEven) {
388
+ digit *= 2;
389
+ if (digit > 9) digit -= 9;
390
+ }
391
+ sum += digit;
392
+ isEven = !isEven;
393
+ }
394
+ return sum % 10 === 0;
395
+ }
396
+ function checkPasswordStrength(password) {
397
+ const suggestions = [];
398
+ let score = 0;
399
+ if (!password) {
400
+ return { strength: "weak", score: 0, suggestions: ["\u8BF7\u8F93\u5165\u5BC6\u7801"] };
401
+ }
402
+ if (password.length >= 8) score += 1;
403
+ else suggestions.push("\u5BC6\u7801\u957F\u5EA6\u81F3\u5C118\u4F4D");
404
+ if (password.length >= 12) score += 1;
405
+ if (password.length >= 16) score += 1;
406
+ if (/[a-z]/.test(password)) score += 1;
407
+ else suggestions.push("\u5EFA\u8BAE\u5305\u542B\u5C0F\u5199\u5B57\u6BCD");
408
+ if (/[A-Z]/.test(password)) score += 1;
409
+ else suggestions.push("\u5EFA\u8BAE\u5305\u542B\u5927\u5199\u5B57\u6BCD");
410
+ if (/\d/.test(password)) score += 1;
411
+ else suggestions.push("\u5EFA\u8BAE\u5305\u542B\u6570\u5B57");
412
+ if (/[!@#$%^&*(),.?":{}|<>]/.test(password)) score += 2;
413
+ else suggestions.push("\u5EFA\u8BAE\u5305\u542B\u7279\u6B8A\u5B57\u7B26");
414
+ const commonPatterns = [
415
+ /^123/,
416
+ /password/i,
417
+ /qwerty/i,
418
+ /^abc/i
419
+ ];
420
+ if (commonPatterns.some((p) => p.test(password))) {
421
+ score -= 2;
422
+ suggestions.push("\u907F\u514D\u4F7F\u7528\u5E38\u89C1\u5BC6\u7801\u6A21\u5F0F");
423
+ }
424
+ let strength;
425
+ if (score <= 2) strength = "weak";
426
+ else if (score <= 4) strength = "medium";
427
+ else if (score <= 6) strength = "strong";
428
+ else strength = "very-strong";
429
+ return { strength, score: Math.max(0, score), suggestions };
430
+ }
431
+ function isEmpty(value) {
432
+ if (value === null || value === void 0) return true;
433
+ if (typeof value === "string") return value.trim() === "";
434
+ if (Array.isArray(value)) return value.length === 0;
435
+ if (typeof value === "object") return Object.keys(value).length === 0;
436
+ return false;
437
+ }
438
+ function isNumeric(value) {
439
+ if (typeof value === "number") return !isNaN(value) && isFinite(value);
440
+ if (typeof value === "string") return !isNaN(parseFloat(value)) && isFinite(parseFloat(value));
441
+ return false;
442
+ }
443
+ function isInteger(value) {
444
+ return Number.isInteger(value);
445
+ }
446
+ function isPositive(value) {
447
+ return typeof value === "number" && value > 0;
448
+ }
449
+ function isInRange(value, min, max) {
450
+ return typeof value === "number" && value >= min && value <= max;
451
+ }
452
+ /**
453
+ * @file format.ts
454
+ * @description 格式化工具函数集
455
+ * @module @brix/utils/format
456
+ * @version 3.0.0
457
+ *
458
+ * 【模块说明】
459
+ * 提供各种数据格式化工具,包括文件大小、日期时间、数字、货币、字符串等。
460
+ * 这些函数遵循中国大陆的常用格式习惯,同时支持国际化配置。
461
+ *
462
+ * 【使用场景】
463
+ * - 文件大小:上传下载、存储空间显示
464
+ * - 日期格式化:时间显示、相对时间、倒计时
465
+ * - 数字格式化:金额、百分比、统计数据
466
+ * - 字符串处理:截断、大小写转换
467
+ *
468
+ * @license Apache-2.0
469
+ */
470
+ /**
471
+ * @file timing.ts
472
+ * @description 时间控制工具函数集
473
+ * @module @brix/utils/timing
474
+ * @version 3.0.0
475
+ *
476
+ * 【模块说明】
477
+ * 提供各种时间控制相关的工具函数,包括防抖、节流、延迟、超时等。
478
+ * 这些函数是前端开发中最常用的性能优化工具。
479
+ *
480
+ * 【使用场景】
481
+ * - 防抖:搜索输入、表单校验、窗口调整
482
+ * - 节流:滚动事件、按钮点击、拖拽操作
483
+ * - 延迟:动画间隔、轮询等待、用户反馈
484
+ * - 超时:网络请求、长时任务控制
485
+ *
486
+ * @license Apache-2.0
487
+ */
488
+ /**
489
+ * @file validators.ts
490
+ * @description 验证工具函数集
491
+ * @module @brix/utils/validators
492
+ * @version 3.0.0
493
+ *
494
+ * 【模块说明】
495
+ * 提供各种数据验证工具函数,包括基础格式验证、中国特有证件验证、密码强度检查等。
496
+ * 验证函数均返回布尔值,不抛出异常,便于条件判断使用。
497
+ *
498
+ * 【使用场景】
499
+ * - 表单验证:邮箱、手机号、密码等
500
+ * - 证件验证:身份证、统一社会信用代码、银行卡等
501
+ * - 数据校验:URL、IP、JSON 格式等
502
+ * - 类型检查:空值、数字、范围等
503
+ *
504
+ * @license Apache-2.0
505
+ */
506
+
507
+ export { assert, assertNotNull, camelCase, cancelableDelay, capitalize, checkPasswordStrength, debounce, deepClone, deepMerge, delay, delayWith, formatCurrency, formatDate, formatDuration, formatFileSize, formatNumber, formatPercent, formatRelativeTime, isArray, isBoolean, isEmpty, isFunction, isInRange, isInteger, isNotNullOrUndefined, isNullOrUndefined, isNumber, isNumeric, isObject, isPositive, isPromise, isString, isValidBankCard, isValidEmail, isValidIPv4, isValidIdCard, isValidJSON, isValidPhone, isValidUnifiedCreditCode, isValidUrl, kebabCase, nextTick, parseFileSize, requestIdleCallback, throttle, truncate, withTimeout };
508
+ //# sourceMappingURL=chunk-OGZE7TFO.js.map
509
+ //# sourceMappingURL=chunk-OGZE7TFO.js.map