ph-utils 0.11.0 → 0.11.2

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 CHANGED
@@ -1,7 +1,7 @@
1
- ## ph-utils
2
-
3
- 整理了 js 前后端开发(web + nodejs)时常用的一些工具;[详细文档](https://gitee.com/towardly/ph/wikis/Home?sort_id=4035190)
4
-
5
- ### 包含如下工具文件
6
-
7
- `index` 基础工具类、`date` 跟日期相关的工具类、`file` 文件操作相关工具类[**服务端**]、`server` 服务端工具类、`validator` 数据验证、`dom` 浏览器节点操作相关[**前端**]、`web` 一些只适用于前端相关的工具、`color` 颜色相关工具
1
+ ## ph-utils
2
+
3
+ 整理了 js 前后端开发(web + nodejs)时常用的一些工具;[详细文档](https://gitee.com/towardly/ph/wikis/Home?sort_id=4035190)
4
+
5
+ ### 包含如下工具文件
6
+
7
+ `index` 基础工具类、`date` 跟日期相关的工具类、`file` 文件操作相关工具类[**服务端**]、`server` 服务端工具类、`validator` 数据验证、`dom` 浏览器节点操作相关[**前端**]、`web` 一些只适用于前端相关的工具、`color` 颜色相关工具
package/lib/array.d.ts CHANGED
@@ -59,14 +59,14 @@ export declare function symmetricDifference<T>(...arrs: T[][]): T[];
59
59
  * @param a2
60
60
  * @returns
61
61
  */
62
- export declare function isSubsetOf<T>(a1: T[] | Set<T>, a2: T[] | Set<T>): boolean;
62
+ export declare function isSubsetOf<T>(a1: T[] | Set<T>, a2: T[] | Set<T>): any;
63
63
  /**
64
64
  * 返回一个布尔值,指示给定集合中的所有元素是否都在此集合中。
65
65
  * @param arr1
66
66
  * @param arr2
67
67
  * @returns
68
68
  */
69
- export declare function isSupersetOf<T>(arr1: T[] | Set<T>, arr2: T[] | Set<T>): boolean;
69
+ export declare function isSupersetOf<T>(arr1: T[] | Set<T>, arr2: T[] | Set<T>): any;
70
70
  /**
71
71
  * 返回一个布尔值,指示此集合是否与给定集合没有公共元素。
72
72
  *
@@ -76,4 +76,4 @@ export declare function isSupersetOf<T>(arr1: T[] | Set<T>, arr2: T[] | Set<T>):
76
76
  * @param arr2
77
77
  * @returns
78
78
  */
79
- export declare function isDisjointFrom<T>(arr1: T[] | Set<T>, arr2: T[] | Set<T>): boolean;
79
+ export declare function isDisjointFrom<T>(arr1: T[] | Set<T>, arr2: T[] | Set<T>): any;
package/lib/dom.d.ts CHANGED
@@ -59,6 +59,7 @@ export declare function on<T extends Event>(element: HTMLElement, listener: stri
59
59
  once?: boolean;
60
60
  eventFlag?: string;
61
61
  eventStop?: boolean;
62
+ capture?: boolean;
62
63
  }): void;
63
64
  /**
64
65
  * 移除指定元素的事件监听器。
package/lib/server.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import type { SpawnOptions } from "node:child_process";
2
3
  /**
3
4
  * 执行命令
package/lib/theme.js CHANGED
@@ -19,10 +19,10 @@ export async function initTheme() {
19
19
  if ($themeStyle == null) {
20
20
  $themeStyle = document.createElement("style");
21
21
  $themeStyle.id = "theme-style";
22
- $themeStyle.innerHTML = `
23
- :root{color-scheme:light dark;}
24
- html.light{color-scheme: light;}
25
- html.dark {color-scheme: dark;}
22
+ $themeStyle.innerHTML = `
23
+ :root{color-scheme:light dark;}
24
+ html.light{color-scheme: light;}
25
+ html.dark {color-scheme: dark;}
26
26
  `;
27
27
  document.head.appendChild($themeStyle);
28
28
  }
@@ -11,9 +11,13 @@ export type RuleType = string | RegExp | ((v: any) => boolean) | (RegExp | strin
11
11
  message?: string;
12
12
  });
13
13
  export interface SchemaType {
14
+ /** 数据字段 */
14
15
  key: string;
16
+ /** 是否必须 */
15
17
  required?: boolean;
18
+ /** 验证规则列表 */
16
19
  rules?: RuleType[];
20
+ /** 错误信息 */
17
21
  message?: string;
18
22
  }
19
23
  /**
package/lib/validator.js CHANGED
@@ -32,11 +32,11 @@ const ruleFns = {
32
32
  },
33
33
  };
34
34
  class ValidateError extends Error {
35
- constructor(errors) {
36
- super(errors[0].message);
35
+ constructor(detail, key, message) {
36
+ super(message);
37
37
  this.name = "ValidateError";
38
- this.key = errors[0].key;
39
- this.errors = errors;
38
+ this.key = key;
39
+ this.detail = detail;
40
40
  }
41
41
  }
42
42
  /**
@@ -80,24 +80,25 @@ class Validator {
80
80
  */
