Compare commits

...

20 Commits
v2.2.0 ... main

Author SHA1 Message Date
nsnail
c9975472bf
chore(release): 2.3.5 (#35)
Co-authored-by: tk <fiyne1a@dingtalk.com>
2025-03-26 15:13:35 +08:00
nsnail
97c93bd854
perf: nuget update (#34)
[skip ci]

Co-authored-by: tk <fiyne1a@dingtalk.com>
2025-03-26 15:13:08 +08:00
nsnail
322cbc32df
chore(release): 2.3.4 (#33)
Co-authored-by: tk <fiyne1a@dingtalk.com>
2025-03-06 09:55:07 +08:00
nsnail
fa84cc315b
perf: nuget update (#32)
[skip ci]

Co-authored-by: tk <fiyne1a@dingtalk.com>
2025-03-06 09:54:33 +08:00
nsnail
d4a92aca6f
chore(release): 2.3.3 (#31)
Co-authored-by: tk <fiyne1a@dingtalk.com>
2025-01-02 12:03:36 +08:00
nsnail
a9f3416c37
perf: nuget update (#30)
[skip ci]

Co-authored-by: tk <fiyne1a@dingtalk.com>
2025-01-02 12:03:13 +08:00
nsnail
890b229683
Merge pull request #29 from nsnail/release
chore(release): 2.3.2
2024-11-25 17:51:14 +08:00
tk
c3c6819a99 chore(release): 2.3.2 2024-11-25 17:50:57 +08:00
nsnail
efa6a564dc
Merge pull request #28 from nsnail/release
chore(release): 2.3.1
2024-11-25 17:39:29 +08:00
tk
7c5b5443cb chore(release): 2.3.1 2024-11-25 17:39:13 +08:00
nsnail
689d9560a8
fix: 🐛 a stable release of a package should not have a prerelease dependency (#27)
[skip ci]

Co-authored-by: tk <fiyne1a@dingtalk.com>
2024-11-25 17:39:04 +08:00
nsnail
49de51d649
Merge pull request #26 from nsnail/release
chore(release): 2.3.0
2024-11-25 17:35:51 +08:00
tk
6676323b26 chore(release): 2.3.0 2024-11-25 17:34:26 +08:00
nsnail
c7c978fe5c
feat: 新增一些扩展方法 (#25)
[skip ci]

Co-authored-by: tk <fiyne1a@dingtalk.com>
2024-11-25 17:34:12 +08:00
nsnail
892df78c26
chore(release): 2.2.2 (#24)
Co-authored-by: tk <fiyne1a@dingtalk.com>
2024-11-25 17:08:38 +08:00
nsnail
7a1c8db6e4
ci: 🎡 deploy scripts (#23)
* ci: 🎡 deploy scripts

[skip ci]

* ci: 🎡 deploy scripts

[skip ci]

---------

Co-authored-by: tk <fiyne1a@dingtalk.com>
2024-11-25 17:07:53 +08:00
nsnail
2b6c7adff8
Merge pull request #22 from nsnail/release
chore(release): 2.2.1
2024-11-25 17:01:58 +08:00
tk
4c515ac127 chore(release): 2.2.1 2024-11-25 17:01:40 +08:00
nsnail
b32fe597dd
perf: 支持.net9 (#21)
Co-authored-by: tk <fiyne1a@dingtalk.com>
2024-11-25 17:01:15 +08:00
nsnail
7557cb0538
Merge pull request #20 from nsnail/release
Release
2024-07-02 11:03:44 +08:00
31 changed files with 461 additions and 238 deletions

View File

@ -64,7 +64,7 @@ module.exports = {
maxSubjectLength: Infinity,
minSubjectLength: 0,
scopeOverrides: undefined,
defaultBody: '',
defaultBody: '[skip ci]',
defaultIssues: '',
defaultScope: '',
defaultSubject: ''

View File

@ -1,56 +1,63 @@
# 此文件为 EditorConfig 配置文件,用于设置跨编辑器的代码格式化规则。
# root = true 表示此文件是根配置文件。
root = true
[*]
charset = utf-8
end_of_line = lf
ij_xml_attribute_wrap = off
ij_xml_text_wrap = off
indent_size = 4
indent_style = space
insert_final_newline = false
trim_trailing_whitespace = true
charset = utf-8 # 文件字符集为 UTF-8
end_of_line = lf # 行结束符为 LF
ij_xml_attribute_wrap = off # IntelliJ IDEA 中 XML 属性不换行
ij_xml_text_wrap = off # IntelliJ IDEA 中 XML 文本不换行
indent_size = 4 # 缩进大小为 4 个空格
indent_style = space # 使用空格进行缩进
insert_final_newline = false # 不在文件末尾插入空行
max_line_length = 150 # 行长度限制为 150 个字符
trim_trailing_whitespace = true # 删除行尾的空格
[{*.json,*.yml}]
indent_size = 2
indent_size = 2 # 对于 JSON 和 YAML 文件,缩进大小为 2 个空格
[*.cs]
dotnet_analyzer_diagnostic.severity = warning
dotnet_analyzer_diagnostic.severity = warning # 设置 C# 文件中所有 dotnet_analyzer_diagnostic 的严重性级别为 warning
[*.g.cs]
dotnet_analyzer_diagnostic.severity = none # 禁用所有代码分析规则
# ReSharper properties
resharper_align_linq_query = true
resharper_align_multiline_argument = true
resharper_align_multiline_array_and_object_initializer = true
resharper_align_multiline_binary_patterns = true
resharper_align_multiline_calls_chain = true
resharper_align_multiline_extends_list = true
resharper_align_multiline_parameter = true
resharper_align_multiline_property_pattern = true
resharper_align_multiline_switch_expression = true
resharper_align_multiple_declaration = true
resharper_align_multline_type_parameter_constrains = true
resharper_align_multline_type_parameter_list = true
resharper_align_tuple_components = true
resharper_allow_comment_after_lbrace = true
resharper_blank_lines_before_single_line_comment = 1
resharper_csharp_empty_block_style = together_same_line
resharper_csharp_outdent_commas = true
resharper_csharp_place_type_constraints_on_same_line = false
resharper_csharp_stick_comment = false
resharper_csharp_wrap_before_comma = true
resharper_indent_nested_for_stmt = true
resharper_indent_nested_foreach_stmt = true
resharper_indent_nested_while_stmt = true
resharper_indent_preprocessor_if = usual_indent
resharper_indent_preprocessor_other = usual_indent
resharper_int_align = true
resharper_keep_existing_arrangement = false
resharper_place_linq_into_on_new_line = false
resharper_place_simple_embedded_statement_on_same_line = false
resharper_place_simple_switch_expression_on_single_line = true
resharper_wrap_before_eq = true
resharper_wrap_chained_method_calls = chop_if_long
resharper_wrap_switch_expression = chop_if_long
resharper_align_linq_query = true # 启用对LINQ查询的对齐
resharper_align_multiline_argument = true # 启用多行参数的对齐
resharper_align_multiline_array_and_object_initializer = true # 启用多行数组和对象初始化器的对齐
resharper_align_multiline_binary_patterns = true # 启用多行二元模式的对齐
resharper_align_multiline_calls_chain = true # 启用多行调用链的对齐
resharper_align_multiline_extends_list = true # 启用多行扩展列表的对齐
resharper_align_multiline_parameter = true # 启用多行参数的对齐
resharper_align_multiline_property_pattern = true # 启用多行属性模式的对齐
resharper_align_multiline_switch_expression = true # 启用多行切换表达式的对齐
resharper_align_multiple_declaration = true # 启用多个声明的对齐
resharper_align_multline_type_parameter_constrains = true # 启用多行类型参数约束的对齐
resharper_align_multline_type_parameter_list = true # 启用多行类型参数列表的对齐
resharper_align_tuple_components = true # 启用元组组件的对齐
resharper_allow_comment_after_lbrace = true # 允许在大括号前添加注释
resharper_blank_lines_before_single_line_comment = 1 # 在单行注释前添加空行
resharper_csharp_empty_block_style = together_same_line # 设置空块的样式为“在一起,在同一行”
resharper_csharp_outdent_commas = true # 是否将逗号后的代码退缩
resharper_csharp_place_type_constraints_on_same_line = false # 在类型约束上是否保持在同一行
resharper_csharp_stick_comment = false # 是否将注释粘贴在代码行的末尾
resharper_csharp_wrap_before_comma = true # 在逗号前是否添加换行
resharper_indent_nested_for_stmt = true # 是否对嵌套的for语句进行缩进
resharper_indent_nested_foreach_stmt = true # 是否对嵌套的foreach语句进行缩进
resharper_indent_nested_while_stmt = true # 是否对嵌套的while语句进行缩进
resharper_indent_preprocessor_if = usual_indent # 设置预处理器指令`if`的缩进方式
resharper_indent_preprocessor_other = usual_indent # 设置其他预处理器指令的缩进方式
resharper_int_align = true # 启用整数对齐
resharper_keep_existing_arrangement = false # 在重新排列时是否保留现有的布局
resharper_place_linq_into_on_new_line = false # 是否将LINQ表达式放在新行
resharper_place_simple_embedded_statement_on_same_line = false # 是否将简单的嵌入式语句放在同一行
resharper_place_simple_switch_expression_on_single_line = true # 是否将简单的切换表达式放在单行
resharper_wrap_before_eq = true # 在等号前是否添加换行
resharper_wrap_chained_method_calls = chop_if_long # 是否拆分链式方法调用
resharper_wrap_switch_expression = chop_if_long # 是否拆分切换表达式
# Microsoft .NET properties
csharp_indent_braces = false
csharp_new_line_before_open_brace = local_functions, methods, types
csharp_indent_braces = false # 设置为false表示花括号不跟随代码行缩进
csharp_new_line_before_open_brace = local_functions, methods, types # 这里设置为local_functions, methods, types表示在局部函数、方法和类型定义的开放花括号前应换行

1
.github/workflows/README.md vendored Normal file
View File

@ -0,0 +1 @@
github workflows

View File

@ -13,13 +13,11 @@ jobs:
filter: tree:0
- uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.x
- working-directory: ./src/backend/NSExt
run: dotnet build -c Release -f net6.0
- working-directory: ./src/backend/NSExt
run: dotnet build -c Release -f net7.0
dotnet-version: 9.0.x
- working-directory: ./src/backend/NSExt
run: dotnet build -c Release -f net8.0
- working-directory: ./src/backend/NSExt
run: dotnet build -c Release -f net9.0
- working-directory: ./src/backend/NSExt
run: dotnet pack -c Release --no-build
- uses: actions/create-release@v1

6
.gitignore vendored
View File

@ -55,7 +55,7 @@ nunit-*.xml
dlldata.c
# Benchmark Results
BenchmarkNSExtNet.Artifacts/
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
@ -130,12 +130,12 @@ $tf/
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.NSExtSettings.user
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# NSExtCover is a Code Coverage Tool
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool

View File

@ -2,6 +2,32 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [2.3.5](https://github.com/nsnail/NSExt/compare/v2.3.2...v2.3.5) (2025-03-26)
### [2.3.4](https://github.com/nsnail/NSExt/compare/v2.3.2...v2.3.4) (2025-03-06)
### [2.3.3](https://github.com/nsnail/NSExt/compare/v2.3.2...v2.3.3) (2025-01-02)
### [2.3.2](https://github.com/nsnail/NSExt/compare/v2.3.1...v2.3.2) (2024-11-25)
### [2.3.1](https://github.com/nsnail/NSExt/compare/v2.3.0...v2.3.1) (2024-11-25)
### Bug Fixes
* 🐛 a stable release of a package should not have a prerelease dependency ([#27](https://github.com/nsnail/NSExt/issues/27)) ([689d956](https://github.com/nsnail/NSExt/commit/689d9560a858c0ac308ec198b041fdc23720beba))
## [2.3.0](https://github.com/nsnail/NSExt/compare/v2.2.1...v2.3.0) (2024-11-25)
### Features
* ✨ 新增一些扩展方法 ([#25](https://github.com/nsnail/NSExt/issues/25)) ([c7c978f](https://github.com/nsnail/NSExt/commit/c7c978fe5cf931e085e40ad1347bdb3f3450dd0a))
### [2.2.2](https://github.com/nsnail/NSExt/compare/v2.2.1...v2.2.2) (2024-11-25)
### [2.2.1](https://github.com/nsnail/NSExt/compare/v2.2.0...v2.2.1) (2024-11-25)
## [2.2.0](https://github.com/nsnail/NSExt/compare/v2.1.0...v2.2.0) (2024-07-02)

View File

@ -17,16 +17,16 @@
<LangVersion>preview</LangVersion>
<MinVerDefaultPreReleaseIdentifiers>beta</MinVerDefaultPreReleaseIdentifiers>
<MinVerTagPrefix>v</MinVerTagPrefix>
<NoWarn>CA1707;IDE0005;IDE0008;IDE0010;IDE0028;IDE0055;IDE0160;IDE0300;IDE0305;RCS1141;RCS1142;RCS1181;S101;S1121;S1135;S125;S2094;S3604;S4663;SYSLIB1045;SA1010;RCS1123;SA1407;IDE0048;S1075;S3928</NoWarn>
<NoWarn>CA1707;CA1720;CA5350;CA5351;IDE0005;IDE0008;IDE0010;IDE0028;IDE0048;IDE0055;IDE0160;IDE0300;IDE0305;RCS1123;RCS1141;RCS1142;RCS1181;S101;S1075;S1121;S1135;S125;S2094;S3604;S3928;S4663;SA1010;SA1407;SYSLIB1045</NoWarn>
<Product>NSExt</Product>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/nsnail/NSExt.git</RepositoryUrl>
<RootNamespace>NSExt</RootNamespace>
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<Title>$(AssemblyName)</Title>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MinVer" Version="5.0.0">
<PackageReference Include="MinVer" Version="6.1.0-beta.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

140
NSExt.sln
View File

@ -8,87 +8,89 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "backend", "backend", "{4DAF9366-855F-46BB-AE4C-660C92FA0697}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "meta", "meta", "{5198A03D-0CAC-4828-A807-34A693F73859}"
ProjectSection(SolutionItems) = preProject
.commitlintrc.js = .commitlintrc.js
.editorconfig = .editorconfig
.gitattributes = .gitattributes
.gitignore = .gitignore
CHANGELOG.md = CHANGELOG.md
Directory.Build.props = Directory.Build.props
dotnet-tools.json = dotnet-tools.json
global.json = global.json
key.snk = key.snk
LICENSE = LICENSE
NSExt.sln.DotSettings = NSExt.sln.DotSettings
nuget.config = nuget.config
package.json = package.json
README.md = README.md
README.zh-CN.md = README.zh-CN.md
EndProjectSection
ProjectSection(SolutionItems) = preProject
.commitlintrc.js = .commitlintrc.js
.editorconfig = .editorconfig
.gitattributes = .gitattributes
.gitignore = .gitignore
CHANGELOG.md = CHANGELOG.md
Directory.Build.props = Directory.Build.props
dotnet-tools.json = dotnet-tools.json
global.json = global.json
key.snk = key.snk
LICENSE = LICENSE
NSExt.sln.DotSettings = NSExt.sln.DotSettings
nuget.config = nuget.config
package.json = package.json
README.md = README.md
README.zh-CN.md = README.zh-CN.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{BB0B25C9-0901-4923-913F-00F9A6B352A5}"
ProjectSection(SolutionItems) = preProject
1.git.pull.request.ps1 = scripts/1.git.pull.request.ps1
2.git.release.ps1 = scripts/2.git.release.ps1
3.git.recreate.branch.ps1 = scripts/3.git.recreate.branch.ps1
clean.ln.csx = scripts/clean.ln.csx
code.clean.csx = scripts/code.clean.csx
code.clean.ps1 = scripts/code.clean.ps1
gen.cs.tt = scripts/gen.cs.tt
gen.ln.cmd = scripts/gen.ln.cmd
gen.resx.tt = scripts/gen.resx.tt
image.optimize.csx = scripts/image.optimize.csx
install.as.tpl.ps1 = scripts/install.as.tpl.ps1
rename.csx = scripts/rename.csx
resharper.full.ps1 = scripts/resharper.full.ps1
switcher.nsext.json = scripts/switcher.nsext.json
switcher.ps1 = scripts/switcher.ps1
sync.sln.files.csx = scripts/sync.sln.files.csx
EndProjectSection
ProjectSection(SolutionItems) = preProject
1.git.pull.request.ps1 = scripts/1.git.pull.request.ps1
2.git.release.ps1 = scripts/2.git.release.ps1
3.git.recreate.branch.ps1 = scripts/3.git.recreate.branch.ps1
4.git.del.obsolete.tags.ps1 = scripts/4.git.del.obsolete.tags.ps1
clean.ln.csx = scripts/clean.ln.csx
code.clean.csx = scripts/code.clean.csx
code.clean.ps1 = scripts/code.clean.ps1
find.unused.ln.csx = scripts/find.unused.ln.csx
gen.cs.tt = scripts/gen.cs.tt
gen.ln.cmd = scripts/gen.ln.cmd
gen.resx.tt = scripts/gen.resx.tt
image.optimize.csx = scripts/image.optimize.csx
install.as.tpl.ps1 = scripts/install.as.tpl.ps1
rename.csx = scripts/rename.csx
resharper.full.ps1 = scripts/resharper.full.ps1
switch.nuget.or.project.csx = scripts/switch.nuget.or.project.csx
sync.sln.files.csx = scripts/sync.sln.files.csx
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{1129FE25-466B-4F4F-85FC-3752664245E1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{3C6F049E-3EE8-4D66-9AFF-E8A369032487}"
ProjectSection(SolutionItems) = preProject
ci.yml = .github/workflows/ci.yml
EndProjectSection
ProjectSection(SolutionItems) = preProject
README.md = .github/workflows/README.md
release.yml = .github/workflows/release.yml
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{8E4C93BA-9493-4892-80C4-5E174C504829}"
ProjectSection(SolutionItems) = preProject
code.quality.props = build/code.quality.props
copy.pkg.xml.comment.files.targets = build/copy.pkg.xml.comment.files.targets
minver.targets = build/minver.targets
nuget.package.props = build/nuget.package.props
prebuild.targets = build/prebuild.targets
stylecop.analyzers.ruleset = build/stylecop.analyzers.ruleset
EndProjectSection
ProjectSection(SolutionItems) = preProject
code.quality.props = build/code.quality.props
copy.pkg.xml.comment.files.targets = build/copy.pkg.xml.comment.files.targets
minver.targets = build/minver.targets
nuget.package.props = build/nuget.package.props
prebuild.targets = build/prebuild.targets
stylecop.analyzers.ruleset = build/stylecop.analyzers.ruleset
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NSExt", "src\backend\NSExt\NSExt.csproj", "{1E62C322-EE42-4699-A6F1-791C53EFA62D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NSExt.Tests", "src\backend\NSExt.Tests\NSExt.Tests.csproj", "{00604162-C444-478B-B773-3AB23C856CA7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1E62C322-EE42-4699-A6F1-791C53EFA62D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1E62C322-EE42-4699-A6F1-791C53EFA62D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E62C322-EE42-4699-A6F1-791C53EFA62D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E62C322-EE42-4699-A6F1-791C53EFA62D}.Release|Any CPU.Build.0 = Release|Any CPU
{00604162-C444-478B-B773-3AB23C856CA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{00604162-C444-478B-B773-3AB23C856CA7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{00604162-C444-478B-B773-3AB23C856CA7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{00604162-C444-478B-B773-3AB23C856CA7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{4DAF9366-855F-46BB-AE4C-660C92FA0697} = {C84EB5A0-37AD-4B17-A51E-E36888C4441E}
{3C6F049E-3EE8-4D66-9AFF-E8A369032487} = {1129FE25-466B-4F4F-85FC-3752664245E1}
{1E62C322-EE42-4699-A6F1-791C53EFA62D} = {4DAF9366-855F-46BB-AE4C-660C92FA0697}
{00604162-C444-478B-B773-3AB23C856CA7} = {4DAF9366-855F-46BB-AE4C-660C92FA0697}
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1E62C322-EE42-4699-A6F1-791C53EFA62D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1E62C322-EE42-4699-A6F1-791C53EFA62D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E62C322-EE42-4699-A6F1-791C53EFA62D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E62C322-EE42-4699-A6F1-791C53EFA62D}.Release|Any CPU.Build.0 = Release|Any CPU
{00604162-C444-478B-B773-3AB23C856CA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{00604162-C444-478B-B773-3AB23C856CA7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{00604162-C444-478B-B773-3AB23C856CA7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{00604162-C444-478B-B773-3AB23C856CA7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{4DAF9366-855F-46BB-AE4C-660C92FA0697} = {C84EB5A0-37AD-4B17-A51E-E36888C4441E}
{3C6F049E-3EE8-4D66-9AFF-E8A369032487} = {1129FE25-466B-4F4F-85FC-3752664245E1}
{1E62C322-EE42-4699-A6F1-791C53EFA62D} = {4DAF9366-855F-46BB-AE4C-660C92FA0697}
{00604162-C444-478B-B773-3AB23C856CA7} = {4DAF9366-855F-46BB-AE4C-660C92FA0697}
EndGlobalSection
EndGlobal

View File

@ -78,6 +78,7 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002EMemberReordering_002EMigrations_002ECSharpFileLayoutPatternRemoveIsAttributeUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>

1
assets/README.md Normal file
View File

@ -0,0 +1 @@
# 资源文件目录

View File

@ -15,15 +15,15 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.10.48">
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.13.61">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Roslynator.Analyzers" Version="4.12.4">
<PackageReference Include="Roslynator.Analyzers" Version="4.13.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.28.0.94264">
<PackageReference Include="SonarAnalyzer.CSharp" Version="10.7.0.110445">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@ -3,8 +3,8 @@
<ItemGroup>
<PackageReferenceFiles
Condition="%(PackageReference.CopyToOutputDirectory) != ''"
Include="$(NugetPackageRoot)\%(PackageReference.Identity)\%(PackageReference.Version)\%(PackageReference.CopyToOutputDirectory)"/>
Include="$(NugetPackageRoot)\%(PackageReference.Identity)\%(PackageReference.Version)\%(PackageReference.CopyToOutputDirectory)" />
</ItemGroup>
<Copy SourceFiles="@(PackageReferenceFiles)" DestinationFolder="$(OutDir)"/>
<Copy SourceFiles="@(PackageReferenceFiles)" DestinationFolder="$(OutDir)" />
</Target>
</Project>

1
docker/README.md Normal file
View File

@ -0,0 +1 @@
docker

View File

@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"dotnet-t4": {
"version": "2.3.1",
"version": "3.0.0",
"commands": [
"t4"
]

View File

@ -2,7 +2,6 @@
<configuration>
<packageSources>
<clear/>
<add key="nuget.cdn.azure.cn" value="https://nuget.cdn.azure.cn/v3/index.json"/>
<add key="nuget.cdn.azure.cn" value="https://nuget.cdn.azure.cn/v3/index.json" />
</packageSources>
</configuration>

View File

@ -1,9 +1,9 @@
{
"version": "2.2.0",
"version": "2.3.5",
"devDependencies": {
"cz-git": "^1.7.1",
"commitizen": "^4.3.0",
"prettier": "^3.1.0",
"cz-git": "^1.11.0",
"commitizen": "^4.3.1",
"prettier": "^3.3.3",
"standard-version": "^9.5.0"
},
"config": {
@ -11,4 +11,4 @@
"path": "node_modules/cz-git"
}
}
}
}

View File

@ -1,6 +1,10 @@
$branch = $( git branch --show-current )
git add ../
./code.clean.ps1
$skipFormat = Read-Host "输入 n 跳过代码整理"
if ($skipFormat -ne "n")
{
./code.clean.ps1
}
git add ../
../node_modules/.bin/git-cz.ps1
git pull

View File

@ -1,7 +1,7 @@
cd ..
$types = @{
'1' = @('major', '主版本')
'2' = @('minor', '版本')
'2' = @('minor', '版本')
'3' = @('patch', '修订版本')
}
$prefix = ''
@ -10,19 +10,20 @@ while ($null -eq $types[$prefix])
$prefix = Read-Host "请选择版本类型`n" $( & { param($i) $i | ForEach-Object { "$_ : $( $types[$_][0] )$( $types[$_][1] )`n" } } $types.Keys | Sort-Object )
}
git checkout main
git pull
git branch -D release
git checkout -b release
./node_modules/.bin/standard-version -r $types[$prefix][0]
cd ./scripts
./code.clean.ps1
git commit --amend --no-edit -a
$tag = $(git describe --tags $(git rev-list --tags --max-count=1))
$tag = $( git describe --tags $( git rev-list --tags --max-count = 1 ) )
git tag -d $tag
git tag $tag
git push --tags origin release
Start-Process -FilePath "https://github.com/nsnail/NSExt/compare/main...release"
Write-Host "按『Enter』回到分支『Ctrl+C』退出"
Write-Host "按『Enter』回到tk分支『Ctrl+C』退出"
Pause
git checkout main
git pull
git branch -D release
git branch -D release
git branch -D tk
git checkout -b tk

View File

@ -0,0 +1,2 @@
git push origin :refs/tags/$(git tag -l "*-*")
git tag -d $(git tag -l "*-*")

View File

@ -0,0 +1,15 @@
using System.Text.RegularExpressions;
Console.WriteLine(string.Join(Environment.NewLine
, Regex
.Matches(File.ReadAllText(@"../assets/res/Ln.resx")
, "data name=\"(.*?)\"")
.Select(x => x.Groups[1].Value)
.Where(x => !Directory
.GetFiles(@"../src/backend/", "*.cs"
, new EnumerationOptions {
RecurseSubdirectories = true
})
.Select(File.ReadAllText)
.Any(y => y.Contains(x)))));
Console.ReadKey();

View File

@ -1,6 +1,7 @@
<#@ template language="C#" #>
<#@ assembly name="System.Xml" #>
<#@ output encoding="utf-8" extension="Designer.cs" #>
<#@ import namespace="System.Xml" #>
//------------------------------------------------------------------------------
// <auto-generated>
@ -27,8 +28,8 @@ namespace NSExt.Languages;
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[System.Diagnostics.DebuggerNonUserCode]
[System.Runtime.CompilerServices.CompilerGenerated]
[DebuggerNonUserCode]
[CompilerGenerated]
public sealed class Ln
{
private static ResourceManager _resourceMan;
@ -61,9 +62,9 @@ public sealed class Ln
[EditorBrowsable(EditorBrowsableState.Advanced)]
public static CultureInfo Culture { get; set; }
<#
var xml = new System.Xml.XmlDocument();
var xml = new XmlDocument();
xml.Load("../assets/res/Ln.resx");
foreach (System.Xml.XmlNode data in xml.SelectNodes("//root/data")!)
foreach (XmlNode data in xml.SelectNodes("//root/data")!)
{
#>
/// <summary>

View File

@ -1,5 +1,8 @@
<#@ template language="C#" #>
<#@ output encoding="utf-8" extension="resx" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
@ -25,15 +28,12 @@
</value>
</resheader>
<#
var regex = new System.Text.RegularExpressions.Regex(@"^\d", System.Text.RegularExpressions.RegexOptions.Compiled);
foreach (var file in System.IO.Directory.GetFiles("../assets/res/", "*.ln"))
var regex = new Regex(@"^\d", RegexOptions.Compiled);
foreach (var line in Directory.GetFiles("../assets/res/", "*.ln").SelectMany(x => File.ReadLines(x)).Distinct())
{
foreach (var line in System.IO.File.ReadLines(file))
{
#>
<data name="<#= regex.IsMatch(line) ? "_" : "" #><#= line #>" xml:space="preserve"><value><#= line #></value></data>
<#
}
}
#>
</root>

View File

@ -1,4 +1,4 @@
#r "nuget: NSExt, 1.1.0"
#r "nuget: NSExt, 2.2.0"
using NSExt.Extensions;
Console.WriteLine("请输入原始名称NSExt");

View File

@ -0,0 +1,42 @@
using System.Text.RegularExpressions;
string input = string.Empty;
while (!new[] { "1", "2" }.Contains(input))
{
Console.WriteLine("1.nuget 2.project");
input = Console.ReadLine();
}
var slnFile = Directory.GetFiles(@"../", "*.sln").First();
var csprojFiles = Directory.GetFiles(@"../src", "*.csproj", new EnumerationOptions { RecurseSubdirectories = true });
var slnContent = File.ReadAllText(slnFile);
if (input == "1")
{
slnContent = Regex.Replace(slnContent, "\\nProject\\((.*)#refs", "\n##Project($1#refs");
slnContent = Regex.Replace(slnContent, "\\nEndProject#refs", "\n##EndProject#refs");
foreach (Match m in Regex.Matches(slnContent, "\"(\\{[A-Z0-9]{8}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{12}\\})\"#refs"))
{
slnContent = slnContent.Replace($" {m.Groups[1].Value}.", $" ##{m.Groups[1].Value}.");
}
foreach (var csprojFile in csprojFiles)
{
var csprojContent = File.ReadAllText(csprojFile);
csprojContent = Regex.Replace(csprojContent," <ProjectReference(.*)Label=\"refs\"(.*)>", " <!--<ProjectReference$1Label=\"refs\"$2>-->");
csprojContent = Regex.Replace(csprojContent," <!--<PackageReference(.*)Label=\"refs\"(.*)>-->", " <PackageReference$1Label=\"refs\"$2>");
File.WriteAllText(csprojFile, csprojContent);
}
}
else
{
slnContent = Regex.Replace(slnContent, "##", "");
foreach (var csprojFile in csprojFiles)
{
var csprojContent = File.ReadAllText(csprojFile);
csprojContent = Regex.Replace(csprojContent," <!--<ProjectReference(.*)Label=\"refs\"(.*)>-->", " <ProjectReference$1Label=\"refs\"$2>");
csprojContent = Regex.Replace(csprojContent," <PackageReference(.*)Label=\"refs\"(.*)>", " <!--<PackageReference$1Label=\"refs\"$2>-->");
File.WriteAllText(csprojFile, csprojContent);
}
}
Console.WriteLine(slnContent);
File.WriteAllText(slnFile, slnContent);

View File

@ -8,12 +8,12 @@ content = Regex.Replace(
"Project\\(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\"\\) = \"meta\", \"meta\", \"{5198A03D-0CAC-4828-A807-34A693F73859}\"(?:.|\n)*?EndProject",
$$"""
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "meta", "meta", "{5198A03D-0CAC-4828-A807-34A693F73859}"
{{'\t'}}ProjectSection(SolutionItems) = preProject
ProjectSection(SolutionItems) = preProject
{{string.Join('\n',
Directory.GetFiles(@"../", "*").Where(x => !x.EndsWith(".sln") && !x.EndsWith(".user"))
.Select(x=>$"\t\t{Path.GetFileName(x)} = {Path.GetFileName(x)}")
.Select(x=>$" {Path.GetFileName(x)} = {Path.GetFileName(x)}")
)}}
{{'\t'}}EndProject
EndProject
"""
);
@ -22,12 +22,12 @@ content = Regex.Replace(
"Project\\(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\"\\) = \"workflows\", \"workflows\", \"{3C6F049E-3EE8-4D66-9AFF-E8A369032487}\"(?:.|\n)*?EndProject",
$$"""
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{3C6F049E-3EE8-4D66-9AFF-E8A369032487}"
{{'\t'}}ProjectSection(SolutionItems) = preProject
ProjectSection(SolutionItems) = preProject
{{string.Join('\n',
Directory.GetFiles(@"../.github/workflows", "*")
.Select(x=>$"\t\t{Path.GetFileName(x)} = .github/workflows/{Path.GetFileName(x)}")
.Select(x=>$" {Path.GetFileName(x)} = .github/workflows/{Path.GetFileName(x)}")
)}}
{{'\t'}}EndProject
EndProject
"""
);
@ -36,12 +36,12 @@ content = Regex.Replace(
"Project\\(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\"\\) = \"scripts\", \"scripts\", \"{BB0B25C9-0901-4923-913F-00F9A6B352A5}\"(?:.|\n)*?EndProject",
$$"""
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{BB0B25C9-0901-4923-913F-00F9A6B352A5}"
{{'\t'}}ProjectSection(SolutionItems) = preProject
ProjectSection(SolutionItems) = preProject
{{string.Join('\n',
Directory.GetFiles(@"../scripts", "*")
.Select(x=>$"\t\t{Path.GetFileName(x)} = scripts/{Path.GetFileName(x)}")
.Select(x=>$" {Path.GetFileName(x)} = scripts/{Path.GetFileName(x)}")
)}}
{{'\t'}}EndProject
EndProject
"""
);
@ -50,12 +50,12 @@ content = Regex.Replace(
"Project\\(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\"\\) = \"build\", \"build\", \"{8E4C93BA-9493-4892-80C4-5E174C504829}\"(?:.|\n)*?EndProject",
$$"""
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{8E4C93BA-9493-4892-80C4-5E174C504829}"
{{'\t'}}ProjectSection(SolutionItems) = preProject
ProjectSection(SolutionItems) = preProject
{{string.Join('\n',
Directory.GetFiles(@"../build", "*")
.Select(x=>$"\t\t{Path.GetFileName(x)} = build/{Path.GetFileName(x)}")
.Select(x=>$" {Path.GetFileName(x)} = build/{Path.GetFileName(x)}")
)}}
{{'\t'}}EndProject
EndProject
"""
);

View File

@ -1,5 +1,6 @@
global using System;
global using System.ComponentModel;
global using System.Diagnostics;
global using System.Globalization;
global using System.Text;
global using System.Text.RegularExpressions;

View File

@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0"/>
<PackageReference Include="xunit" Version="2.8.1"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0-preview-25107-01"/>
<PackageReference Include="xunit" Version="2.9.3"/>
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PackageReference Include="coverlet.collector" Version="6.0.4">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>

View File

@ -27,7 +27,7 @@ public static class EnumExtensions
var resDescAttr = typeOfField!.GetCustomAttribute<ResourceDescriptionAttribute<T>>(true);
return resDescAttr is null
? Enum.GetName(typeOfEnum, e)
: typeof(T).GetProperty(resDescAttr.ResourceName)?.GetValue(default) as string;
: typeof(T).GetProperty(resDescAttr.ResourceName)?.GetValue(null) as string;
}
/// <summary>

View File

@ -36,6 +36,8 @@ public static class IntExtensions
/// </summary>
public static string ToIpV4(this int me)
{
return string.Join(".", BitConverter.GetBytes(me).Reverse());
var bytes = BitConverter.GetBytes(me);
Array.Reverse(bytes);
return string.Join('.', bytes);
}
}

View File

@ -1,10 +1,10 @@
// ReSharper disable UnusedMember.Global
// ReSharper disable MemberCanBePrivate.Global
#pragma warning disable CA1720
using System.Numerics;
using System.Reflection;
using System.Security.Cryptography;
using System.Text.Json;
using System.Web;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
using NSExt.Constant;
namespace NSExt.Extensions;
@ -12,9 +12,11 @@ namespace NSExt.Extensions;
/// <summary>
/// StringExtensions
/// </summary>
#pragma warning disable CodeLinesAnalyzer
public static class StringExtensions
public static partial class StringExtensions
{
private const string _CHARACTERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
private static readonly Regex _regexIpV4 = RegexIpV4();
/// <summary>
/// aes加密
/// </summary>
@ -24,11 +26,11 @@ public static class StringExtensions
{
using var aes = System.Security.Cryptography.Aes.Create();
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.ECB;
aes.Key = key.Hex();
aes.Mode = CipherMode.ECB;
aes.Key = key.Hex();
using var encryptor = aes.CreateEncryptor();
var bytes = me.Hex();
var decrypted = encryptor.TransformFinalBlock(bytes, 0, bytes.Length);
var bytes = me.Hex();
var decrypted = encryptor.TransformFinalBlock(bytes, 0, bytes.Length);
return decrypted.Base64();
}
@ -41,14 +43,72 @@ public static class StringExtensions
{
using var aes = System.Security.Cryptography.Aes.Create();
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.ECB;
aes.Key = key.Hex();
aes.Mode = CipherMode.ECB;
aes.Key = key.Hex();
using var encryptor = aes.CreateDecryptor();
var bytes = me.Base64De();
var decrypted = encryptor.TransformFinalBlock(bytes, 0, bytes.Length);
var bytes = me.Base64De();
var decrypted = encryptor.TransformFinalBlock(bytes, 0, bytes.Length);
return decrypted.HexDe();
}
/// <summary>
/// 将指定的输入字符串进行Base62解码
/// </summary>
/// <exception cref="ArgumentException">ArgumentException</exception>
public static string Base62Decode(this string me)
{
BigInteger result = 0;
foreach (var index in me.Select(c => _CHARACTERS.IndexOf(c)))
{
if (index < 0)
{
throw new ArgumentException("Invalid character in Base62 string.");
}
result = result * 62 + index;
}
// Convert BigInteger back to byte array and then to string
var bytes = result.ToByteArray();
// Handle the sign bit
if (bytes[^1] == 0)
{
Array.Resize(ref bytes, bytes.Length - 1);
}
return Encoding.UTF8.GetString(bytes);
}
/// <summary>
/// 将指定的输入字符串进行Base62编码
/// </summary>
public static string Base62Encode(this string me)
{
// Convert string to byte array
var bytes = Encoding.UTF8.GetBytes(me);
// Convert byte array to BigInteger for easier processing
var bigInteger = new BigInteger(bytes);
if (bigInteger == 0)
{
return _CHARACTERS[0].ToString();
}
var result = new StringBuilder();
while (bigInteger > 0)
{
var remainder = (int)(bigInteger % 62);
bigInteger /= 62;
_ = result.Insert(0, _CHARACTERS[remainder]);
}
return result.ToString();
}
/// <summary>
/// base64编码
/// </summary>
@ -81,6 +141,22 @@ public static class StringExtensions
return e.GetString(me.Base64De());
}
/// <summary>
/// 解码避免转义的Base64
/// </summary>
public static string Base64InUrlDecode(this string me)
{
return me.Replace("-", "+").Replace("_", "/");
}
/// <summary>
/// 编码避免转义的Base64
/// </summary>
public static string Base64InUrlEncode(this string me)
{
return me.Replace("+", "-").Replace("/", "_");
}
/// <summary>
/// 将易于web传输的base64web字符串转换为原生base64
/// </summary>
@ -99,6 +175,14 @@ public static class StringExtensions
return me.Replace("+", "-").Replace("/", "_").Replace("=", ".");
}
/// <summary>
/// 计算Crc32
/// </summary>
public static int Crc32(this string me)
{
return BitConverter.ToInt32(System.IO.Hashing.Crc32.Hash(Encoding.UTF8.GetBytes(me)));
}
/// <summary>
/// 将字符串转换成日期对象
/// </summary>
@ -129,9 +213,7 @@ public static class StringExtensions
/// <returns>转换后的日期对象</returns>
public static DateTime DateTimeExactTry(this string me, string format, DateTime def)
{
return !System.DateTime.TryParseExact(me, format, CultureInfo.CurrentCulture, DateTimeStyles.None, out var ret)
? def
: ret;
return !System.DateTime.TryParseExact(me, format, CultureInfo.CurrentCulture, DateTimeStyles.None, out var ret) ? def : ret;
}
/// <summary>
@ -142,9 +224,7 @@ public static class StringExtensions
/// <returns>转换后的日期对象</returns>
public static DateTime DateTimeTry(this string me, DateTime def)
{
return !System.DateTime.TryParse(me, CultureInfo.InvariantCulture, DateTimeStyles.None, out var ret)
? def
: ret;
return !System.DateTime.TryParse(me, CultureInfo.InvariantCulture, DateTimeStyles.None, out var ret) ? def : ret;
}
/// <summary>
@ -196,6 +276,15 @@ public static class StringExtensions
return !System.Enum.TryParse(typeof(T), name, out var ret) ? def : (T)ret;
}
/// <summary>
/// 执行C#代码
/// </summary>
public static Task<T> ExecuteCSharpCodeAsync<T>(this string me, Assembly[] assemblies, params string[] importNamespaces)
{
// 使用 Roslyn 编译并执行代码
return CSharpScript.EvaluateAsync<T>(me, ScriptOptions.Default.WithReferences(assemblies).WithImports(importNamespaces));
}
/// <summary>
/// string to float
/// </summary>
@ -255,13 +344,13 @@ public static class StringExtensions
/// <returns>hash摘要的16进制文本形式无连字符小写</returns>
public static string HmacSha1(this string me, string secret, Encoding e)
{
#pragma warning disable CA5350
using var hmacSha1 = new HMACSHA1(e.GetBytes(secret));
#pragma warning restore CA5350
return BitConverter.ToString(hmacSha1.ComputeHash(e.GetBytes(me)))
.Replace("-", string.Empty)
.ToLower(CultureInfo.CurrentCulture);
#if NET9_0_OR_GREATER
return Convert.ToHexStringLower(hmacSha1.ComputeHash(e.GetBytes(me)));
#else
return BitConverter.ToString(hmacSha1.ComputeHash(e.GetBytes(me))).Replace("-", string.Empty).ToLower(CultureInfo.CurrentCulture);
#endif
}
/// <summary>
@ -341,16 +430,19 @@ public static class StringExtensions
// 一个合法的Base64有着以下特征
// 字符串的长度为4的整数倍。
// 字符串的符号取值只能在A -Z, a -z, 0 -9, +, /, =共计65个字符中且 = 如果出现就必须在结尾出现。
if (!me.All(x => x.IsBase64Character())) {
if (!me.All(x => x.IsBase64Character()))
{
return false;
}
if (me.Length % 4 != 0) {
if (me.Length % 4 != 0)
{
return false;
}
var firstEqualSignPos = me.IndexOf('=');
if (firstEqualSignPos < 0) {
if (firstEqualSignPos < 0)
{
return true;
}
@ -358,20 +450,31 @@ public static class StringExtensions
return lastEqualSignPos == me.Length - 1 && me[firstEqualSignPos..lastEqualSignPos].All(x => x == '=');
}
/// <summary>
/// 是否IPV4地址
/// </summary>
public static bool IsIpV4(this string me)
{
return _regexIpV4.IsMatch(me);
}
/// <summary>
/// 是否json字符串
/// </summary>
/// <param name="me">me</param>
public static bool IsJsonString(this string me)
{
if (me.NullOrEmpty()) {
if (me.NullOrEmpty())
{
return false;
}
try {
try
{
_ = JsonDocument.Parse(me);
}
catch {
catch
{
return false;
}
@ -404,11 +507,13 @@ public static class StringExtensions
/// <returns>hash摘要的16进制文本形式无连字符小写</returns>
public static string Md5(this string me, Encoding e)
{
#pragma warning disable CA5351
#if NET9_0_OR_GREATER
return Convert.ToHexStringLower(MD5.HashData(e.GetBytes(me)));
#else
return BitConverter.ToString(MD5.HashData(e.GetBytes(me)))
#pragma warning restore CA5351
.Replace("-", string.Empty)
.ToLower(CultureInfo.CurrentCulture);
.Replace("-", string.Empty)
.ToLower(CultureInfo.CurrentCulture);
#endif
}
/// <summary>
@ -489,11 +594,13 @@ public static class StringExtensions
/// <returns>hash摘要的16进制文本形式无连字符小写</returns>
public static string Sha1(this string me, Encoding e)
{
#pragma warning disable CA5350
#if NET9_0_OR_GREATER
return Convert.ToHexStringLower(SHA1.HashData(e.GetBytes(me)));
#else
return BitConverter.ToString(SHA1.HashData(e.GetBytes(me)))
#pragma warning restore CA5350
.Replace("-", string.Empty)
.ToLower(CultureInfo.CurrentCulture);
.Replace("-", string.Empty)
.ToLower(CultureInfo.CurrentCulture);
#endif
}
/// <summary>
@ -509,7 +616,8 @@ public static class StringExtensions
/// </summary>
public static string Sub(this string me, int startIndex, int length)
{
if (startIndex + length > me.Length) {
if (startIndex + length > me.Length)
{
length = me.Length - startIndex;
}
@ -529,10 +637,7 @@ public static class StringExtensions
/// </summary>
public static string ToLowerCamelCase(this string me)
{
return string.IsNullOrWhiteSpace(me)
? me
: string.Concat( //
me[0].ToString(CultureInfo.InvariantCulture).ToLowerInvariant(), me.AsSpan(1));
return string.IsNullOrWhiteSpace(me) ? me : string.Concat(me[0].ToString(CultureInfo.InvariantCulture).ToLowerInvariant(), me.AsSpan(1));
}
/// <summary>
@ -543,6 +648,14 @@ public static class StringExtensions
return string.IsNullOrWhiteSpace(me) ? me : string.Concat(me[0].ToString().ToUpperInvariant(), me.AsSpan(1));
}
/// <summary>
/// 去掉前部字符串
/// </summary>
public static string TrimPrefix(this string me, string clearStr)
{
return Regex.Replace(me, $"^{clearStr}", string.Empty);
}
/// <summary>
/// 将连续多个空格替换成一个空格
/// </summary>
@ -554,24 +667,25 @@ public static class StringExtensions
return ret == me ? ret : ret.TrimSpaces();
}
/// <summary>
/// 去掉尾部字符串
/// </summary>
public static string TrimSuffix(this string me, string clearStr)
{
return Regex.Replace(me, $"{clearStr}$", string.Empty);
}
/// <summary>
/// 将\ux0000 、 %u0000 、 &amp;#x0000; 编码转换成可读字符串
/// </summary>
public static string UnicodeDe(this string me)
{
#pragma warning disable S3358, RCS1238
const string replacement = "&#x$1;";
if (me.Contains(@"\u")) {
return Regexes.RegexBacksLantUnicode.Replace(me, replacement).HtmlDe();
}
// ReSharper disable once ConvertIfStatementToReturnStatement
#pragma warning disable IDE0046
if (me.Contains("%u")) {
#pragma warning restore IDE0046
return Regexes.RegexPercentUnicode.Replace(me, replacement).HtmlDe();
}
return me.HtmlDe();
return !me.Contains(@"\u")
? me.Contains("%u") ? Regexes.RegexPercentUnicode.Replace(me, replacement).HtmlDe() : me.HtmlDe()
: Regexes.RegexBacksLantUnicode.Replace(me, replacement).HtmlDe();
#pragma warning restore S3358, RCS1238
}
/// <summary>
@ -603,12 +717,15 @@ public static class StringExtensions
/// <returns>hash摘要的16进制文本形式无连字符小写</returns>
private static string Md5Hmac(this string me, string key, Encoding e)
{
#pragma warning disable CA5351
using var md5Hmac = new HMACMD5(e.GetBytes(key));
#pragma warning restore CA5351
return BitConverter.ToString(md5Hmac.ComputeHash(e.GetBytes(me)))
.Replace("-", string.Empty)
.ToLower(CultureInfo.CurrentCulture);
#if NET9_0_OR_GREATER
return Convert.ToHexStringLower(md5Hmac.ComputeHash(e.GetBytes(me)));
#else
return BitConverter.ToString(md5Hmac.ComputeHash(e.GetBytes(me))).Replace("-", string.Empty).ToLower(CultureInfo.CurrentCulture);
#endif
}
}
#pragma warning restore CodeLinesAnalyzer
[GeneratedRegex(@"^(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})){3}$")]
private static partial Regex RegexIpV4();
}

View File

@ -7,7 +7,9 @@
<Import Project="$(SolutionDir)/build/copy.pkg.xml.comment.files.targets"/>
<Import Project="$(SolutionDir)/build/prebuild.targets"/>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0"/>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.13.0"/>
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.3"/>
<PackageReference Include="System.IO.Hashing" Version="9.0.3"/>
</ItemGroup>
<ItemGroup>
<None Update="*.json">