@maiyunnet/kebab 9.9.0 → 9.10.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/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.9.0"` = `'9.9.0'`
1363
+ > `const` **VER**: `"9.10.1"` = `'9.10.1'`
1364
1364
 
1365
1365
  Defined in: [index.ts:10](https://github.com/maiyunnet/kebab/blob/master/index.ts#L10)
1366
1366
 
@@ -3691,7 +3691,7 @@ Defined in: [lib/core.ts:1123](https://github.com/maiyunnet/kebab/blob/master/li
3691
3691
 
3692
3692
  `string`
3693
3693
 
3694
- 如 2024/08/01/22,无所谓开头结尾
3694
+ 如 2024/08/01/22,无所谓开头结尾是否有 /,不会逃逸出 cwd 路径
3695
3695
 
3696
3696
  ## Returns
3697
3697
 
@@ -15902,7 +15902,7 @@ lib/text/functions/csvescape.md
15902
15902
 
15903
15903
  > **csvescape**(`str`): `string`
15904
15904
 
15905
- Defined in: [lib/text.ts:497](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L497)
15905
+ Defined in: [lib/text.ts:514](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L514)
15906
15906
 
15907
15907
  CSV 特殊字符转换为实体字符
15908
15908
 
@@ -15929,7 +15929,7 @@ lib/text/functions/getFileExt.md
15929
15929
 
15930
15930
  > **getFileExt**(`path`): `string`
15931
15931
 
15932
- Defined in: [lib/text.ts:538](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L538)
15932
+ Defined in: [lib/text.ts:555](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L555)
15933
15933
 
15934
15934
  获取文件后缀
15935
15935
 
@@ -15958,7 +15958,7 @@ lib/text/functions/getFileNameExt.md
15958
15958
 
15959
15959
  > **getFileNameExt**(`path`): `object`
15960
15960
 
15961
- Defined in: [lib/text.ts:551](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L551)
15961
+ Defined in: [lib/text.ts:568](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L568)
15962
15962
 
15963
15963
  获取文件名和后缀
15964
15964
 
@@ -15995,7 +15995,7 @@ lib/text/functions/getFilename.md
15995
15995
 
15996
15996
  > **getFilename**(`path`, `ext?`): `string`
15997
15997
 
15998
- Defined in: [lib/text.ts:518](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L518)
15998
+ Defined in: [lib/text.ts:535](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L535)
15999
15999
 
16000
16000
  获取文件名
16001
16001
 
@@ -16030,7 +16030,7 @@ lib/text/functions/htmlescape.md
16030
16030
 
16031
16031
  > **htmlescape**(`html`): `string`
16032
16032
 
16033
- Defined in: [lib/text.ts:488](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L488)
16033
+ Defined in: [lib/text.ts:505](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L505)
16034
16034
 
16035
16035
  HTML 特殊字符转换为实体字符
16036
16036
 
@@ -16059,7 +16059,7 @@ lib/text/functions/int2str.md
16059
16059
 
16060
16060
  > **int2str**(`int`, `digits?`, `decimal?`): `string`
16061
16061
 
16062
- Defined in: [lib/text.ts:751](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L751)
16062
+ Defined in: [lib/text.ts:768](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L768)
16063
16063
 
16064
16064
  为解决精度问题,将整数转换为小数字符串
16065
16065
  以下几个示例都是当 digits 为 3、decimal 为 2 时
@@ -16105,7 +16105,7 @@ lib/text/functions/isAscii.md
16105
16105
 
16106
16106
  > **isAscii**(`text`): `boolean`
16107
16107
 
16108
- Defined in: [lib/text.ts:256](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L256)
16108
+ Defined in: [lib/text.ts:273](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L273)
16109
16109
 
16110
16110
  判断是否在 ascii 字符集内,仅可输入部分
16111
16111
 
@@ -16134,7 +16134,7 @@ lib/text/functions/isDomain.md
16134
16134
 
16135
16135
  > **isDomain**(`domain`): `boolean`
16136
16136
 
16137
- Defined in: [lib/text.ts:245](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L245)
16137
+ Defined in: [lib/text.ts:262](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L262)
16138
16138
 
16139
16139
  判断是否是域名
16140
16140
 
@@ -16165,7 +16165,7 @@ lib/text/functions/isEMail.md
16165
16165
 
16166
16166
  > **isEMail**(`email`): `boolean`
16167
16167
 
16168
- Defined in: [lib/text.ts:214](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L214)
16168
+ Defined in: [lib/text.ts:231](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L231)
16169
16169
 
16170
16170
  是否是邮件地址
16171
16171
 
@@ -16192,7 +16192,7 @@ lib/text/functions/isFalsy.md
16192
16192
 
16193
16193
  > **isFalsy**(`val`): `val is TFalsy`
16194
16194
 
16195
- Defined in: [lib/text.ts:702](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L702)
16195
+ Defined in: [lib/text.ts:719](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L719)
16196
16196
 
16197
16197
  判断一个值是否是虚假的(为 null/undefined/空字符串/false/0)
16198
16198
 
@@ -16221,7 +16221,7 @@ lib/text/functions/isIdCardCN.md
16221
16221
 
16222
16222
  > **isIdCardCN**(`idcard`): `boolean`
16223
16223
 
16224
- Defined in: [lib/text.ts:368](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L368)
16224
+ Defined in: [lib/text.ts:385](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L385)
16225
16225
 
16226
16226
  是否是中国大陆身份证号码
16227
16227
 
@@ -16250,7 +16250,7 @@ lib/text/functions/isIPv4.md
16250
16250
 
16251
16251
  > **isIPv4**(`ip`): `boolean`
16252
16252
 
16253
- Defined in: [lib/text.ts:224](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L224)
16253
+ Defined in: [lib/text.ts:241](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L241)
16254
16254
 
16255
16255
  是否是 IPv4
16256
16256
 
@@ -16277,7 +16277,7 @@ lib/text/functions/isIPv6.md
16277
16277
 
16278
16278
  > **isIPv6**(`ip`): `boolean`
16279
16279
 
16280
- Defined in: [lib/text.ts:234](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L234)
16280
+ Defined in: [lib/text.ts:251](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L251)
16281
16281
 
16282
16282
  是否是 IPv6
16283
16283
 
@@ -16304,7 +16304,7 @@ lib/text/functions/isPhoneCN.md
16304
16304
 
16305
16305
  > **isPhoneCN**(`p`): `boolean`
16306
16306
 
16307
- Defined in: [lib/text.ts:360](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L360)
16307
+ Defined in: [lib/text.ts:377](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L377)
16308
16308
 
16309
16309
  判断手机号是否是 11 位,不做真实性校验
16310
16310
 
@@ -16333,7 +16333,7 @@ lib/text/functions/isRealPath.md
16333
16333
 
16334
16334
  > **isRealPath**(`path`): `boolean`
16335
16335
 
16336
- Defined in: [lib/text.ts:505](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L505)
16336
+ Defined in: [lib/text.ts:522](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L522)
16337
16337
 
16338
16338
  判断是否是绝对路径,是返回 true,相对路径返回 false
16339
16339
 
@@ -16362,7 +16362,7 @@ lib/text/functions/isTruthy.md
16362
16362
 
16363
16363
  > **isTruthy**\<`T`\>(`val`): `val is Exclude<T, TFalsy>`
16364
16364
 
16365
- Defined in: [lib/text.ts:710](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L710)
16365
+ Defined in: [lib/text.ts:727](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L727)
16366
16366
 
16367
16367
  判断一个值是否是真实的(不为 null/undefined/空字符串/false/0)
16368
16368
 
@@ -16397,7 +16397,7 @@ lib/text/functions/logicalOr.md
16397
16397
 
16398
16398
  > **logicalOr**\<`T`, `T2`\>(`v1`, `v2`): `T` *extends* [`TFalsy`](../type-aliases/TFalsy.md) ? `T2` : `T`
16399
16399
 
16400
- Defined in: [lib/text.ts:719](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L719)
16400
+ Defined in: [lib/text.ts:736](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L736)
16401
16401
 
16402
16402
  类似 || 运算符的效果
16403
16403
 
@@ -16442,7 +16442,7 @@ lib/text/functions/match.md
16442
16442
 
16443
16443
  > **match**(`str`, `regs`): `boolean`
16444
16444
 
16445
- Defined in: [lib/text.ts:345](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L345)
16445
+ Defined in: [lib/text.ts:362](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L362)
16446
16446
 
16447
16447
  传入正则进行匹配 str 是否有一项满足
16448
16448
 
@@ -16477,7 +16477,7 @@ lib/text/functions/nlReplace.md
16477
16477
 
16478
16478
  > **nlReplace**(`str`, `to?`): `string`
16479
16479
 
16480
- Defined in: [lib/text.ts:265](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L265)
16480
+ Defined in: [lib/text.ts:282](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L282)
16481
16481
 
16482
16482
  换行替换为别的
16483
16483
 
@@ -16512,7 +16512,7 @@ lib/text/functions/parseDomain.md
16512
16512
 
16513
16513
  > **parseDomain**(`domain`): `Promise`\<[`IDomain`](../interfaces/IDomain.md)\>
16514
16514
 
16515
- Defined in: [lib/text.ts:288](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L288)
16515
+ Defined in: [lib/text.ts:305](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L305)
16516
16516
 
16517
16517
  解析域名并获取 tld/sld/domain/sub
16518
16518
 
@@ -16582,7 +16582,7 @@ lib/text/functions/parseJson.md
16582
16582
 
16583
16583
  > **parseJson**\<`T`\>(`str`): `false` \| `T`
16584
16584
 
16585
- Defined in: [lib/text.ts:613](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L613)
16585
+ Defined in: [lib/text.ts:630](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L630)
16586
16586
 
16587
16587
  将字符串解析为对象,返回 false 代表解析失败,支持 BigInt
16588
16588
 
@@ -16644,7 +16644,7 @@ lib/text/functions/queryParse.md
16644
16644
 
16645
16645
  > **queryParse**(`query`): `Record`\<`string`, `string` \| `string`[]\>
16646
16646
 
16647
- Defined in: [lib/text.ts:445](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L445)
16647
+ Defined in: [lib/text.ts:462](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L462)
16648
16648
 
16649
16649
  将 query string 转换为对象
16650
16650
 
@@ -16675,7 +16675,7 @@ lib/text/functions/queryStringify.md
16675
16675
 
16676
16676
  > **queryStringify**(`query`, `encode?`): `string`
16677
16677
 
16678
- Defined in: [lib/text.ts:396](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L396)
16678
+ Defined in: [lib/text.ts:413](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L413)
16679
16679
 
16680
16680
  将对象转换为 query string
16681
16681
 
@@ -16701,7 +16701,7 @@ Defined in: [lib/text.ts:396](https://github.com/maiyunnet/kebab/blob/master/lib
16701
16701
 
16702
16702
  > **queryStringify**(`query`, `options`): `string`
16703
16703
 
16704
- Defined in: [lib/text.ts:402](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L402)
16704
+ Defined in: [lib/text.ts:419](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L419)
16705
16705
 
16706
16706
  将对象转换为 query string
16707
16707
 
@@ -16781,7 +16781,7 @@ lib/text/functions/str2int.md
16781
16781
 
16782
16782
  > **str2int**(`str`, `digits?`): `number`
16783
16783
 
16784
- Defined in: [lib/text.ts:733](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L733)
16784
+ Defined in: [lib/text.ts:750](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L750)
16785
16785
 
16786
16786
  为解决精度问题,将字符串数字转换为整数显示
16787
16787
  以下几个示例都是当 digits 为 2 时
@@ -16821,7 +16821,7 @@ lib/text/functions/stringifyBuffer.md
16821
16821
 
16822
16822
  > **stringifyBuffer**(`buf`): `string`
16823
16823
 
16824
- Defined in: [lib/text.ts:656](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L656)
16824
+ Defined in: [lib/text.ts:673](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L673)
16825
16825
 
16826
16826
  输出文本格式的 buffer
16827
16827
 
@@ -16850,7 +16850,7 @@ lib/text/functions/stringifyJson.md
16850
16850
 
16851
16851
  > **stringifyJson**(`obj`, `space?`): `string`
16852
16852
 
16853
- Defined in: [lib/text.ts:643](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L643)
16853
+ Defined in: [lib/text.ts:660](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L660)
16854
16854
 
16855
16855
  将对象转换为 json 字符串,返回 false 代表解析失败,支持 BigInt
16856
16856
 
@@ -16885,7 +16885,7 @@ lib/text/functions/stringifyResult.md
16885
16885
 
16886
16886
  > **stringifyResult**(`rtn`): `string`
16887
16887
 
16888
- Defined in: [lib/text.ts:573](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L573)
16888
+ Defined in: [lib/text.ts:590](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L590)
16889
16889
 
16890
16890
  将普通的返回 JSON 对象序列化为字符串
16891
16891
 
@@ -16914,7 +16914,7 @@ lib/text/functions/trimJson.md
16914
16914
 
16915
16915
  > **trimJson**(`json`): `any`
16916
16916
 
16917
- Defined in: [lib/text.ts:664](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L664)
16917
+ Defined in: [lib/text.ts:681](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L681)
16918
16918
 
16919
16919
  递归删除 json 中的字符串首尾空格,会返回一个新的对象
16920
16920
 
@@ -16941,7 +16941,7 @@ lib/text/functions/urlAtom.md
16941
16941
 
16942
16942
  > **urlAtom**(`url`): `string`
16943
16943
 
16944
- Defined in: [lib/text.ts:195](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L195)
16944
+ Defined in: [lib/text.ts:212](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L212)
16945
16945
 
16946
16946
  将路径中的 ../ ./ 都按规范妥善处理
16947
16947
 
@@ -16968,9 +16968,9 @@ lib/text/functions/urlResolve.md
16968
16968
 
16969
16969
  # Function: urlResolve()
16970
16970
 
16971
- > **urlResolve**(`from`, `to`): `string`
16971
+ > **urlResolve**(`from`, `to`, `limit?`): `string`
16972
16972
 
16973
- Defined in: [lib/text.ts:133](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L133)
16973
+ Defined in: [lib/text.ts:146](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L146)
16974
16974
 
16975
16975
  将相对路径根据基准路径进行转换
16976
16976
 
@@ -16988,6 +16988,12 @@ Defined in: [lib/text.ts:133](https://github.com/maiyunnet/kebab/blob/master/lib
16988
16988
 
16989
16989
  相对路径
16990
16990
 
16991
+ ### limit?
16992
+
16993
+ `boolean` = `false`
16994
+
16995
+ 是否限定结果不能逃逸出基准路径
16996
+
16991
16997
  ## Returns
16992
16998
 
16993
16999
  `string`
@@ -17066,7 +17072,7 @@ lib/text/interfaces/IDomain.md
17066
17072
 
17067
17073
  # Interface: IDomain
17068
17074
 
17069
- Defined in: [lib/text.ts:277](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L277)
17075
+ Defined in: [lib/text.ts:294](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L294)
17070
17076
 
17071
17077
  解析后的 domain
17072
17078
 
@@ -17076,7 +17082,7 @@ Defined in: [lib/text.ts:277](https://github.com/maiyunnet/kebab/blob/master/lib
17076
17082
 
17077
17083
  > **domain**: `string` \| `null`
17078
17084
 
17079
- Defined in: [lib/text.ts:280](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L280)
17085
+ Defined in: [lib/text.ts:297](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L297)
17080
17086
 
17081
17087
  ***
17082
17088
 
@@ -17084,7 +17090,7 @@ Defined in: [lib/text.ts:280](https://github.com/maiyunnet/kebab/blob/master/lib
17084
17090
 
17085
17091
  > **sld**: `string` \| `null`
17086
17092
 
17087
- Defined in: [lib/text.ts:279](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L279)
17093
+ Defined in: [lib/text.ts:296](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L296)
17088
17094
 
17089
17095
  ***
17090
17096
 
@@ -17092,7 +17098,7 @@ Defined in: [lib/text.ts:279](https://github.com/maiyunnet/kebab/blob/master/lib
17092
17098
 
17093
17099
  > **sub**: `string` \| `null`
17094
17100
 
17095
- Defined in: [lib/text.ts:281](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L281)
17101
+ Defined in: [lib/text.ts:298](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L298)
17096
17102
 
17097
17103
  ***
17098
17104
 
@@ -17100,7 +17106,7 @@ Defined in: [lib/text.ts:281](https://github.com/maiyunnet/kebab/blob/master/lib
17100
17106
 
17101
17107
  > **tld**: `string` \| `null`
17102
17108
 
17103
- Defined in: [lib/text.ts:278](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L278)
17109
+ Defined in: [lib/text.ts:295](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L295)
17104
17110
 
17105
17111
  lib/text/type-aliases/TFalsy.md
17106
17112
  ---
@@ -17115,7 +17121,7 @@ lib/text/type-aliases/TFalsy.md
17115
17121
 
17116
17122
  > **TFalsy** = `false` \| `""` \| `0` \| `null` \| `undefined` \| *typeof* `NaN`
17117
17123
 
17118
- Defined in: [lib/text.ts:696](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L696)
17124
+ Defined in: [lib/text.ts:713](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L713)
17119
17125
 
17120
17126
  虚假值类型
17121
17127
 
@@ -17132,7 +17138,7 @@ lib/text/variables/REGEXP_ASCII.md
17132
17138
 
17133
17139
  > `const` **REGEXP\_ASCII**: `RegExp`
17134
17140
 
17135
- Defined in: [lib/text.ts:250](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L250)
17141
+ Defined in: [lib/text.ts:267](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L267)
17136
17142
 
17137
17143
  可打印的 ascii 字符集
17138
17144
 
@@ -17149,7 +17155,7 @@ lib/text/variables/REGEXP_DOMAIN.md
17149
17155
 
17150
17156
  > `const` **REGEXP\_DOMAIN**: `RegExp`
17151
17157
 
17152
- Defined in: [lib/text.ts:238](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L238)
17158
+ Defined in: [lib/text.ts:255](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L255)
17153
17159
 
17154
17160
  lib/text/variables/REGEXP_EMAIL.md
17155
17161
  ---
@@ -17164,7 +17170,7 @@ lib/text/variables/REGEXP_EMAIL.md
17164
17170
 
17165
17171
  > `const` **REGEXP\_EMAIL**: `RegExp`
17166
17172
 
17167
- Defined in: [lib/text.ts:208](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L208)
17173
+ Defined in: [lib/text.ts:225](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L225)
17168
17174
 
17169
17175
  lib/text/variables/REGEXP_IPV4.md
17170
17176
  ---
@@ -17179,7 +17185,7 @@ lib/text/variables/REGEXP_IPV4.md
17179
17185
 
17180
17186
  > `const` **REGEXP\_IPV4**: `RegExp`
17181
17187
 
17182
- Defined in: [lib/text.ts:218](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L218)
17188
+ Defined in: [lib/text.ts:235](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L235)
17183
17189
 
17184
17190
  lib/text/variables/REGEXP_IPV6.md
17185
17191
  ---
@@ -17194,7 +17200,7 @@ lib/text/variables/REGEXP_IPV6.md
17194
17200
 
17195
17201
  > `const` **REGEXP\_IPV6**: `RegExp`
17196
17202
 
17197
- Defined in: [lib/text.ts:228](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L228)
17203
+ Defined in: [lib/text.ts:245](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L245)
17198
17204
 
17199
17205
  lib/time/classes/Time.md
17200
17206
  ---
package/index.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * --- 本文件用来定义每个目录实体地址的常量 ---
6
6
  */
7
7
  /** --- 当前系统版本号 --- */
8
- export declare const VER = "9.9.0";
8
+ export declare const VER = "9.10.1";
9
9
  /** --- 框架根目录,以 / 结尾 --- */
10
10
  export declare const ROOT_PATH: string;
11
11
  /** --- 框架的 LIB,以 / 结尾 --- */
package/index.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * --- 本文件用来定义每个目录实体地址的常量 ---
7
7
  */
8
8
  /** --- 当前系统版本号 --- */
9
- export const VER = '9.9.0';
9
+ export const VER = '9.10.1';
10
10
  // --- 服务端用的路径 ---
11
11
  const imu = decodeURIComponent(import.meta.url).replace('file://', '').replace(/^\/(\w:)/, '$1');
12
12
  /** --- /xxx/xxx --- */
package/lib/core.d.ts CHANGED
@@ -299,7 +299,7 @@ export declare function getLog(opt: {
299
299
  * @param opt 参数
300
300
  */
301
301
  export declare function ls(opt: {
302
- /** --- 如 2024/08/01/22,无所谓开头结尾 --- */
302
+ /** --- 如 2024/08/01/22,无所谓开头结尾是否有 /,不会逃逸出 cwd 路径 --- */
303
303
  'path': string;
304
304
  'encoding'?: BufferEncoding;
305
305
  /** --- 获取局域网服务器的目录列表,为空代表获取本机的 --- */
package/lib/text.d.ts CHANGED
@@ -28,8 +28,9 @@ export declare function parseUrl(url: string): kebab.IUrlParse;
28
28
  * --- 将相对路径根据基准路径进行转换 ---
29
29
  * @param from 基准路径
30
30
  * @param to 相对路径
31
+ * @param limit 是否限定结果不能逃逸出基准路径
31
32
  */
32
- export declare function urlResolve(from: string, to: string): string;
33
+ export declare function urlResolve(from: string, to: string, limit?: boolean): string;
33
34
  /**
34
35
  * --- 将路径中的 ../ ./ 都按规范妥善处理 ---
35
36
  * @param url 要处理的地址
package/lib/text.js CHANGED
@@ -117,14 +117,30 @@ export function parseUrl(url) {
117
117
  rtn['path'] = rtn['pathname'] + (rtn['query'] ? '?' + rtn['query'] : '');
118
118
  return rtn;
119
119
  }
120
+ /** --- 限定结果不能逃逸出基准路径 --- */
121
+ function urlResolveLimit(from, limit, rtn) {
122
+ if (!limit) {
123
+ return rtn;
124
+ }
125
+ const base = urlAtom(from).replace(/\/+$/, '') + '/';
126
+ if ((rtn === base.slice(0, -1)) || rtn.startsWith(base)) {
127
+ return rtn;
128
+ }
129
+ return base;
130
+ }
120
131
  /**
121
132
  * --- 将相对路径根据基准路径进行转换 ---
122
133
  * @param from 基准路径
123
134
  * @param to 相对路径
135
+ * @param limit 是否限定结果不能逃逸出基准路径
124
136
  */
125
- export function urlResolve(from, to) {
126
- from = from.replace('\\', '/');
127
- to = to.replace('\\', '/');
137
+ export function urlResolve(from, to, limit = false) {
138
+ from = from.replace(/\\/g, '/');
139
+ to = to.replace(/\\/g, '/');
140
+ if (limit) {
141
+ // --- 限定模式下,开头的 / 代表从 from 内部开始,而不是系统根目录 ---
142
+ to = to.replace(/^\/+/, '');
143
+ }
128
144
  // --- to 为空,直接返回 form ---
129
145
  if (to === '') {
130
146
  return urlAtom(from);
@@ -144,7 +160,7 @@ export function urlResolve(from, to) {
144
160
  // --- 已经是绝对路径,直接返回 ---
145
161
  if (t.protocol) {
146
162
  // --- 获取小写的 protocol ---
147
- return urlAtom(t.protocol + to.slice(t.protocol.length));
163
+ return urlResolveLimit(from, limit, urlAtom(t.protocol + to.slice(t.protocol.length)));
148
164
  }
149
165
  // --- # 或 ? 替换后返回 ---
150
166
  if (to.startsWith('#') || to.startsWith('?')) {
@@ -172,11 +188,11 @@ export function urlResolve(from, to) {
172
188
  // --- 返回最终结果 ---
173
189
  if (f.protocol && (f.protocol !== 'file:') && !f.host) {
174
190
  // --- 类似 c:/ ---
175
- return urlAtom(f.protocol + abs);
191
+ return urlResolveLimit(from, limit, urlAtom(f.protocol + abs));
176
192
  }
177
193
  else {
178
194
  // --- 类似 http:// ---
179
- return urlAtom((f.protocol ? f.protocol + '//' : '') + abs);
195
+ return urlResolveLimit(from, limit, urlAtom((f.protocol ? f.protocol + '//' : '') + abs));
180
196
  }
181
197
  }
182
198
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maiyunnet/kebab",
3
- "version": "9.9.0",
3
+ "version": "9.10.1",
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": [
package/sys/master.js CHANGED
@@ -519,8 +519,88 @@ function createRpcListener() {
519
519
  }));
520
520
  return;
521
521
  }
522
- // --- wc -l 高效获取总行数 ---
522
+ let limit = msg.limit ?? 100;
523
+ const offset = msg.offset ?? 0;
523
524
  let total = 0;
525
+ if (msg.search) {
526
+ // === 搜索模式:total 为匹配行数,offset/limit 均基于匹配行 ===
527
+ // --- shell 单引号安全转义(防止特殊字符破坏命令)---
528
+ const escaped = msg.search.replace(/'/g, "'\\''");
529
+ // --- 获取匹配行总数(grep -c 无匹配时退出码 1,|| echo 0 兜底)---
530
+ const countCmd = format === 'csv'
531
+ ? `tail -n +2 "${path}" | grep -F -c '${escaped}' || echo 0`
532
+ : `grep -F -c '${escaped}' "${path}" || echo 0`;
533
+ const countRtn = await lCore.exec(countCmd);
534
+ if (countRtn !== false) {
535
+ total = parseInt(countRtn.trim()) || 0;
536
+ }
537
+ // --- 获取分页数据:第 offset+1 到 offset+limit 条匹配行(1-indexed)---
538
+ const from = offset + 1;
539
+ const to = offset + limit;
540
+ const dataCmd = format === 'csv'
541
+ ? `tail -n +2 "${path}" | grep -F '${escaped}' | sed -n '${from},${to}p'`
542
+ : `grep -F '${escaped}' "${path}" | sed -n '${from},${to}p'`;
543
+ const dataRtn = await lCore.exec(dataCmd);
544
+ if (dataRtn === false) {
545
+ res.end(lText.stringifyJson({
546
+ 'result': 1,
547
+ 'list': [],
548
+ 'total': total,
549
+ }));
550
+ return;
551
+ }
552
+ /**
553
+ * --- csv 格式:string[][] 每行是字段数组,顺序与表头一致 ---
554
+ * --- [['H:i:s', unix, url, cookie, session, userAgent, realIp, cfIp, xIp, osMem, procMem, message], ...] ---
555
+ * --- jsonl 格式:object[] 每行是解析后的 JSON 对象 ---
556
+ * --- [{ time, unix, url, cookie, session, userAgent, realIp, cfIp, xIp, osMem, procMem, message }, ...] ---
557
+ */
558
+ const sList = [];
559
+ for (const rawLine of dataRtn.split('\n')) {
560
+ if (!rawLine) {
561
+ continue;
562
+ }
563
+ if (format === 'jsonl') {
564
+ const obj = lText.parseJson(rawLine);
565
+ if (obj) {
566
+ sList.push(obj);
567
+ }
568
+ }
569
+ else {
570
+ const result = [];
571
+ let currentField = '';
572
+ let inQuotes = false;
573
+ for (let i = 0; i < rawLine.length; ++i) {
574
+ const char = rawLine[i];
575
+ if (char === '"') {
576
+ if (inQuotes && rawLine[i + 1] === '"') {
577
+ currentField += '"';
578
+ ++i;
579
+ }
580
+ else {
581
+ inQuotes = !inQuotes;
582
+ }
583
+ }
584
+ else if (char === ',' && !inQuotes) {
585
+ result.push(currentField);
586
+ currentField = '';
587
+ }
588
+ else {
589
+ currentField += char;
590
+ }
591
+ }
592
+ result.push(currentField);
593
+ sList.push(result);
594
+ }
595
+ }
596
+ res.end(lText.stringifyJson({
597
+ 'result': 1,
598
+ 'list': sList,
599
+ 'total': total,
600
+ }));
601
+ return;
602
+ }
603
+ // === 无搜索模式:wc -l 获取总行数,grep -b '^' 定位字节偏移直接跳至 offset ===
524
604
  const wclRtn = await lCore.exec(`wc -l "${path}"`);
525
605
  if (wclRtn !== false) {
526
606
  const wclMatch = /^\s*(\d+)/.exec(wclRtn);
@@ -532,10 +612,6 @@ function createRpcListener() {
532
612
  }
533
613
  }
534
614
  }
535
- /** --- 剩余 limit --- */
536
- let limit = msg.limit ?? 100;
537
- /** --- offset --- */
538
- const offset = msg.offset ?? 0;
539
615
  /**
540
616
  * --- 用 grep -b '^' 获取目标行的字节偏移,直接传给 createReadStream start 跳过 offset ---
541
617
  * --- jsonl 无表头:跳过 offset 行,从第 offset+1 行开始读 ---
@@ -560,7 +636,7 @@ function createRpcListener() {
560
636
  // --- offset 超出文件范围,返回空列表 ---
561
637
  res.end(lText.stringifyJson({
562
638
  'result': 1,
563
- 'data': [],
639
+ 'list': [],
564
640
  'total': total,
565
641
  }));
566
642
  return;
@@ -602,41 +678,39 @@ function createRpcListener() {
602
678
  // --- startByte > 0 时已跳过 offset(及 csv 表头),从第一行起均为数据行 ---
603
679
  // --- startByte === 0 且 csv 时仍需跳过表头(line > 1)---
604
680
  if (format === 'csv' && startByte === 0 ? line > 1 : line >= 1) {
605
- if (!msg.search || packet.includes(msg.search)) {
606
- if (format === 'jsonl') {
607
- const obj = lText.parseJson(packet);
608
- if (obj) {
609
- list.push(obj);
610
- --limit;
611
- }
681
+ if (format === 'jsonl') {
682
+ const obj = lText.parseJson(packet);
683
+ if (obj) {
684
+ list.push(obj);
685
+ --limit;
612
686
  }
613
- else {
614
- const result = [];
615
- let currentField = '';
616
- let inQuotes = false;
617
- for (let i = 0; i < packet.length; ++i) {
618
- const char = packet[i];
619
- if (char === '"') {
620
- if (inQuotes && packet[i + 1] === '"') {
621
- currentField += '"';
622
- ++i;
623
- }
624
- else {
625
- inQuotes = !inQuotes;
626
- }
627
- }
628
- else if (char === ',' && !inQuotes) {
629
- result.push(currentField);
630
- currentField = '';
687
+ }
688
+ else {
689
+ const result = [];
690
+ let currentField = '';
691
+ let inQuotes = false;
692
+ for (let i = 0; i < packet.length; ++i) {
693
+ const char = packet[i];
694
+ if (char === '"') {
695
+ if (inQuotes && packet[i + 1] === '"') {
696
+ currentField += '"';
697
+ ++i;
631
698
  }
632
699
  else {
633
- currentField += char;
700
+ inQuotes = !inQuotes;
634
701
  }
635
702
  }
636
- result.push(currentField);
637
- list.push(result);
638
- --limit;
703
+ else if (char === ',' && !inQuotes) {
704
+ result.push(currentField);
705
+ currentField = '';
706
+ }
707
+ else {
708
+ currentField += char;
709
+ }
639
710
  }
711
+ result.push(currentField);
712
+ list.push(result);
713
+ --limit;
640
714
  }
641
715
  }
642
716
  // --- 处理结束 ---
@@ -663,7 +737,11 @@ function createRpcListener() {
663
737
  }
664
738
  case 'ls': {
665
739
  // --- 获取目录内文件/文件夹列表 ---
666
- const path = lText.urlResolve(kebab.ROOT_CWD, msg.path);
740
+ if (typeof msg.path !== 'string') {
741
+ res.end('Invalid path');
742
+ return;
743
+ }
744
+ const path = lText.urlResolve(kebab.ROOT_CWD, msg.path, true);
667
745
  res.end(lText.stringifyJson({
668
746
  'result': 1,
669
747
  'data': (await lFs.readDir(path, msg.encoding)).map(item => ({
@@ -3692,6 +3692,8 @@ ${lText.htmlescape(lText.urlResolve('C:\\Windows\\Misc', '/'))}
3692
3692
  ${lText.htmlescape(lText.urlResolve('C:\\Windows\\Misc', '/xxx/yyy'))}
3693
3693
  <pre>lText.urlResolve('/abc/def/', '');</pre>
3694
3694
  ${lText.htmlescape(lText.urlResolve('/abc/def/', ''))}
3695
+ <pre>lText.urlResolve('/abc/def/', '../1/2/3', true);</pre>
3696
+ ${lText.htmlescape(lText.urlResolve('/abc/def/', '../1/2/3', true))}
3695
3697
  <pre>lText.isEMail('test@gmail.com');</pre>
3696
3698
  ${JSON.stringify(lText.isEMail('test@gmail.com'))}
3697
3699
  <pre>lText.isEMail('test@x');</pre>