81
81
  async validate(data, all = false) {
82
82
  return new Promise((resolve, reject) => {
83
- const errors = [];
83
+ const detail = {};
84
+ let currentKey = undefined;
85
+ let currentMessage = undefined;
84
86
  for (let key in this.rules) {
85
- // eslint-disable-next-line no-prototype-builtins
86
- if (this.rules.hasOwnProperty(key)) {
87
- let errMsg = this._validateRule(this.rules[key], data[key], data);
88
- if (errMsg !== "") {
89
- errMsg = errMsg.replace("%s", key);
90
- errors.push({ message: errMsg, key });
91
- if (all)
92
- break;
93
- }
87
+ let errMsg = this._validateRule(this.rules[key], data[key], data);
88
+ if (errMsg !== "") {
89
+ errMsg = errMsg.replace("%s", key);
90
+ detail[key] = errMsg;
91
+ currentKey = key;
92
+ currentMessage = errMsg;
93
+ if (all)
94
+ break;
94
95
  }
95
96
  }
96
- if (errors.length === 0) {
97
+ if (currentKey == null) {
97
98
  resolve(true);
98
99
  }
99
100
  else {
100
- reject(new ValidateError(errors));
101
+ reject(new ValidateError(detail, currentKey, currentMessage));
101
102
  }
102
103
  });
103
104
  }
@@ -110,10 +111,14 @@ class Validator {
110
111
  async validateKey(key, value, data) {
111
112
  return new Promise((resolve, reject) => {
112
113
  let keyRules = this.rules[key];
114
+ if (keyRules == null) {
115
+ resolve(true);
116
+ return;
117
+ }
113
118
  let errMsg = this._validateRule(keyRules, value, data);
114
119
  if (errMsg !== "") {
115
120
  errMsg = errMsg.replace("%s", key);
116
- reject(new ValidateError([{ key, message: errMsg }]));
121
+ reject(new ValidateError({ [key]: errMsg }, key, errMsg));
117
122
  }
118
123
  else {
119
124
  resolve(true);
@@ -129,7 +134,7 @@ class Validator {
129
134
  errMsg = rule.message;
130
135
  }
131
136
  }
132
- if (typeof rule.rule === "function") {
137
+ else if (typeof rule.rule === "function") {
133
138
  if (!rule.rule(value)) {
134
139
  errMsg = rule.message;
135
140
  }
@@ -141,13 +146,8 @@ class Validator {
141
146
  }
142
147
  }
143
148
  }
144
- else if (rule.rule === "required") {
145
- if (!ruleFns.pattern(ruleRegexs.required, String(value))) {
146
- errMsg = rule.message;
147
- }
148
- }
149
149
  else {
150
- if (!ruleFns.pattern(rule.rule, String(value))) {
150
+ if (!ruleFns.pattern(rule.rule, value)) {
151
151
  errMsg = rule.message;
152
152
  }
153
153
  }
@@ -161,6 +161,9 @@ class Validator {
161
161
  // 解析规则
162
162
  let rules = [];
163
163
  let rule = schema.rules;
164
+ if (schema.required === true) {
165
+ rules.push(...this._parseStringRule("required", schema.message));
166
+ }
164
167
  if (rule != null) {
165
168
  if (typeof rule === "string") {
166
169
  rules = rules.concat(this._parseStringRule(rule, schema.message));
@@ -194,10 +197,6 @@ class Validator {
194
197
  rules.push({ rule, message: defaultMsg });
195
198
  }
196
199
  }
197
- if (schema.required === true &&
198
- (rules == null || rules.findIndex((r) => r.rule === "required") === -1)) {
199
- rules.push(...this._parseStringRule("required", schema.message));
200
- }
201
200
  return rules;
202
201
  }
203
202
  _parseStringRule(rule, ruleErrMsg) {
@@ -207,7 +206,11 @@ class Validator {
207
206
  let message = ruleErrMsg;
208
207
  let rrule = null;
209
208
  let sameKey;
210
- if (ruleRegexs.same.test(r)) {
209
+ if (rule === "required") {
210
+ rrule = "required";
211
+ message = message || ruleErrMsg || defaultMsgs.required;
212
+ }
213
+ else if (ruleRegexs.same.test(r)) {
211
214
  let m = r.match(ruleRegexs.same);
212
215
  if (m != null) {
213
216
  rrule = ruleRegexs.same;
@@ -218,12 +221,7 @@ class Validator {
218
221
  message = message || defaultMsgs["same"];
219
222
  }
220
223
  }
221
- else if (rule === "required") {
222
- rrule = "required";
223
- message = message || ruleErrMsg || defaultMsgs.required;
224
- // eslint-disable-next-line no-prototype-builtins
225
- }
226
- else if (ruleRegexs.hasOwnProperty(r)) {
224
+ else if (Object.hasOwn(ruleRegexs, r)) {
227
225
  rrule = ruleRegexs[r];
228
226
  message = message || defaultMsgs[r];
229
227
  }
package/package.json CHANGED
@@ -68,7 +68,7 @@
68
68
  },
69
69
  "./*": "./lib/*"
70
70
  },
71
- "version": "0.11.0",
71
+ "version": "0.11.2",
72
72
  "type": "module",
73
73
  "repository": {
74
74
  "type": "git",
@@ -1,11 +0,0 @@
1
- /**
2
- * 复制数据, 可以从多种类型的数据
3
- * 1. 直接复制文本: await copy("待复制的文本")
4
- * 2. 复制节点上的 data-copy-text:
5
- * <button data-copy-text="这是待复制的文本">复制</button>
6
- * await copy(e.target) // or await copy("#a") or await copy(document.querySelector('#a'))
7
- * 3. 直接复制节点本身数据: await copy('#a')
8
- * @param {string | HTMLElement} source 复制源, 从中解析待复制的数据
9
- * @returns {Promise<boolean>} 是否复制成功
10
- */
11
- export declare function copy(source: string | HTMLElement): Promise<boolean>;
package/lib/clipboard.js DELETED
@@ -1,101 +0,0 @@
1
- /**
2
- * 创建一个临时节点缓存待复制数据
3
- * @param {String} value - 待复制文本
4
- * @return {HTMLElement}
5
- */
6
- function createFakeElement(value) {
7
- const fakeElement = document.createElement("textarea");
8
- fakeElement.style.border = "0";
9
- fakeElement.style.padding = "0";
10
- fakeElement.style.margin = "0";
11
- fakeElement.style.position = "absolute";
12
- fakeElement.style.left = "-9999px";
13
- fakeElement.style.top = "-9999";
14
- fakeElement.setAttribute("readonly", "");
15
- fakeElement.value = value;
16
- return fakeElement;
17
- }
18
- /** 通过执行 execCommand 来执行复制 */
19
- function copyFromCommand(text) {
20
- // 添加节点
21
- const fakeEl = createFakeElement(text);
22
- document.body.append(fakeEl);
23
- fakeEl.focus();
24
- fakeEl.select();
25
- // 执行复制
26
- const res = document.execCommand("copy");
27
- fakeEl.remove(); // 删除节点
28
- return Promise.resolve(res);
29
- }
30
- /** 使用 navigator.clipboard 复制 */
31
- function copyFromClipboard(text) {
32
- const theClipboard = navigator.clipboard;
33
- if (theClipboard != null) {
34
- return theClipboard
35
- .writeText(text)
36
- .then(() => {
37
- Promise.resolve(true);
38
- })
39
- .catch(() => Promise.resolve(false));
40
- }
41
- return Promise.resolve(false);
42
- }
43
- /** 解析待复制的文本 */
44
- function parseCopyText(source) {
45
- let copyText = null; // 待复制文本
46
- let sourceEl = null;
47
- // 获取待复制数据
48
- if (typeof source === "string") {
49
- // 从节点拿数据
50
- if (source.startsWith("#") || source.startsWith(".")) {
51
- sourceEl = document.querySelector(source);
52
- if (sourceEl == null) {
53
- copyText = source;
54
- }
55
- }
56
- else {
57
- copyText = source;
58
- }
59
- }
60
- if (source instanceof HTMLElement) {
61
- sourceEl = source;
62
- }
63
- // 从节点获取待复制数据
64
- if (sourceEl != null) {
65
- if (sourceEl.hasAttribute("data-copy-text")) {
66
- copyText = sourceEl.getAttribute("data-copy-text");
67
- }
68
- else {
69
- const tagName = sourceEl.tagName;
70
- if (tagName === "INPUT" || tagName === "TEXTAREA") {
71
- copyText = sourceEl.value;
72
- }
73
- else {
74
- copyText = sourceEl.textContent;
75
- }
76
- }
77
- }
78
- return copyText;
79
- }
80
- /**
81
- * 复制数据, 可以从多种类型的数据
82
- * 1. 直接复制文本: await copy("待复制的文本")
83
- * 2. 复制节点上的 data-copy-text:
84
- * <button data-copy-text="这是待复制的文本">复制</button>
85
- * await copy(e.target) // or await copy("#a") or await copy(document.querySelector('#a'))
86
- * 3. 直接复制节点本身数据: await copy('#a')
87
- * @param {string | HTMLElement} source 复制源, 从中解析待复制的数据
88
- * @returns {Promise<boolean>} 是否复制成功
89
- */
90
- export async function copy(source) {
91
- // 待复制文本
92
- const copyText = parseCopyText(source);
93
- if (copyText == null) {
94
- return Promise.resolve(false);
95
- }
96
- const v = await copyFromClipboard(copyText);
97
- if (v === false) {
98
- return copyFromCommand(copyText);
99
- }
100
- return Promise.resolve(true);
101
- }