ph-utils 0.10.2 → 0.11.1

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
@@ -156,7 +156,7 @@ export declare function formatClass(classObj: (boolean | string | undefined | nu
156
156
  * @param styleObj - 样式对象,可以是字符串数组或键值对对象。
157
157
  * @returns 格式化后的 CSS 样式字符串。
158
158
  */
159
- export declare function formatStyle(styleObj: (string | undefined | null | "")[] | Record<string, string>): string;
159
+ export declare function formatStyle(styleObj: (string | undefined | null | "")[] | Record<string, string | undefined | null>): string;
160
160
  /**
161
161
  * 对指定的 HTML 元素应用显示过渡效果。
162
162
  * @param target - 要应用过渡效果的 HTML 元素。
package/lib/dom.js CHANGED
@@ -333,8 +333,9 @@ export function formatStyle(styleObj) {
333
333
  }
334
334
  else {
335
335
  for (const key in styleObj) {
336
- if (styleObj[key]) {
337
- styleStr += `${key}:${styleObj[key]};`;
336
+ const value = styleObj[key];
337
+ if (value) {
338
+ styleStr += `${key}:${value};`;
338
339
  }
339
340
  }
340
341
  }
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,10 +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;
16
- type?: string | ((v: any) => void);
18
+ /** 验证规则列表 */
17
19
  rules?: RuleType[];
20
+ /** 错误信息 */
18
21
  message?: string;
19
22
  }
20
23
  /**
@@ -42,6 +45,8 @@ declare class Validator {
42
45
  * validator.validateKey().then(res => {})
43
46
  */
44
47
  constructor(schemas: SchemaType[]);
48
+ addSchemas(schemas: SchemaType[]): void;
49
+ addSchema(schema: SchemaType): void;
45
50
  /**
46
51
  * 进行数据验证
47
52
  * @param data 待验证的数据
@@ -57,6 +62,7 @@ declare class Validator {
57
62
  */
58
63
  validateKey(key: string, value: any, data?: any): Promise<boolean>;
59
64
  private _validateRule;
65
+ private _parseSchemaRules;
60
66
  private _parseStringRule;
61
67
  }
62
68
  export default Validator;
