@maiyunnet/kebab 9.2.0 → 9.2.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/doc/kebab-rag.md +90 -16
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/lib/text.d.ts +15 -1
- package/lib/text.js +41 -3
- package/package.json +17 -17
- package/sys/master.js +23 -13
- package/www/example/stc/view/react.page.js +2 -10
package/doc/kebab-rag.md
CHANGED
|
@@ -1360,7 +1360,7 @@ index/variables/VER.md
|
|
|
1360
1360
|
|
|
1361
1361
|
# Variable: VER
|
|
1362
1362
|
|
|
1363
|
-
> `const` **VER**: `"9.2.
|
|
1363
|
+
> `const` **VER**: `"9.2.2"` = `'9.2.2'`
|
|
1364
1364
|
|
|
1365
1365
|
Defined in: [index.ts:10](https://github.com/maiyunnet/kebab/blob/master/index.ts#L10)
|
|
1366
1366
|
|
|
@@ -10514,7 +10514,7 @@ Defined in: [lib/net/formdata.ts:37](https://github.com/maiyunnet/kebab/blob/mas
|
|
|
10514
10514
|
|
|
10515
10515
|
> **new FormData**(`options?`): `FormData`
|
|
10516
10516
|
|
|
10517
|
-
Defined in: node\_modules/@types/node/stream.d.ts:
|
|
10517
|
+
Defined in: node\_modules/@types/node/stream.d.ts:80
|
|
10518
10518
|
|
|
10519
10519
|
#### Parameters
|
|
10520
10520
|
|
|
@@ -15691,6 +15691,72 @@ lib/ssh/shell/index.md
|
|
|
15691
15691
|
|
|
15692
15692
|
- [Connection](classes/Connection.md)
|
|
15693
15693
|
|
|
15694
|
+
lib/text/functions/getFileExt.md
|
|
15695
|
+
---
|
|
15696
|
+
|
|
15697
|
+
[**Documents for @maiyunnet/kebab**](../../../index.md)
|
|
15698
|
+
|
|
15699
|
+
***
|
|
15700
|
+
|
|
15701
|
+
[Documents for @maiyunnet/kebab](../../../index.md) / [lib/text](../index.md) / getFileExt
|
|
15702
|
+
|
|
15703
|
+
# Function: getFileExt()
|
|
15704
|
+
|
|
15705
|
+
> **getFileExt**(`path`): `string`
|
|
15706
|
+
|
|
15707
|
+
Defined in: [lib/text.ts:527](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L527)
|
|
15708
|
+
|
|
15709
|
+
获取文件后缀
|
|
15710
|
+
|
|
15711
|
+
## Parameters
|
|
15712
|
+
|
|
15713
|
+
### path
|
|
15714
|
+
|
|
15715
|
+
`string`
|
|
15716
|
+
|
|
15717
|
+
文件路径
|
|
15718
|
+
|
|
15719
|
+
## Returns
|
|
15720
|
+
|
|
15721
|
+
`string`
|
|
15722
|
+
|
|
15723
|
+
lib/text/functions/getFileNameExt.md
|
|
15724
|
+
---
|
|
15725
|
+
|
|
15726
|
+
[**Documents for @maiyunnet/kebab**](../../../index.md)
|
|
15727
|
+
|
|
15728
|
+
***
|
|
15729
|
+
|
|
15730
|
+
[Documents for @maiyunnet/kebab](../../../index.md) / [lib/text](../index.md) / getFileNameExt
|
|
15731
|
+
|
|
15732
|
+
# Function: getFileNameExt()
|
|
15733
|
+
|
|
15734
|
+
> **getFileNameExt**(`path`): `object`
|
|
15735
|
+
|
|
15736
|
+
Defined in: [lib/text.ts:540](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L540)
|
|
15737
|
+
|
|
15738
|
+
获取文件名和后缀
|
|
15739
|
+
|
|
15740
|
+
## Parameters
|
|
15741
|
+
|
|
15742
|
+
### path
|
|
15743
|
+
|
|
15744
|
+
`string`
|
|
15745
|
+
|
|
15746
|
+
文件路径
|
|
15747
|
+
|
|
15748
|
+
## Returns
|
|
15749
|
+
|
|
15750
|
+
`object`
|
|
15751
|
+
|
|
15752
|
+
### ext
|
|
15753
|
+
|
|
15754
|
+
> **ext**: `string`
|
|
15755
|
+
|
|
15756
|
+
### name
|
|
15757
|
+
|
|
15758
|
+
> **name**: `string`
|
|
15759
|
+
|
|
15694
15760
|
lib/text/functions/getFilename.md
|
|
15695
15761
|
---
|
|
15696
15762
|
|
|
@@ -15702,9 +15768,9 @@ lib/text/functions/getFilename.md
|
|
|
15702
15768
|
|
|
15703
15769
|
# Function: getFilename()
|
|
15704
15770
|
|
|
15705
|
-
> **getFilename**(`path`): `string`
|
|
15771
|
+
> **getFilename**(`path`, `ext?`): `string`
|
|
15706
15772
|
|
|
15707
|
-
Defined in: [lib/text.ts:
|
|
15773
|
+
Defined in: [lib/text.ts:507](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L507)
|
|
15708
15774
|
|
|
15709
15775
|
获取文件名
|
|
15710
15776
|
|
|
@@ -15716,6 +15782,12 @@ Defined in: [lib/text.ts:506](https://github.com/maiyunnet/kebab/blob/master/lib
|
|
|
15716
15782
|
|
|
15717
15783
|
文件路径
|
|
15718
15784
|
|
|
15785
|
+
### ext?
|
|
15786
|
+
|
|
15787
|
+
`boolean` = `true`
|
|
15788
|
+
|
|
15789
|
+
是否包含后缀,默认包含
|
|
15790
|
+
|
|
15719
15791
|
## Returns
|
|
15720
15792
|
|
|
15721
15793
|
`string`
|
|
@@ -15762,7 +15834,7 @@ lib/text/functions/int2str.md
|
|
|
15762
15834
|
|
|
15763
15835
|
> **int2str**(`int`, `digits?`, `decimal?`): `string`
|
|
15764
15836
|
|
|
15765
|
-
Defined in: [lib/text.ts:
|
|
15837
|
+
Defined in: [lib/text.ts:740](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L740)
|
|
15766
15838
|
|
|
15767
15839
|
为解决精度问题,将整数转换为小数字符串
|
|
15768
15840
|
以下几个示例都是当 digits 为 3、decimal 为 2 时
|
|
@@ -15895,7 +15967,7 @@ lib/text/functions/isFalsy.md
|
|
|
15895
15967
|
|
|
15896
15968
|
> **isFalsy**(`val`): `val is TFalsy`
|
|
15897
15969
|
|
|
15898
|
-
Defined in: [lib/text.ts:
|
|
15970
|
+
Defined in: [lib/text.ts:691](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L691)
|
|
15899
15971
|
|
|
15900
15972
|
判断一个值是否是虚假的(为 null/undefined/空字符串/false/0)
|
|
15901
15973
|
|
|
@@ -16065,7 +16137,7 @@ lib/text/functions/isTruthy.md
|
|
|
16065
16137
|
|
|
16066
16138
|
> **isTruthy**\<`T`\>(`val`): `val is Exclude<T, TFalsy>`
|
|
16067
16139
|
|
|
16068
|
-
Defined in: [lib/text.ts:
|
|
16140
|
+
Defined in: [lib/text.ts:699](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L699)
|
|
16069
16141
|
|
|
16070
16142
|
判断一个值是否是真实的(不为 null/undefined/空字符串/false/0)
|
|
16071
16143
|
|
|
@@ -16100,7 +16172,7 @@ lib/text/functions/logicalOr.md
|
|
|
16100
16172
|
|
|
16101
16173
|
> **logicalOr**\<`T`, `T2`\>(`v1`, `v2`): `T` *extends* [`TFalsy`](../type-aliases/TFalsy.md) ? `T2` : `T`
|
|
16102
16174
|
|
|
16103
|
-
Defined in: [lib/text.ts:
|
|
16175
|
+
Defined in: [lib/text.ts:708](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L708)
|
|
16104
16176
|
|
|
16105
16177
|
类似 || 运算符的效果
|
|
16106
16178
|
|
|
@@ -16285,7 +16357,7 @@ lib/text/functions/parseJson.md
|
|
|
16285
16357
|
|
|
16286
16358
|
> **parseJson**\<`T`\>(`str`): `false` \| `T`
|
|
16287
16359
|
|
|
16288
|
-
Defined in: [lib/text.ts:
|
|
16360
|
+
Defined in: [lib/text.ts:602](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L602)
|
|
16289
16361
|
|
|
16290
16362
|
将字符串解析为对象,返回 false 代表解析失败,支持 BigInt
|
|
16291
16363
|
|
|
@@ -16484,7 +16556,7 @@ lib/text/functions/str2int.md
|
|
|
16484
16556
|
|
|
16485
16557
|
> **str2int**(`str`, `digits?`): `number`
|
|
16486
16558
|
|
|
16487
|
-
Defined in: [lib/text.ts:
|
|
16559
|
+
Defined in: [lib/text.ts:722](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L722)
|
|
16488
16560
|
|
|
16489
16561
|
为解决精度问题,将字符串数字转换为整数显示
|
|
16490
16562
|
以下几个示例都是当 digits 为 2 时
|
|
@@ -16524,7 +16596,7 @@ lib/text/functions/stringifyBuffer.md
|
|
|
16524
16596
|
|
|
16525
16597
|
> **stringifyBuffer**(`buf`): `string`
|
|
16526
16598
|
|
|
16527
|
-
Defined in: [lib/text.ts:
|
|
16599
|
+
Defined in: [lib/text.ts:645](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L645)
|
|
16528
16600
|
|
|
16529
16601
|
输出文本格式的 buffer
|
|
16530
16602
|
|
|
@@ -16553,7 +16625,7 @@ lib/text/functions/stringifyJson.md
|
|
|
16553
16625
|
|
|
16554
16626
|
> **stringifyJson**(`obj`, `space?`): `string`
|
|
16555
16627
|
|
|
16556
|
-
Defined in: [lib/text.ts:
|
|
16628
|
+
Defined in: [lib/text.ts:632](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L632)
|
|
16557
16629
|
|
|
16558
16630
|
将对象转换为 json 字符串,返回 false 代表解析失败,支持 BigInt
|
|
16559
16631
|
|
|
@@ -16588,7 +16660,7 @@ lib/text/functions/stringifyResult.md
|
|
|
16588
16660
|
|
|
16589
16661
|
> **stringifyResult**(`rtn`): `string`
|
|
16590
16662
|
|
|
16591
|
-
Defined in: [lib/text.ts:
|
|
16663
|
+
Defined in: [lib/text.ts:562](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L562)
|
|
16592
16664
|
|
|
16593
16665
|
将普通的返回 JSON 对象序列化为字符串
|
|
16594
16666
|
|
|
@@ -16617,7 +16689,7 @@ lib/text/functions/trimJson.md
|
|
|
16617
16689
|
|
|
16618
16690
|
> **trimJson**(`json`): `any`
|
|
16619
16691
|
|
|
16620
|
-
Defined in: [lib/text.ts:
|
|
16692
|
+
Defined in: [lib/text.ts:653](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L653)
|
|
16621
16693
|
|
|
16622
16694
|
递归删除 json 中的字符串首尾空格,会返回一个新的对象
|
|
16623
16695
|
|
|
@@ -16724,7 +16796,9 @@ lib/text/index.md
|
|
|
16724
16796
|
|
|
16725
16797
|
## Functions
|
|
16726
16798
|
|
|
16799
|
+
- [getFileExt](functions/getFileExt.md)
|
|
16727
16800
|
- [getFilename](functions/getFilename.md)
|
|
16801
|
+
- [getFileNameExt](functions/getFileNameExt.md)
|
|
16728
16802
|
- [htmlescape](functions/htmlescape.md)
|
|
16729
16803
|
- [int2str](functions/int2str.md)
|
|
16730
16804
|
- [isAscii](functions/isAscii.md)
|
|
@@ -16815,7 +16889,7 @@ lib/text/type-aliases/TFalsy.md
|
|
|
16815
16889
|
|
|
16816
16890
|
> **TFalsy** = `false` \| `""` \| `0` \| `null` \| `undefined` \| *typeof* `NaN`
|
|
16817
16891
|
|
|
16818
|
-
Defined in: [lib/text.ts:
|
|
16892
|
+
Defined in: [lib/text.ts:685](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L685)
|
|
16819
16893
|
|
|
16820
16894
|
虚假值类型
|
|
16821
16895
|
|
|
@@ -17389,7 +17463,7 @@ Defined in: [lib/undici/formdata.ts:37](https://github.com/maiyunnet/kebab/blob/
|
|
|
17389
17463
|
|
|
17390
17464
|
> **new FormData**(`options?`): `FormData`
|
|
17391
17465
|
|
|
17392
|
-
Defined in: node\_modules/@types/node/stream.d.ts:
|
|
17466
|
+
Defined in: node\_modules/@types/node/stream.d.ts:80
|
|
17393
17467
|
|
|
17394
17468
|
#### Parameters
|
|
17395
17469
|
|
package/index.d.ts
CHANGED
package/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* --- 本文件用来定义每个目录实体地址的常量 ---
|
|
7
7
|
*/
|
|
8
8
|
/** --- 当前系统版本号 --- */
|
|
9
|
-
export const VER = '9.2.
|
|
9
|
+
export const VER = '9.2.2';
|
|
10
10
|
// --- 服务端用的路径 ---
|
|
11
11
|
const imu = decodeURIComponent(import.meta.url).replace('file://', '').replace(/^\/(\w:)/, '$1');
|
|
12
12
|
/** --- /xxx/xxx --- */
|
package/lib/text.d.ts
CHANGED
|
@@ -136,8 +136,22 @@ export declare function isRealPath(path: string): boolean;
|
|
|
136
136
|
/**
|
|
137
137
|
* --- 获取文件名 ---
|
|
138
138
|
* @param path 文件路径
|
|
139
|
+
* @param ext 是否包含后缀,默认包含
|
|
139
140
|
*/
|
|
140
|
-
export declare function getFilename(path: string): string;
|
|
141
|
+
export declare function getFilename(path: string, ext?: boolean): string;
|
|
142
|
+
/**
|
|
143
|
+
* --- 获取文件后缀 ---
|
|
144
|
+
* @param path 文件路径
|
|
145
|
+
*/
|
|
146
|
+
export declare function getFileExt(path: string): string;
|
|
147
|
+
/**
|
|
148
|
+
* --- 获取文件名和后缀 ---
|
|
149
|
+
* @param path 文件路径
|
|
150
|
+
*/
|
|
151
|
+
export declare function getFileNameExt(path: string): {
|
|
152
|
+
name: string;
|
|
153
|
+
ext: string;
|
|
154
|
+
};
|
|
141
155
|
/**
|
|
142
156
|
* --- 将普通的返回 JSON 对象序列化为字符串 ---
|
|
143
157
|
* @param rtn 返回 JSON 对象
|
package/lib/text.js
CHANGED
|
@@ -439,14 +439,52 @@ export function isRealPath(path) {
|
|
|
439
439
|
/**
|
|
440
440
|
* --- 获取文件名 ---
|
|
441
441
|
* @param path 文件路径
|
|
442
|
+
* @param ext 是否包含后缀,默认包含
|
|
442
443
|
*/
|
|
443
|
-
export function getFilename(path) {
|
|
444
|
+
export function getFilename(path, ext = true) {
|
|
444
445
|
path = path.replace(/\\/g, '/');
|
|
445
446
|
const lio = path.lastIndexOf('/');
|
|
446
|
-
if (lio
|
|
447
|
+
if (lio !== -1) {
|
|
448
|
+
path = path.slice(lio + 1);
|
|
449
|
+
}
|
|
450
|
+
if (ext) {
|
|
451
|
+
return path;
|
|
452
|
+
}
|
|
453
|
+
const dot = path.lastIndexOf('.');
|
|
454
|
+
if (dot === -1) {
|
|
447
455
|
return path;
|
|
448
456
|
}
|
|
449
|
-
return path.slice(
|
|
457
|
+
return path.slice(0, dot);
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* --- 获取文件后缀 ---
|
|
461
|
+
* @param path 文件路径
|
|
462
|
+
*/
|
|
463
|
+
export function getFileExt(path) {
|
|
464
|
+
const filename = getFilename(path);
|
|
465
|
+
const dot = filename.lastIndexOf('.');
|
|
466
|
+
if (dot === -1) {
|
|
467
|
+
return '';
|
|
468
|
+
}
|
|
469
|
+
return filename.slice(dot + 1).toLowerCase();
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* --- 获取文件名和后缀 ---
|
|
473
|
+
* @param path 文件路径
|
|
474
|
+
*/
|
|
475
|
+
export function getFileNameExt(path) {
|
|
476
|
+
const filename = getFilename(path);
|
|
477
|
+
const dot = filename.lastIndexOf('.');
|
|
478
|
+
if (dot === -1) {
|
|
479
|
+
return {
|
|
480
|
+
'name': filename,
|
|
481
|
+
'ext': ''
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
return {
|
|
485
|
+
'name': filename.slice(0, dot),
|
|
486
|
+
'ext': filename.slice(dot + 1).toLowerCase()
|
|
487
|
+
};
|
|
450
488
|
}
|
|
451
489
|
/**
|
|
452
490
|
* --- 将普通的返回 JSON 对象序列化为字符串 ---
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maiyunnet/kebab",
|
|
3
|
-
"version": "9.2.
|
|
3
|
+
"version": "9.2.2",
|
|
4
4
|
"description": "Simple, easy-to-use, and fully-featured Node.js framework that is ready-to-use out of the box.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -22,48 +22,48 @@
|
|
|
22
22
|
"#kebab/*": "./*"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@aws-sdk/client-s3": "^3.
|
|
26
|
-
"@aws-sdk/lib-storage": "^3.
|
|
25
|
+
"@aws-sdk/client-s3": "^3.1034.0",
|
|
26
|
+
"@aws-sdk/lib-storage": "^3.1034.0",
|
|
27
27
|
"@litert/http-client": "^1.1.2",
|
|
28
28
|
"@litert/mime": "^0.1.3",
|
|
29
|
-
"@litert/redis": "^3.2.
|
|
29
|
+
"@litert/redis": "^3.2.1",
|
|
30
30
|
"@litert/websocket": "^0.2.8",
|
|
31
31
|
"@radix-ui/react-checkbox": "^1.3.3",
|
|
32
32
|
"@radix-ui/react-label": "^2.1.8",
|
|
33
33
|
"@radix-ui/react-slot": "^1.2.4",
|
|
34
34
|
"@radix-ui/react-switch": "^1.2.6",
|
|
35
|
-
"@tailwindcss/cli": "^4.2.
|
|
35
|
+
"@tailwindcss/cli": "^4.2.4",
|
|
36
36
|
"@types/ssh2": "^1.15.5",
|
|
37
|
-
"@zilliz/milvus2-sdk-node": "^2.6.
|
|
37
|
+
"@zilliz/milvus2-sdk-node": "^2.6.13",
|
|
38
38
|
"ajv": "^8.18.0",
|
|
39
39
|
"ajv-formats": "^3.0.1",
|
|
40
40
|
"class-variance-authority": "^0.7.1",
|
|
41
41
|
"clsx": "^2.1.1",
|
|
42
|
-
"ejs": "^5.0.
|
|
43
|
-
"esbuild": "^0.
|
|
42
|
+
"ejs": "^5.0.2",
|
|
43
|
+
"esbuild": "^0.28.0",
|
|
44
44
|
"jszip": "^3.10.1",
|
|
45
|
-
"mysql2": "^3.
|
|
45
|
+
"mysql2": "^3.22.2",
|
|
46
46
|
"node-cron": "^4.2.1",
|
|
47
|
-
"openai": "^6.
|
|
47
|
+
"openai": "^6.34.0",
|
|
48
48
|
"pg": "^8.20.0",
|
|
49
|
-
"react": "^19.2.
|
|
50
|
-
"react-dom": "^19.2.
|
|
51
|
-
"react-router-dom": "^7.
|
|
49
|
+
"react": "^19.2.5",
|
|
50
|
+
"react-dom": "^19.2.5",
|
|
51
|
+
"react-router-dom": "^7.14.2",
|
|
52
52
|
"ssh2": "^1.17.0",
|
|
53
53
|
"svg-captcha": "^1.4.0",
|
|
54
54
|
"tailwind-merge": "^3.5.0",
|
|
55
|
-
"tencentcloud-sdk-nodejs": "^4.1.
|
|
55
|
+
"tencentcloud-sdk-nodejs": "^4.1.219",
|
|
56
56
|
"undici": "^8.1.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@litert/eslint-plugin-rules": "^0.3.1",
|
|
60
60
|
"@types/ejs": "^3.1.5",
|
|
61
|
-
"@types/node": "^25.
|
|
61
|
+
"@types/node": "^25.6.0",
|
|
62
62
|
"@types/pg": "^8.20.0",
|
|
63
63
|
"@types/react": "^19.2.14",
|
|
64
64
|
"@types/react-dom": "^19.2.3",
|
|
65
|
-
"typedoc": "^0.28.
|
|
65
|
+
"typedoc": "^0.28.19",
|
|
66
66
|
"typedoc-plugin-markdown": "^4.11.0",
|
|
67
|
-
"typescript": "^
|
|
67
|
+
"typescript": "^6.0.3"
|
|
68
68
|
}
|
|
69
69
|
}
|
package/sys/master.js
CHANGED
|
@@ -546,19 +546,26 @@ function startFileWatcher() {
|
|
|
546
546
|
* --- 监听指定目录的文件变化 ---
|
|
547
547
|
* @param dir 要监听的目录路径
|
|
548
548
|
*/
|
|
549
|
-
const watchDir = (dir) => {
|
|
549
|
+
const watchDir = async (dir) => {
|
|
550
|
+
if (!await lFs.isDir(dir)) {
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
550
553
|
try {
|
|
551
|
-
fs.watch(dir, { 'recursive': true }, (eventType, filename) => {
|
|
554
|
+
const watcher = fs.watch(dir, { 'recursive': true }, (eventType, filename) => {
|
|
552
555
|
if (!filename) {
|
|
553
556
|
return;
|
|
554
557
|
}
|
|
558
|
+
const formatName = filename.replace(/\\/g, '/');
|
|
555
559
|
// --- 仅关注 .js 文件和 .json 配置文件的变更 ---
|
|
556
|
-
if (!
|
|
557
|
-
!
|
|
560
|
+
if (!formatName.endsWith('.js') &&
|
|
561
|
+
!formatName.endsWith('.json')) {
|
|
558
562
|
return;
|
|
559
563
|
}
|
|
560
|
-
// ---
|
|
561
|
-
if (
|
|
564
|
+
// --- 忽略日志目录、临时目录、git 目录和 node_modules ---
|
|
565
|
+
if (formatName.includes('log/') ||
|
|
566
|
+
formatName.includes('ftmp/') ||
|
|
567
|
+
formatName.includes('node_modules/') ||
|
|
568
|
+
formatName.includes('.git/')) {
|
|
562
569
|
return;
|
|
563
570
|
}
|
|
564
571
|
// --- 防抖:500ms 内多次变化只触发一次 ---
|
|
@@ -571,7 +578,7 @@ function startFileWatcher() {
|
|
|
571
578
|
return;
|
|
572
579
|
}
|
|
573
580
|
restarting = true;
|
|
574
|
-
lCore.display(`[HMR] File changed: ${
|
|
581
|
+
lCore.display(`[HMR] File changed: ${formatName}, reloading workers...`);
|
|
575
582
|
(async () => {
|
|
576
583
|
// --- 为所有子进程发送 stop 信息并重启 ---
|
|
577
584
|
for (const pid in workerList) {
|
|
@@ -589,20 +596,23 @@ function startFileWatcher() {
|
|
|
589
596
|
});
|
|
590
597
|
}, 500);
|
|
591
598
|
});
|
|
599
|
+
watcher.on('error', (err) => {
|
|
600
|
+
lCore.display(`[HMR] Watcher error on ${dir}:`, err);
|
|
601
|
+
});
|
|
592
602
|
lCore.display(`[HMR] Watching directory: ${dir}`);
|
|
593
603
|
}
|
|
594
|
-
catch {
|
|
595
|
-
lCore.display(`[HMR] Cannot watch directory: ${dir}
|
|
604
|
+
catch (err) {
|
|
605
|
+
lCore.display(`[HMR] Cannot watch directory: ${dir}`, err);
|
|
596
606
|
}
|
|
597
607
|
};
|
|
598
608
|
// --- 监听 www/ 目录(用户项目代码)---
|
|
599
|
-
watchDir(kebab.WWW_CWD);
|
|
609
|
+
watchDir(kebab.WWW_CWD).catch(() => { });
|
|
600
610
|
// --- 监听 ind/ 目录(独立任务代码)---
|
|
601
|
-
watchDir(kebab.IND_CWD);
|
|
611
|
+
watchDir(kebab.IND_CWD).catch(() => { });
|
|
602
612
|
// --- 监听 lib/ 目录(用户自定义库)---
|
|
603
|
-
watchDir(kebab.LIB_CWD);
|
|
613
|
+
watchDir(kebab.LIB_CWD).catch(() => { });
|
|
604
614
|
// --- 监听 mod/ 目录(用户模型)---
|
|
605
|
-
watchDir(kebab.MOD_CWD);
|
|
615
|
+
watchDir(kebab.MOD_CWD).catch(() => { });
|
|
606
616
|
}
|
|
607
617
|
run().catch(function (e) {
|
|
608
618
|
lCore.display('[master] ------ [Process fatal Error] ------');
|
|
@@ -136,9 +136,7 @@ export default function ReactPage({ title, serverTime, node, _urlBase, _urlStc,
|
|
|
136
136
|
setIsFetching(false);
|
|
137
137
|
});
|
|
138
138
|
}
|
|
139
|
-
return (
|
|
140
|
-
// --- 组件渲染完整 HTML 文档,无需外部 EJS 模板 ---
|
|
141
|
-
_jsxs("html", { lang: "en", children: [_jsxs("head", { children: [_jsx("meta", { charSet: "UTF-8" }), _jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0" }), _jsx("title", { children: title }), _jsx("link", { href: `${_urlStc}view/react.page.css?v=${_staticVer}`, rel: "stylesheet" })] }), _jsx("body", { className: "bg-slate-50 min-h-screen font-sans", children: _jsxs("div", { className: "max-w-3xl mx-auto px-4 py-10 space-y-6", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex gap-2 mb-2", children: [_jsx(Badge, { children: "SSR \u00B7 Kebab" }), _jsx(Badge, { variant: hydrated ? 'success' : 'warn', children: hydrated ? 'Hydrated ✓' : 'Rendering...' })] }), _jsx("h1", { className: "text-2xl font-bold text-slate-900", children: title }), _jsxs("p", { className: "text-slate-500 text-sm mt-1", children: [serverTime, " \u00B7 ", node] })] }), _jsx("div", { className: "flex gap-1 bg-slate-100 p-1 rounded-lg w-fit", children: ['overview', 'routing', 'fetch', 'shadcn'].map(t => (_jsx("button", { onClick: () => setTab(t), className: [
|
|
139
|
+
return (_jsxs("html", { lang: "en", children: [_jsxs("head", { children: [_jsx("meta", { charSet: "UTF-8" }), _jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0" }), _jsx("title", { children: title }), _jsx("link", { href: `${_urlStc}view/react.page.css?v=${_staticVer}`, rel: "stylesheet" })] }), _jsx("body", { className: "bg-slate-50 min-h-screen font-sans", children: _jsxs("div", { className: "max-w-3xl mx-auto px-4 py-10 space-y-6", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex gap-2 mb-2", children: [_jsx(Badge, { children: "SSR \u00B7 Kebab" }), _jsx(Badge, { variant: hydrated ? 'success' : 'warn', children: hydrated ? 'Hydrated ✓' : 'Rendering...' })] }), _jsx("h1", { className: "text-2xl font-bold text-slate-900", children: title }), _jsxs("p", { className: "text-slate-500 text-sm mt-1", children: [serverTime, " \u00B7 ", node] })] }), _jsx("div", { className: "flex gap-1 bg-slate-100 p-1 rounded-lg w-fit", children: ['overview', 'routing', 'fetch', 'shadcn'].map(t => (_jsx("button", { onClick: () => setTab(t), className: [
|
|
142
140
|
'px-4 py-2 rounded-md text-sm font-medium transition-colors cursor-pointer',
|
|
143
141
|
tab === t ? 'bg-white shadow text-slate-900' : 'text-slate-500 hover:text-slate-900',
|
|
144
142
|
].join(' '), children: t.charAt(0).toUpperCase() + t.slice(1) }, t))) }), tab === 'overview' && (_jsxs("div", { className: "space-y-4", children: [_jsxs(Card, { children: [_jsx("h2", { className: "font-semibold text-slate-900 mb-1", children: "Counter\uFF08useState + hydration\uFF09" }), _jsx("p", { className: "text-slate-500 text-xs mb-4", children: "SSR renders with initial value 0; props are serialized as inline JSON. After hydration the state becomes interactive \u2014 click the buttons to test:" }), _jsxs("div", { className: "flex items-center gap-4", children: [_jsx("button", { onClick: () => setCount(c => c - 1), className: "w-10 h-10 rounded-lg border border-slate-300 hover:bg-slate-50 font-bold text-slate-700 text-xl cursor-pointer", children: "\u2212" }), _jsx("span", { className: "text-3xl font-bold text-slate-900 w-10 text-center tabular-nums", children: count }), _jsx("button", { onClick: () => setCount(c => c + 1), className: "w-10 h-10 rounded-lg bg-blue-500 hover:bg-blue-600 text-white font-bold text-xl cursor-pointer", children: "+" })] })] }), _jsxs(Card, { children: [_jsx("h2", { className: "font-semibold text-slate-900 mb-3", children: "Server Props (from Ctr method)" }), _jsxs("p", { className: "text-slate-500 text-xs mb-3", children: ["Passed via", ' ', _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "_loadReactPage(path, props)" }), ". The framework auto-injects constants like _urlBase and serializes all props as inline JSON, reused directly during client hydration \u2014 no extra request needed."] }), _jsx("div", { className: "space-y-2", children: [
|
|
@@ -155,13 +153,7 @@ export default function ReactPage({ title, serverTime, node, _urlBase, _urlStc,
|
|
|
155
153
|
checkbox.tsx # shadcn Checkbox
|
|
156
154
|
switch.tsx # shadcn Switch
|
|
157
155
|
view/
|
|
158
|
-
react-page.tsx # Page component (import + compose)` }), _jsxs("p", { className: "text-slate-500 text-xs mt-3", children: ["Mirrors the shadcn/ui ", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "components/ui/" }), " convention. In dev mode, the framework auto-scans imports \u2014 no manual import map configuration needed."] })] })] })), tab === 'routing' && (
|
|
159
|
-
/*
|
|
160
|
-
MemoryRouter:路由状态保存在内存中,服务端 SSR 和客户端水合均可运行,
|
|
161
|
-
无需服务端配置 catch-all 路由,适合在页面内嵌入独立的路由演示。
|
|
162
|
-
若要整页接管 URL,改用 BrowserRouter(需服务端对所有子路径返回同一页面)。
|
|
163
|
-
*/
|
|
164
|
-
_jsxs(MemoryRouter, { children: [_jsxs(Card, { children: [_jsx("h2", { className: "font-semibold text-slate-900 mb-1", children: "React Router Demo" }), _jsxs("p", { className: "text-slate-500 text-xs mb-4", children: ["Uses ", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "MemoryRouter" }), ' ', "to demonstrate route navigation, dynamic params (useParams), and programmatic navigation (useNavigate). Works on both server SSR and client hydration with no extra server configuration."] }), _jsxs(Routes, { children: [_jsx(Route, { path: "/", element: _jsx(RouterHome, {}) }), _jsx(Route, { path: "/about", element: _jsx(RouterAbout, {}) }), _jsx(Route, { path: "/user/:id", element: _jsx(RouterUser, {}) })] })] }), _jsxs(Card, { className: "mt-4", children: [_jsx("h2", { className: "font-semibold text-slate-900 mb-2", children: "Full-Page BrowserRouter Setup" }), _jsx("p", { className: "text-slate-500 text-xs mb-3", children: "To let React Router manage the real URL (e.g. /app, /app/about), replace MemoryRouter with BrowserRouter and route all sub-paths to the same Ctr method on the server:" }), _jsx("pre", { className: "bg-slate-50 border border-slate-200 rounded-lg p-4 text-xs overflow-auto leading-relaxed text-slate-700", children: `// 1. route.json: 将所有子路径路由到同一 Ctr 方法
|
|
156
|
+
react-page.tsx # Page component (import + compose)` }), _jsxs("p", { className: "text-slate-500 text-xs mt-3", children: ["Mirrors the shadcn/ui ", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "components/ui/" }), " convention. In dev mode, the framework auto-scans imports \u2014 no manual import map configuration needed."] })] })] })), tab === 'routing' && (_jsxs(MemoryRouter, { children: [_jsxs(Card, { children: [_jsx("h2", { className: "font-semibold text-slate-900 mb-1", children: "React Router Demo" }), _jsxs("p", { className: "text-slate-500 text-xs mb-4", children: ["Uses ", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "MemoryRouter" }), ' ', "to demonstrate route navigation, dynamic params (useParams), and programmatic navigation (useNavigate). Works on both server SSR and client hydration with no extra server configuration."] }), _jsxs(Routes, { children: [_jsx(Route, { path: "/", element: _jsx(RouterHome, {}) }), _jsx(Route, { path: "/about", element: _jsx(RouterAbout, {}) }), _jsx(Route, { path: "/user/:id", element: _jsx(RouterUser, {}) })] })] }), _jsxs(Card, { className: "mt-4", children: [_jsx("h2", { className: "font-semibold text-slate-900 mb-2", children: "Full-Page BrowserRouter Setup" }), _jsx("p", { className: "text-slate-500 text-xs mb-3", children: "To let React Router manage the real URL (e.g. /app, /app/about), replace MemoryRouter with BrowserRouter and route all sub-paths to the same Ctr method on the server:" }), _jsx("pre", { className: "bg-slate-50 border border-slate-200 rounded-lg p-4 text-xs overflow-auto leading-relaxed text-slate-700", children: `// 1. route.json: 将所有子路径路由到同一 Ctr 方法
|
|
165
157
|
{
|
|
166
158
|
"app": "ctr/app@reactPage",
|
|
167
159
|
"app\\/.*": "ctr/app@reactPage"
|