@jayfong/x-utils 1.0.0-202510061015 → 3.4.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.
- package/lib/ai.d.mts +103 -0
- package/lib/ai.mjs +75 -0
- package/lib/cache.d.mts +464 -0
- package/lib/cache.mjs +531 -0
- package/lib/captcha.d.mts +259 -0
- package/lib/captcha.mjs +174 -0
- package/lib/case.d.mts +184 -0
- package/lib/case.mjs +120 -0
- package/lib/chinese.d.mts +57 -0
- package/lib/chinese.mjs +79 -0
- package/lib/cli.d.mts +52 -0
- package/lib/cli.mjs +62 -0
- package/lib/clipboard.d.mts +50 -0
- package/lib/clipboard.mjs +122 -0
- package/lib/cmd.d.mts +38 -0
- package/lib/cmd.mjs +52 -0
- package/lib/crawler.d.mts +330 -0
- package/lib/crawler.mjs +313 -0
- package/lib/crypto.d.mts +158 -0
- package/lib/crypto.mjs +213 -0
- package/lib/csv.d.mts +67 -0
- package/lib/csv.mjs +76 -0
- package/lib/data_set.d.mts +76 -0
- package/lib/data_set.mjs +104 -0
- package/lib/db_value.d.mts +213 -0
- package/lib/db_value.mjs +208 -0
- package/lib/dispose.d.mts +98 -0
- package/lib/dispose.mjs +107 -0
- package/lib/file_store.d.mts +167 -0
- package/lib/file_store.mjs +120 -0
- package/lib/fs.d.mts +111 -0
- package/lib/fs.mjs +127 -0
- package/lib/html.d.mts +103 -0
- package/lib/html.mjs +112 -0
- package/lib/json.d.mts +50 -0
- package/lib/json.mjs +74 -0
- package/lib/jwt.d.mts +128 -0
- package/lib/jwt.mjs +104 -0
- package/lib/mail.d.mts +125 -0
- package/lib/mail.mjs +108 -0
- package/lib/pay.d.mts +394 -0
- package/lib/pay.mjs +343 -0
- package/lib/puppeteer.d.mts +88 -0
- package/lib/puppeteer.mjs +219 -0
- package/lib/random.d.mts +71 -0
- package/lib/random.mjs +92 -0
- package/lib/redis.d.mts +32 -0
- package/lib/redis.mjs +24 -0
- package/lib/runner.d.mts +80 -0
- package/lib/runner.mjs +66 -0
- package/lib/sensitive_words.d.mts +82 -0
- package/lib/sensitive_words.mjs +73 -0
- package/lib/sms.d.mts +133 -0
- package/lib/sms.mjs +100 -0
- package/lib/task.d.mts +37 -0
- package/lib/task.mjs +43 -0
- package/lib/text.d.mts +84 -0
- package/lib/text.mjs +141 -0
- package/lib/yaml.d.mts +51 -0
- package/lib/yaml.mjs +64 -0
- package/package.json +82 -164
- package/_cjs/ai.js +0 -80
- package/_cjs/alipan.js +0 -173
- package/_cjs/cli.js +0 -51
- package/_cjs/clipboard.js +0 -65
- package/_cjs/cmd.js +0 -42
- package/_cjs/compressor.js +0 -47
- package/_cjs/crawler.js +0 -341
- package/_cjs/csv.js +0 -97
- package/_cjs/data_set.js +0 -115
- package/_cjs/env.js +0 -82
- package/_cjs/fs.js +0 -86
- package/_cjs/html.js +0 -62
- package/_cjs/http_server.js +0 -79
- package/_cjs/json.js +0 -49
- package/_cjs/ksb.js +0 -218
- package/_cjs/number.js +0 -39
- package/_cjs/ocr.js +0 -74
- package/_cjs/package.json +0 -3
- package/_cjs/path.js +0 -35
- package/_cjs/pinyin.js +0 -37
- package/_cjs/puppeteer.js +0 -271
- package/_cjs/runner.js +0 -88
- package/_cjs/task.js +0 -41
- package/_cjs/text.js +0 -136
- package/_cjs/unicode/lib_unicode.js +0 -58643
- package/_cjs/unicode/unicode.js +0 -441
- package/_cjs/upload.js +0 -101
- package/_cjs/yaml.js +0 -52
- package/ai.d.ts +0 -26
- package/ai.js +0 -60
- package/alipan.d.ts +0 -209
- package/alipan.js +0 -153
- package/cli.d.ts +0 -14
- package/cli.js +0 -21
- package/clipboard.d.ts +0 -6
- package/clipboard.js +0 -35
- package/cmd.d.ts +0 -5
- package/cmd.js +0 -22
- package/compressor.d.ts +0 -5
- package/compressor.js +0 -17
- package/crawler.d.ts +0 -162
- package/crawler.js +0 -332
- package/csv.d.ts +0 -14
- package/csv.js +0 -67
- package/data_set.d.ts +0 -22
- package/data_set.js +0 -85
- package/env.d.ts +0 -6
- package/env.js +0 -52
- package/fs.d.ts +0 -23
- package/fs.js +0 -56
- package/html.d.ts +0 -7
- package/html.js +0 -45
- package/http_server.d.ts +0 -13
- package/http_server.js +0 -49
- package/json.d.ts +0 -6
- package/json.js +0 -19
- package/ksb.d.ts +0 -37
- package/ksb.js +0 -198
- package/number.d.ts +0 -3
- package/number.js +0 -9
- package/ocr.d.ts +0 -17
- package/ocr.js +0 -54
- package/path.d.ts +0 -2
- package/path.js +0 -5
- package/pinyin.d.ts +0 -8
- package/pinyin.js +0 -17
- package/puppeteer.d.ts +0 -38
- package/puppeteer.js +0 -241
- package/runner.d.ts +0 -13
- package/runner.js +0 -58
- package/task.d.ts +0 -6
- package/task.js +0 -21
- package/text.d.ts +0 -63
- package/text.js +0 -119
- package/unicode/lib_unicode.d.ts +0 -4
- package/unicode/lib_unicode.js +0 -58623
- package/unicode/unicode.d.ts +0 -347
- package/unicode/unicode.js +0 -426
- package/upload.d.ts +0 -34
- package/upload.js +0 -71
- package/yaml.d.ts +0 -6
- package/yaml.js +0 -22
package/lib/case.mjs
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { camelCase, capitalCase, constantCase, dotCase, kebabCase, pascalCase, pascalSnakeCase, pathCase, sentenceCase, snakeCase, trainCase } from "change-case";
|
|
2
|
+
// src/case.ts
|
|
3
|
+
/**
|
|
4
|
+
* 字符串大小写风格转换工具。
|
|
5
|
+
*
|
|
6
|
+
* 所有方法均委托给 `change-case` 包实现,方法名去掉了原函数名的 `Case`
|
|
7
|
+
* 后缀(如 `camelCase` → `camel`,`pascalSnakeCase` → `pascalSnake`)。
|
|
8
|
+
*
|
|
9
|
+
* 各方法的 `options` 参数会原样透传给 `change-case` 对应函数,
|
|
10
|
+
* 类型分别为导出的 `XCaseCamelOptions`、`XCasePascalOptions`、
|
|
11
|
+
* `XCasePascalSnakeOptions`、`XCaseCapitalOptions`、`XCaseConstantOptions`、
|
|
12
|
+
* `XCaseDotOptions`、`XCaseKebabOptions`、`XCasePathOptions`、
|
|
13
|
+
* `XCaseSentenceOptions`、`XCaseSnakeOptions`、`XCaseTrainOptions`,
|
|
14
|
+
* 可配置 `locale`、`delimiter`、`split` 等(`camel`/`pascal` 额外支持
|
|
15
|
+
* `mergeAmbiguousCharacters`)。
|
|
16
|
+
*
|
|
17
|
+
* 以 `Hello World` 为例,各方法的输出:
|
|
18
|
+
* - `camel` → `helloWorld`
|
|
19
|
+
* - `pascal` → `HelloWorld`
|
|
20
|
+
* - `pascalSnake` → `Hello_World`
|
|
21
|
+
* - `capital` → `Hello World`
|
|
22
|
+
* - `constant` → `HELLO_WORLD`
|
|
23
|
+
* - `dot` → `hello.world`
|
|
24
|
+
* - `kebab` → `hello-world`
|
|
25
|
+
* - `path` → `hello/world`
|
|
26
|
+
* - `sentence` → `Hello world`
|
|
27
|
+
* - `snake` → `hello_world`
|
|
28
|
+
* - `train` → `Hello-World`
|
|
29
|
+
*/
|
|
30
|
+
var XCase = class {
|
|
31
|
+
/**
|
|
32
|
+
* 转换为 camelCase(小驼峰)命名。
|
|
33
|
+
*
|
|
34
|
+
* @example XCase.camel('Hello World') // 'helloWorld'
|
|
35
|
+
*/
|
|
36
|
+
static camel(text, options) {
|
|
37
|
+
return camelCase(text, options);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 转换为 PascalCase(大驼峰)命名。
|
|
41
|
+
*
|
|
42
|
+
* @example XCase.pascal('hello world') // 'HelloWorld'
|
|
43
|
+
*/
|
|
44
|
+
static pascal(text, options) {
|
|
45
|
+
return pascalCase(text, options);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 转换为 Pascal_Snake_Case(大驼峰 + 下划线)命名。
|
|
49
|
+
*
|
|
50
|
+
* @example XCase.pascalSnake('hello world') // 'Hello_World'
|
|
51
|
+
*/
|
|
52
|
+
static pascalSnake(text, options) {
|
|
53
|
+
return pascalSnakeCase(text, options);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 转换为 Capital Case(首字母大写的空格分隔)命名。
|
|
57
|
+
*
|
|
58
|
+
* @example XCase.capital('hello world') // 'Hello World'
|
|
59
|
+
*/
|
|
60
|
+
static capital(text, options) {
|
|
61
|
+
return capitalCase(text, options);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* 转换为 CONSTANT_CASE(全大写下划线)命名。
|
|
65
|
+
*
|
|
66
|
+
* @example XCase.constant('hello world') // 'HELLO_WORLD'
|
|
67
|
+
*/
|
|
68
|
+
static constant(text, options) {
|
|
69
|
+
return constantCase(text, options);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* 转换为 dot.case(点号分隔)命名。
|
|
73
|
+
*
|
|
74
|
+
* @example XCase.dot('hello world') // 'hello.world'
|
|
75
|
+
*/
|
|
76
|
+
static dot(text, options) {
|
|
77
|
+
return dotCase(text, options);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 转换为 kebab-case(短横线分隔)命名。
|
|
81
|
+
*
|
|
82
|
+
* @example XCase.kebab('Hello World') // 'hello-world'
|
|
83
|
+
*/
|
|
84
|
+
static kebab(text, options) {
|
|
85
|
+
return kebabCase(text, options);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 转换为 path/case(斜杠分隔)命名。
|
|
89
|
+
*
|
|
90
|
+
* @example XCase.path('hello world') // 'hello/world'
|
|
91
|
+
*/
|
|
92
|
+
static path(text, options) {
|
|
93
|
+
return pathCase(text, options);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 转换为 Sentence case(首字母大写的句子)命名。
|
|
97
|
+
*
|
|
98
|
+
* @example XCase.sentence('hello world') // 'Hello world'
|
|
99
|
+
*/
|
|
100
|
+
static sentence(text, options) {
|
|
101
|
+
return sentenceCase(text, options);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* 转换为 snake_case(小写下划线)命名。
|
|
105
|
+
*
|
|
106
|
+
* @example XCase.snake('Hello World') // 'hello_world'
|
|
107
|
+
*/
|
|
108
|
+
static snake(text, options) {
|
|
109
|
+
return snakeCase(text, options);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* 转换为 Train-Case(短横线分隔、各单词首字母大写)命名。
|
|
113
|
+
*
|
|
114
|
+
* @example XCase.train('hello world') // 'Hello-World'
|
|
115
|
+
*/
|
|
116
|
+
static train(text, options) {
|
|
117
|
+
return trainCase(text, options);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
export { XCase };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 中文拼音转换工具。
|
|
3
|
+
*
|
|
4
|
+
* 基于 `pinyin-pro` 实现,返回逐字的拼音数组:
|
|
5
|
+
* - `pinyin`:无声调拼音,如 `XChinese.pinyin('我们')` → `['wo', 'men']`;
|
|
6
|
+
* - `pinyinWithTone`:带声调拼音(声调标在韵母上),
|
|
7
|
+
* 如 `XChinese.pinyinWithTone('我们')` → `['wǒ', 'men']`;
|
|
8
|
+
* - `pinyinInitials`:拼音首字母缩写(小写字符串),
|
|
9
|
+
* 如 `XChinese.pinyinInitials('我们')` → `'wm'`。
|
|
10
|
+
*
|
|
11
|
+
* 处理规则:
|
|
12
|
+
* - 每个汉字对应数组中的一个拼音元素;
|
|
13
|
+
* - 非汉字字符(字母、数字、符号、空白等)原样保留在结果中;
|
|
14
|
+
* - 多音字按 `pinyin-pro` 默认的逆向最大匹配分词规则取常用读音;
|
|
15
|
+
* - 空字符串返回空数组 `[]`。
|
|
16
|
+
*/
|
|
17
|
+
export declare class XChinese {
|
|
18
|
+
/**
|
|
19
|
+
* 获取无声调拼音。
|
|
20
|
+
*
|
|
21
|
+
* @param text 要转换的汉语字符串,可混含非汉字字符。
|
|
22
|
+
* @returns 拼音字符串数组,每个汉字对应一个元素,非汉字原样保留。
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* XChinese.pinyin('我们') // ['wo', 'men']
|
|
26
|
+
* XChinese.pinyin('我爱你') // ['wo', 'ai', 'ni']
|
|
27
|
+
* XChinese.pinyin('我爱ABC') // ['wo', 'ai', 'A', 'B', 'C']
|
|
28
|
+
*/
|
|
29
|
+
static pinyin(text: string): string[];
|
|
30
|
+
/**
|
|
31
|
+
* 获取带声调拼音(声调标在韵母上,如 `wǒ`、`ài`、`nǐ`)。
|
|
32
|
+
*
|
|
33
|
+
* @param text 要转换的汉语字符串,可混含非汉字字符。
|
|
34
|
+
* @returns 拼音字符串数组,每个汉字对应一个带声调元素,非汉字原样保留。
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* XChinese.pinyinWithTone('我们') // ['wǒ', 'men']
|
|
38
|
+
* XChinese.pinyinWithTone('我爱你') // ['wǒ', 'ài', 'nǐ']
|
|
39
|
+
*/
|
|
40
|
+
static pinyinWithTone(text: string): string[];
|
|
41
|
+
/**
|
|
42
|
+
* 获取拼音首字母缩写(小写字符串)。
|
|
43
|
+
*
|
|
44
|
+
* 每个汉字取对应拼音的首字母,并统一转为小写;非汉字字符原样保留
|
|
45
|
+
* (其中的英文字母也会被转为小写,如 `ABC` → `abc`)。
|
|
46
|
+
*
|
|
47
|
+
* @param text 要转换的汉语字符串,可混含非汉字字符。
|
|
48
|
+
* @returns 小写拼音首字母字符串,例如 `'我们'` → `'wm'`、`'我爱你'` → `'wan'`。
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* XChinese.pinyinInitials('我们') // 'wm'
|
|
52
|
+
* XChinese.pinyinInitials('我爱你') // 'wan'
|
|
53
|
+
* XChinese.pinyinInitials('我爱ABC') // 'waabc'
|
|
54
|
+
* XChinese.pinyinInitials('重庆') // 'cq'
|
|
55
|
+
*/
|
|
56
|
+
static pinyinInitials(text: string): string;
|
|
57
|
+
}
|
package/lib/chinese.mjs
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { pinyin } from "pinyin-pro";
|
|
2
|
+
// src/chinese.ts
|
|
3
|
+
/**
|
|
4
|
+
* 中文拼音转换工具。
|
|
5
|
+
*
|
|
6
|
+
* 基于 `pinyin-pro` 实现,返回逐字的拼音数组:
|
|
7
|
+
* - `pinyin`:无声调拼音,如 `XChinese.pinyin('我们')` → `['wo', 'men']`;
|
|
8
|
+
* - `pinyinWithTone`:带声调拼音(声调标在韵母上),
|
|
9
|
+
* 如 `XChinese.pinyinWithTone('我们')` → `['wǒ', 'men']`;
|
|
10
|
+
* - `pinyinInitials`:拼音首字母缩写(小写字符串),
|
|
11
|
+
* 如 `XChinese.pinyinInitials('我们')` → `'wm'`。
|
|
12
|
+
*
|
|
13
|
+
* 处理规则:
|
|
14
|
+
* - 每个汉字对应数组中的一个拼音元素;
|
|
15
|
+
* - 非汉字字符(字母、数字、符号、空白等)原样保留在结果中;
|
|
16
|
+
* - 多音字按 `pinyin-pro` 默认的逆向最大匹配分词规则取常用读音;
|
|
17
|
+
* - 空字符串返回空数组 `[]`。
|
|
18
|
+
*/
|
|
19
|
+
var XChinese = class {
|
|
20
|
+
/**
|
|
21
|
+
* 获取无声调拼音。
|
|
22
|
+
*
|
|
23
|
+
* @param text 要转换的汉语字符串,可混含非汉字字符。
|
|
24
|
+
* @returns 拼音字符串数组,每个汉字对应一个元素,非汉字原样保留。
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* XChinese.pinyin('我们') // ['wo', 'men']
|
|
28
|
+
* XChinese.pinyin('我爱你') // ['wo', 'ai', 'ni']
|
|
29
|
+
* XChinese.pinyin('我爱ABC') // ['wo', 'ai', 'A', 'B', 'C']
|
|
30
|
+
*/
|
|
31
|
+
static pinyin(text) {
|
|
32
|
+
return pinyin(text, {
|
|
33
|
+
type: "array",
|
|
34
|
+
toneType: "none"
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 获取带声调拼音(声调标在韵母上,如 `wǒ`、`ài`、`nǐ`)。
|
|
39
|
+
*
|
|
40
|
+
* @param text 要转换的汉语字符串,可混含非汉字字符。
|
|
41
|
+
* @returns 拼音字符串数组,每个汉字对应一个带声调元素,非汉字原样保留。
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* XChinese.pinyinWithTone('我们') // ['wǒ', 'men']
|
|
45
|
+
* XChinese.pinyinWithTone('我爱你') // ['wǒ', 'ài', 'nǐ']
|
|
46
|
+
*/
|
|
47
|
+
static pinyinWithTone(text) {
|
|
48
|
+
return pinyin(text, {
|
|
49
|
+
type: "array",
|
|
50
|
+
toneType: "symbol"
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 获取拼音首字母缩写(小写字符串)。
|
|
55
|
+
*
|
|
56
|
+
* 每个汉字取对应拼音的首字母,并统一转为小写;非汉字字符原样保留
|
|
57
|
+
* (其中的英文字母也会被转为小写,如 `ABC` → `abc`)。
|
|
58
|
+
*
|
|
59
|
+
* @param text 要转换的汉语字符串,可混含非汉字字符。
|
|
60
|
+
* @returns 小写拼音首字母字符串,例如 `'我们'` → `'wm'`、`'我爱你'` → `'wan'`。
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* XChinese.pinyinInitials('我们') // 'wm'
|
|
64
|
+
* XChinese.pinyinInitials('我爱你') // 'wan'
|
|
65
|
+
* XChinese.pinyinInitials('我爱ABC') // 'waabc'
|
|
66
|
+
* XChinese.pinyinInitials('重庆') // 'cq'
|
|
67
|
+
*/
|
|
68
|
+
static pinyinInitials(text) {
|
|
69
|
+
return pinyin(text, {
|
|
70
|
+
type: "string",
|
|
71
|
+
pattern: "first",
|
|
72
|
+
toneType: "none",
|
|
73
|
+
separator: "",
|
|
74
|
+
removeNonZh: false,
|
|
75
|
+
nonZh: "consecutive"
|
|
76
|
+
}).toLowerCase();
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
export { XChinese };
|
package/lib/cli.d.mts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { checkbox, confirm, editor, expand, input, number, password, rawlist, search, select } from "@inquirer/prompts";
|
|
2
|
+
/**
|
|
3
|
+
* 命令行交互与表格输出工具。
|
|
4
|
+
*
|
|
5
|
+
* 基于 `@inquirer/prompts` 与 `cli-table3` 封装:
|
|
6
|
+
* - 以静态属性的形式直接透出 `input`、`select`、`checkbox`、`confirm`、
|
|
7
|
+
* `search`、`password`、`expand`、`editor`、`number`、`rawlist` 等交互提问函数,
|
|
8
|
+
* 签名与返回类型与 `@inquirer/prompts` 保持一致;
|
|
9
|
+
* - `table`:将二维数组渲染为对齐的文本表格。
|
|
10
|
+
*/
|
|
11
|
+
export declare class XCli {
|
|
12
|
+
/** 发起一次文本输入交互,返回 `Promise<string>`。 */
|
|
13
|
+
static input: typeof input;
|
|
14
|
+
/** 发起一次单选交互,返回选中项的值。 */
|
|
15
|
+
static select: typeof select;
|
|
16
|
+
/** 发起一次多选交互,返回选中项的数组。 */
|
|
17
|
+
static checkbox: typeof checkbox;
|
|
18
|
+
/** 发起一次是/否确认交互,返回 `Promise<boolean>`。 */
|
|
19
|
+
static confirm: typeof confirm;
|
|
20
|
+
/** 发起一次带搜索过滤的单选交互,返回选中项的值。 */
|
|
21
|
+
static search: typeof search;
|
|
22
|
+
/** 发起一次隐藏输入的密码交互,返回 `Promise<string>`。 */
|
|
23
|
+
static password: typeof password;
|
|
24
|
+
/** 发起一次可展开选项的交互,返回选中项的值。 */
|
|
25
|
+
static expand: typeof expand;
|
|
26
|
+
/** 打开外部编辑器进行文本输入,返回 `Promise<string>`。 */
|
|
27
|
+
static editor: typeof editor;
|
|
28
|
+
/** 发起一次数字输入交互,返回数字结果(未强制必填时可能为 `undefined`)。 */
|
|
29
|
+
static number: typeof number;
|
|
30
|
+
/** 发起一次原始列表单选交互,返回选中项的值。 */
|
|
31
|
+
static rawlist: typeof rawlist;
|
|
32
|
+
/**
|
|
33
|
+
* 将二维数组渲染为对齐的文本表格。
|
|
34
|
+
*
|
|
35
|
+
* 返回纯文本(不含 ANSI 颜色码),保证在任意终端环境下输出一致。
|
|
36
|
+
*
|
|
37
|
+
* @param data 表格行数据,每行为一个单元格数组。
|
|
38
|
+
* @returns 使用 Unicode 边框绘制的表格字符串。
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* XCli.table([
|
|
42
|
+
* ['姓名', '年龄'],
|
|
43
|
+
* ['张三', '18'],
|
|
44
|
+
* ])
|
|
45
|
+
* // ┌──────┬──────┐
|
|
46
|
+
* // │ 姓名 │ 年龄 │
|
|
47
|
+
* // ├──────┼──────┤
|
|
48
|
+
* // │ 张三 │ 18 │
|
|
49
|
+
* // └──────┴──────┘
|
|
50
|
+
*/
|
|
51
|
+
static table(data: any[][]): string;
|
|
52
|
+
}
|
package/lib/cli.mjs
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { checkbox, confirm, editor, expand, input, number, password, rawlist, search, select } from "@inquirer/prompts";
|
|
2
|
+
import Table from "cli-table3";
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
/**
|
|
5
|
+
* 命令行交互与表格输出工具。
|
|
6
|
+
*
|
|
7
|
+
* 基于 `@inquirer/prompts` 与 `cli-table3` 封装:
|
|
8
|
+
* - 以静态属性的形式直接透出 `input`、`select`、`checkbox`、`confirm`、
|
|
9
|
+
* `search`、`password`、`expand`、`editor`、`number`、`rawlist` 等交互提问函数,
|
|
10
|
+
* 签名与返回类型与 `@inquirer/prompts` 保持一致;
|
|
11
|
+
* - `table`:将二维数组渲染为对齐的文本表格。
|
|
12
|
+
*/
|
|
13
|
+
var XCli = class {
|
|
14
|
+
/** 发起一次文本输入交互,返回 `Promise<string>`。 */
|
|
15
|
+
static input = input;
|
|
16
|
+
/** 发起一次单选交互,返回选中项的值。 */
|
|
17
|
+
static select = select;
|
|
18
|
+
/** 发起一次多选交互,返回选中项的数组。 */
|
|
19
|
+
static checkbox = checkbox;
|
|
20
|
+
/** 发起一次是/否确认交互,返回 `Promise<boolean>`。 */
|
|
21
|
+
static confirm = confirm;
|
|
22
|
+
/** 发起一次带搜索过滤的单选交互,返回选中项的值。 */
|
|
23
|
+
static search = search;
|
|
24
|
+
/** 发起一次隐藏输入的密码交互,返回 `Promise<string>`。 */
|
|
25
|
+
static password = password;
|
|
26
|
+
/** 发起一次可展开选项的交互,返回选中项的值。 */
|
|
27
|
+
static expand = expand;
|
|
28
|
+
/** 打开外部编辑器进行文本输入,返回 `Promise<string>`。 */
|
|
29
|
+
static editor = editor;
|
|
30
|
+
/** 发起一次数字输入交互,返回数字结果(未强制必填时可能为 `undefined`)。 */
|
|
31
|
+
static number = number;
|
|
32
|
+
/** 发起一次原始列表单选交互,返回选中项的值。 */
|
|
33
|
+
static rawlist = rawlist;
|
|
34
|
+
/**
|
|
35
|
+
* 将二维数组渲染为对齐的文本表格。
|
|
36
|
+
*
|
|
37
|
+
* 返回纯文本(不含 ANSI 颜色码),保证在任意终端环境下输出一致。
|
|
38
|
+
*
|
|
39
|
+
* @param data 表格行数据,每行为一个单元格数组。
|
|
40
|
+
* @returns 使用 Unicode 边框绘制的表格字符串。
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* XCli.table([
|
|
44
|
+
* ['姓名', '年龄'],
|
|
45
|
+
* ['张三', '18'],
|
|
46
|
+
* ])
|
|
47
|
+
* // ┌──────┬──────┐
|
|
48
|
+
* // │ 姓名 │ 年龄 │
|
|
49
|
+
* // ├──────┼──────┤
|
|
50
|
+
* // │ 张三 │ 18 │
|
|
51
|
+
* // └──────┴──────┘
|
|
52
|
+
*/
|
|
53
|
+
static table(data) {
|
|
54
|
+
const table = new Table({ style: {
|
|
55
|
+
head: [],
|
|
56
|
+
border: []
|
|
57
|
+
} });
|
|
58
|
+
table.push(...data);
|
|
59
|
+
return table.toString();
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
export { XCli };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 剪贴板文本/HTML 读写工具。
|
|
3
|
+
*
|
|
4
|
+
* 说明:
|
|
5
|
+
* - `readText` / `writeText` 使用 `clipboardy`,跨平台处理纯文本;
|
|
6
|
+
* - `readHtml` / `writeHtml` 在不同平台走不同实现:
|
|
7
|
+
* - macOS:`osascript` + AppleScript HTML 数据;
|
|
8
|
+
* - Windows:`powershell` + `HTML Format`(CF_HTML);
|
|
9
|
+
* - 其他平台:抛出不支持错误。
|
|
10
|
+
*/
|
|
11
|
+
export declare class XClipboard {
|
|
12
|
+
/**
|
|
13
|
+
* 构建 Windows CF_HTML 文本。
|
|
14
|
+
*
|
|
15
|
+
* 参考规范中 Start/End 偏移均按字节计数(UTF-8)。
|
|
16
|
+
*/
|
|
17
|
+
private static toWindowsCfHtml;
|
|
18
|
+
/**
|
|
19
|
+
* 从 Windows `HTML Format` 文本中提取 fragment。
|
|
20
|
+
*
|
|
21
|
+
* 若缺少偏移字段,会尝试用标记提取;再失败时返回原始文本。
|
|
22
|
+
*/
|
|
23
|
+
private static fromWindowsCfHtml;
|
|
24
|
+
/**
|
|
25
|
+
* 将 PowerShell 脚本编码为 `-EncodedCommand` 可执行格式(UTF-16LE)。
|
|
26
|
+
*/
|
|
27
|
+
private static buildPowerShellCommand;
|
|
28
|
+
/**
|
|
29
|
+
* 读取纯文本剪贴板内容。
|
|
30
|
+
*/
|
|
31
|
+
static readText(): Promise<string>;
|
|
32
|
+
/**
|
|
33
|
+
* 读取 HTML 剪贴板内容(macOS / Windows)。
|
|
34
|
+
*
|
|
35
|
+
* - macOS:读取 AppleScript `«data HTML...»` 十六进制文本并解码;
|
|
36
|
+
* - Windows:读取 `HTML Format`(CF_HTML)并提取 fragment。
|
|
37
|
+
*/
|
|
38
|
+
static readHtml(): Promise<string>;
|
|
39
|
+
/**
|
|
40
|
+
* 写入纯文本到剪贴板。
|
|
41
|
+
*/
|
|
42
|
+
static writeText(text: string): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* 写入 HTML 到剪贴板(macOS / Windows)。
|
|
45
|
+
*
|
|
46
|
+
* - macOS:将 HTML 编码为十六进制后写入 AppleScript HTML 数据;
|
|
47
|
+
* - Windows:封装为 CF_HTML(`HTML Format`)后调用 PowerShell 写入。
|
|
48
|
+
*/
|
|
49
|
+
static writeHtml(html: string): Promise<void>;
|
|
50
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { XCmd } from "./cmd.mjs";
|
|
2
|
+
import clipboardy from "clipboardy";
|
|
3
|
+
// src/clipboard.ts
|
|
4
|
+
/**
|
|
5
|
+
* 剪贴板文本/HTML 读写工具。
|
|
6
|
+
*
|
|
7
|
+
* 说明:
|
|
8
|
+
* - `readText` / `writeText` 使用 `clipboardy`,跨平台处理纯文本;
|
|
9
|
+
* - `readHtml` / `writeHtml` 在不同平台走不同实现:
|
|
10
|
+
* - macOS:`osascript` + AppleScript HTML 数据;
|
|
11
|
+
* - Windows:`powershell` + `HTML Format`(CF_HTML);
|
|
12
|
+
* - 其他平台:抛出不支持错误。
|
|
13
|
+
*/
|
|
14
|
+
var XClipboard = class XClipboard {
|
|
15
|
+
/**
|
|
16
|
+
* 构建 Windows CF_HTML 文本。
|
|
17
|
+
*
|
|
18
|
+
* 参考规范中 Start/End 偏移均按字节计数(UTF-8)。
|
|
19
|
+
*/
|
|
20
|
+
static toWindowsCfHtml(fragmentHtml) {
|
|
21
|
+
const htmlPrefix = "<!DOCTYPE html><html><body><!--StartFragment-->";
|
|
22
|
+
const html = `${htmlPrefix}${fragmentHtml}<!--EndFragment--></body></html>`;
|
|
23
|
+
const startHtml = Buffer.byteLength("Version:0.9\r\nStartHTML:0000000000\r\nEndHTML:0000000000\r\nStartFragment:0000000000\r\nEndFragment:0000000000\r\n", "utf8");
|
|
24
|
+
const startFragment = startHtml + Buffer.byteLength(htmlPrefix, "utf8");
|
|
25
|
+
const endFragment = startFragment + Buffer.byteLength(fragmentHtml, "utf8");
|
|
26
|
+
const endHtml = startHtml + Buffer.byteLength(html, "utf8");
|
|
27
|
+
const pad = (num) => num.toString().padStart(10, "0");
|
|
28
|
+
return `${`Version:0.9\r
|
|
29
|
+
StartHTML:${pad(startHtml)}\r\nEndHTML:${pad(endHtml)}\r\nStartFragment:${pad(startFragment)}\r\nEndFragment:${pad(endFragment)}\r\n`}${html}`;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 从 Windows `HTML Format` 文本中提取 fragment。
|
|
33
|
+
*
|
|
34
|
+
* 若缺少偏移字段,会尝试用标记提取;再失败时返回原始文本。
|
|
35
|
+
*/
|
|
36
|
+
static fromWindowsCfHtml(value) {
|
|
37
|
+
const startMatch = value.match(/StartFragment:(\d+)/);
|
|
38
|
+
const endMatch = value.match(/EndFragment:(\d+)/);
|
|
39
|
+
if (startMatch && endMatch) {
|
|
40
|
+
const start = Number(startMatch[1]);
|
|
41
|
+
const end = Number(endMatch[1]);
|
|
42
|
+
if (Number.isFinite(start) && Number.isFinite(end) && end >= start) {
|
|
43
|
+
const bytes = Buffer.from(value, "utf8");
|
|
44
|
+
if (start >= 0 && end <= bytes.length) return bytes.subarray(start, end).toString("utf8");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const markerMatch = value.match(/<!--StartFragment-->([\s\S]*?)<!--EndFragment-->/);
|
|
48
|
+
if (markerMatch) return markerMatch[1];
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 将 PowerShell 脚本编码为 `-EncodedCommand` 可执行格式(UTF-16LE)。
|
|
53
|
+
*/
|
|
54
|
+
static buildPowerShellCommand(script) {
|
|
55
|
+
return `powershell -NoProfile -NonInteractive -STA -EncodedCommand ${Buffer.from(script, "utf16le").toString("base64")}`;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 读取纯文本剪贴板内容。
|
|
59
|
+
*/
|
|
60
|
+
static async readText() {
|
|
61
|
+
return clipboardy.read();
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* 读取 HTML 剪贴板内容(macOS / Windows)。
|
|
65
|
+
*
|
|
66
|
+
* - macOS:读取 AppleScript `«data HTML...»` 十六进制文本并解码;
|
|
67
|
+
* - Windows:读取 `HTML Format`(CF_HTML)并提取 fragment。
|
|
68
|
+
*/
|
|
69
|
+
static async readHtml() {
|
|
70
|
+
if (process.platform === "darwin") {
|
|
71
|
+
const { result: hex } = await XCmd.exec(`osascript -e "the clipboard as «class HTML»"`);
|
|
72
|
+
const normalized = hex.trim();
|
|
73
|
+
const matched = normalized.match(/^«data HTML([0-9a-fA-F]*)»$/);
|
|
74
|
+
if (!matched) throw new Error(`读取剪贴板 HTML 失败,返回内容格式无效: ${normalized}`);
|
|
75
|
+
return Buffer.from(matched[1], "hex").toString();
|
|
76
|
+
}
|
|
77
|
+
if (process.platform === "win32") {
|
|
78
|
+
const command = XClipboard.buildPowerShellCommand([
|
|
79
|
+
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8",
|
|
80
|
+
"Add-Type -AssemblyName System.Windows.Forms",
|
|
81
|
+
"$data = [System.Windows.Forms.Clipboard]::GetData('HTML Format')",
|
|
82
|
+
"if ($null -eq $data) { return }",
|
|
83
|
+
"Write-Output $data"
|
|
84
|
+
].join("; "));
|
|
85
|
+
const { result } = await XCmd.exec(command);
|
|
86
|
+
return XClipboard.fromWindowsCfHtml(result.trim());
|
|
87
|
+
}
|
|
88
|
+
throw new Error(`当前平台不支持读取 HTML 剪贴板: ${process.platform}`);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* 写入纯文本到剪贴板。
|
|
92
|
+
*/
|
|
93
|
+
static async writeText(text) {
|
|
94
|
+
await clipboardy.write(text);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* 写入 HTML 到剪贴板(macOS / Windows)。
|
|
98
|
+
*
|
|
99
|
+
* - macOS:将 HTML 编码为十六进制后写入 AppleScript HTML 数据;
|
|
100
|
+
* - Windows:封装为 CF_HTML(`HTML Format`)后调用 PowerShell 写入。
|
|
101
|
+
*/
|
|
102
|
+
static async writeHtml(html) {
|
|
103
|
+
if (process.platform === "darwin") {
|
|
104
|
+
const hex = Buffer.from(html).toString("hex");
|
|
105
|
+
await XCmd.exec(`osascript -e "set the clipboard to «data HTML${hex}»"`);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (process.platform === "win32") {
|
|
109
|
+
const cfHtml = XClipboard.toWindowsCfHtml(html);
|
|
110
|
+
const cfHtmlBase64 = Buffer.from(cfHtml, "utf8").toString("base64");
|
|
111
|
+
const command = XClipboard.buildPowerShellCommand([
|
|
112
|
+
"$cfHtml = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('" + cfHtmlBase64 + "'))",
|
|
113
|
+
"Add-Type -AssemblyName System.Windows.Forms",
|
|
114
|
+
"[System.Windows.Forms.Clipboard]::SetData('HTML Format', $cfHtml)"
|
|
115
|
+
].join("; "));
|
|
116
|
+
await XCmd.exec(command);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
throw new Error(`当前平台不支持写入 HTML 剪贴板: ${process.platform}`);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
export { XClipboard };
|
package/lib/cmd.d.mts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ChildProcess } from "node:child_process";
|
|
2
|
+
export interface XCmdExecOptions {
|
|
3
|
+
/** 命令执行目录;不传时使用当前进程工作目录。 */
|
|
4
|
+
cwd?: string;
|
|
5
|
+
/** 额外环境变量;会覆盖同名系统环境变量。 */
|
|
6
|
+
env?: NodeJS.ProcessEnv;
|
|
7
|
+
/**
|
|
8
|
+
* 子进程标准 IO 策略。
|
|
9
|
+
*
|
|
10
|
+
* - `ignore`(默认):不向当前终端输出,但会在结果中返回 `stdout/stderr`;
|
|
11
|
+
* - `inherit`:直连当前终端,适合需要实时查看输出的命令。
|
|
12
|
+
*/
|
|
13
|
+
stdio?: 'inherit' | 'ignore';
|
|
14
|
+
}
|
|
15
|
+
export type XCmdExecResult = Promise<{
|
|
16
|
+
/** 命令执行成功时的标准输出文本(stdout)。 */
|
|
17
|
+
result: string;
|
|
18
|
+
}> & {
|
|
19
|
+
/** 外部终止当前子进程的方法。 */
|
|
20
|
+
kill: ChildProcess['kill'];
|
|
21
|
+
};
|
|
22
|
+
export declare class XCmd {
|
|
23
|
+
/**
|
|
24
|
+
* 执行一条 shell 命令。
|
|
25
|
+
*
|
|
26
|
+
* 典型用法:
|
|
27
|
+
* - `await XCmd.exec('npm run build')`
|
|
28
|
+
* - `await XCmd.exec('fnm i 24')`
|
|
29
|
+
*
|
|
30
|
+
* 行为说明:
|
|
31
|
+
* 1. 默认 `stdio = 'ignore'`,适合静默执行命令,并将 `stdout` 作为结果返回;
|
|
32
|
+
* 2. 可通过 `cwd` 指定执行目录;
|
|
33
|
+
* 3. 可通过 `env` 传入额外环境变量(会与当前进程环境合并);
|
|
34
|
+
* 4. 返回值是“可 kill 的 Promise”,可在外部中断进程;
|
|
35
|
+
* 5. 子进程非零退出时会抛出包含退出码/信号和错误输出的异常,方便定位失败原因。
|
|
36
|
+
*/
|
|
37
|
+
static exec(command: string, options?: XCmdExecOptions): XCmdExecResult;
|
|
38
|
+
}
|
package/lib/cmd.mjs
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
// src/cmd.ts
|
|
3
|
+
var XCmd = class {
|
|
4
|
+
/**
|
|
5
|
+
* 执行一条 shell 命令。
|
|
6
|
+
*
|
|
7
|
+
* 典型用法:
|
|
8
|
+
* - `await XCmd.exec('npm run build')`
|
|
9
|
+
* - `await XCmd.exec('fnm i 24')`
|
|
10
|
+
*
|
|
11
|
+
* 行为说明:
|
|
12
|
+
* 1. 默认 `stdio = 'ignore'`,适合静默执行命令,并将 `stdout` 作为结果返回;
|
|
13
|
+
* 2. 可通过 `cwd` 指定执行目录;
|
|
14
|
+
* 3. 可通过 `env` 传入额外环境变量(会与当前进程环境合并);
|
|
15
|
+
* 4. 返回值是“可 kill 的 Promise”,可在外部中断进程;
|
|
16
|
+
* 5. 子进程非零退出时会抛出包含退出码/信号和错误输出的异常,方便定位失败原因。
|
|
17
|
+
*/
|
|
18
|
+
static exec(command, options) {
|
|
19
|
+
const shouldInheritStdio = options?.stdio === "inherit";
|
|
20
|
+
const child = spawn(command, {
|
|
21
|
+
cwd: options?.cwd,
|
|
22
|
+
env: {
|
|
23
|
+
...process.env,
|
|
24
|
+
...options?.env
|
|
25
|
+
},
|
|
26
|
+
stdio: shouldInheritStdio ? "inherit" : "pipe",
|
|
27
|
+
shell: true
|
|
28
|
+
});
|
|
29
|
+
let stdout = "";
|
|
30
|
+
let stderr = "";
|
|
31
|
+
if (!shouldInheritStdio) {
|
|
32
|
+
child.stdout?.on("data", (chunk) => {
|
|
33
|
+
stdout += chunk.toString();
|
|
34
|
+
});
|
|
35
|
+
child.stderr?.on("data", (chunk) => {
|
|
36
|
+
stderr += chunk.toString();
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
const promise = new Promise((resolve, reject) => {
|
|
40
|
+
child.once("error", reject);
|
|
41
|
+
child.once("close", (code, signal) => {
|
|
42
|
+
if (code === 0) {
|
|
43
|
+
resolve({ result: stdout });
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
reject(/* @__PURE__ */ new Error(`Command failed: "${command}" (code: ${code ?? "null"}, signal: ${signal ?? "null"}, stderr: ${stderr.trim() || "empty"})`));
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
return Object.assign(promise, { kill: child.kill.bind(child) });
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
export { XCmd };
|