ph-utils 0.5.1 → 0.6.1

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` 颜色相关工具
@@ -0,0 +1,11 @@
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>;
@@ -0,0 +1,101 @@
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
+ }
package/lib/date.d.ts CHANGED
@@ -12,9 +12,9 @@ export declare function format(date?: Date | string | number | null, pattern?: s
12
12
  export declare function parse(date?: Date | string | number | null): Date;
13
13
  /**
14
14
  * 设置日期的开始或者结束的点
15
- * @param {Object} date 日期,能够被 parse 解析的日期
16
- * @param {String} unit 单位,Date|date, 默认为 Date
17
- * @param {Boolean} isEnd true则为 endOf
15
+ * @param date 日期,能够被 parse 解析的日期
16
+ * @param unit 单位,Date|date, 默认为 Date
17
+ * @param isEnd true则为 endOf
18
18
  */
19
19
  export declare function dateOf(date?: Date | string | number, unit?: string, isEnd?: boolean): Date;
20
20
  /**
@@ -45,6 +45,10 @@ export declare function timeStamp(ctime?: Date | string | number, pre?: "s" | "m
45
45
  * @param unit 需要添加的单位,date、month、year、hours、minute、second
46
46
  *
47
47
  * 查阅文档: {@link https://gitee.com/towardly/ph/wikis/utils/date ph-utils}
48
+ *
49
+ * @example <caption>1. 分钟加1并格式化显示时间</caption>
50
+ *
51
+ * add(new Date(), 1, 'minute', 'HHMMss')
48
52
  */
49
53
  export declare function add(date: Date | string | number | null, num: number, unit: string): Date;
50
54
  /**
package/lib/date.js CHANGED
@@ -131,9 +131,9 @@ export function parse(date) {
131
131
  }
132
132
  /**
133
133
  * 设置日期的开始或者结束的点
134
- * @param {Object} date 日期,能够被 parse 解析的日期
135
- * @param {String} unit 单位,Date|date, 默认为 Date
136
- * @param {Boolean} isEnd true则为 endOf
134
+ * @param date 日期,能够被 parse 解析的日期
135
+ * @param unit 单位,Date|date, 默认为 Date
136
+ * @param isEnd true则为 endOf
137
137
  */
138
138
  export function dateOf(date, unit, isEnd = false) {
139
139
  /* 如果是设置某一天的开始时刻, 就需要将时、分、秒、毫秒设置为0,依次类推设置 */
package/lib/file.d.ts CHANGED
@@ -1,14 +1,14 @@
1
1
  /**
2
- * 读取文件内容为JSON格式
3
- * @param filepath 读取的文件路径
4
- * @param defaultValue 读取失败时,提供默认值, 如果不提供传参数则[抛出异常]
5
- *
6
- * @example <caption>1. 文件不存在时, 默认为: null</caption>
7
- * await readJSON("./not-exists.json", true);
8
- *
9
- * @returns Promise<unknown>
2
+ * 读取文件内容
3
+ * @example <caption>1. 读取JSON文件, 内容为字符串列表</caption>
4
+ * read<string[]>('a.json', []);
5
+ * @example <caption>2. 读取JSON文件, 内容为对象</caption>
6
+ * read<{ name: string }>('b.json', {});
7
+ * @param filepath 文件路径
8
+ * @param defaultValue 文件不存在时默认值, 不传则抛异常, 如果传递的是对象形式则会将结果转换为 JSON
9
+ * @returns 文件内容
10
10
  */
11
- export declare function readJSON<T>(filepath: string, defaultValue?: T): Promise<T>;
11
+ export declare function read<T>(filepath: string, defaultValue?: T): Promise<any>;
12
12
  /**
13
13
  * 写入 JSON 格式的数据到文件
14
14
  * @param file 待写入的文件
@@ -20,7 +20,7 @@ export declare function readJSON<T>(filepath: string, defaultValue?: T): Promise
20
20
  export declare function write(file: string, data: any, opts?: {
21
21
  json: boolean;
22
22
  format: boolean;
23
- }): Promise<unknown>;
23
+ }): Promise<void>;
24
24
  /**
25
25
  * 根据文件的 stat 获取文件的 etag
26
26
  * @param filePath 文件地址
package/lib/file.js CHANGED
@@ -1,32 +1,30 @@
1
1
  /** nodejs 文件操作工具类 */
2
2
  import path from "node:path";
3
- import fs from "node:fs";
3
+ import fs from "node:fs/promises";
4
4
  /**
5
- * 读取文件内容为JSON格式
6
- * @param filepath 读取的文件路径
7
- * @param defaultValue 读取失败时,提供默认值, 如果不提供传参数则[抛出异常]
8
- *
9
- * @example <caption>1. 文件不存在时, 默认为: null</caption>
10
- * await readJSON("./not-exists.json", true);
11
- *
12
- * @returns Promise<unknown>
5
+ * 读取文件内容
6
+ * @example <caption>1. 读取JSON文件, 内容为字符串列表</caption>
7
+ * read<string[]>('a.json', []);
8
+ * @example <caption>2. 读取JSON文件, 内容为对象</caption>
9
+ * read<{ name: string }>('b.json', {});
10
+ * @param filepath 文件路径
11
+ * @param defaultValue 文件不存在时默认值, 不传则抛异常, 如果传递的是对象形式则会将结果转换为 JSON
12
+ * @returns 文件内容
13
13
  */
14
- export function readJSON(filepath, defaultValue) {
15
- return new Promise((resolve, reject) => {
16
- fs.readFile(path.resolve(filepath), "utf-8", (err, data) => {
17
- if (err) {
18
- if (defaultValue !== undefined) {
19
- resolve(defaultValue);
20
- }
21
- else {
22
- reject(err);
23
- }
24
- }
25
- else {
26
- resolve(JSON.parse(data));
27
- }
28
- });
29
- });
14
+ export async function read(filepath, defaultValue) {
15
+ let content;
16
+ try {
17
+ content = await fs.readFile(filepath, "utf8");
18
+ if (defaultValue != null && typeof defaultValue === "object") {
19
+ return JSON.parse(content);
20
+ }
21
+ }
22
+ catch (error) {
23
+ if (defaultValue === undefined) {
24
+ throw error;
25
+ }
26
+ return defaultValue;
27
+ }
30
28
  }
31
29
  /**
32
30
  * 写入 JSON 格式的数据到文件
@@ -36,22 +34,13 @@ export function readJSON(filepath, defaultValue) {
36
34
  * @property opts.json 是否写入 JSON 格式的数据,写入数据时对数据进行 JSON 格式化,默认为:true
37
35
  * @property opts.format 是否在写入 json 数据时,将 JSON 数据格式化2个空格写入, 默认为 true
38
36
  */
39
- export function write(file, data, opts) {
40
- return new Promise((resolve, reject) => {
41
- let writeData = data.toString();
42
- opts = { json: true, format: true, ...opts };
43
- if (opts.json === true && typeof data === "object") {
44
- writeData = JSON.stringify(data, null, opts.format === true ? 2 : 0);
45
- }
46
- fs.writeFile(path.resolve(file), writeData, (err) => {
47
- if (err) {
48
- reject(err);
49
- }
50
- else {
51
- resolve(0);
52
- }
53
- });
54
- });
37
+ export async function write(file, data, opts) {
38
+ let writeData = data.toString();
39
+ opts = { json: true, format: true, ...opts };
40
+ if (opts.json === true && typeof data === "object") {
41
+ writeData = JSON.stringify(data, null, opts.format === true ? 2 : 0);
42
+ }
43
+ return await fs.writeFile(path.resolve(file), writeData);
55
44
  }
56
45
  /**
57
46
  * 根据文件的 stat 获取文件的 etag
@@ -59,6 +48,6 @@ export function write(file, data, opts) {
59
48
  * @returns file stat etag
60
49
  */
61
50
  export async function statTag(filePath) {
62
- let stat = await fs.promises.stat(filePath);
51
+ let stat = await fs.stat(filePath);
63
52
  return `${stat.size.toString(16)}-${stat.mtimeMs.toString(16)}`;
64
53
  }
package/lib/server.d.ts CHANGED
@@ -1,32 +1,10 @@
1
+ /// <reference types="node" />
2
+ import type { SpawnOptions } from "node:child_process";
1
3
  /**
2
4
  * 执行命令
3
- * @param cmd 执行的命令
4
- * @returns
5
+ * @param command 待执行的命令
6
+ * @param args 命令参数
5
7
  */
6
- export declare function exec(cmd: string): Promise<string>;
7
- interface SpawnCmdOptions {
8
- /** 命令运行目录 */
9
- cwd?: string;
10
- /** 每一行的输出 */
11
- data?: (lineText?: string) => void;
12
- /** 错误输出 */
13
- error?: (err: Error) => void;
14
- /** 最终结果 */
15
- finally?: (err?: Error) => void;
16
- }
17
- /**
18
- * 执行 spawn 命令
19
- * @param command 执行的命令: 例如: git
20
- * @param args 命令参数: ['clone', 'https://xxxx.git']
21
- * @param options 参数
22
- */
23
- export declare function spawnCmd(command: string, args?: string[], options?: SpawnCmdOptions): void;
24
- /**
25
- * 执行 spawn 命令
26
- * @param command 执行的命令: 例如: git
27
- * @param args 命令参数: ['clone', 'https://xxxx.git']
28
- * @param options 参数
29
- * @returns
30
- */
31
- export declare function spawnPromise(command: string, args?: string[], options?: SpawnCmdOptions): Promise<unknown>;
32
- export {};
8
+ export declare function exec(command: string, args?: string[]): Promise<string>;
9
+ export declare function exec(command: string, options?: SpawnOptions): Promise<string>;
10
+ export declare function exec(command: string, args?: string[], options?: SpawnOptions): Promise<string>;
package/lib/server.js CHANGED
@@ -1,77 +1,52 @@
1
- import { exec as execCmd, spawn } from 'child_process';
2
- import { isBlank } from './index.js';
1
+ import { spawn } from "node:child_process";
3
2
  /**
4
3
  * 执行命令
5
4
  * @param cmd 执行的命令
6
5
  * @returns
7
6
  */
8
- export function exec(cmd) {
7
+ export function exec(command, ...params) {
9
8
  return new Promise((resolve, reject) => {
10
- execCmd(cmd, (err, stdout, stderr) => {
11
- if (err) {
12
- reject(err);
9
+ let argvs = [];
10
+ const commandItems = command.split(" ");
11
+ const cmd = commandItems.shift();
12
+ if (commandItems.length > 0) {
13
+ argvs = commandItems;
14
+ }
15
+ let opts = undefined;
16
+ if (params[0] != null) {
17
+ if (params[0] instanceof Array) {
18
+ argvs.push(...params[0]);
19
+ if (params[1] != null) {
20
+ opts = params[1];
21
+ }
13
22
  }
14
23
  else {
15
- if (!isBlank(stderr) && stderr.indexOf('error') !== -1) {
16
- reject(new Error(stderr));
17
- }
18
- else {
19
- resolve((isBlank(stdout) ? stderr : stdout).trim());
20
- }
24
+ opts = params[0];
21
25
  }
22
- });
23
- });
24
- }
25
- /**
26
- * 执行 spawn 命令
27
- * @param command 执行的命令: 例如: git
28
- * @param args 命令参数: ['clone', 'https://xxxx.git']
29
- * @param options 参数
30
- */
31
- export function spawnCmd(command, args, options) {
32
- const spawnClient = spawn(command, args, { cwd: options?.cwd });
33
- let err;
34
- spawnClient.stdout.on('data', (chunk) => {
35
- if (options?.data != null && typeof options.data === 'function') {
36
- options.data(chunk);
37
- }
38
- });
39
- spawnClient.stderr.on('error', (error) => {
40
- err = error;
41
- if (options?.error && typeof options.error === 'function') {
42
- options.error(error);
43
- }
44
- });
45
- spawnClient.on('error', (error) => {
46
- err = error;
47
- if (options?.error && typeof options.error === 'function') {
48
- options.error(error);
49
26
  }
50
- });
51
- spawnClient.on('close', () => {
52
- if (options?.finally && typeof options.finally === 'function') {
53
- options.finally(err);
54
- }
55
- });
56
- }
57
- /**
58
- * 执行 spawn 命令
59
- * @param command 执行的命令: 例如: git
60
- * @param args 命令参数: ['clone', 'https://xxxx.git']
61
- * @param options 参数
62
- * @returns
63
- */
64
- export function spawnPromise(command, args, options) {
65
- return new Promise((resolve, reject) => {
66
- options = options || {};
67
- options.finally = (err) => {
68
- if (err == null) {
69
- resolve(1);
27
+ const prs = spawn(cmd, argvs, opts);
28
+ let msg = [];
29
+ let error;
30
+ prs.stderr.on("data", (chunk) => {
31
+ msg.push(chunk.toString("utf-8"));
32
+ });
33
+ prs.stdout.on("data", (chunk) => {
34
+ msg.push(chunk.toString("utf-8"));
35
+ });
36
+ prs.on("error", (err) => {
37
+ error = err;
38
+ });
39
+ prs.on("close", (code, signal) => {
40
+ if (code === 0) {
41
+ resolve(msg.join("\n"));
70
42
  }
71
43
  else {
72
- reject(err);
44
+ if (error == null) {
45
+ error = new Error(msg[msg.length - 1]);
46
+ }
47
+ error.errno = code;
48
+ reject(error);
73
49
  }
74
- };
75
- spawnCmd(command, args, options);
50
+ });
76
51
  });
77
52
  }
package/package.json CHANGED
@@ -52,7 +52,7 @@
52
52
  },
53
53
  "./*": "./lib/*"
54
54
  },
55
- "version": "0.5.1",
55
+ "version": "0.6.1",
56
56
  "type": "module",
57
57
  "repository": {
58
58
  "type": "git",
@@ -80,9 +80,6 @@
80
80
  "dom",
81
81
  "file"
82
82
  ],
83
- "dependencies": {
84
- "@ctrl/tinycolor": "^4.1.0"
85
- },
86
83
  "scripts": {
87
84
  "build": "node scripts/build.js"
88
85
  }