package/lib/validator.js CHANGED
@@ -61,51 +61,16 @@ class Validator {
61
61
  * validator.validateKey().then(res => {})
62
62
  */
63
63
  constructor(schemas) {
64
- let parsedRules = {};
64
+ this.rules = {};
65
+ this.addSchemas(schemas);
66
+ }
67
+ addSchemas(schemas) {
65
68
  for (let schema of schemas) {
66
- // 解析规则
67
- let rules = [];
68
- let rule = schema.rules;
69
- if (rule != null) {
70
- if (typeof rule === "string") {
71
- rules = rules.concat(this._parseStringRule(rule, schema.message));
72
- }
73
- else if (rule instanceof Array) {
74
- for (let ruleItem of rule) {
75
- if (typeof ruleItem === "string") {
76
- rules.push(...this._parseStringRule(ruleItem, schema.message));
77
- }
78
- else if (ruleItem instanceof RegExp ||
79
- typeof ruleItem === "function") {
80
- rules.push({
81
- rule: ruleItem,
82
- message: schema.message || defaultMsg,
83
- });
84
- }
85
- else {
86
- if (typeof ruleItem.rule === "string") {
87
- rules.push(...this._parseStringRule(ruleItem.rule, ruleItem.message));
88
- }
89
- else {
90
- rules.push({
91
- rule: ruleItem.rule,
92
- message: ruleItem.message || defaultMsg,
93
- });
94
- }
95
- }
96
- }
97
- }
98
- else {
99
- rules.push({ rule, message: defaultMsg });
100
- }
101
- }
102
- if (schema.required === true &&
103
- (rules == null || rules.findIndex((r) => r.rule === "required") === -1)) {
104
- rules.push(...this._parseStringRule("required", schema.message));
105
- }
106
- parsedRules[schema.key] = rules;
69
+ this.rules[schema.key] = this._parseSchemaRules(schema);
107
70
  }
108
- this.rules = parsedRules;
71
+ }
72
+ addSchema(schema) {
73
+ this.rules[schema.key] = this._parseSchemaRules(schema);
109
74
  }
110
75
  /**
111
76
  * 进行数据验证
@@ -117,15 +82,12 @@ class Validator {
117
82
  return new Promise((resolve, reject) => {
118
83
  const errors = [];
119
84
  for (let key in this.rules) {
120
- // eslint-disable-next-line no-prototype-builtins
121
- if (this.rules.hasOwnProperty(key)) {
122
- let errMsg = this._validateRule(this.rules[key], data[key], data);
123
- if (errMsg !== "") {
124
- errMsg = errMsg.replace("%s", key);
125
- errors.push({ message: errMsg, key });
126
- if (all)
127
- break;
128
- }
85
+ let errMsg = this._validateRule(this.rules[key], data[key], data);
86
+ if (errMsg !== "") {
87
+ errMsg = errMsg.replace("%s", key);
88
+ errors.push({ message: errMsg, key });
89
+ if (all)
90
+ break;
129
91
  }
130
92
  }
131
93
  if (errors.length === 0) {
@@ -145,6 +107,10 @@ class Validator {
145
107
  async validateKey(key, value, data) {
146
108
  return new Promise((resolve, reject) => {
147
109
  let keyRules = this.rules[key];
110
+ if (keyRules == null) {
111
+ resolve(true);
112
+ return;
113
+ }
148
114
  let errMsg = this._validateRule(keyRules, value, data);
149
115
  if (errMsg !== "") {
150
116
  errMsg = errMsg.replace("%s", key);
@@ -164,7 +130,7 @@ class Validator {
164
130
  errMsg = rule.message;
165
131
  }
166
132
  }
167
- if (typeof rule.rule === "function") {
133
+ else if (typeof rule.rule === "function") {
168
134
  if (!rule.rule(value)) {
169
135
  errMsg = rule.message;
170
136
  }
@@ -176,13 +142,8 @@ class Validator {
176
142
  }
177
143
  }
178
144
  }
179
- else if (rule.rule === "required") {
180
- if (!ruleFns.pattern(ruleRegexs.required, String(value))) {
181
- errMsg = rule.message;
182
- }
183
- }
184
145
  else {
185
- if (!ruleFns.pattern(rule.rule, String(value))) {
146
+ if (!ruleFns.pattern(rule.rule, value)) {
186
147
  errMsg = rule.message;
187
148
  }
188
149
  }
@@ -192,6 +153,48 @@ class Validator {
192
153
  }
193
154
  return errMsg;
194
155
  }
156
+ _parseSchemaRules(schema) {
157
+ // 解析规则
158
+ let rules = [];
159
+ let rule = schema.rules;
160
+ if (schema.required === true) {
161
+ rules.push(...this._parseStringRule("required", schema.message));
162
+ }
163
+ if (rule != null) {
164
+ if (typeof rule === "string") {
165
+ rules = rules.concat(this._parseStringRule(rule, schema.message));
166
+ }
167
+ else if (rule instanceof Array) {
168
+ for (let ruleItem of rule) {
169
+ if (typeof ruleItem === "string") {
170
+ rules.push(...this._parseStringRule(ruleItem, schema.message));
171
+ }
172
+ else if (ruleItem instanceof RegExp ||
173
+ typeof ruleItem === "function") {
174
+ rules.push({
175
+ rule: ruleItem,
176
+ message: schema.message || defaultMsg,
177
+ });
178
+ }
179
+ else {
180
+ if (typeof ruleItem.rule === "string") {
181
+ rules.push(...this._parseStringRule(ruleItem.rule, ruleItem.message));
182
+ }
183
+ else {
184
+ rules.push({
185
+ rule: ruleItem.rule,
186
+ message: ruleItem.message || defaultMsg,
187
+ });
188
+ }
189
+ }
190
+ }
191
+ }
192
+ else {
193
+ rules.push({ rule, message: defaultMsg });
194
+ }
195
+ }
196
+ return rules;
197
+ }
195
198
  _parseStringRule(rule, ruleErrMsg) {
196
199
  let rules = [];
197
200
  let trule = rule.split("|");
@@ -199,7 +202,11 @@ class Validator {
199
202
  let message = ruleErrMsg;
200
203
  let rrule = null;
201
204
  let sameKey;
202
- if (ruleRegexs.same.test(r)) {
205
+ if (rule === "required") {
206
+ rrule = "required";
207
+ message = message || ruleErrMsg || defaultMsgs.required;
208
+ }
209
+ else if (ruleRegexs.same.test(r)) {
203
210
  let m = r.match(ruleRegexs.same);
204
211
  if (m != null) {
205
212
  rrule = ruleRegexs.same;
@@ -210,12 +217,7 @@ class Validator {
210
217
  message = message || defaultMsgs["same"];
211
218
  }
212
219
  }
213
- else if (rule === "required") {
214
- rrule = "required";
215
- message = message || ruleErrMsg || defaultMsgs.required;
216
- // eslint-disable-next-line no-prototype-builtins
217
- }
218
- else if (ruleRegexs.hasOwnProperty(r)) {
220
+ else if (Object.hasOwn(ruleRegexs, r)) {
219
221
  rrule = ruleRegexs[r];
220
222
  message = message || defaultMsgs[r];
221
223
  }
package/package.json CHANGED
@@ -68,7 +68,7 @@
68
68
  },
69
69
  "./*": "./lib/*"
70
70
  },
71
- "version": "0.10.2",
71
+ "version": "0.11.1",
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
- }