ph-utils 0.4.6 → 0.4.8

Sign up to get free protection for your applications and to get access to all the features.
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/index.d.ts CHANGED
@@ -50,6 +50,13 @@ interface RandomConfig {
50
50
  * 1. 生成指定长度的随机数
51
51
  * 2. 生成介于 [min, max] 之间的随机数
52
52
  * @param opts 生成随机数的配置
53
+ *
54
+ * @example <caption>1. 生成指定长度的随机字符串</caption>
55
+ * random(1); // 长度为 1 的随机字符串
56
+ *
57
+ * @example <caption>2. 生成纯数字且不能为0长度为1的随机字符</caption>
58
+ * random({ length: 1, hasLetter: false, firstIsZero: false })
59
+ *
53
60
  * @returns
54
61
  */
55
62
  export declare function random(opts: number | RandomConfig): string | number;
package/lib/index.js CHANGED
@@ -58,6 +58,13 @@ export function isBoolean(str) {
58
58
  * 1. 生成指定长度的随机数
59
59
  * 2. 生成介于 [min, max] 之间的随机数
60
60
  * @param opts 生成随机数的配置
61
+ *
62
+ * @example <caption>1. 生成指定长度的随机字符串</caption>
63
+ * random(1); // 长度为 1 的随机字符串
64
+ *
65
+ * @example <caption>2. 生成纯数字且不能为0长度为1的随机字符</caption>
66
+ * random({ length: 1, hasLetter: false, firstIsZero: false })
67
+ *
61
68
  * @returns
62
69
  */
63
70
  export function random(opts) {
@@ -74,12 +81,11 @@ export function random(opts) {
74
81
  }
75
82
  const len = typeof opts === "object" ? opts.length : opts;
76
83
  /* 生成指定长度的随机数 */
77
- const charLens = RANDOM_CHARS.length;
78
84
  let chars = RANDOM_CHARS;
79
85
  if (typeof opts === "object" && opts.hasLetter === false) {
80
86
  chars = NUMBER_RANDOM_CHARTS;
81
87
  }
82
- const resRandom = Array.from({ length: len }, () => chars.charAt(Math.floor(Math.random() * charLens))).join("");
88
+ const resRandom = Array.from({ length: len }, () => chars.charAt(random({ min: 0, max: 9, hasEnd: true }))).join("");
83
89
  if (typeof opts === "object" &&
84
90
  opts.firstIsZero === false &&
85
91
  resRandom.indexOf("0") === 0) {
@@ -2,7 +2,7 @@
2
2
  * 数据验证器
3
3
  */
4
4
  interface RuleItem {
5
- rule: RegExp | ((v: any) => boolean) | 'required';
5
+ rule: RegExp | ((v: any) => boolean) | "required";
6
6
  message: string;
7
7
  sameKey?: string;
8
8
  }
@@ -18,7 +18,7 @@ export interface SchemaType {
18
18
  message?: string;
19
19
  }
20
20
  /**
21
- * 数据验证器,除了进行数据验证外,还可以同时进行数据转化
21
+ * 数据验证器
22
22
  */
23
23
  declare class Validator {
24
24
  rules: {
@@ -40,7 +40,10 @@ declare class Validator {
40
40
  * @param key 指定待验证的 key
41
41
  * @param value 待验证的数据
42
42
  */
43
- validateKey(key: string, value: any, data?: any): Promise<boolean>;
43
+ validateKey(key: string, value: any, data?: any): Promise<{
44
+ key: string;
45
+ value: any;
46
+ }>;
44
47
  private _validateRule;
45
48
  private _parseStringRule;
46
49
  }
package/lib/validator.js CHANGED
@@ -3,17 +3,17 @@
3
3
  */
4
4
  // 默认的错误提示信息
5
5
  const defaultMsgs = {
6
- mobile: '请输入正确的手机号',
7
- same: '两次输入不一致',
8
- required: '%s为必填字段',
6
+ mobile: "请输入正确的手机号",
7
+ same: "两次输入不一致",
8
+ required: "%s为必填字段",
9
9
  };
10
- const defaultMsg = '请输入正确的数据';
10
+ const defaultMsg = "请输入正确的数据";
11
11
  // 一些常用的验证正则
12
12
  const ruleRegexs = {
13
13
  /** 验证跟其余数据相等的正则,一般用于验证再次输入密码 */
14
14
  same: /^same:(.+)$/i,
15
15
  /** 验证手机号的正则表达式 */
16
- mobile: /^1[34578]\d{9}$/,
16
+ mobile: /^1[345678]\d{9}$/,
17
17
  /** 非空验证的正则表达式 */
18
18
  required: /^\S{1}.*/,
19
19
  };
@@ -36,12 +36,12 @@ class ValidateError extends Error {
36
36
  key;
37
37
  constructor(key, msg) {
38
38
  super(msg);
39
- this.name = 'ValidateError';
39
+ this.name = "ValidateError";
40
40
  this.key = key;
41
41
  }
42
42
  }
43
43
  /**
44
- * 数据验证器,除了进行数据验证外,还可以同时进行数据转化
44
+ * 数据验证器
45
45
  */
46
46
  class Validator {
47
47
  rules;
@@ -56,22 +56,23 @@ class Validator {
56
56
  let rules = [];
57
57
  let rule = schema.rules;
58
58
  if (rule != null) {
59
- if (typeof rule === 'string') {
59
+ if (typeof rule === "string") {
60
60
  rules = rules.concat(this._parseStringRule(rule, schema.message));
61
61
  }
62
62
  else if (rule instanceof Array) {
63
63
  for (let ruleItem of rule) {
64
- if (typeof ruleItem === 'string') {
64
+ if (typeof ruleItem === "string") {
65
65
  rules.push(...this._parseStringRule(ruleItem, schema.message));
66
66
  }
67
- else if (ruleItem instanceof RegExp || typeof ruleItem === 'function') {
67
+ else if (ruleItem instanceof RegExp ||
68
+ typeof ruleItem === "function") {
68
69
  rules.push({
69
70
  rule: ruleItem,
70
71
  message: schema.message || defaultMsg,
71
72
  });
72
73
  }
73
74
  else {
74
- if (typeof ruleItem.rule === 'string') {
75
+ if (typeof ruleItem.rule === "string") {
75
76
  rules.push(...this._parseStringRule(ruleItem.rule, ruleItem.message));
76
77
  }
77
78
  else {
@@ -87,8 +88,9 @@ class Validator {
87
88
  rules.push({ rule, message: defaultMsg });
88
89
  }
89
90
  }
90
- if (schema.required === true && (rules == null || rules.findIndex((r) => r.rule === 'required') === -1)) {
91
- rules.push(...this._parseStringRule('required', schema.message));
91
+ if (schema.required === true &&
92
+ (rules == null || rules.findIndex((r) => r.rule === "required") === -1)) {
93
+ rules.push(...this._parseStringRule("required", schema.message));
92
94
  }
93
95
  parsedRules[schema.key] = rules;
94
96
  }
@@ -99,57 +101,54 @@ class Validator {
99
101
  * @param data 待验证的数据
100
102
  * @returns
101
103
  */
102
- validate(data) {
103
- return new Promise((resolve, reject) => {
104
- let errMsg = '';
105
- let errKey = '';
106
- for (let key in this.rules) {
107
- // eslint-disable-next-line no-prototype-builtins
108
- if (this.rules.hasOwnProperty(key)) {
109
- errMsg = this._validateRule(this.rules[key], data[key], data);
110
- if (errMsg !== '') {
111
- errKey = key;
112
- errMsg = errMsg.replace('%s', key);
113
- break;
114
- }
104
+ async validate(data) {
105
+ let errMsg = "";
106
+ let errKey = "";
107
+ for (let key in this.rules) {
108
+ // eslint-disable-next-line no-prototype-builtins
109
+ if (this.rules.hasOwnProperty(key)) {
110
+ errMsg = this._validateRule(this.rules[key], data[key], data);
111
+ if (errMsg !== "") {
112
+ errKey = key;
113
+ errMsg = errMsg.replace("%s", key);
114
+ break;
115
115
  }
116
116
  }
117
- if (errMsg === '') {
118
- resolve(true);
119
- }
120
- else {
121
- reject(new ValidateError(errKey, errMsg));
122
- }
123
- });
117
+ }
118
+ if (errMsg === "") {
119
+ return true;
120
+ }
121
+ else {
122
+ throw new ValidateError(errKey, errMsg);
123
+ }
124
124
  }
125
125
  /**
126
126
  * 只验证指定 key 的数据格式
127
127
  * @param key 指定待验证的 key
128
128
  * @param value 待验证的数据
129
129
  */
130
- validateKey(key, value, data) {
131
- return new Promise((resolve, reject) => {
132
- let keyRules = this.rules[key];
133
- let errMsg = this._validateRule(keyRules, value, data);
134
- if (errMsg !== '') {
135
- errMsg = errMsg.replace('%s', key);
136
- reject(new ValidateError(key, errMsg));
137
- }
138
- else {
139
- resolve(true);
140
- }
141
- });
130
+ async validateKey(key, value, data) {
131
+ let keyRules = this.rules[key];
132
+ let errMsg = this._validateRule(keyRules, value, data);
133
+ if (errMsg !== "") {
134
+ errMsg = errMsg.replace("%s", key);
135
+ throw new ValidateError(key, errMsg);
136
+ }
137
+ else {
138
+ return { key, value };
139
+ }
142
140
  }
143
141
  _validateRule(rules, value, data) {
144
- let errMsg = '';
142
+ this.validateKey("", 1).catch((err) => { });
143
+ let errMsg = "";
145
144
  for (let rule of rules) {
146
145
  // 如果数据为空,则判断是否是必填
147
- if (rule.rule === 'required') {
146
+ if (rule.rule === "required") {
148
147
  if (value == null || !ruleFns.pattern(ruleRegexs.required, value)) {
149
148
  errMsg = rule.message;
150
149
  }
151
150
  }
152
- if (typeof rule.rule === 'function') {
151
+ if (typeof rule.rule === "function") {
153
152
  if (!rule.rule(value)) {
154
153
  errMsg = rule.message;
155
154
  }
@@ -161,7 +160,7 @@ class Validator {
161
160
  }
162
161
  }
163
162
  }
164
- else if (rule.rule === 'required') {
163
+ else if (rule.rule === "required") {
165
164
  if (!ruleFns.pattern(ruleRegexs.required, String(value))) {
166
165
  errMsg = rule.message;
167
166
  }
@@ -171,7 +170,7 @@ class Validator {
171
170
  errMsg = rule.message;
172
171
  }
173
172
  }
174
- if (errMsg !== '') {
173
+ if (errMsg !== "") {
175
174
  break;
176
175
  }
177
176
  }
@@ -179,7 +178,7 @@ class Validator {
179
178
  }
180
179
  _parseStringRule(rule, ruleErrMsg) {
181
180
  let rules = [];
182
- let trule = rule.split('|');
181
+ let trule = rule.split("|");
183
182
  for (let r of trule) {
184
183
  let message = ruleErrMsg;
185
184
  let rrule = null;
@@ -192,11 +191,11 @@ class Validator {
192
191
  if (m != null) {
193
192
  sameKey = m[1];
194
193
  }
195
- message = message || defaultMsgs['same'];
194
+ message = message || defaultMsgs["same"];
196
195
  }
197
196
  }
198
- else if (rule === 'required') {
199
- rrule = 'required';
197
+ else if (rule === "required") {
198
+ rrule = "required";
200
199
  message = message || ruleErrMsg || defaultMsgs.required;
201
200
  // eslint-disable-next-line no-prototype-builtins
202
201
  }
package/package.json CHANGED
@@ -52,7 +52,7 @@
52
52
  },
53
53
  "./*": "./lib/*"
54
54
  },
55
- "version": "0.4.6",
55
+ "version": "0.4.8",
56
56
  "type": "module",
57
57
  "repository": {
58
58
  "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
- }