Compare commits

..

11 Commits
main ... 1.0.9

Author SHA1 Message Date
nsnail
52b3170e10 bugfix 2023-01-04 18:12:44 +08:00
nsnail
f3d0f98970 <fix> 2022-12-27 16:14:38 +08:00
nsnail
8c1083f732 <doc> 2022-12-15 16:03:02 +08:00
nsnail
31e31c5d49 <doc> 2022-12-15 15:49:47 +08:00
nsnail
3095dc783e <refactor> 2022-12-15 14:18:09 +08:00
nsnail
9ae1046dca <chore> 2022-12-13 16:15:20 +08:00
nsnail
cb63791dbc <chore> 2022-12-13 16:10:50 +08:00
nsnail
3a1a71d1c1 <adjust> 2022-12-09 16:55:52 +08:00
nsnail
54082a82f1 1.0.8 2022-12-09 11:27:39 +08:00
nsnail
1ea481e749 1.0.7 2022-12-09 11:24:01 +08:00
nsnail
d9aae8fe95 <chore> 2022-12-04 22:22:35 +08:00
88 changed files with 823 additions and 2232 deletions

View File

@ -1,72 +0,0 @@
// .commitlintrc.js
/** @type {import('cz-git').UserConfig} */
module.exports = {
rules: {
// @see: https://commitlint.js.org/#/reference-rules
},
prompt: {
alias: { fd: 'docs: fix typos' },
messages: {
type: '选择你要提交的类型 :',
scope: '选择一个提交范围(可选):',
customScope: '请输入自定义的提交范围 :',
subject: '填写简短精炼的变更描述 :\n',
body: '填写更加详细的变更描述(可选)。使用 "|" 换行 :\n',
breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行 :\n',
footerPrefixesSelect: '选择关联issue前缀可选:',
customFooterPrefix: '输入自定义issue前缀 :',
footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
confirmCommit: '是否提交或修改commit ?'
},
types: [
{ value: 'wip', name: 'wip: 开发之中 | In development ', emoji:'🧠' },
{ value: 'feat', name: 'feat: 新增功能 | A new feature', emoji:'✨' },
{ value: 'fix', name: 'fix: 修复缺陷 | A bug fix', emoji:'🐛' },
{ value: 'docs', name: 'docs: 文档更新 | Documentation only changes', emoji:'📝' },
{ value: 'style', name: 'style: 代码格式 | Changes that do not affect the meaning of the code', emoji:'💄' },
{ value: 'refactor', name: 'refactor: 代码重构 | A code change that neither fixes a bug nor adds a feature', emoji:'♻️' },
{ value: 'perf', name: 'perf: 性能提升 | A code change that improves performance', emoji:'⚡' },
{ value: 'test', name: 'test: 测试相关 | Adding missing tests or correcting existing tests', emoji:'✅' },
{ value: 'build', name: 'build: 构建相关 | Changes that affect the build system or external dependencies', emoji:'📦' },
{ value: 'ci', name: 'ci: 持续集成 | Changes to our CI configuration files and scripts', emoji:'🎡' },
{ value: 'revert', name: 'revert: 回退代码 | Revert to a commit', emoji:'⏪' },
{ value: 'chore', name: 'chore: 其他修改 | Other changes that do not modify src or test files', emoji:'🔨' },
],
useEmoji: true,
emojiAlign: 'center',
useAI: false,
aiNumber: 1,
themeColorCode: '',
scopes: [],
allowCustomScopes: true,
allowEmptyScopes: true,
customScopesAlign: 'bottom',
customScopesAlias: 'custom',
emptyScopesAlias: 'empty',
upperCaseSubject: false,
markBreakingChangeMode: false,
allowBreakingChanges: ['feat', 'fix'],
breaklineNumber: 100,
breaklineChar: '|',
skipQuestions: [],
issuePrefixes: [
// 如果使用 gitee 作为开发管理
{ value: 'link', name: 'link: 链接 ISSUES 进行中' },
{ value: 'closed', name: 'closed: 标记 ISSUES 已完成' }
],
customIssuePrefixAlign: 'top',
emptyIssuePrefixAlias: 'skip',
customIssuePrefixAlias: 'custom',
allowCustomIssuePrefix: true,
allowEmptyIssuePrefix: true,
confirmColorize: true,
maxHeaderLength: Infinity,
maxSubjectLength: Infinity,
minSubjectLength: 0,
scopeOverrides: undefined,
defaultBody: '[skip ci]',
defaultIssues: '',
defaultScope: '',
defaultSubject: ''
}
}

View File

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

View File

@ -1 +0,0 @@
github workflows

View File

@ -1,33 +0,0 @@
name: CI
on:
push:
tags:
- v*
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
filter: tree:0
- uses: actions/setup-dotnet@v3
with:
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
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: false
- id: get_version
run: echo ::set-output name=VERSION::${GITHUB_REF#refs/tags/v}
- run: dotnet nuget push ./dist/backend/NSExt/bin/Release/NSExt.${{ steps.get_version.outputs.VERSION }}.nupkg --skip-duplicate --api-key ${{ secrets.NUGET_TOKEN }} --source https://api.nuget.org/v3/index.json

10
.gitignore vendored
View File

@ -29,7 +29,7 @@ x86/
bld/ bld/
[Bb]in/ [Bb]in/
[Oo]bj/ [Oo]bj/
# [Ll]og/ [Ll]og/
[Ll]ogs/ [Ll]ogs/
# Visual Studio 2015/2017 cache/options directory # Visual Studio 2015/2017 cache/options directory
@ -399,8 +399,6 @@ FodyWeavers.xsd
.idea/ .idea/
# User Define # User Define
dist/ build/
*.[Dd]esigner.cs nuget.config
*.db *.[Dd]esigner.cs
cache
/assets/res/Ln.resx

View File

@ -1,30 +0,0 @@
{
"author": "nsnail", //
"classifications": [
"Web/WebAPI"
], //Tags
"name": "NSExt", //Templates
"identity": "NSExt", //
"shortName": "lop", //Short Name
"tags": {
"language": "C#",
"type": "project"
},
"sourceName": "NSExt", //
"preferNameDirectory": true, //
"sources": [
{
"modifiers": [
{
"exclude": [
"**/.vs/**",
"**/.idea/**",
"**/.git/**",
"**/dist/**",
"**/node_modules/**"
]
}
]
}
],
}

4
.tgitconfig Normal file
View File

@ -0,0 +1,4 @@
[hook "startcommit"]
cmdline = code-format.cmd
wait = true
show = true

14
AddMetaFilesToSln.csx Normal file
View File

@ -0,0 +1,14 @@
using System.Text.RegularExpressions;
var slnFile = Directory.GetFiles(@".", "*.sln").First();
var content = File.ReadAllText(slnFile);
content = Regex.Replace(content,@"ProjectSection\(SolutionItems\) = preProject(?:.|\n)*?EndProjectSection",
$"""
ProjectSection(SolutionItems) = preProject
{string.Join('\n',
Directory.GetFiles(@".", "*").Where(x => !x.EndsWith(".sln"))
.Select(x=>$"\t\t{Path.GetFileName(x)} = {Path.GetFileName(x)}"))}
{'\t'}EndProjectSection
""");
Console.WriteLine(content);
File.WriteAllText(slnFile, content);

View File

@ -1,49 +0,0 @@
# Changelog
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)
### Features
* ✨ 新增string扩展函数 IsJsonString ([41208a5](https://github.com/nsnail/NSExt/commit/41208a5d7f63ad595ec985d3616fbce2c9bdc4d0))
* ✨ 新增string扩展函数 IsJsonString ([#19](https://github.com/nsnail/NSExt/issues/19)) ([32b7bdf](https://github.com/nsnail/NSExt/commit/32b7bdf700f694fec7f5dcef43dc05244dcd02d5))
* ✨ 异步累加器函数 ([#17](https://github.com/nsnail/NSExt/issues/17)) ([3de9d3b](https://github.com/nsnail/NSExt/commit/3de9d3b8d06143c93c9acad43df22eb09242ac29))
## [2.1.0](https://github.com/nsnail/NSExt/compare/v2.0.11...v2.1.0) (2024-03-01)
### Features
* ✨ 异步累加器函数 ([ddf07fc](https://github.com/nsnail/NSExt/commit/ddf07fce5732e576db1512f870196c20f7b297e2))
### [2.0.11](https://github.com/nsnail/NSExt/compare/v2.0.10...v2.0.11) (2023-12-15)
### [2.0.10](https://github.com/nsnail/NSExt/compare/v2.0.9...v2.0.10) (2023-12-14)

16
CodeCleanupOnSave.csx Normal file
View File

@ -0,0 +1,16 @@
var path = Directory.GetFiles(@".idea", "workspace.xml", SearchOption.AllDirectories).First();
const string findStr = """
&quot;keyToString&quot;: {
""";
const string replaceStr = """
&quot;keyToString&quot;: {
&quot;rider.code.cleanup.on.save&quot;: &quot;true&quot;,
""";
var content = File.ReadAllText(path);
if(content.Contains("rider.code.cleanup.on.save")){
Console.WriteLine("alreay added");
return;
}
content = content.Replace(findStr, replaceStr);
Console.WriteLine(content);
File.WriteAllText(path, content);

17
CodeQuality.props Normal file
View File

@ -0,0 +1,17 @@
<Project>
<PropertyGroup>
<CodeAnalysisRuleSet>../StyleCopAnalyzers.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<MSBuildTreatWarningsAsErrors>true</MSBuildTreatWarningsAsErrors>
<MSBuildWarningsAsErrors>true</MSBuildWarningsAsErrors>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors>true</WarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@ -1,37 +1,22 @@
<!-- 注意此文件名大小写不可变更 -->
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<SolutionDir>$(MSBuildThisFileDirectory)</SolutionDir>
</PropertyGroup>
<Import Project="$(SolutionDir)/build/minver.targets"/>
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Authors>nsnail</Authors>
<BaseIntermediateOutputPath>$(SolutionDir)/dist/backend/$(MSBuildProjectName)/obj</BaseIntermediateOutputPath>
<BaseOutputPath>$(SolutionDir)/dist/backend/$(MSBuildProjectName)/bin</BaseOutputPath>
<Copyright>© 2006-2023 nsnail</Copyright>
<Description>The NSExt is a .NET extension function library</Description>
<EnableBaseIntermediateOutputPathMismatchWarning>false</EnableBaseIntermediateOutputPathMismatchWarning>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<LangVersion>preview</LangVersion> <BaseOutputPath>../dist</BaseOutputPath>
<MinVerDefaultPreReleaseIdentifiers>beta</MinVerDefaultPreReleaseIdentifiers> <BaseIntermediateOutputPath>../dist</BaseIntermediateOutputPath>
<MinVerTagPrefix>v</MinVerTagPrefix> <OutputPath>$(BaseOutputPath)/$(MSBuildProjectName)/bin</OutputPath>
<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> <IntermediateOutputPath>$(BaseIntermediateOutputPath)/$(MSBuildProjectName)/obj</IntermediateOutputPath>
<MSBuildProjectExtensionsPath>$(BaseIntermediateOutputPath)/$(MSBuildProjectName)/obj</MSBuildProjectExtensionsPath>
<Authors>nsnail</Authors>
<Product>NSExt</Product> <Product>NSExt</Product>
<RepositoryType>git</RepositoryType> <Copyright>© 2006-2022 nsnail</Copyright>
<RepositoryUrl>https://github.com/nsnail/NSExt.git</RepositoryUrl> <RepositoryUrl>https://github.com/nsnail/ns-ext.git</RepositoryUrl>
<RootNamespace>NSExt</RootNamespace> <PublishRepositoryUrl>true</PublishRepositoryUrl>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks> <EmbedUntrackedSource>true</EmbedUntrackedSource>
<Title>$(AssemblyName)</Title> <EmbedAllSources>true</EmbedAllSources>
<RepositoryType>Git</RepositoryType>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/nsnail/ns-ext.git</PackageProjectUrl>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="MinVer" Version="6.1.0-beta.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Compile Include="../GlobalUsings.cs" Link="GlobalUsings.cs"/>
</ItemGroup>
</Project> </Project>

45
ImageOptimize.csx Normal file
View File

@ -0,0 +1,45 @@
/*
for %%i in (*.png) do pngquant %%i --force --output %%i --skip-if-larger
for %%i in (*.jpg) do jpegtran -copy none -optimize -perfect %%i %%i
*
*/
var files = Directory.EnumerateFiles(".", "*.png"
, new EnumerationOptions {
RecurseSubdirectories = true
, AttributesToSkip = FileAttributes.ReparsePoint
, IgnoreInaccessible = true
})
.ToArray();
Parallel.ForEach(files, file => {
var startInfo = new ProcessStartInfo {
FileName = "pngquant"
, Arguments
= $"\"{file}\" --force --output \"{file}\" --skip-if-larger"
};
using var p = Process.Start(startInfo);
p.WaitForExit();
Console.WriteLine($"{file}: {p.ExitCode}");
});
files = new[] { "*.jpg", "*.jpeg" }
.SelectMany(x => Directory.EnumerateFiles(
".", x
, new EnumerationOptions {
RecurseSubdirectories = true
, AttributesToSkip = FileAttributes.ReparsePoint
, IgnoreInaccessible = true
}))
.ToArray();
Parallel.ForEach(files, file => {
var startInfo = new ProcessStartInfo {
FileName = "jpegtran"
, Arguments = $"-copy none -optimize -perfect \"{file}\" \"{file}\""
};
using var p = Process.Start(startInfo);
p.WaitForExit();
Console.WriteLine($"{file}: {p.ExitCode}");
});

View File

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2023 nsnail Copyright (c) 2022 nsnail
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

124
NSExt.sln
View File

@ -3,94 +3,44 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59 VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C84EB5A0-37AD-4B17-A51E-E36888C4441E}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NSExt", "src\NSExt.csproj", "{70DD1C27-7ACB-4BE0-A9CD-D781E4050DE5}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "backend", "backend", "{4DAF9366-855F-46BB-AE4C-660C92FA0697}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "meta", "meta", "{85E669CB-FC0A-4C1D-92DE-38D0662C257D}"
EndProject ProjectSection(SolutionItems) = preProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "meta", "meta", "{5198A03D-0CAC-4828-A807-34A693F73859}" .editorconfig = .editorconfig
ProjectSection(SolutionItems) = preProject .gitattributes = .gitattributes
.commitlintrc.js = .commitlintrc.js .gitignore = .gitignore
.editorconfig = .editorconfig .tgitconfig = .tgitconfig
.gitattributes = .gitattributes AddMetaFilesToSln.csx = AddMetaFilesToSln.csx
.gitignore = .gitignore build.cake = build.cake
CHANGELOG.md = CHANGELOG.md code-format.cmd = code-format.cmd
Directory.Build.props = Directory.Build.props CodeCleanupOnSave.csx = CodeCleanupOnSave.csx
dotnet-tools.json = dotnet-tools.json CodeQuality.props = CodeQuality.props
global.json = global.json Directory.Build.props = Directory.Build.props
key.snk = key.snk dot.sln.DotSettings = dot.sln.DotSettings
LICENSE = LICENSE dotnet-tools.json = dotnet-tools.json
NSExt.sln.DotSettings = NSExt.sln.DotSettings git-clean.cmd = git-clean.cmd
nuget.config = nuget.config global.json = global.json
package.json = package.json ImageOptimize.csx = ImageOptimize.csx
README.md = README.md LICENSE = LICENSE
README.zh-CN.md = README.zh-CN.md push2nuget.ps1 = push2nuget.ps1
EndProjectSection README.md = README.md
EndProject stylecop.json = stylecop.json
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{BB0B25C9-0901-4923-913F-00F9A6B352A5}" StyleCopAnalyzers.ruleset = StyleCopAnalyzers.ruleset
ProjectSection(SolutionItems) = preProject EndProjectSection
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
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
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 EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1E62C322-EE42-4699-A6F1-791C53EFA62D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {70DD1C27-7ACB-4BE0-A9CD-D781E4050DE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1E62C322-EE42-4699-A6F1-791C53EFA62D}.Debug|Any CPU.Build.0 = Debug|Any CPU {70DD1C27-7ACB-4BE0-A9CD-D781E4050DE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E62C322-EE42-4699-A6F1-791C53EFA62D}.Release|Any CPU.ActiveCfg = Release|Any CPU {70DD1C27-7ACB-4BE0-A9CD-D781E4050DE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E62C322-EE42-4699-A6F1-791C53EFA62D}.Release|Any CPU.Build.0 = Release|Any CPU {70DD1C27-7ACB-4BE0-A9CD-D781E4050DE5}.Release|Any CPU.Build.0 = Release|Any CPU
{00604162-C444-478B-B773-3AB23C856CA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU EndGlobalSection
{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 EndGlobal

View File

@ -1,37 +1,17 @@
<wpf:ResourceDictionary xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xml:space="preserve"> <wpf:ResourceDictionary xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xml:space="preserve">
<!-- CodeEditing--> <s:Boolean x:Key="/Default/ReSpeller/ReSpellerEnabled/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeEditing/TypingAssist/SkipClosingBracesOnTabInStringLiterals/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeEditing/GenerateMemberBody/DocumentationGenerationKind/@EntryValue">Inherit</s:String>
<!-- CodeInspection-->
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Ett/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/CodeInspection/Highlighting/AnalysisEnabled/@EntryValue">OFF</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=AssignmentInConditionalExpression/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ClassNeverInstantiated_002EGlobal/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=DuplicateResource/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantPatternParentheses/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestBaseTypeForParameter/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestBaseTypeForParameterInConstructor/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=TooWideLocalVariableScope/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UnusedAutoPropertyAccessor_002EGlobal/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UnusedAutoPropertyAccessor_002ELocal/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<!-- CodeStyle-->
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_CODE/@EntryValue">1</s:Int64> <s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_CODE/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue">1</s:Int64> <s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue">1</s:Int64>
<s:String x:Key="/Default/CodeInspection/Highlighting/AnalysisEnabled/@EntryValue">OFF</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=TooWideLocalVariableScope/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOR/@EntryValue">Required</s:String> <s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOR/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOREACH/@EntryValue">Required</s:String> <s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOREACH/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String> <s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_WHILE/@EntryValue">Required</s:String> <s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_WHILE/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_RECORD_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=15b5b1f1_002D457c_002D4ca6_002Db278_002D5615aedc07d3/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=236f7aa5_002D7b06_002D43ca_002Dbf2a_002D9b31bfcff09a/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Private" Description="Constant fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="CONSTANT_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="AA_BB" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=669e5282_002Dfb4b_002D4e90_002D91e7_002D07d269d04b60/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Constant fields (not private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="CONSTANT_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=a0b4bc4d_002Dd13b_002D4a37_002Db37e_002Dc9c6864e4302/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Types and namespaces"&gt;&lt;ElementKinds&gt;&lt;Kind Name="NAMESPACE" /&gt;&lt;Kind Name="CLASS" /&gt;&lt;Kind Name="STRUCT" /&gt;&lt;Kind Name="ENUM" /&gt;&lt;Kind Name="DELEGATE" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=c873eafb_002Dd57f_002D481d_002D8c93_002D77f6863c2f88/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Static readonly fields (not private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue">&lt;?xml version="1.0" encoding="utf-16"?&gt; <s:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;
&lt;Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"&gt; &lt;Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"&gt;
@ -74,21 +54,4 @@
&lt;/TypePattern&gt; &lt;/TypePattern&gt;
&lt;/Patterns&gt;</s:String> &lt;/Patterns&gt;</s:String>
<!-- Environment-->
<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>
<!-- ReSpeller-->
<s:Boolean x:Key="/Default/ReSpeller/ReSpellerEnabled/@EntryValue">True</s:Boolean>
<!-- UserDictionary-->
<s:Boolean x:Key="/Default/UserDictionary/Words/=FLG/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=FLGL/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=RGX/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=RGXL/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary> </wpf:ResourceDictionary>

View File

@ -1,27 +1,27 @@
# ns-ext # ns-ext
[](README.zh-CN.md) | **En** [](README.zh-CN.md) | **En**
The **ns-ext** is a .NET extension function library, containing the following types of extension modules: The **ns-ext** is a .NET extension function library, containing the following types of extension modules:
| Features | File name |
|------------------------------------------|------------------------------------| | Features | File name |
| Byte type extension | ByteExtensions.cs | | -------- | ---------------------------------- |
| Character Type Extensions | CharExtensions.cs | | Byte type extension | ByteExtensions.cs |
| Date Type Extensions | DateTimeExtensions.cs | | Character Type Extensions | CharExtensions.cs |
| Database command type extension | DbCommandExtensions.cs | | Date Type Extensions | DateTimeExtensions.cs |
| Decimal Number Type extension | DecimalExtensions.cs | | Database command type extension | DbCommandExtensions.cs |
| Enumable type extension | EnumerableExtensions.cs | | Decimal Number Type extension | DecimalExtensions.cs |
| Enumeration type extension | EnumExtensions.cs | | Enumable type extension | EnumerableExtensions.cs |
| General type extension | GenericExtensions.cs | | Enumeration type extension | EnumExtensions.cs |
| Integer type extension | IntExtensions.cs | | General type extension | GenericExtensions.cs |
| Integer type extension | IntExtensions.cs |
| Json Serialization option type extension | JsonSerializerOptionsExtensions.cs | | Json Serialization option type extension | JsonSerializerOptionsExtensions.cs |
| Log type extension | LoggerExtensions.cs | | Log type extension | LoggerExtensions.cs |
| Long integer extension | LongExtensions.cs | | Long integer extension | LongExtensions.cs |
| Object type extension | ObjectExtensions.cs | | Object type extension | ObjectExtensions.cs |
| Stream type extension | StreamExtensions.cs | | Stream type extension | StreamExtensions.cs |
| String type extension | StringExtensions.cs | | String type extension | StringExtensions.cs |
| Prototype type extension | TypeExtensions.cs | | Prototype type extension | TypeExtensions.cs |
| Resource locator type extension | UriExtensions.cs | | Resource locator type extension | UriExtensions.cs |
## Quick start ## Quick start

View File

@ -6,13 +6,14 @@
<Rule Id="SA0001" Action="Warning"/> <!-- XML comment analysis disabled --> <Rule Id="SA0001" Action="Warning"/> <!-- XML comment analysis disabled -->
<Rule Id="SA0002" Action="Warning"/> <!-- Invalid settings file --> <Rule Id="SA0002" Action="Warning"/> <!-- Invalid settings file -->
</Rules> </Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.SpacingRules"> <Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.SpacingRules">
<Rule Id="SA1000" Action="Warning"/> <!-- Keywords should be spaced correctly --> <Rule Id="SA1000" Action="Warning"/> <!-- Keywords should be spaced correctly -->
<Rule Id="SA1001" Action="None"/> <!-- Commas should be spaced correctly --> <Rule Id="SA1001" Action="None"/> <!-- Commas should be spaced correctly -->
<Rule Id="SA1002" Action="Warning"/> <!-- Semicolons should be spaced correctly --> <Rule Id="SA1002" Action="Warning"/> <!-- Semicolons should be spaced correctly -->
<Rule Id="SA1003" Action="Warning"/> <!-- Symbols should be spaced correctly --> <Rule Id="SA1003" Action="Warning"/> <!-- Symbols should be spaced correctly -->
<Rule Id="SA1004" Action="Warning"/> <!-- Documentation lines should begin with single space --> <Rule Id="SA1004" Action="Warning"/> <!-- Documentation lines should begin with single space -->
<Rule Id="SA1005" Action="Warning"/> <!-- Single line comments should begin with single space --> <Rule Id="SA1005" Action="None"/> <!-- Single line comments should begin with single space -->
<Rule Id="SA1006" Action="Warning"/> <!-- Preprocessor keywords should not be preceded by space --> <Rule Id="SA1006" Action="Warning"/> <!-- Preprocessor keywords should not be preceded by space -->
<Rule Id="SA1007" Action="Warning"/> <!-- Operator keyword should be followed by space --> <Rule Id="SA1007" Action="Warning"/> <!-- Operator keyword should be followed by space -->
<Rule Id="SA1008" Action="None"/> <!-- Opening parenthesis should be spaced correctly --> <Rule Id="SA1008" Action="None"/> <!-- Opening parenthesis should be spaced correctly -->
@ -30,41 +31,34 @@
<Rule Id="SA1020" Action="Warning"/> <!-- Increment decrement symbols should be spaced correctly --> <Rule Id="SA1020" Action="Warning"/> <!-- Increment decrement symbols should be spaced correctly -->
<Rule Id="SA1021" Action="Warning"/> <!-- Negative signs should be spaced correctly --> <Rule Id="SA1021" Action="Warning"/> <!-- Negative signs should be spaced correctly -->
<Rule Id="SA1022" Action="Warning"/> <!-- Positive signs should be spaced correctly --> <Rule Id="SA1022" Action="Warning"/> <!-- Positive signs should be spaced correctly -->
<Rule Id="SA1023" <Rule Id="SA1023" Action="Warning"/> <!-- Dereference and access of symbols should be spaced correctly -->
Action="Warning"/> <!-- Dereference and access of symbols should be spaced correctly -->
<Rule Id="SA1024" Action="Warning"/> <!-- Colons should be spaced correctly --> <Rule Id="SA1024" Action="Warning"/> <!-- Colons should be spaced correctly -->
<Rule Id="SA1025" Action="None"/> <!-- Code should not contain multiple whitespace in a row --> <Rule Id="SA1025" Action="None"/> <!-- Code should not contain multiple whitespace in a row -->
<Rule Id="SA1026" <Rule Id="SA1026" Action="Warning"/> <!-- Code should not contain space after new or stackalloc keyword in implicitly typed array allocation -->
Action="Warning"/> <!-- Code should not contain space after new or stackalloc keyword in implicitly typed array allocation -->
<Rule Id="SA1027" Action="Warning"/> <!-- Use tabs correctly --> <Rule Id="SA1027" Action="Warning"/> <!-- Use tabs correctly -->
<Rule Id="SA1028" Action="Warning"/> <!-- Code should not contain trailing whitespace --> <Rule Id="SA1028" Action="Warning"/> <!-- Code should not contain trailing whitespace -->
</Rules> </Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.ReadabilityRules"> <Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.ReadabilityRules">
<Rule Id="SA1100" <Rule Id="SA1100" Action="Warning"/> <!-- Do not prefix calls with base unless local implementation exists -->
Action="Warning"/> <!-- Do not prefix calls with base unless local implementation exists -->
<Rule Id="SA1101" Action="None"/> <!-- Prefix local calls with this --> <Rule Id="SA1101" Action="None"/> <!-- Prefix local calls with this -->
<Rule Id="SA1102" Action="Warning"/> <!-- Query clause should follow previous clause --> <Rule Id="SA1102" Action="Warning"/> <!-- Query clause should follow previous clause -->
<Rule Id="SA1103" <Rule Id="SA1103" Action="Warning"/> <!-- Query clauses should be on separate lines or all on one line -->
Action="Warning"/> <!-- Query clauses should be on separate lines or all on one line --> <Rule Id="SA1104" Action="Warning"/> <!-- Query clause should begin on new line when previous clause spans multiple lines -->
<Rule Id="SA1104" <Rule Id="SA1105" Action="Warning"/> <!-- Query clauses spanning multiple lines should begin on own line -->
Action="Warning"/> <!-- Query clause should begin on new line when previous clause spans multiple lines -->
<Rule Id="SA1105"
Action="Warning"/> <!-- Query clauses spanning multiple lines should begin on own line -->
<Rule Id="SA1106" Action="Warning"/> <!-- Code should not contain empty statements --> <Rule Id="SA1106" Action="Warning"/> <!-- Code should not contain empty statements -->
<Rule Id="SA1107" Action="Warning"/> <!-- Code should not contain multiple statements on one line --> <Rule Id="SA1107" Action="Warning"/> <!-- Code should not contain multiple statements on one line -->
<Rule Id="SA1108" Action="Warning"/> <!-- Block statements should not contain embedded comments --> <Rule Id="SA1108" Action="Warning"/> <!-- Block statements should not contain embedded comments -->
<Rule Id="SA1109" Action="Warning"/> <!-- Block statements should not contain embedded regions --> <Rule Id="SA1109" Action="Warning"/> <!-- Block statements should not contain embedded regions -->
<Rule Id="SA1110" <Rule Id="SA1110" Action="Warning"/> <!-- Opening parenthesis or bracket should be on declaration line -->
Action="Warning"/> <!-- Opening parenthesis or bracket should be on declaration line -->
<Rule Id="SA1111" Action="Warning"/> <!-- Closing parenthesis should be on line of last parameter --> <Rule Id="SA1111" Action="Warning"/> <!-- Closing parenthesis should be on line of last parameter -->
<Rule Id="SA1112" <Rule Id="SA1112" Action="Warning"/> <!-- Closing parenthesis should be on line of opening parenthesis -->
Action="Warning"/> <!-- Closing parenthesis should be on line of opening parenthesis -->
<Rule Id="SA1113" Action="None"/> <!-- Comma should be on the same line as previous parameter --> <Rule Id="SA1113" Action="None"/> <!-- Comma should be on the same line as previous parameter -->
<Rule Id="SA1114" Action="Warning"/> <!-- Parameter list should follow declaration --> <Rule Id="SA1114" Action="Warning"/> <!-- Parameter list should follow declaration -->
<Rule Id="SA1115" Action="Warning"/> <!-- Parameter should follow comma --> <Rule Id="SA1115" Action="Warning"/> <!-- Parameter should follow comma -->
<Rule Id="SA1116" Action="Warning"/> <!-- Split parameters should start on line after declaration --> <Rule Id="SA1116" Action="Warning"/> <!-- Split parameters should start on line after declaration -->
<Rule Id="SA1117" Action="None"/> <!-- Parameters should be on same line or separate lines --> <Rule Id="SA1117" Action="None"/> <!-- Parameters should be on same line or separate lines -->
<Rule Id="SA1118" Action="None"/> <!-- Parameter should not span multiple lines --> <Rule Id="SA1118" Action="Warning"/> <!-- Parameter should not span multiple lines -->
<Rule Id="SA1120" Action="None"/> <!-- Comments should contain text --> <Rule Id="SA1120" Action="None"/> <!-- Comments should contain text -->
<Rule Id="SA1121" Action="Warning"/> <!-- Use built-in type alias --> <Rule Id="SA1121" Action="Warning"/> <!-- Use built-in type alias -->
<Rule Id="SA1122" Action="Warning"/> <!-- Use string.Empty for empty strings --> <Rule Id="SA1122" Action="Warning"/> <!-- Use string.Empty for empty strings -->
@ -79,13 +73,14 @@
<Rule Id="SA1131" Action="Warning"/> <!-- Use readable conditions --> <Rule Id="SA1131" Action="Warning"/> <!-- Use readable conditions -->
<Rule Id="SA1132" Action="Warning"/> <!-- Do not combine fields --> <Rule Id="SA1132" Action="Warning"/> <!-- Do not combine fields -->
<Rule Id="SA1133" Action="Warning"/> <!-- Do not combine attributes --> <Rule Id="SA1133" Action="Warning"/> <!-- Do not combine attributes -->
<Rule Id="SA1134" Action="Warning"/> <!-- Attributes should not share line --> <Rule Id="SA1134" Action="None"/> <!-- Attributes should not share line -->
<Rule Id="SA1135" Action="Warning"/> <!-- Using directives should be qualified --> <Rule Id="SA1135" Action="Warning"/> <!-- Using directives should be qualified -->
<Rule Id="SA1136" Action="Warning"/> <!-- Enum values should be on separate lines --> <Rule Id="SA1136" Action="Warning"/> <!-- Enum values should be on separate lines -->
<Rule Id="SA1137" Action="Warning"/> <!-- Elements should have the same indentation --> <Rule Id="SA1137" Action="Warning"/> <!-- Elements should have the same indentation -->
<Rule Id="SA1139" Action="Warning"/> <!-- Use literal suffix notation instead of casting --> <Rule Id="SA1139" Action="Warning"/> <!-- Use literal suffix notation instead of casting -->
<Rule Id="SX1101" Action="Warning"/> <!-- Do not prefix local calls with 'this.' --> <Rule Id="SX1101" Action="Warning"/> <!-- Do not prefix local calls with 'this.' -->
</Rules> </Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.OrderingRules"> <Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.OrderingRules">
<Rule Id="SA1200" Action="None"/> <!-- Using directives should be placed correctly --> <Rule Id="SA1200" Action="None"/> <!-- Using directives should be placed correctly -->
<Rule Id="SA1201" Action="Warning"/> <!-- Elements should appear in the correct order --> <Rule Id="SA1201" Action="Warning"/> <!-- Elements should appear in the correct order -->
@ -95,87 +90,79 @@
<Rule Id="SA1205" Action="Warning"/> <!-- Partial elements should declare access --> <Rule Id="SA1205" Action="Warning"/> <!-- Partial elements should declare access -->
<Rule Id="SA1206" Action="Warning"/> <!-- Declaration keywords should follow order --> <Rule Id="SA1206" Action="Warning"/> <!-- Declaration keywords should follow order -->
<Rule Id="SA1207" Action="Warning"/> <!-- Protected should come before internal --> <Rule Id="SA1207" Action="Warning"/> <!-- Protected should come before internal -->
<Rule Id="SA1208" <Rule Id="SA1208" Action="Warning"/> <!-- System using directives should be placed before other using directives -->
Action="Warning"/> <!-- System using directives should be placed before other using directives --> <Rule Id="SA1209" Action="Warning"/> <!-- Using alias directives should be placed after other using directives -->
<Rule Id="SA1209" <Rule Id="SA1210" Action="Warning"/> <!-- Using directives should be ordered alphabetically by namespace -->
Action="Warning"/> <!-- Using alias directives should be placed after other using directives --> <Rule Id="SA1211" Action="Warning"/> <!-- Using alias directives should be ordered alphabetically by alias name -->
<Rule Id="SA1210"
Action="Warning"/> <!-- Using directives should be ordered alphabetically by namespace -->
<Rule Id="SA1211"
Action="Warning"/> <!-- Using alias directives should be ordered alphabetically by alias name -->
<Rule Id="SA1212" Action="Warning"/> <!-- Property accessors should follow order --> <Rule Id="SA1212" Action="Warning"/> <!-- Property accessors should follow order -->
<Rule Id="SA1213" Action="Warning"/> <!-- Event accessors should follow order --> <Rule Id="SA1213" Action="Warning"/> <!-- Event accessors should follow order -->
<Rule Id="SA1214" Action="Warning"/> <!-- Readonly fields should appear before non-readonly fields --> <Rule Id="SA1214" Action="Warning"/> <!-- Readonly fields should appear before non-readonly fields -->
<Rule Id="SA1216" <Rule Id="SA1216" Action="Warning"/> <!-- Using static directives should be placed at the correct location -->
Action="Warning"/> <!-- Using static directives should be placed at the correct location -->
<Rule Id="SA1217" Action="Warning"/> <!-- Using static directives should be ordered alphabetically --> <Rule Id="SA1217" Action="Warning"/> <!-- Using static directives should be ordered alphabetically -->
</Rules> </Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.NamingRules"> <Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.NamingRules">
<Rule Id="SA1300" Action="Warning"/> <!-- Element should begin with upper-case letter --> <Rule Id="SA1300" Action="Warning"/> <!-- Element should begin with upper-case letter -->
<Rule Id="SA1301" Action="Warning"/> <!-- Element should begin with lower-case letter --> <Rule Id="SA1301" Action="Warning"/> <!-- Element should begin with lower-case letter -->
<Rule Id="SA1302" Action="Warning"/> <!-- Interface names should begin with I --> <Rule Id="SA1302" Action="Warning"/> <!-- Interface names should begin with I -->
<Rule Id="SA1303" Action="Warning"/> <!-- Const field names should begin with upper-case letter --> <Rule Id="SA1303" Action="Warning"/> <!-- Const field names should begin with upper-case letter -->
<Rule Id="SA1304" <Rule Id="SA1304" Action="Warning"/> <!-- Non-private readonly fields should begin with upper-case letter -->
Action="Warning"/> <!-- Non-private readonly fields should begin with upper-case letter -->
<Rule Id="SA1305" Action="None"/> <!-- Field names should not use Hungarian notation --> <Rule Id="SA1305" Action="None"/> <!-- Field names should not use Hungarian notation -->
<Rule Id="SA1306" Action="Warning"/> <!-- Field names should begin with lower-case letter --> <Rule Id="SA1306" Action="Warning"/> <!-- Field names should begin with lower-case letter -->
<Rule Id="SA1307" Action="Warning"/> <!-- Accessible fields should begin with upper-case letter --> <Rule Id="SA1307" Action="Warning"/> <!-- Accessible fields should begin with upper-case letter -->
<Rule Id="SA1308" Action="Warning"/> <!-- Variable names should not be prefixed --> <Rule Id="SA1308" Action="Warning"/> <!-- Variable names should not be prefixed -->
<Rule Id="SA1309" Action="None"/> <!-- Field names should not begin with underscore --> <Rule Id="SA1309" Action="None"/> <!-- Field names should not begin with underscore -->
<Rule Id="SA1310" Action="None"/> <!-- Field names should not contain underscore --> <Rule Id="SA1310" Action="None"/> <!-- Field names should not contain underscore -->
<Rule Id="SA1311" <Rule Id="SA1311" Action="Warning"/> <!-- Static readonly fields should begin with upper-case letter -->
Action="Warning"/> <!-- Static readonly fields should begin with upper-case letter -->
<Rule Id="SA1312" Action="Warning"/> <!-- Variable names should begin with lower-case letter --> <Rule Id="SA1312" Action="Warning"/> <!-- Variable names should begin with lower-case letter -->
<Rule Id="SA1313" Action="None"/> <!-- Parameter names should begin with lower-case letter --> <Rule Id="SA1313" Action="None"/> <!-- Parameter names should begin with lower-case letter -->
<Rule Id="SA1314" Action="Warning"/> <!-- Type parameter names should begin with T --> <Rule Id="SA1314" Action="Warning"/> <!-- Type parameter names should begin with T -->
<Rule Id="SX1309" Action="Warning"/> <!-- Field names should begin with underscore --> <Rule Id="SX1309" Action="Warning"/> <!-- Field names should begin with underscore -->
<Rule Id="SX1309S" Action="Warning"/> <!-- Static field names should begin with underscore --> <Rule Id="SX1309S" Action="Warning"/> <!-- Static field names should begin with underscore -->
</Rules> </Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.MaintainabilityRules"> <Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.MaintainabilityRules">
<Rule Id="SA1119" Action="Warning"/> <!-- Statement should not use unnecessary parenthesis --> <Rule Id="SA1119" Action="Warning"/> <!-- Statement should not use unnecessary parenthesis -->
<Rule Id="SA1400" Action="Warning"/> <!-- Access modifier should be declared --> <Rule Id="SA1400" Action="Warning"/> <!-- Access modifier should be declared -->
<Rule Id="SA1401" Action="Warning"/> <!-- Fields should be private --> <Rule Id="SA1401" Action="Warning"/> <!-- Fields should be private -->
<Rule Id="SA1402" Action="None"/> <!-- File may only contain a single type --> <Rule Id="SA1402" Action="Warning"/> <!-- File may only contain a single type -->
<Rule Id="SA1403" Action="Warning"/> <!-- File may only contain a single namespace --> <Rule Id="SA1403" Action="Warning"/> <!-- File may only contain a single namespace -->
<Rule Id="SA1404" Action="Warning"/> <!-- Code analysis suppression should have justification --> <Rule Id="SA1404" Action="Warning"/> <!-- Code analysis suppression should have justification -->
<Rule Id="SA1405" Action="Warning"/> <!-- Debug.Assert should provide message text --> <Rule Id="SA1405" Action="Warning"/> <!-- Debug.Assert should provide message text -->
<Rule Id="SA1406" Action="Warning"/> <!-- Debug.Fail should provide message text --> <Rule Id="SA1406" Action="Warning"/> <!-- Debug.Fail should provide message text -->
<Rule Id="SA1407" Action="Warning"/> <!-- Arithmetic expressions should declare precedence --> <Rule Id="SA1407" Action="None"/> <!-- Arithmetic expressions should declare precedence -->
<Rule Id="SA1408" Action="Warning"/> <!-- Conditional expressions should declare precedence --> <Rule Id="SA1408" Action="Warning"/> <!-- Conditional expressions should declare precedence -->
<Rule Id="SA1409" Action="Warning"/> <!-- Remove unnecessary code --> <Rule Id="SA1409" Action="Warning"/> <!-- Remove unnecessary code -->
<Rule Id="SA1410" Action="Warning"/> <!-- Remove delegate parenthesis when possible --> <Rule Id="SA1410" Action="Warning"/> <!-- Remove delegate parenthesis when possible -->
<Rule Id="SA1411" <Rule Id="SA1411" Action="Warning"/> <!-- Attribute constructor should not use unnecessary parenthesis -->
Action="Warning"/> <!-- Attribute constructor should not use unnecessary parenthesis -->
<Rule Id="SA1412" Action="None"/> <!-- Store files as UTF-8 with byte order mark --> <Rule Id="SA1412" Action="None"/> <!-- Store files as UTF-8 with byte order mark -->
<Rule Id="SA1413" Action="None"/> <!-- Use trailing comma in multi-line initializers --> <Rule Id="SA1413" Action="None"/> <!-- Use trailing comma in multi-line initializers -->
</Rules> </Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.LayoutRules"> <Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.LayoutRules">
<Rule Id="SA1500" Action="None"/> <!-- Braces for multi-line statements should not share line --> <Rule Id="SA1500" Action="None"/> <!-- Braces for multi-line statements should not share line -->
<Rule Id="SA1501" Action="Warning"/> <!-- Statement should not be on a single line --> <Rule Id="SA1501" Action="Warning"/> <!-- Statement should not be on a single line -->
<Rule Id="SA1502" Action="None"/> <!-- Element should not be on a single line --> <Rule Id="SA1502" Action="None"/> <!-- Element should not be on a single line -->
<Rule Id="SA1503" Action="Warning"/> <!-- Braces should not be omitted --> <Rule Id="SA1503" Action="None"/> <!-- Braces should not be omitted -->
<Rule Id="SA1504" Action="Warning"/> <!-- All accessors should be single-line or multi-line --> <Rule Id="SA1504" Action="Warning"/> <!-- All accessors should be single-line or multi-line -->
<Rule Id="SA1505" Action="Warning"/> <!-- Opening braces should not be followed by blank line --> <Rule Id="SA1505" Action="Warning"/> <!-- Opening braces should not be followed by blank line -->
<Rule Id="SA1506" <Rule Id="SA1506" Action="Warning"/> <!-- Element documentation headers should not be followed by blank line -->
Action="Warning"/> <!-- Element documentation headers should not be followed by blank line -->
<Rule Id="SA1507" Action="Warning"/> <!-- Code should not contain multiple blank lines in a row --> <Rule Id="SA1507" Action="Warning"/> <!-- Code should not contain multiple blank lines in a row -->
<Rule Id="SA1508" Action="Warning"/> <!-- Closing braces should not be preceded by blank line --> <Rule Id="SA1508" Action="Warning"/> <!-- Closing braces should not be preceded by blank line -->
<Rule Id="SA1509" Action="Warning"/> <!-- Opening braces should not be preceded by blank line --> <Rule Id="SA1509" Action="Warning"/> <!-- Opening braces should not be preceded by blank line -->
<Rule Id="SA1510" <Rule Id="SA1510" Action="Warning"/> <!-- Chained statement blocks should not be preceded by blank line -->
Action="Warning"/> <!-- Chained statement blocks should not be preceded by blank line -->
<Rule Id="SA1511" Action="Warning"/> <!-- While-do footer should not be preceded by blank line --> <Rule Id="SA1511" Action="Warning"/> <!-- While-do footer should not be preceded by blank line -->
<Rule Id="SA1512" Action="Warning"/> <!-- Single-line comments should not be followed by blank line --> <Rule Id="SA1512" Action="Warning"/> <!-- Single-line comments should not be followed by blank line -->
<Rule Id="SA1513" Action="Warning"/> <!-- Closing brace should be followed by blank line --> <Rule Id="SA1513" Action="Warning"/> <!-- Closing brace should be followed by blank line -->
<Rule Id="SA1514" <Rule Id="SA1514" Action="Warning"/> <!-- Element documentation header should be preceded by blank line -->
Action="Warning"/> <!-- Element documentation header should be preceded by blank line -->
<Rule Id="SA1515" Action="Warning"/> <!-- Single-line comment should be preceded by blank line --> <Rule Id="SA1515" Action="Warning"/> <!-- Single-line comment should be preceded by blank line -->
<Rule Id="SA1516" Action="Warning"/> <!-- Elements should be separated by blank line --> <Rule Id="SA1516" Action="Warning"/> <!-- Elements should be separated by blank line -->
<Rule Id="SA1517" Action="Warning"/> <!-- Code should not contain blank lines at start of file --> <Rule Id="SA1517" Action="Warning"/> <!-- Code should not contain blank lines at start of file -->
<Rule Id="SA1518" Action="Warning"/> <!-- Use line endings correctly at end of file --> <Rule Id="SA1518" Action="Warning"/> <!-- Use line endings correctly at end of file -->
<Rule Id="SA1519" <Rule Id="SA1519" Action="Warning"/> <!-- Braces should not be omitted from multi-line child statement -->
Action="Warning"/> <!-- Braces should not be omitted from multi-line child statement -->
<Rule Id="SA1520" Action="Warning"/> <!-- Use braces consistently --> <Rule Id="SA1520" Action="Warning"/> <!-- Use braces consistently -->
</Rules> </Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.DocumentationRules"> <Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.DocumentationRules">
<Rule Id="SA1600" Action="None"/> <!-- Elements should be documented --> <Rule Id="SA1600" Action="None"/> <!-- Elements should be documented -->
<Rule Id="SA1601" Action="None"/> <!-- Partial elements should be documented --> <Rule Id="SA1601" Action="None"/> <!-- Partial elements should be documented -->
@ -186,34 +173,27 @@
<Rule Id="SA1606" Action="Warning"/> <!-- Element documentation should have summary text --> <Rule Id="SA1606" Action="Warning"/> <!-- Element documentation should have summary text -->
<Rule Id="SA1607" Action="Warning"/> <!-- Partial element documentation should have summary text --> <Rule Id="SA1607" Action="Warning"/> <!-- Partial element documentation should have summary text -->
<Rule Id="SA1608" Action="Warning"/> <!-- Element documentation should not have default summary --> <Rule Id="SA1608" Action="Warning"/> <!-- Element documentation should not have default summary -->
<Rule Id="SA1609" Action="None"/> <!-- Property documentation should have value --> <Rule Id="SA1609" Action="Warning"/> <!-- Property documentation should have value -->
<Rule Id="SA1610" Action="Warning"/> <!-- Property documentation should have value text --> <Rule Id="SA1610" Action="Warning"/> <!-- Property documentation should have value text -->
<Rule Id="SA1611" Action="None"/> <!-- Element parameters should be documented --> <Rule Id="SA1611" Action="None"/> <!-- Element parameters should be documented -->
<Rule Id="SA1612" <Rule Id="SA1612" Action="Warning"/> <!-- Element parameter documentation should match element parameters -->
Action="Warning"/> <!-- Element parameter documentation should match element parameters --> <Rule Id="SA1613" Action="Warning"/> <!-- Element parameter documentation should declare parameter name -->
<Rule Id="SA1613"
Action="Warning"/> <!-- Element parameter documentation should declare parameter name -->
<Rule Id="SA1614" Action="Warning"/> <!-- Element parameter documentation should have text --> <Rule Id="SA1614" Action="Warning"/> <!-- Element parameter documentation should have text -->
<Rule Id="SA1615" Action="None"/> <!-- Element return value should be documented --> <Rule Id="SA1615" Action="None"/> <!-- Element return value should be documented -->
<Rule Id="SA1616" Action="Warning"/> <!-- Element return value documentation should have text --> <Rule Id="SA1616" Action="Warning"/> <!-- Element return value documentation should have text -->
<Rule Id="SA1617" Action="Warning"/> <!-- Void return value should not be documented --> <Rule Id="SA1617" Action="Warning"/> <!-- Void return value should not be documented -->
<Rule Id="SA1618" Action="None"/> <!-- Generic type parameters should be documented --> <Rule Id="SA1618" Action="None"/> <!-- Generic type parameters should be documented -->
<Rule Id="SA1619" <Rule Id="SA1619" Action="None"/> <!-- Generic type parameters should be documented partial class -->
Action="None"/> <!-- Generic type parameters should be documented partial class --> <Rule Id="SA1620" Action="Warning"/> <!-- Generic type parameter documentation should match type parameters -->
<Rule Id="SA1620" <Rule Id="SA1621" Action="Warning"/> <!-- Generic type parameter documentation should declare parameter name -->
Action="Warning"/> <!-- Generic type parameter documentation should match type parameters -->
<Rule Id="SA1621"
Action="Warning"/> <!-- Generic type parameter documentation should declare parameter name -->
<Rule Id="SA1622" Action="Warning"/> <!-- Generic type parameter documentation should have text --> <Rule Id="SA1622" Action="Warning"/> <!-- Generic type parameter documentation should have text -->
<Rule Id="SA1623" Action="None"/> <!-- Property summary documentation should match accessors --> <Rule Id="SA1623" Action="Warning"/> <!-- Property summary documentation should match accessors -->
<Rule Id="SA1624" <Rule Id="SA1624" Action="Warning"/> <!-- Property summary documentation should omit accessor with restricted access -->
Action="Warning"/> <!-- Property summary documentation should omit accessor with restricted access -->
<Rule Id="SA1625" Action="Warning"/> <!-- Element documentation should not be copied and pasted --> <Rule Id="SA1625" Action="Warning"/> <!-- Element documentation should not be copied and pasted -->
<Rule Id="SA1626" <Rule Id="SA1626" Action="Warning"/> <!-- Single-line comments should not use documentation style slashes -->
Action="Warning"/> <!-- Single-line comments should not use documentation style slashes -->
<Rule Id="SA1627" Action="Warning"/> <!-- Documentation text should not be empty --> <Rule Id="SA1627" Action="Warning"/> <!-- Documentation text should not be empty -->
<Rule Id="SA1628" Action="Warning"/> <!-- Documentation text should begin with a capital letter --> <Rule Id="SA1628" Action="Warning"/> <!-- Documentation text should begin with a capital letter -->
<Rule Id="SA1629" Action="None"/> <!-- Documentation text should end with a period --> <Rule Id="SA1629" Action="None"/> <!-- Documentation text should end with a period -->
<Rule Id="SA1630" Action="Warning"/> <!-- Documentation text should contain whitespace --> <Rule Id="SA1630" Action="Warning"/> <!-- Documentation text should contain whitespace -->
<Rule Id="SA1631" Action="Warning"/> <!-- Documentation should meet character percentage --> <Rule Id="SA1631" Action="Warning"/> <!-- Documentation should meet character percentage -->
<Rule Id="SA1632" Action="Warning"/> <!-- Documentation text should meet minimum character length --> <Rule Id="SA1632" Action="Warning"/> <!-- Documentation text should meet minimum character length -->
@ -222,15 +202,12 @@
<Rule Id="SA1635" Action="Warning"/> <!-- File header should have copyright text --> <Rule Id="SA1635" Action="Warning"/> <!-- File header should have copyright text -->
<Rule Id="SA1636" Action="Warning"/> <!-- File header copyright text should match --> <Rule Id="SA1636" Action="Warning"/> <!-- File header copyright text should match -->
<Rule Id="SA1637" Action="Warning"/> <!-- File header should contain file name --> <Rule Id="SA1637" Action="Warning"/> <!-- File header should contain file name -->
<Rule Id="SA1638" <Rule Id="SA1638" Action="Warning"/> <!-- File header file name documentation should match file name -->
Action="Warning"/> <!-- File header file name documentation should match file name -->
<Rule Id="SA1639" Action="Warning"/> <!-- File header should have summary --> <Rule Id="SA1639" Action="Warning"/> <!-- File header should have summary -->
<Rule Id="SA1640" Action="Warning"/> <!-- File header should have valid company text --> <Rule Id="SA1640" Action="Warning"/> <!-- File header should have valid company text -->
<Rule Id="SA1641" Action="Warning"/> <!-- File header company name text should match --> <Rule Id="SA1641" Action="Warning"/> <!-- File header company name text should match -->
<Rule Id="SA1642" <Rule Id="SA1642" Action="Warning"/> <!-- Constructor summary documentation should begin with standard text -->
Action="Warning"/> <!-- Constructor summary documentation should begin with standard text --> <Rule Id="SA1643" Action="Warning"/> <!-- Destructor summary documentation should begin with standard text -->
<Rule Id="SA1643"
Action="Warning"/> <!-- Destructor summary documentation should begin with standard text -->
<Rule Id="SA1644" Action="Warning"/> <!-- Documentation headers should not contain blank lines --> <Rule Id="SA1644" Action="Warning"/> <!-- Documentation headers should not contain blank lines -->
<Rule Id="SA1645" Action="Warning"/> <!-- Included documentation file does not exist --> <Rule Id="SA1645" Action="Warning"/> <!-- Included documentation file does not exist -->
<Rule Id="SA1646" Action="Warning"/> <!-- Included documentation XPath does not exist --> <Rule Id="SA1646" Action="Warning"/> <!-- Included documentation XPath does not exist -->
@ -239,5 +216,6 @@
<Rule Id="SA1649" Action="Warning"/> <!-- File name should match first type name --> <Rule Id="SA1649" Action="Warning"/> <!-- File name should match first type name -->
<Rule Id="SA1650" Action="Warning"/> <!-- Element documentation should be spelled correctly --> <Rule Id="SA1650" Action="Warning"/> <!-- Element documentation should be spelled correctly -->
<Rule Id="SA1651" Action="Warning"/> <!-- Do not use placeholder elements --> <Rule Id="SA1651" Action="Warning"/> <!-- Do not use placeholder elements -->
</Rules> </Rules>
</RuleSet> </RuleSet>

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

132
build.cake Normal file
View File

@ -0,0 +1,132 @@
var target = Argument("target", "Default");
var configuration = Argument("configuration", "Release");
var pkgOutPath = $"./dist/NSExt/pkg/{configuration}";
////////////////////////////////////////////////////////////////
// Tasks
Task("Clean")
.Does(context =>
{
context.CleanDirectory(pkgOutPath);
});
Task("Build")
.IsDependentOn("Clean")
.Does(context =>
{
DotNetBuild("./NSExt.sln", new DotNetBuildSettings {
Configuration = configuration,
NoIncremental = context.HasArgument("rebuild"),
MSBuildSettings = new DotNetMSBuildSettings()
.TreatAllWarningsAs(MSBuildTreatAllWarningsAs.Error)
});
});
Task("Test")
.IsDependentOn("Build")
.Does(context =>
{
DotNetTest("./test/Spectre.Console.Tests/Spectre.Console.Tests.csproj", new DotNetTestSettings {
Configuration = configuration,
NoRestore = true,
NoBuild = true,
});
DotNetTest("./test/Spectre.Console.Cli.Tests/Spectre.Console.Cli.Tests.csproj", new DotNetTestSettings {
Configuration = configuration,
NoRestore = true,
NoBuild = true,
});
DotNetTest("./test/Spectre.Console.Analyzer.Tests/Spectre.Console.Analyzer.Tests.csproj", new DotNetTestSettings {
Configuration = configuration,
NoRestore = true,
NoBuild = true,
});
});
Task("Package")
.IsDependentOn("Build")
.Does(context =>
{
context.DotNetPack("./NSExt.sln", new DotNetPackSettings {
Configuration = configuration,
NoRestore = true,
NoBuild = true,
OutputDirectory = pkgOutPath,
MSBuildSettings = new DotNetMSBuildSettings()
.TreatAllWarningsAs(MSBuildTreatAllWarningsAs.Error)
});
});
Task("Publish-GitHub")
.WithCriteria(ctx => BuildSystem.IsRunningOnGitHubActions, "Not running on GitHub Actions")
.IsDependentOn("Package")
.Does(context =>
{
var apiKey = Argument<string>("github-key", null);
if(string.IsNullOrWhiteSpace(apiKey)) {
throw new CakeException("No GitHub API key was provided.");
}
// Publish to GitHub Packages
var exitCode = 0;
foreach(var file in context.GetFiles("./.artifacts/*.nupkg"))
{
context.Information("Publishing {0}...", file.GetFilename().FullPath);
exitCode += StartProcess("dotnet",
new ProcessSettings {
Arguments = new ProcessArgumentBuilder()
.Append("gpr")
.Append("push")
.AppendQuoted(file.FullPath)
.AppendSwitchSecret("-k", " ", apiKey)
}
);
}
if(exitCode != 0)
{
throw new CakeException("Could not push GitHub packages.");
}
});
Task("Publish-NuGet")
// .WithCriteria(ctx => BuildSystem.IsRunningOnGitHubActions, "Not running on GitHub Actions")
.IsDependentOn("Package")
.Does(context =>
{
var apiKey = Argument<string>("nuget-key", null);
if(string.IsNullOrWhiteSpace(apiKey)) {
throw new CakeException("No NuGet API key was provided.");
}
// Publish to GitHub Packages
foreach(var file in context.GetFiles($"{pkgOutPath}/*.*nupkg"))
{
context.Information("Publishing {0}...", file.GetFilename().FullPath);
DotNetNuGetPush(file.FullPath, new DotNetNuGetPushSettings
{
Source = "https://api.nuget.org/v3/index.json",
ApiKey = apiKey,
SkipDuplicate = true
});
}
});
////////////////////////////////////////////////////////////////
// Targets
Task("Publish")
//.IsDependentOn("Publish-GitHub")
.IsDependentOn("Publish-NuGet");
Task("Default")
.IsDependentOn("Package");
////////////////////////////////////////////////////////////////
// Execution
RunTarget(target)

View File

@ -1,47 +0,0 @@
<Project>
<PropertyGroup>
<CodeAnalysisRuleSet>$(SolutionDir)/build/stylecop.analyzers.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup>
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<MSBuildTreatWarningsAsErrors>true</MSBuildTreatWarningsAsErrors>
<MSBuildWarningsAsErrors>true</MSBuildWarningsAsErrors>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors>true</WarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<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.13.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="SonarAnalyzer.CSharp" Version="10.7.0.110445">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="AsyncSuffixAnalyzer" Version="1.0.6285.32977">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="AsyncFixer" Version="1.6.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="ProductiveRage.SealedClassVerification.Net" Version="1.7.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<!-- <PackageReference Include="NSCodeAnalysis" Version="1.0.1-alpha.0.2">-->
<!-- <PrivateAssets>all</PrivateAssets>-->
<!-- <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>-->
<!-- </PackageReference>-->
</ItemGroup>
</Project>

View File

@ -1,10 +0,0 @@
<Project>
<Target Name="AfterTargetsBuild" AfterTargets="Build">
<ItemGroup>
<PackageReferenceFiles
Condition="%(PackageReference.CopyToOutputDirectory) != ''"
Include="$(NugetPackageRoot)\%(PackageReference.Identity)\%(PackageReference.Version)\%(PackageReference.CopyToOutputDirectory)" />
</ItemGroup>
<Copy SourceFiles="@(PackageReferenceFiles)" DestinationFolder="$(OutDir)" />
</Target>
</Project>

View File

@ -1,11 +0,0 @@
<Project>
<Target Name="MyTarget" AfterTargets="MinVer">
<PropertyGroup>
<AssemblyVersion>$(MinVerMajor).$(MinVerMinor).$(MinVerPatch)</AssemblyVersion>
<FileVersion>$(MinVerMajor).$(MinVerMinor).$(MinVerPatch)</FileVersion>
<PackageVersion>$(MinVerVersion)</PackageVersion>
<ProductVersion>$(MinVerVersion)</ProductVersion>
<Version>$(MinVerVersion)</Version>
</PropertyGroup>
</Target>
</Project>

View File

@ -1,20 +0,0 @@
<Project>
<PropertyGroup>
<AssemblyOriginatorKeyFile>../../../key.snk</AssemblyOriginatorKeyFile>
<DelaySign>false</DelaySign>
<EmbedAllSources>true</EmbedAllSources>
<IncludeSymbols>true</IncludeSymbols>
<IsPackable>true</IsPackable>
<PackageIcon>logo.png</PackageIcon>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageTags>extensions</PackageTags>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<SignAssembly>true</SignAssembly>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
<ItemGroup>
<None Include="../../../assets/logo.png" Pack="true" PackagePath="/"/>
<None Include="../../../README.md" Pack="true" PackagePath="/"/>
</ItemGroup>
</Project>

View File

@ -1,24 +0,0 @@
<Project>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Command="dotnet tool restore" StdOutEncoding="utf-8"/>
<Exec Condition="!Exists('$(SolutionDir)/assets/res/Ln.resx')" WorkingDirectory="$(SolutionDir)/scripts"
Command="dotnet t4 ./gen.resx.tt -o ../assets/res/Ln.resx"
StdOutEncoding="utf-8"/>
<Exec Condition="!Exists('$(SolutionDir)/dist/backend/$(ProjectName)/Ln.cs')"
WorkingDirectory="$(SolutionDir)/scripts"
Command="dotnet t4 ./gen.cs.tt -o ../dist/backend/$(ProjectName)/Ln.cs"
StdOutEncoding="utf-8"/>
</Target>
<ItemGroup>
<None Include="$(SolutionDir)/assets/res/Statements.ln">
<Link>Languages/Statements.ln</Link>
</None>
<EmbeddedResource Include="$(SolutionDir)/assets/res/Ln.resx">
<Link>Languages/Ln.resx</Link>
<Generator>PublicResXFileCodeGenerator</Generator>
</EmbeddedResource>
<Compile Include="$(SolutionDir)/dist/backend/$(ProjectName)/Ln.Designer.cs">
<Link>Languages/Ln.Designer.cs</Link>
</Compile>
</ItemGroup>
</Project>

3
code-format.cmd Normal file
View File

@ -0,0 +1,3 @@
dot rbom -w
dot trim -w
dot tolf -w

View File

@ -1 +0,0 @@
docker

View File

@ -1,182 +0,0 @@
# 约定式提交 1.0.0
## [](#概述)概述
约定式提交规范是一种基于提交信息的轻量级约定。 它提供了一组简单规则来创建清晰的提交历史; 这更有利于编写自动化工具。 通过在提交信息中描述功能、修复和破坏性变更, 使这种惯例与 [SemVer](http://semver.org/lang/zh-CN) 相互对应。
提交说明的结构如下所示:
* * *
原文:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
译文:
<类型>[可选 范围]: <描述>
[可选 正文]
[可选 脚注]
* * *
提交说明包含了下面的结构化元素,以向类库使用者表明其意图:
1. **fix:** _类型_`fix` 的提交表示在代码库中修复了一个 bug这和语义化版本中的 [`PATCH`](https://semver.org/lang/zh-CN/#%E6%91%98%E8%A6%81) 相对应)。
2. **feat:** _类型_`feat` 的提交表示在代码库中新增了一个功能(这和语义化版本中的 [`MINOR`](https://semver.org/lang/zh-CN/#%E6%91%98%E8%A6%81) 相对应)。
3. **BREAKING CHANGE:** 在脚注中包含 `BREAKING CHANGE:`<类型>(范围) 后面有一个 `!` 的提交,表示引入了破坏性 API 变更(这和语义化版本中的 [`MAJOR`](https://semver.org/lang/zh-CN/#%E6%91%98%E8%A6%81) 相对应)。 破坏性变更可以是任意 _类型_ 提交的一部分。
4. 除 `fix:``feat:` 之外,也可以使用其它提交 _类型_ ,例如 [@commitlint/config-conventional](https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional)(基于 [Angular 约定](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines))中推荐的 `build:``chore:``ci:``docs:``style:``refactor:``perf:``test:`,等等。
* build: 用于修改项目构建系统,例如修改依赖库、外部接口或者升级 Node 版本等;
* chore: 用于对非业务性代码进行修改,例如修改构建流程或者工具配置等;
* ci: 用于修改持续集成流程,例如修改 Travis、Jenkins 等工作流配置;
* docs: 用于修改文档,例如修改 README 文件、API 文档等;
* style: 用于修改代码的样式,例如调整缩进、空格、空行等;
* refactor: 用于重构代码,例如修改代码结构、变量名、函数名等但不修改功能逻辑;
* perf: 用于优化性能,例如提升代码的性能、减少内存占用等;
* test: 用于修改测试用例,例如添加、删除、修改代码的测试用例等。
5. 脚注中除了 `BREAKING CHANGE: <description>` ,其它条目应该采用类似 [git trailer format](https://git-scm.com/docs/git-interpret-trailers) 这样的惯例。
其它提交类型在约定式提交规范中并没有强制限制,并且在语义化版本中没有隐式影响(除非它们包含 BREAKING CHANGE。 可以为提交类型添加一个围在圆括号内的范围,以为其提供额外的上下文信息。例如 `feat(parser): adds ability to parse arrays.`
## [](#示例)示例
### [](#包含了描述并且脚注中有破坏性变更的提交说明)包含了描述并且脚注中有破坏性变更的提交说明
feat: allow provided config object to extend other configs
BREAKING CHANGE: `extends` key in config file is now used for extending other config files
### [](#包含了--字符以提醒注意破坏性变更的提交说明)包含了 `!` 字符以提醒注意破坏性变更的提交说明
feat!: send an email to the customer when a product is shipped
### [](#包含了范围和破坏性变更--的提交說明)包含了范围和破坏性变更 `!` 的提交說明
feat(api)!: send an email to the customer when a product is shipped
### [](#包含了--和-breaking-change-脚注的提交说明)包含了 `!` 和 BREAKING CHANGE 脚注的提交说明
chore!: drop support for Node 6
BREAKING CHANGE: use JavaScript features not available in Node 6.
### [](#不包含正文的提交说明)不包含正文的提交说明
docs: correct spelling of CHANGELOG
### [](#包含范围的提交说明)包含范围的提交说明
feat(lang): add polish language
### [](#包含多行正文和多行脚注的提交说明)包含多行正文和多行脚注的提交说明
fix: prevent racing of requests
Introduce a request id and a reference to latest request. Dismiss
incoming responses other than from latest request.
Remove timeouts which were used to mitigate the racing issue but are
obsolete now.
Reviewed-by: Z
Refs: #123
## [](#约定式提交规范)约定式提交规范
本文中的关键词 “必须MUST”、“禁止MUST NOT”、“必要REQUIRED”、“应当SHALL”、“不应当SHALL NOT”、“应该SHOULD”、“不应该SHOULD NOT”、“推荐RECOMMENDED”、“可以MAY” 和 “可选OPTIONAL” ,其相关解释参考 [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) 。
1. 每个提交都**必须**使用类型字段前缀,它由一个名词构成,诸如 `feat``fix` 其后接**可选的**范围字段,**可选的** `!`,以及**必要的**冒号(英文半角)和空格。
2. 当一个提交为应用或类库实现了新功能时,**必须**使用 `feat` 类型。
3. 当一个提交为应用修复了 bug 时,**必须**使用 `fix` 类型。
4. 范围字段**可以**跟随在类型字段后面。范围**必须**是一个描述某部分代码的名词,并用圆括号包围,例如: `fix(parser):`
5. 描述字段**必须**直接跟在 <类型>(范围) 前缀的冒号和空格之后。 描述指的是对代码变更的简短总结,例如: _fix: array parsing issue when multiple spaces were contained in string_
6. 在简短描述之后,**可以**编写较长的提交正文,为代码变更提供额外的上下文信息。正文**必须**起始于描述字段结束的一个空行后。
7. 提交的正文内容自由编写,并**可以**使用空行分隔不同段落。
8. 在正文结束的一个空行之后,**可以**编写一行或多行脚注。每行脚注都**必须**包含 一个令牌token后面紧跟 `:<space>``<space>#` 作为分隔符,后面再紧跟令牌的值(受 [git trailer convention](https://git-scm.com/docs/git-interpret-trailers) 启发)。
9. 脚注的令牌**必须**使用 `-` 作为连字符,比如 `Acked-by` (这样有助于 区分脚注和多行正文)。有一种例外情况就是 `BREAKING CHANGE`,它**可以**被认为是一个令牌。
10. 脚注的值**可以**包含空格和换行,值的解析过程**必须**直到下一个脚注的令牌/分隔符出现为止。
11. 破坏性变更**必须**在提交信息中标记出来,要么在 <类型>(范围) 前缀中标记,要么作为脚注的一项。
12. 包含在脚注中时,破坏性变更**必须**包含大写的文本 `BREAKING CHANGE`,后面紧跟着冒号、空格,然后是描述,例如: _BREAKING CHANGE: environment variables now take precedence over config files_
13. 包含在 <类型>(范围) 前缀时,破坏性变更**必须**通过把 `!` 直接放在 `:` 前面标记出来。 如果使用了 `!`,那么脚注中**可以**不写 `BREAKING CHANGE:` 同时提交信息的描述中**应该**用来描述破坏性变更。
14. 在提交说明中,**可以**使用 `feat``fix` 之外的类型比如_docs: updated ref docs._ 。
15. 工具的实现必须**不区分**大小写地解析构成约定式提交的信息单元,只有 `BREAKING CHANGE` **必须**是大写的。
16. BREAKING-CHANGE 作为脚注的令牌时**必须**是 BREAKING CHANGE 的同义词。
## [](#为什么使用约定式提交)为什么使用约定式提交
* 自动化生成 CHANGELOG。
* 基于提交的类型,自动决定语义化的版本变更。
* 向同事、公众与其他利益关系者传达变化的性质。
* 触发构建和部署流程。
* 让人们探索一个更加结构化的提交历史,以便降低对你的项目做出贡献的难度。
## [](#faq)FAQ
### [](#在初始开发阶段我该如何处理提交说明)在初始开发阶段我该如何处理提交说明?
我们建议你按照假设你已发布了产品那样来处理。因为通常总 _有人_ 使用你的软件,即便那是你软件开发的同事们。他们会希望知道诸如修复了什么、哪里不兼容等信息。
### [](#提交标题中的类型是大写还是小写)提交标题中的类型是大写还是小写?
大小写都可以,但最好是一致的。
### [](#如果提交符合多种类型我该如何操作)如果提交符合多种类型我该如何操作?
回退并尽可能创建多次提交。约定式提交的好处之一是能够促使我们做出更有组织的提交和 PR。
### [](#这不会阻碍快速开发和迭代吗)这不会阻碍快速开发和迭代吗?
它阻碍的是以杂乱无章的方式快速前进。它助你能在横跨多个项目以及和多个贡献者协作时长期地快速演进。
### [](#约定式提交会让开发者受限于提交的类型吗因为他们会想着已提供的类型)约定式提交会让开发者受限于提交的类型吗(因为他们会想着已提供的类型)?
约定式提交鼓励我们更多地使用某些类型的提交,比如 `fixes`。除此之外,约定式提交的灵活性也允许你的团队使用自己的类型,并随着时间的推移更改这些类型。
### [](#这和-semver-有什么关联呢)这和 SemVer 有什么关联呢?
`fix` 类型提交应当对应到 `PATCH` 版本。`feat` 类型提交应该对应到 `MINOR` 版本。带有 `BREAKING CHANGE` 的提交不管类型如何,都应该对应到 `MAJOR` 版本。
### [](#我对约定式提交做了形如-jameswomackconventional-commit-spec-的扩展该如何版本化管理这些扩展呢)我对约定式提交做了形如 `@jameswomack/conventional-commit-spec` 的扩展,该如何版本化管理这些扩展呢?
我们推荐使用 SemVer 来发布你对于这个规范的扩展(并鼓励你创建这些扩展!)
### [](#如果我不小心使用了错误的提交类型该怎么办呢)如果我不小心使用了错误的提交类型,该怎么办呢?
#### [](#当你使用了在规范中但错误的类型时例如将-feat-写成了-fix)当你使用了在规范中但错误的类型时,例如将 `feat` 写成了 `fix`
在合并或发布这个错误之前,我们建议使用 `git rebase -i` 来编辑提交历史。而在发布之后,根据你使用的工具和流程不同,会有不同的清理方案。
#### [](#当使用了-不在-规范中的类型时例如将-feat-写成了-feet)当使用了 _不在_ 规范中的类型时,例如将 `feat` 写成了 `feet`
在最坏的场景下,即便提交没有满足约定式提交的规范,也不会是世界末日。这只意味着这个提交会被基于规范的工具错过而已。
### [](#所有的贡献者都需要使用约定式提交规范吗)所有的贡献者都需要使用约定式提交规范吗?
并不!如果你使用基于 squash 的 Git 工作流,主管维护者可以在合并时清理提交信息——这不会对普通提交者产生额外的负担。 有种常见的工作流是让 git 系统自动从 pull request 中 squash 出提交,并向主管维护者提供一份表单,用以在合并时输入合适的 git 提交信息。
### [](#约定式提交规范中如何处理还原revert提交)约定式提交规范中如何处理还原revert提交?
还原提交Reverting会比较复杂你还原的是多个提交吗如果你还原了一个功能模块下次发布的应该是补丁吗
约定式提交不能明确的定义还原行为。所以我们把这个问题留给工具开发者, 基于 _类型__脚注_ 的灵活性来开发他们自己的还原处理逻辑。
一种建议是使用 `revert` 类型,和一个指向被还原提交摘要的脚注:
revert: let us never again speak of the noodle incident
Refs: 676104e, a215868

View File

@ -1,226 +0,0 @@
语义化版本 2.0.0
===
摘要
---
版本格式:主版本号.次版本号.修订号,版本号递增规则如下:
1. 主版本号:当你做了不兼容的 API 修改,
2. 次版本号:当你做了向下兼容的功能性新增,
3. 修订号:当你做了向下兼容的问题修正。
先行版本号及版本编译信息可以加到“主版本号.次版本号.修订号”的后面,作为延伸。
简介
---
在软件管理的领域里存在着被称作“依赖地狱”的死亡之谷,系统规模越大,加入的包越多,你就越有可能在未来的某一天发现自己已深陷绝望之中。
在依赖高的系统中发布新版本包可能很快会成为噩梦。如果依赖关系过高,可能面临版本控制被锁死的风险(必须对每一个依赖包改版才能完成某次升级)。而如果依赖关系过于松散,又将无法避免版本的混乱(假设兼容于未来的多个版本已超出了合理数量)。当你项目的进展因为版本依赖被锁死或版本混乱变得不够简便和可靠,就意味着你正处于依赖地狱之中。
作为这个问题的解决方案之一,我提议用一组简单的规则及条件来约束版本号的配置和增长。这些规则是根据(但不局限于)已经被各种封闭、开放源码软件所广泛使用的惯例所设计。为了让这套理论运作,你必须先有定义好的公共 API。这可能包括文档或代码的强制要求。无论如何这套 API 的清楚明了是十分重要的。一旦你定义了公共 API你就可以透过修改相应的版本号来向大家说明你的修改。考虑使用这样的版本号格式X.Y.Z主版本号.次版本号.修订号)修复问题但不影响 API 时递增修订号API 保持向下兼容的新增及修改时,递增次版本号;进行不向下兼容的修改时,递增主版本号。
我称这套系统为“语义化的版本控制”,在这套约定下,版本号及其更新方式包含了相邻版本间的底层代码和修改内容的信息。
语义化版本控制规范SemVer
---
以下关键词 MUST、MUST NOT、REQUIRED、SHALL、SHALL NOT、SHOULD、SHOULD NOT、 RECOMMENDED、MAY、OPTIONAL 依照 RFC 2119 的叙述解读。
1. 使用语义化版本控制的软件必须MUST定义公共 API。该 API 可以在代码中被定义或出现于严谨的文档内。无论何种形式都应该力求精确且完整。
2. 标准的版本号必须MUST采用 X.Y.Z 的格式,其中 X、Y 和 Z 为非负的整数且禁止MUST NOT在数字前方补零。X 是主版本号、Y 是次版本号、而 Z 为修订号。每个元素必须MUST以数值来递增。例如1.9.1 -> 1.10.0 -> 1.11.0。
3. 标记版本号的软件发行后禁止MUST NOT改变该版本软件的内容。任何修改都必须MUST以新版本发行。
4. 主版本号为零0.y.z的软件处于开发初始阶段一切都可能随时被改变。这样的公共 API 不应该被视为稳定版。
5. 1.0.0 的版本号用于界定公共 API 的形成。这一版本之后所有的版本号更新都基于公共 API 及其修改内容。
6. 修订号 Zx.y.Z `|` x > 0必须MUST在只做了向下兼容的修正时才递增。这里的修正指的是针对不正确结果而进行的内部修改。
7. 次版本号 Yx.Y.z `|` x > 0必须MUST在有向下兼容的新功能出现时递增。在任何公共 API 的功能被标记为弃用时也必须MUST递增。也可以MAY在内部程序有大量新功能或改进被加入时递增其中可以MAY包括修订级别的改变。每当次版本号递增时修订号必须MUST归零。
8. 主版本号 XX.y.z `|` X > 0必须MUST在有任何不兼容的修改被加入公共 API 时递增。其中可以MAY包括次版本号及修订级别的改变。每当主版本号递增时次版本号和修订号必须MUST归零。
9. 先行版本号可以MAY被标注在修订版之后先加上一个连接号再加上一连串以句点分隔的标识符来修饰。标识符必须MUST由 ASCII 字母数字和连接号 [0-9A-Za-z-] 组成且禁止MUST NOT留白。数字型的标识符禁止MUST NOT在前方补零。先行版的优先级低于相关联的标准版本。被标上先行版本号则表示这个版本并非稳定而且可能无法满足预期的兼容性需求。范例1.0.0-alpha、1.0.0-alpha.1、1.0.0-0.3.7、1.0.0-x.7.z.92。
10. 版本编译信息可以MAY被标注在修订版或先行版本号之后先加上一个加号再加上一连串以句点分隔的标识符来修饰。标识符必须MUST由 ASCII 字母数字和连接号 [0-9A-Za-z-] 组成且禁止MUST NOT留白。当判断版本的优先层级时版本编译信息可SHOULD被忽略。因此当两个版本只有在版本编译信息有差别时属于相同的优先层级。范例1.0.0-alpha+001、1.0.0+20130313144700、1.0.0-beta+exp.sha.5114f85。
11. 版本的优先层级指的是不同版本在排序时如何比较。
1. 判断优先层级时必须MUST把版本依序拆分为主版本号、次版本号、修订号及先行版本号后进行比较版本编译信息不在这份比较的列表中
2. 由左到右依序比较每个标识符,第一个差异值用来决定优先层级:主版本号、次版本号及修订号以数值比较。
例如1.0.0 < 2.0.0 < 2.1.0 < 2.1.1
3. 当主版本号、次版本号及修订号都相同时,改以优先层级比较低的先行版本号决定。
例如1.0.0-alpha < 1.0.0
4. 有相同主版本号、次版本号及修订号的两个先行版本号其优先层级必须MUST透过由左到右的每个被句点分隔的标识符来比较直到找到一个差异值后决定
1. 只有数字的标识符以数值高低比较。
2. 有字母或连接号时则逐字以 ASCII 的排序来比较。
3. 数字的标识符比非数字的标识符优先层级低。
4. 若开头的标识符都相同时,栏位比较多的先行版本号优先层级比较高。
例如1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0
合法语义化版本的巴科斯范式语法
--------------------------------------------------
```
<valid semver> ::= <version core>
| <version core> "-" <pre-release>
| <version core> "+" <build>
| <version core> "-" <pre-release> "+" <build>
<version core> ::= <major> "." <minor> "." <patch>
<major> ::= <numeric identifier>
<minor> ::= <numeric identifier>
<patch> ::= <numeric identifier>
<pre-release> ::= <dot-separated pre-release identifiers>
<dot-separated pre-release identifiers> ::= <pre-release identifier>
| <pre-release identifier> "." <dot-separated pre-release identifiers>
<build> ::= <dot-separated build identifiers>
<dot-separated build identifiers> ::= <build identifier>
| <build identifier> "." <dot-separated build identifiers>
<pre-release identifier> ::= <alphanumeric identifier>
| <numeric identifier>
<build identifier> ::= <alphanumeric identifier>
| <digits>
<alphanumeric identifier> ::= <non-digit>
| <non-digit> <identifier characters>
| <identifier characters> <non-digit>
| <identifier characters> <non-digit> <identifier characters>
<numeric identifier> ::= "0"
| <positive digit>
| <positive digit> <digits>
<identifier characters> ::= <identifier character>
| <identifier character> <identifier characters>
<identifier character> ::= <digit>
| <non-digit>
<non-digit> ::= <letter>
| "-"
<digits> ::= <digit>
| <digit> <digits>
<digit> ::= "0"
| <positive digit>
<positive digit> ::= "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
<letter> ::= "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J"
| "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T"
| "U" | "V" | "W" | "X" | "Y" | "Z" | "a" | "b" | "c" | "d"
| "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n"
| "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x"
| "y" | "z"
```
为什么要使用语义化的版本控制?
---
这并不是一个新的或者革命性的想法。实际上,你可能已经在做一些近似的事情了。问题在于只是“近似”还不够。如果没有某个正式的规范可循,版本号对于依赖的管理并无实质意义。将上述的想法命名并给予清楚的定义,让你对软件使用者传达意向变得容易。一旦这些意向变得清楚,弹性(但又不会太弹性)的依赖规范就能达成。
举个简单的例子就可以展示语义化的版本控制如何让依赖地狱成为过去。假设有个名为“救火车”的函数库,它需要另一个名为“梯子”并已经有使用语义化版本控制的包。当救火车创建时,梯子的版本号为 3.1.0。因为救火车使用了一些版本 3.1.0 所新增的功能,你可以放心地指定依赖于梯子的版本号大于等于 3.1.0 但小于 4.0.0。这样,当梯子版本 3.1.1 和 3.2.0 发布时,你可以将直接它们纳入你的包管理系统,因为它们能与原有依赖的软件兼容。
作为一位负责任的开发者,你理当确保每次包升级的运作与版本号的表述一致。现实世界是复杂的,我们除了提高警觉外能做的不多。你所能做的就是让语义化的版本控制为你提供一个健全的方式来发行以及升级包,而无需推出新的依赖包,节省你的时间及烦恼。
如果你对此认同,希望立即开始使用语义化版本控制,你只需声明你的函数库正在使用它并遵循这些规则就可以了。请在你的 README 文件中保留此页链接,让别人也知道这些规则并从中受益。
FAQ
---
### 在 0.y.z 初始开发阶段,我该如何进行版本控制?
最简单的做法是以 0.1.0 作为你的初始化开发版本,并在后续的每次发行时递增次版本号。
### 如何判断发布 1.0.0 版本的时机?
当你的软件被用于正式环境,它应该已经达到了 1.0.0 版。如果你已经有个稳定的 API 被使用者依赖,也会是 1.0.0 版。如果你很担心向下兼容的问题,也应该算是 1.0.0 版了。
### 这不会阻碍快速开发和迭代吗?
主版本号为零的时候就是为了做快速开发。如果你每天都在改变 API那么你应该仍在主版本号为零的阶段0.y.z或是正在下个主版本的独立开发分支中。
### 对于公共 API若即使是最小但不向下兼容的改变都需要产生新的主版本号岂不是很快就达到 42.0.0 版?
这是开发的责任感和前瞻性的问题。不兼容的改变不应该轻易被加入到有许多依赖代码的软件中。升级所付出的代价可能是巨大的。要递增主版本号来发行不兼容的改版,意味着你必须为这些改变所带来的影响深思熟虑,并且评估所涉及的成本及效益比。
### 为整个公共 API 写文档太费事了!
为供他人使用的软件编写适当的文档,是你作为一名专业开发者应尽的职责。保持项目高效的一个非常重要的部分是掌控软件的复杂度,如果没有人知道如何使用你的软件或不知道哪些函数的调用是可靠的,要掌控复杂度会是困难的。长远来看,使用语义化版本控制以及对于公共 API 有良好规范的坚持,可以让每个人及每件事都运行顺畅。
### 万一不小心把一个不兼容的改版当成了次版本号发行了该怎么办?
一旦发现自己破坏了语义化版本控制的规范,就要修正这个问题,并发行一个新的次版本号来更正这个问题并且恢复向下兼容。即使是这种情况,也不能去修改已发行的版本。可以的话,将有问题的版本号记录到文档中,告诉使用者问题所在,让他们能够意识到这是有问题的版本。
### 如果我更新了自己的依赖但没有改变公共 API 该怎么办?
由于没有影响到公共 API这可以被认定是兼容的。若某个软件和你的包有共同依赖则它会有自己的依赖规范作者也会告知可能的冲突。要判断改版是属于修订等级或是次版等级是依据你更新的依赖关系是为了修复问题或是加入新功能。对于后者我经常会预期伴随着更多的代码这显然会是一个次版本号级别的递增。
### 如果我变更了公共 API 但无意中未遵循版本号的改动怎么办呢?(意即在修订等级的发布中,误将重大且不兼容的改变加到代码之中)
自行做最佳的判断。如果你有庞大的使用者群在依照公共 API 的意图而变更行为后会大受影响,那么最好做一次主版本的发布,即使严格来说这个修复仅是修订等级的发布。记住, 语义化的版本控制就是透过版本号的改变来传达意义。若这些改变对你的使用者是重要的,那就透过版本号来向他们说明。
### 我该如何处理即将弃用的功能?
弃用现存的功能是软件开发中的家常便饭,也通常是向前发展所必须的。当你弃用部分公共 API 时你应该做两件事1更新你的文档让使用者知道这个改变2在适当的时机将弃用的功能透过新的次版本号发布。在新的主版本完全移除弃用功能前至少要有一个次版本包含这个弃用信息这样使用者才能平顺地转移到新版 API。
### 语义化版本对于版本的字符串长度是否有限制呢?
没有,请自行做适当的判断。举例来说,长到 255 个字符的版本已过度夸张。再者,特定的系统对于字符串长度可能会有他们自己的限制。
### “v1.2.3” 是一个语义化版本号吗?
“v1.2.3” 并不是一个语义化的版本号。但是,在语义化版本号之前增加前缀 “v” 是用来表示版本号的常用做法。在版本控制系统中,将 “version” 缩写为 “v” 是很常见的。比如:`git tag v1.2.3 -m "Release version 1.2.3"`“v1.2.3” 表示标签名称,而 “1.2.3” 是语义化版本号。
### 是否有推荐的正则表达式用以检查语义化版本号的正确性?
有两个推荐的正则表达式。第一个用于支持按组名称提取的语言PCRE[Perl 兼容正则表达式,比如 Perl、PHP 和 R]、Python 和 Go
参见:<https://regex101.com/r/Ly7O1x/3/>
```
^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
```
第二个用于支持按编号提取的语言与第一个对应的提取项按顺序分别为major、minor、patch、prerelease、buildmetadata。主要包括 ECMA ScriptJavaScript、PCREPerl 兼容正则表达式,比如 Perl、PHP 和 R、Python 和 Go。
参见:<https://regex101.com/r/vkijKf/1/>
```
^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
```
关于
---
语义化版本控制的规范是由 Gravatars 创办者兼 GitHub 共同创办者 [Tom Preston-Werner](http://tom.preston-werner.com) 所建立。
如果您有任何建议,请到 [GitHub 上提出您的问题](https://github.com/semver/semver/issues)。
许可证
---
[知识共享 署名 3.0 (CC BY 3.0)](http://creativecommons.org/licenses/by/3.0/)

View File

@ -1,12 +1,6 @@
{ {
"version": 1, "version": 1,
"isRoot": true, "isRoot": true,
"tools": { "tools": {
"dotnet-t4": {
"version": "3.0.0",
"commands": [
"t4"
]
} }
}
} }

1
git-clean.cmd Normal file
View File

@ -0,0 +1 @@
git reset --hard | git clean -d -fx .

View File

@ -1,10 +1,10 @@
{ {
"sdk": { "sdk": {
"version": "8.0.0", "version": "7.0.100",
"rollForward": "latestMajor", "allowPrerelease": true,
"allowPrerelease": true "rollForward": "major"
}, },
"tools": { "tools": {
"dotnet": "8.0.0" "dotnet": "7.0.100"
} }
} }

BIN
key.snk

Binary file not shown.

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nuget.cdn.azure.cn" value="https://nuget.cdn.azure.cn/v3/index.json" />
</packageSources>
</configuration>

View File

@ -1,14 +0,0 @@
{
"version": "2.3.5",
"devDependencies": {
"cz-git": "^1.11.0",
"commitizen": "^4.3.1",
"prettier": "^3.3.3",
"standard-version": "^9.5.0"
},
"config": {
"commitizen": {
"path": "node_modules/cz-git"
}
}
}

25
push2nuget.ps1 Normal file
View File

@ -0,0 +1,25 @@
Param(
# Nuget APIKey
[string] $apikey
)
if ($apikey -eq $null -or $apikey -eq "")
{
Write-Error "require apiKey";
return;
}
rm -r ./build/nupkgs
dotnet build -c Release
$files = Get-ChildItem -Path ./build/nupkgs/ -Filter *.nupkg
foreach ($file in $files)
{
dotnet nuget push $file.fullName --skip-duplicate --api-key $apikey --source https://api.nuget.org/v3/index.json
nuget add $file.fullName -source d:\nuget-pkg
}
$files = Get-ChildItem -Path ./build/nupkgs/ -Filter *.snupkg
foreach ($file in $files)
{
dotnet nuget push $file.fullName --skip-duplicate --api-key $apikey --source https://api.nuget.org/v3/index.json
nuget add $file.fullName -source d:\nuget-pkg
}

View File

@ -1,15 +0,0 @@
$branch = $( git branch --show-current )
git add ../
$skipFormat = Read-Host "输入 n 跳过代码整理"
if ($skipFormat -ne "n")
{
./code.clean.ps1
}
git add ../
../node_modules/.bin/git-cz.ps1
git pull
git push --set-upstream origin $branch
Start-Process -FilePath "https://github.com/nsnail/NSExt/compare/main...$branch"
Write-Host "按『Enter』重建分支『Ctrl+C』退出"
Pause
./3.git.recreate.branch.ps1

View File

@ -1,29 +0,0 @@
cd ..
$types = @{
'1' = @('major', '主版本')
'2' = @('minor', '次版本')
'3' = @('patch', '修订版本')
}
$prefix = ''
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]
git commit --amend --no-edit -a
$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』回到tk分支『Ctrl+C』退出"
Pause
git checkout main
git pull
git branch -D release
git branch -D tk
git checkout -b tk

View File

@ -1,6 +0,0 @@
$branch = $( git branch --show-current )
git checkout main
git pull
git branch -D $branch
git branch $branch
git checkout $branch

View File

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

View File

@ -1,26 +0,0 @@
using System.Text.RegularExpressions;
var csFiles = Directory.EnumerateFiles(@"../src/backend", $"*.cs", new EnumerationOptions { RecurseSubdirectories = true });
foreach (var lnFile in Directory.EnumerateFiles("../assets/res", "*.ln"))
{
var newLines = new List<string>();
foreach (var line in File.ReadAllLines(lnFile))
{
var found = false;
foreach (var csFile in csFiles)
{
if (File.ReadAllText(csFile).Contains($"Ln.{(Regex.IsMatch(line, @"^\d") ? "_" : "") + line}"))
{
found = true;
newLines.Add(line);
break;
}
}
if (!found)
{
Console.WriteLine(line);
}
}
File.WriteAllLines(lnFile, newLines);
}

View File

@ -1,44 +0,0 @@
using System.Text.RegularExpressions;
using System.Net.Http;
using System.Net.Http.Json;
{
var files = string.Join(
';',
Args[0]
.Split('\n', StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Replace('\\', '/').Trim())
);
Console.WriteLine(files);
using var p = Process.Start(
new ProcessStartInfo
{
CreateNoWindow = true,
FileName = "dotnet",
Arguments = $"jb cleanupcode --include=\"{files}\" --no-build ../NSExt.sln",
UseShellExecute = false,
RedirectStandardOutput = true
}
);
p.WaitForExit();
Console.WriteLine(p.StandardOutput.ReadToEnd());
using var p2 = Process.Start(
new ProcessStartInfo
{
CreateNoWindow = true,
FileName = "git",
Arguments = $"status",
UseShellExecute = false,
RedirectStandardOutput = true
}
);
p2.WaitForExit();
var content = p2.StandardOutput.ReadToEnd();
Console.WriteLine(content);
return content.Contains("working tree clean") ? 0 : 1;
}

View File

@ -1,4 +0,0 @@
jb cleanupcode --no-build --include = $( $( git status --porcelain | Where-Object { $_ -match "^\s*[MA]" } | ForEach-Object { $_.TrimStart(" M").TrimStart(" A") } ) -join ";" ) ../NSExt.sln
dot rbom -w -e refs -e .git -e node_modules ../
dot trim -w -e refs -e .git -e node_modules ../
dot tolf -w -e refs -e .git -e node_modules ../

View File

@ -1,15 +0,0 @@
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,78 +0,0 @@
<#@ template language="C#" #>
<#@ assembly name="System.Xml" #>
<#@ output encoding="utf-8" extension="Designer.cs" #>
<#@ import namespace="System.Xml" #>
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System.CodeDom.Compiler;
using System.Diagnostics.CodeAnalysis;
using System.Resources;
using System.Runtime.CompilerServices;
namespace NSExt.Languages;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// 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")]
[DebuggerNonUserCode]
[CompilerGenerated]
public sealed class Ln
{
private static ResourceManager _resourceMan;
/// <summary>
/// Initializes a new instance of the <see cref="Ln" /> class.
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
public Ln() { }
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public static ResourceManager ResourceManager {
get {
if (ReferenceEquals(_resourceMan, null)) {
var temp = new ResourceManager("NSExt.Languages.Ln", typeof(Ln).Assembly);
_resourceMan = temp;
}
return _resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public static CultureInfo Culture { get; set; }
<#
var xml = new XmlDocument();
xml.Load("../assets/res/Ln.resx");
foreach (XmlNode data in xml.SelectNodes("//root/data")!)
{
#>
/// <summary>
/// <#= data.SelectSingleNode("value")?.InnerText #>
/// </summary>
public static string <#=
data.Attributes!["name"].Value.Replace(" ", "_") #> => ResourceManager.GetString("<#= data.Attributes!["name"].Value #>", Culture);
<#
}
#>
}

View File

@ -1,2 +0,0 @@
dotnet t4 ./gen.resx.tt -o ../assets/res/Ln.resx
dotnet t4 ./gen.cs.tt -o ../dist/backend/NSExt/Ln.cs

View File

@ -1,39 +0,0 @@
<#@ 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"
id="root"
xmlns="">
<xsd:element name="root" msdata:IsDataSet="true">
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<#
var regex = new Regex(@"^\d", RegexOptions.Compiled);
foreach (var line in Directory.GetFiles("../assets/res/", "*.ln").SelectMany(x => File.ReadLines(x)).Distinct())
{
#>
<data name="<#= regex.IsMatch(line) ? "_" : "" #><#= line #>" xml:space="preserve"><value><#= line #></value></data>
<#
}
#>
</root>

View File

@ -1,65 +0,0 @@
/*
for %%i in (*.png) do pngquant %%i --force --output %%i --skip-if-larger
for %%i in (*.jpg) do jpegtran -copy none -optimize -perfect %%i %%i
*
*/
var files = Directory
.EnumerateFiles(
"../",
"*.png",
new EnumerationOptions
{
RecurseSubdirectories = true,
AttributesToSkip = FileAttributes.ReparsePoint,
IgnoreInaccessible = true
}
)
.ToArray();
Parallel.ForEach(
files,
file =>
{
var startInfo = new ProcessStartInfo
{
FileName = "pngquant",
Arguments = $"\"{file}\" --force --output \"{file}\" --skip-if-larger"
};
using var p = Process.Start(startInfo);
p.WaitForExit();
Console.WriteLine($"{file}: {p.ExitCode}");
}
);
files = new[] { "*.jpg", "*.jpeg" }
.SelectMany(
x =>
Directory.EnumerateFiles(
"../",
x,
new EnumerationOptions
{
RecurseSubdirectories = true,
AttributesToSkip = FileAttributes.ReparsePoint,
IgnoreInaccessible = true
}
)
)
.ToArray();
Parallel.ForEach(
files,
file =>
{
var startInfo = new ProcessStartInfo
{
FileName = "jpegtran",
Arguments = $"-copy none -optimize -perfect \"{file}\" \"{file}\""
};
using var p = Process.Start(startInfo);
p.WaitForExit();
Console.WriteLine($"{file}: {p.ExitCode}");
}
);

View File

@ -1,2 +0,0 @@
dotnet new uninstall ../
dotnet new --install ../

View File

@ -1,27 +0,0 @@
#r "nuget: NSExt, 2.2.0"
using NSExt.Extensions;
Console.WriteLine("请输入原始名称NSExt");
var oldName = Console.ReadLine().NullOrEmpty("NSExt");
Console.WriteLine("请输入替换名称:");
var newName = Console.ReadLine();
foreach (var path in Directory.EnumerateDirectories("../", $"*{oldName}*",
SearchOption.AllDirectories))
{
Console.Write($"{path} --> ");
var newPath = path.Replace(oldName, newName);
Directory.Move(path, newPath);
Console.WriteLine(newPath);
}
Console.WriteLine();
foreach (var path in Directory.EnumerateFiles("../", $"*.*", SearchOption.AllDirectories))
{
File.WriteAllText(path, File.ReadAllText(path).Replace(oldName, newName));
var newPath = path.Replace(oldName, newName);
if (newPath == path) continue;
Console.Write($"{path} --> ");
Directory.Move(path, newPath);
Console.WriteLine(newPath);
}

View File

@ -1 +0,0 @@
jb cleanupcode --no-build ../NSExt.sln

View File

@ -1,42 +0,0 @@
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

@ -1,63 +0,0 @@
using System.Text.RegularExpressions;
var slnFile = Directory.GetFiles(@"../", "*.sln").First();
var content = File.ReadAllText(slnFile);
content = Regex.Replace(
content,
"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}"
ProjectSection(SolutionItems) = preProject
{{string.Join('\n',
Directory.GetFiles(@"../", "*").Where(x => !x.EndsWith(".sln") && !x.EndsWith(".user"))
.Select(x=>$" {Path.GetFileName(x)} = {Path.GetFileName(x)}")
)}}
EndProject
"""
);
content = Regex.Replace(
content,
"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}"
ProjectSection(SolutionItems) = preProject
{{string.Join('\n',
Directory.GetFiles(@"../.github/workflows", "*")
.Select(x=>$" {Path.GetFileName(x)} = .github/workflows/{Path.GetFileName(x)}")
)}}
EndProject
"""
);
content = Regex.Replace(
content,
"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}"
ProjectSection(SolutionItems) = preProject
{{string.Join('\n',
Directory.GetFiles(@"../scripts", "*")
.Select(x=>$" {Path.GetFileName(x)} = scripts/{Path.GetFileName(x)}")
)}}
EndProject
"""
);
content = Regex.Replace(
content,
"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}"
ProjectSection(SolutionItems) = preProject
{{string.Join('\n',
Directory.GetFiles(@"../build", "*")
.Select(x=>$" {Path.GetFileName(x)} = build/{Path.GetFileName(x)}")
)}}
EndProject
"""
);
Console.WriteLine(content);
File.WriteAllText(slnFile, content);

13
src/Constant/Regexes.cs Normal file
View File

@ -0,0 +1,13 @@
namespace NSExt.Constant;
#pragma warning disable SYSLIB1045
// 使用 RegexGenerator 新特性会生成重复key值的xmlcomment导致出错
internal static class Regexes
{
public static readonly Regex RegexHtmlTag = new("<[^>]*>", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static readonly Regex RegexMobile
= new("^(\\d{3})\\d{4}(\\d{4})$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static readonly Regex RegexUpLetter = new("([A-Z])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
}

View File

@ -8,7 +8,7 @@ public static class ByteExtensions
/// <summary> /// <summary>
/// base64编码 /// base64编码
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">待编码的字节数组</param>
/// <returns>编码后的base64字符串</returns> /// <returns>编码后的base64字符串</returns>
public static string Base64(this byte[] me) public static string Base64(this byte[] me)
{ {
@ -18,7 +18,7 @@ public static class ByteExtensions
/// <summary> /// <summary>
/// 将字节数组解码成字符串 /// 将字节数组解码成字符串
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">字节数组</param>
/// <param name="e">字符串使用的编码方式</param> /// <param name="e">字符串使用的编码方式</param>
/// <returns>解码后的原始字符串</returns> /// <returns>解码后的原始字符串</returns>
public static string HexDe(this byte[] me, Encoding e) public static string HexDe(this byte[] me, Encoding e)
@ -29,7 +29,7 @@ public static class ByteExtensions
/// <summary> /// <summary>
/// 将字节数组解码成字符串 /// 将字节数组解码成字符串
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">字节数组</param>
/// <returns>解码后的原始字符串</returns> /// <returns>解码后的原始字符串</returns>
public static string HexDe(this byte[] me) public static string HexDe(this byte[] me)
{ {
@ -42,20 +42,17 @@ public static class ByteExtensions
/// <param name="me">me</param> /// <param name="me">me</param>
/// <param name="upperCase">是否大写</param> /// <param name="upperCase">是否大写</param>
/// <param name="splitShar">字节间分隔符</param> /// <param name="splitShar">字节间分隔符</param>
/// <param name="splitInterval">分隔符跳跃字节数</param> public static string String(this byte[] me, bool upperCase = true, string splitShar = null)
public static string Str(this IEnumerable<byte> me, bool upperCase = true, string splitShar = ""
, int splitInterval = 1)
{ {
var sb = new StringBuilder(); var ret = BitConverter.ToString(me);
var i = 0; if (!upperCase) {
foreach (var c in me.Select(x => x.ToString(upperCase ? "X2" : "x2", CultureInfo.InvariantCulture))) { ret = ret.ToLower(CultureInfo.InvariantCulture);
if (i++ % splitInterval == 0) {
_ = sb.Append(splitShar);
}
_ = sb.Append(c);
} }
return sb.ToString(); if (splitShar != "-") {
ret = ret.Replace("-", splitShar ?? string.Empty);
}
return ret;
} }
} }

View File

@ -1,7 +1,8 @@
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
// ReSharper disable UnusedMember.Global // ReSharper disable UnusedMember.Global
#pragma warning disable SA1300, IDE1006 #pragma warning disable SA1300
#pragma warning disable IDE1006
namespace NSExt.Extensions; namespace NSExt.Extensions;
/// <summary> /// <summary>
@ -9,10 +10,23 @@ namespace NSExt.Extensions;
/// </summary> /// </summary>
public static class DateTimeExtensions public static class DateTimeExtensions
{ {
/// <summary>
/// 将一个过去时间对象与当前时间相减转换成“xx以前”的字符串, 如2秒以前, 3天以前
/// </summary>
/// <param name="me">时间对象</param>
/// <returns>字符串</returns>
public static string TimeAgo(this DateTime me)
{
var ts = DateTime.Now - me;
return ts.Days > 0 ? ts.Days + "天前" :
ts.Hours > 0 ? ts.Hours + "小时前" :
ts.Minutes > 0 ? ts.Minutes + "分钟前" : ts.Seconds + "秒前";
}
/// <summary> /// <summary>
/// 指定时间的世界协调时的unix时间戳形式 /// 指定时间的世界协调时的unix时间戳形式
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">指定时间</param>
/// <returns>unix时间戳</returns> /// <returns>unix时间戳</returns>
public static long TimeUnixUtc(this DateTime me) public static long TimeUnixUtc(this DateTime me)
{ {
@ -27,31 +41,6 @@ public static class DateTimeExtensions
return (me.ToUniversalTime().Ticks - 621355968000000000) / 10000; return (me.ToUniversalTime().Ticks - 621355968000000000) / 10000;
} }
/// <summary>
/// ToString 的 Invariant 版本
/// </summary>
public static string ToInvString(this DateTime me)
{
return me.ToString(CultureInfo.InvariantCulture);
}
/// <summary>
/// 将一个过去时间对象与当前时间相减转换成“xx以前”的字符串, 如2秒以前, 3天以前
/// </summary>
/// <param name="me">me</param>
/// <returns>字符串</returns>
public static string UtcTimeAgo(this DateTime me)
{
var ts = DateTime.UtcNow - me;
return ts.Days switch {
> 0 => ts.Days + "天前"
, _ => ts.Hours switch {
> 0 => ts.Hours + "小时前"
, _ => ts.Minutes switch { > 0 => ts.Minutes + "分钟前", _ => ts.Seconds + "秒前" }
}
};
}
/// <summary> /// <summary>
/// yyyy_MM /// yyyy_MM
/// </summary> /// </summary>

View File

@ -1,10 +1,7 @@
using System.Data;
using System.Data.Common;
namespace NSExt.Extensions; namespace NSExt.Extensions;
/// <summary> /// <summary>
/// DbCommandExtensions /// DbCommandExtensions
/// </summary> /// </summary>
public static class DbCommandExtensions public static class DbCommandExtensions
{ {
@ -13,23 +10,22 @@ public static class DbCommandExtensions
/// </summary> /// </summary>
public static string ParameterFormat(this DbCommand me) public static string ParameterFormat(this DbCommand me)
{ {
//var aa = pars.ToDictionary(it => it.ParameterName, it => it.Value);
var sql = me.CommandText; var sql = me.CommandText;
// 应逆向替换,否则由于 多个表的过滤器问题导致替换不完整 如 @TenantId1 @TenantId10 //应逆向替换,否则由于 多个表的过滤器问题导致替换不完整 如 @TenantId1 @TenantId10
for (var i = me.Parameters.Count - 1; i >= 0; i--) { for (var i = me.Parameters.Count - 1; i >= 0; i--) {
#pragma warning disable IDE0072 #pragma warning disable IDE0072
sql = me.Parameters[i].DbType switch { sql = me.Parameters[i].DbType switch {
#pragma warning restore IDE0072 #pragma warning restore IDE0072
DbType.String or DbType.DateTime or DbType.Date or DbType.Time or DbType.DateTime2 DbType.String or DbType.DateTime or DbType.Date or DbType.Time or DbType.DateTime2
or DbType.DateTimeOffset or DbType.Guid or DbType.VarNumeric or DbType.AnsiStringFixedLength or DbType.DateTimeOffset or DbType.Guid or DbType.VarNumeric or DbType.AnsiStringFixedLength
or DbType.AnsiString or DbType.StringFixedLength => sql.Replace( // or DbType.AnsiString
me.Parameters[i].ParameterName, "'" + me.Parameters[i].Value + "'") or DbType.StringFixedLength =>
, DbType.Boolean => sql.Replace( // sql.Replace(me.Parameters[i].ParameterName, "'" + me.Parameters[i].Value + "'")
me.Parameters[i].ParameterName , DbType.Boolean => sql.Replace(//
, me.Parameters[i].Value != DBNull.Value && me.Parameters[i].ParameterName
Convert.ToBoolean(me.Parameters[i].Value, CultureInfo.InvariantCulture) , Convert.ToBoolean(me.Parameters[i].Value, CultureInfo.InvariantCulture) ? "1" : "0")
? "1"
: "0")
, _ => sql.Replace(me.Parameters[i].ParameterName, me.Parameters[i].Value?.ToString()) , _ => sql.Replace(me.Parameters[i].ParameterName, me.Parameters[i].Value?.ToString())
}; };
} }

View File

@ -8,19 +8,12 @@ public static class DecimalExtensions
/// <summary> /// <summary>
/// 四舍五入后的近似值 /// 四舍五入后的近似值
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">数字</param>
/// <param name="place">小数点位数</param> /// <param name="place">小数点位数</param>
/// <returns>处理后的值</returns> /// <returns>处理后的值</returns>
public static decimal Round(this decimal me, int place) public static decimal Round(this decimal me, int place)
{ {
return Math.Round(me, place); var dec = Math.Round(me, place);
} return dec;
/// <summary>
/// ToString 的 Invariant 版本
/// </summary>
public static string ToInvString(this decimal me)
{
return me.ToString(CultureInfo.InvariantCulture);
} }
} }

View File

@ -0,0 +1,20 @@
namespace NSExt.Extensions;
/// <summary>
/// EnumExtensions
/// </summary>
public static class EnumExtensions
{
/// <summary>
/// 获取枚举的description属性
/// </summary>
/// <param name="e">枚举对象</param>
/// <returns>description属性</returns>
public static string Desc(this Enum e)
{
var t = e.GetType();
var fi = t.GetField(Enum.GetName(t, e)!);
var attrs = (DescriptionAttribute[])fi!.GetCustomAttributes(typeof(DescriptionAttribute), false);
return (attrs.Length != 0 ? attrs[0].Description : Enum.GetName(t, e)) ?? string.Empty;
}
}

View File

@ -0,0 +1,26 @@
namespace NSExt.Extensions;
/// <summary>
/// EnumerableExtensions
/// </summary>
public static class EnumerableExtensions
{
/// <summary>
/// 将列表转成分隔符分隔的字符串
/// </summary>
public static string Join(this IEnumerable<object> me, string separator)
{
return string.Join(separator, me);
}
/// <summary>
/// 判断对象是否为null或不存在子元素如果为集合对象
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="me">指定对象</param>
/// <returns>空则返回true</returns>
public static bool NullOrEmpty<T>(this IEnumerable<T> me)
{
return me is null || !me.Any();
}
}

View File

@ -9,7 +9,7 @@ public static class GenericExtensions
/// 从指定的对象拷贝属性 /// 从指定的对象拷贝属性
/// </summary> /// </summary>
/// <typeparam name="T">对象类型</typeparam> /// <typeparam name="T">对象类型</typeparam>
/// <param name="me">me</param> /// <param name="me">拷贝目标</param>
/// <param name="copyObj">拷贝来源</param> /// <param name="copyObj">拷贝来源</param>
/// <param name="propNameList">需要处理的属性名</param> /// <param name="propNameList">需要处理的属性名</param>
/// <param name="isIncludeOrExclude">True包含false排除</param> /// <param name="isIncludeOrExclude">True包含false排除</param>

View File

@ -17,27 +17,17 @@ public static class IntExtensions
/// <summary> /// <summary>
/// 生成随机数 /// 生成随机数
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">大于等于[0],小于[1]</param>
public static int Rand(this int[] me) public static int Rand(this int[] me)
{ {
return new Random(Guid.NewGuid().GetHashCode()).Next(me[0], me[1]); return new Random(Guid.NewGuid().GetHashCode()).Next(me[0], me[1]);
} }
/// <summary>
/// ToString 的 Invariant 版本
/// </summary>
public static string ToInvString(this int me)
{
return me.ToString(CultureInfo.InvariantCulture);
}
/// <summary> /// <summary>
/// 转换成ipv4 /// 转换成ipv4
/// </summary> /// </summary>
public static string ToIpV4(this int me) public static string ToIpV4(this int me)
{ {
var bytes = BitConverter.GetBytes(me); return string.Join(".", BitConverter.GetBytes(me).Reverse());
Array.Reverse(bytes);
return string.Join('.', bytes);
} }
} }

View File

@ -0,0 +1,27 @@
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace NSExt.Extensions;
/// <summary>
/// JsonSerializerOptionsExtensions
/// </summary>
public static class JsonSerializerOptionsExtensions
{
/// <summary>
/// NewJsonSerializerOptions
/// </summary>
public static JsonSerializerOptions NewJsonSerializerOptions(this JsonSerializerOptions _)
{
return new JsonSerializerOptions {
ReadCommentHandling = JsonCommentHandling.Skip
, AllowTrailingCommas = true
, DictionaryKeyPolicy = JsonNamingPolicy.CamelCase
, PropertyNamingPolicy = JsonNamingPolicy.CamelCase
, Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
, NumberHandling = JsonNumberHandling.AllowReadingFromString
, PropertyNameCaseInsensitive = true
};
}
}

View File

@ -0,0 +1,88 @@
// ReSharper disable TemplateIsNotCompileTimeConstantProblem
namespace NSExt.Extensions;
/// <summary>
/// LoggerExtensions
/// </summary>
public static class LoggerExtensions
{
private const string _MESSAGE_S_THREADID_CALLERNAME_CALLERFILEPATH_CALLERLINENUMBER
= "{Message} <s:{ThreadId}#{CallerName}@{CallerFilePath}:{CallerLineNumber}>";
private static readonly Action<ILogger, string, string, string, string, string, Exception> _logDebug
= LoggerMessage.Define<string, string, string, string, string>(LogLevel.Debug, default
, _MESSAGE_S_THREADID_CALLERNAME_CALLERFILEPATH_CALLERLINENUMBER);
private static readonly Action<ILogger, string, string, string, string, string, Exception> _logError
= LoggerMessage.Define<string, string, string, string, string>(LogLevel.Error, default
, _MESSAGE_S_THREADID_CALLERNAME_CALLERFILEPATH_CALLERLINENUMBER);
private static readonly Action<ILogger, string, string, string, string, string, Exception> _logFatal
= LoggerMessage.Define<string, string, string, string, string>(LogLevel.Critical, default
, _MESSAGE_S_THREADID_CALLERNAME_CALLERFILEPATH_CALLERLINENUMBER);
private static readonly Action<ILogger, string, string, string, string, string, Exception> _logInfo
= LoggerMessage.Define<string, string, string, string, string>(LogLevel.Information, default
, _MESSAGE_S_THREADID_CALLERNAME_CALLERFILEPATH_CALLERLINENUMBER);
private static readonly Action<ILogger, string, string, string, string, string, Exception> _logWarn
= LoggerMessage.Define<string, string, string, string, string>(LogLevel.Warning, default
, _MESSAGE_S_THREADID_CALLERNAME_CALLERFILEPATH_CALLERLINENUMBER);
/// <summary>
/// Debug
/// </summary>
public static void Debug(this ILogger me, object message, [CallerMemberName] string callerName = null
, [CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = 0)
{
_logDebug(me, message.ToString(), Environment.CurrentManagedThreadId.ToString(CultureInfo.InvariantCulture)
, callerName, Path.GetFileName(callerFilePath), callerLineNumber.ToString(CultureInfo.InvariantCulture)
, null);
}
/// <summary>
/// Error
/// </summary>
public static void Error(this ILogger me, object message, [CallerMemberName] string callerName = null
, [CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = 0)
{
_logError(me, message.ToString(), Environment.CurrentManagedThreadId.ToString(CultureInfo.InvariantCulture)
, callerName, Path.GetFileName(callerFilePath), callerLineNumber.ToString(CultureInfo.InvariantCulture)
, null);
}
/// <summary>
/// Fatal
/// </summary>
public static void Fatal(this ILogger me, object message, Exception ex = null
, [CallerMemberName] string callerName = null, [CallerFilePath] string callerFilePath = null
, [CallerLineNumber] int callerLineNumber = 0)
{
_logFatal(me, message.ToString(), Environment.CurrentManagedThreadId.ToString(CultureInfo.InvariantCulture)
, callerName, Path.GetFileName(callerFilePath), callerLineNumber.ToString(CultureInfo.InvariantCulture)
, ex);
}
/// <summary>
/// Info
/// </summary>
public static void Info(this ILogger me, object message, [CallerMemberName] string callerName = null
, [CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = 0)
{
_logInfo(me, message.ToString(), Environment.CurrentManagedThreadId.ToString(CultureInfo.InvariantCulture)
, callerName, Path.GetFileName(callerFilePath), callerLineNumber.ToString(CultureInfo.InvariantCulture)
, null);
}
/// <summary>
/// Warn
/// </summary>
public static void Warn(this ILogger me, object message, [CallerMemberName] string callerName = null
, [CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = 0)
{
_logWarn(me, message.ToString(), Environment.CurrentManagedThreadId.ToString(CultureInfo.InvariantCulture)
, callerName, Path.GetFileName(callerFilePath), callerLineNumber.ToString(CultureInfo.InvariantCulture)
, null);
}
}

View File

@ -0,0 +1,25 @@
namespace NSExt.Extensions;
/// <summary>
/// LongExtensions
/// </summary>
public static class LongExtensions
{
/// <summary>
/// 判断枚举是否包含某个位
/// </summary>
public static bool HasFlag<T>(this long me, T flag)
where T : Enum
{
var val = (long)(object)flag;
return (me & val) == val;
}
/// <summary>
/// 1970毫秒数转换成日期对象
/// </summary>
public static DateTime Time(this long msFrom1970)
{
return new DateTime(1970, 1, 1).AddMilliseconds(msFrom1970).ToLocalTime();
}
}

View File

@ -0,0 +1,21 @@
using System.Text.Json;
namespace NSExt.Extensions;
/// <summary>
/// ObjectExtensions
/// </summary>
public static class ObjectExtensions
{
/// <summary>
/// 将一个对象序列化成json文本
/// </summary>
/// <param name="me">指定对象</param>
/// <param name="format">是否格式化</param>
/// <returns>json文本</returns>
public static string Json(this object me, bool format = false)
{
return JsonSerializer.Serialize(
me, new JsonSerializerOptions { WriteIndented = format, PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
}
}

View File

@ -25,8 +25,6 @@ public static class StreamExtensions
/// </summary> /// </summary>
public static bool IsTextStream(this Stream me) public static bool IsTextStream(this Stream me)
{ {
#pragma warning disable IDE0300 return me.FirstByteIndex(new byte[] { 0x00, 0xff }) < 0;
return me.FirstByteIndex([0x00, 0xff]) < 0;
#pragma warning restore IDE0300
} }
} }

View File

@ -1,10 +1,9 @@
using System.Numerics; // ReSharper disable UnusedMember.Global
using System.Reflection; // ReSharper disable MemberCanBePrivate.Global
#pragma warning disable CA1720
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text.Json; using System.Text.Json;
using System.Web;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
using NSExt.Constant; using NSExt.Constant;
namespace NSExt.Extensions; namespace NSExt.Extensions;
@ -12,107 +11,49 @@ namespace NSExt.Extensions;
/// <summary> /// <summary>
/// StringExtensions /// StringExtensions
/// </summary> /// </summary>
public static partial class StringExtensions public static class StringExtensions
{ {
private const string _CHARACTERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; private static readonly JsonSerializerOptions _defaultJsonSerializerOptions
private static readonly Regex _regexIpV4 = RegexIpV4(); = default(JsonSerializerOptions).NewJsonSerializerOptions();
/// <summary> /// <summary>
/// aes加密 /// aes加密
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">要加密的串</param>
/// <param name="key">密钥</param> /// <param name="key">密钥</param>
public static string Aes(this string me, string key) public static string Aes(this string me, string key)
{ {
using var aes = System.Security.Cryptography.Aes.Create(); using var aes = System.Security.Cryptography.Aes.Create();
aes.Padding = PaddingMode.PKCS7; aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.ECB; aes.Mode = CipherMode.ECB;
aes.Key = key.Hex(); aes.Key = key.Hex();
using var encryptor = aes.CreateEncryptor(); using var encryptor = aes.CreateEncryptor();
var bytes = me.Hex(); var bytes = me.Hex();
var decrypted = encryptor.TransformFinalBlock(bytes, 0, bytes.Length); var decrypted = encryptor.TransformFinalBlock(bytes, 0, bytes.Length);
return decrypted.Base64(); return decrypted.Base64();
} }
/// <summary> /// <summary>
/// aes解密 /// aes解密
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">要加密的串</param>
/// <param name="key">密钥</param> /// <param name="key">密钥</param>
public static string AesDe(this string me, string key) public static string AesDe(this string me, string key)
{ {
using var aes = System.Security.Cryptography.Aes.Create(); using var aes = System.Security.Cryptography.Aes.Create();
aes.Padding = PaddingMode.PKCS7; aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.ECB; aes.Mode = CipherMode.ECB;
aes.Key = key.Hex(); aes.Key = key.Hex();
using var encryptor = aes.CreateDecryptor(); using var encryptor = aes.CreateDecryptor();
var bytes = me.Base64De(); var bytes = me.Base64De();
var decrypted = encryptor.TransformFinalBlock(bytes, 0, bytes.Length); var decrypted = encryptor.TransformFinalBlock(bytes, 0, bytes.Length);
return decrypted.HexDe(); 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> /// <summary>
/// base64编码 /// base64编码
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">待base64编码的字符串</param>
/// <param name="e">字符串的编码方式</param> /// <param name="e">字符串的编码方式</param>
/// <returns>编码后的base64字符串</returns> /// <returns>编码后的base64字符串</returns>
public static string Base64(this string me, Encoding e) public static string Base64(this string me, Encoding e)
@ -123,7 +64,7 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// base64解码 /// base64解码
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">待解码的字符串</param>
/// <returns>解码后的原始字节数组</returns> /// <returns>解码后的原始字节数组</returns>
public static byte[] Base64De(this string me) public static byte[] Base64De(this string me)
{ {
@ -133,7 +74,7 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// base64解码 /// base64解码
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">待解码的字符串</param>
/// <param name="e">字符串的编码方式</param> /// <param name="e">字符串的编码方式</param>
/// <returns>解码后的原始字符串</returns> /// <returns>解码后的原始字符串</returns>
public static string Base64De(this string me, Encoding e) public static string Base64De(this string me, Encoding e)
@ -141,22 +82,6 @@ public static partial class StringExtensions
return e.GetString(me.Base64De()); 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> /// <summary>
/// 将易于web传输的base64web字符串转换为原生base64 /// 将易于web传输的base64web字符串转换为原生base64
/// </summary> /// </summary>
@ -175,18 +100,10 @@ public static partial class StringExtensions
return me.Replace("+", "-").Replace("/", "_").Replace("=", "."); 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>
/// 将字符串转换成日期对象 /// 将字符串转换成日期对象
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">待转换字符串</param>
/// <returns>转换后的日期对象</returns> /// <returns>转换后的日期对象</returns>
public static DateTime DateTime(this string me) public static DateTime DateTime(this string me)
{ {
@ -196,7 +113,7 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// 将字符串转换成日期对象 /// 将字符串转换成日期对象
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">待转换字符串</param>
/// <param name="format">日期格式</param> /// <param name="format">日期格式</param>
/// <returns>转换后的日期对象</returns> /// <returns>转换后的日期对象</returns>
public static DateTime DateTimeExact(this string me, string format) public static DateTime DateTimeExact(this string me, string format)
@ -207,30 +124,32 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// 将字符串转换成日期对象 /// 将字符串转换成日期对象
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">待转换字符串</param>
/// <param name="format">日期格式</param> /// <param name="format">日期格式</param>
/// <param name="def">转换失败时返回的日期对象</param> /// <param name="def">转换失败时返回的日期对象</param>
/// <returns>转换后的日期对象</returns> /// <returns>转换后的日期对象</returns>
public static DateTime DateTimeExactTry(this string me, string format, DateTime def) 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> /// <summary>
/// 将字符串转换成日期对象 /// 将字符串转换成日期对象
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">待转换字符串</param>
/// <param name="def">转换失败时返回的日期对象</param> /// <param name="def">转换失败时返回的日期对象</param>
/// <returns>转换后的日期对象</returns> /// <returns>转换后的日期对象</returns>
public static DateTime DateTimeTry(this string me, DateTime def) 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, out var ret) ? def : ret;
} }
/// <summary> /// <summary>
/// string to decimal /// string to decimal
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">string</param>
/// <returns>decimal</returns> /// <returns>decimal</returns>
public static decimal Dec(this string me) public static decimal Dec(this string me)
{ {
@ -240,7 +159,7 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// 尝试将字符串转为decimal /// 尝试将字符串转为decimal
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">字符串</param>
/// <param name="def">转换失败后返回的默认值</param> /// <param name="def">转换失败后返回的默认值</param>
/// <returns>转换后的decimal</returns> /// <returns>转换后的decimal</returns>
public static decimal DecTry(this string me, decimal def) public static decimal DecTry(this string me, decimal def)
@ -251,7 +170,7 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// string to double /// string to double
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">string</param>
/// <returns>Int32</returns> /// <returns>Int32</returns>
public static double Double(this string me) public static double Double(this string me)
{ {
@ -276,19 +195,10 @@ public static partial class StringExtensions
return !System.Enum.TryParse(typeof(T), name, out var ret) ? def : (T)ret; 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> /// <summary>
/// string to float /// string to float
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">string</param>
/// <returns>Int32</returns> /// <returns>Int32</returns>
public static float Float(this string me) public static float Float(this string me)
{ {
@ -298,7 +208,7 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// 将字符串转为guid /// 将字符串转为guid
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">字符串</param>
public static Guid Guid(this string me) public static Guid Guid(this string me)
{ {
return System.Guid.Parse(me); return System.Guid.Parse(me);
@ -307,7 +217,7 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// 将字符串转换成guid /// 将字符串转换成guid
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">字符串</param>
/// <param name="def">转换失败的返回值</param> /// <param name="def">转换失败的返回值</param>
public static Guid Guid(this string me, Guid def) public static Guid Guid(this string me, Guid def)
{ {
@ -317,7 +227,7 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// 将字符串转换成字节数组形式 /// 将字符串转换成字节数组形式
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">字符串</param>
/// <param name="e">字符串使用的编码</param> /// <param name="e">字符串使用的编码</param>
/// <returns>字节数组</returns> /// <returns>字节数组</returns>
public static byte[] Hex(this string me, Encoding e) public static byte[] Hex(this string me, Encoding e)
@ -328,7 +238,7 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// 将字符串转换成字节数组形式 /// 将字符串转换成字节数组形式
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">字符串</param>
/// <returns>字节数组</returns> /// <returns>字节数组</returns>
public static byte[] Hex(this string me) public static byte[] Hex(this string me)
{ {
@ -346,11 +256,9 @@ public static partial class StringExtensions
{ {
using var hmacSha1 = new HMACSHA1(e.GetBytes(secret)); using var hmacSha1 = new HMACSHA1(e.GetBytes(secret));
#if NET9_0_OR_GREATER return BitConverter.ToString(hmacSha1.ComputeHash(e.GetBytes(me)))
return Convert.ToHexStringLower(hmacSha1.ComputeHash(e.GetBytes(me))); .Replace("-", string.Empty)
#else .ToLower(CultureInfo.CurrentCulture);
return BitConverter.ToString(hmacSha1.ComputeHash(e.GetBytes(me))).Replace("-", string.Empty).ToLower(CultureInfo.CurrentCulture);
#endif
} }
/// <summary> /// <summary>
@ -364,7 +272,7 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// 解码html编码 /// 解码html编码
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">html编码后的字符串</param>
/// <returns>解码后的原始字符串</returns> /// <returns>解码后的原始字符串</returns>
public static string HtmlDe(this string me) public static string HtmlDe(this string me)
{ {
@ -374,7 +282,7 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// string to Int32 /// string to Int32
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">string</param>
/// <returns>Int32</returns> /// <returns>Int32</returns>
public static int Int32(this string me) public static int Int32(this string me)
{ {
@ -384,7 +292,7 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// 尝试将字符串转为int32 /// 尝试将字符串转为int32
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">字符串</param>
/// <param name="def">转换失败后返回的默认值</param> /// <param name="def">转换失败后返回的默认值</param>
/// <returns>转换后的int32</returns> /// <returns>转换后的int32</returns>
public static int Int32Try(this string me, int def) public static int Int32Try(this string me, int def)
@ -395,7 +303,7 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// string to Int64 /// string to Int64
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">string</param>
/// <returns>Int64</returns> /// <returns>Int64</returns>
public static long Int64(this string me) public static long Int64(this string me)
{ {
@ -405,7 +313,7 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// 尝试将字符串转为int64 /// 尝试将字符串转为int64
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">字符串</param>
/// <param name="def">转换失败后返回的默认值</param> /// <param name="def">转换失败后返回的默认值</param>
/// <returns>转换后的int64</returns> /// <returns>转换后的int64</returns>
public static long Int64Try(this string me, long def) public static long Int64Try(this string me, long def)
@ -424,25 +332,22 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// 是否base64字符串 /// 是否base64字符串
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">字符串</param>
public static bool IsBase64String(this string me) public static bool IsBase64String(this string me)
{ {
// 一个合法的Base64有着以下特征 // 一个合法的Base64有着以下特征
// 字符串的长度为4的整数倍。 // 字符串的长度为4的整数倍。
// 字符串的符号取值只能在A -Z, a -z, 0 -9, +, /, =共计65个字符中且 = 如果出现就必须在结尾出现。 // 字符串的符号取值只能在A -Z, a -z, 0 -9, +, /, =共计65个字符中且 = 如果出现就必须在结尾出现。
if (!me.All(x => x.IsBase64Character())) if (!me.All(x => x.IsBase64Character())) {
{
return false; return false;
} }
if (me.Length % 4 != 0) if (me.Length % 4 != 0) {
{
return false; return false;
} }
var firstEqualSignPos = me.IndexOf('='); var firstEqualSignPos = me.IndexOf('=');
if (firstEqualSignPos < 0) if (firstEqualSignPos < 0) {
{
return true; return true;
} }
@ -450,37 +355,6 @@ public static partial class StringExtensions
return lastEqualSignPos == me.Length - 1 && me[firstEqualSignPos..lastEqualSignPos].All(x => x == '='); 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())
{
return false;
}
try
{
_ = JsonDocument.Parse(me);
}
catch
{
return false;
}
return true;
}
/// <summary> /// <summary>
/// 中文姓名打马赛克 /// 中文姓名打马赛克
/// </summary> /// </summary>
@ -492,7 +366,7 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// 对一个手机号进行掩码处理 /// 对一个手机号进行掩码处理
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">手机号</param>
/// <returns>掩码后的手机号</returns> /// <returns>掩码后的手机号</returns>
public static string MaskMobile(this string me) public static string MaskMobile(this string me)
{ {
@ -502,24 +376,20 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// 对一个字符串进行md5hash运算 /// 对一个字符串进行md5hash运算
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">字符串</param>
/// <param name="e">字符串使用的编码</param> /// <param name="e">字符串使用的编码</param>
/// <returns>hash摘要的16进制文本形式无连字符小写</returns> /// <returns>hash摘要的16进制文本形式无连字符小写</returns>
public static string Md5(this string me, Encoding e) public static string Md5(this string me, Encoding e)
{ {
#if NET9_0_OR_GREATER
return Convert.ToHexStringLower(MD5.HashData(e.GetBytes(me)));
#else
return BitConverter.ToString(MD5.HashData(e.GetBytes(me))) return BitConverter.ToString(MD5.HashData(e.GetBytes(me)))
.Replace("-", string.Empty) .Replace("-", string.Empty)
.ToLower(CultureInfo.CurrentCulture); .ToLower(CultureInfo.CurrentCulture);
#endif
} }
/// <summary> /// <summary>
/// 判断字符串是否为null或不存在子元素如果为集合对象如果为空返回指定的默认值否则返回字符串本身 /// 判断字符串是否为null或不存在子元素如果为集合对象如果为空返回指定的默认值否则返回字符串本身
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">指定字符串</param>
/// <param name="defVal">指定的默认值</param> /// <param name="defVal">指定的默认值</param>
/// <returns>如果为空,返回指定的默认值,否则返回字符串本身</returns> /// <returns>如果为空,返回指定的默认值,否则返回字符串本身</returns>
public static string NullOrEmpty(this string me, string defVal) public static string NullOrEmpty(this string me, string defVal)
@ -538,30 +408,30 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// 反序列化一个文件获得指定类型的数据对象 /// 反序列化一个文件获得指定类型的数据对象
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">等待反序列化的json文本</param>
/// <param name="options">序列化选项</param> /// <param name="options">序列化选项</param>
/// <returns>反序列化后生成的对象</returns> /// <returns>反序列化后生成的对象</returns>
public static T Object<T>(this string me, JsonSerializerOptions options = null) public static T Object<T>(this string me, JsonSerializerOptions options = null)
{ {
return JsonSerializer.Deserialize<T>(me, options); return JsonSerializer.Deserialize<T>(me, options ?? _defaultJsonSerializerOptions);
} }
/// <summary> /// <summary>
/// 反序列化一个文件获得指定类型的数据对象 /// 反序列化一个文件获得指定类型的数据对象
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">等待反序列化的json文本</param>
/// <param name="type">实际类型</param> /// <param name="type">实际类型</param>
/// <param name="options">序列化选项</param> /// <param name="options">序列化选项</param>
/// <returns>反序列化后生成的对象</returns> /// <returns>反序列化后生成的对象</returns>
public static object Object(this string me, Type type, JsonSerializerOptions options = null) public static object Object(this string me, Type type, JsonSerializerOptions options = null)
{ {
return JsonSerializer.Deserialize(me, type, options); return JsonSerializer.Deserialize(me, type, options ?? _defaultJsonSerializerOptions);
} }
/// <summary> /// <summary>
/// 生成密码 /// 生成密码
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">密码原文</param>
/// <returns>密文</returns> /// <returns>密文</returns>
public static string Pwd(this string me) public static string Pwd(this string me)
{ {
@ -571,7 +441,7 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// 移除字符串中的html标签 /// 移除字符串中的html标签
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">字符串</param>
/// <returns>处理之后的字符串</returns> /// <returns>处理之后的字符串</returns>
public static string RemoveHtmlTag(this string me) public static string RemoveHtmlTag(this string me)
{ {
@ -589,24 +459,20 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// 对一个字符串进行sha1 hash运算 /// 对一个字符串进行sha1 hash运算
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">字符串</param>
/// <param name="e">字符串使用的编码</param> /// <param name="e">字符串使用的编码</param>
/// <returns>hash摘要的16进制文本形式无连字符小写</returns> /// <returns>hash摘要的16进制文本形式无连字符小写</returns>
public static string Sha1(this string me, Encoding e) public static string Sha1(this string me, Encoding e)
{ {
#if NET9_0_OR_GREATER
return Convert.ToHexStringLower(SHA1.HashData(e.GetBytes(me)));
#else
return BitConverter.ToString(SHA1.HashData(e.GetBytes(me))) return BitConverter.ToString(SHA1.HashData(e.GetBytes(me)))
.Replace("-", string.Empty) .Replace("-", string.Empty)
.ToLower(CultureInfo.CurrentCulture); .ToLower(CultureInfo.CurrentCulture);
#endif
} }
/// <summary> /// <summary>
/// 蛇形命名 /// 蛇形命名
/// </summary> /// </summary>
public static string SnakeCase(this string me) public static string Snakecase(this string me)
{ {
return Regexes.RegexUpLetter.Replace(me, "-$1").ToLower(CultureInfo.InvariantCulture).TrimStart('-'); return Regexes.RegexUpLetter.Replace(me, "-$1").ToLower(CultureInfo.InvariantCulture).TrimStart('-');
} }
@ -616,8 +482,7 @@ public static partial class StringExtensions
/// </summary> /// </summary>
public static string Sub(this string me, int startIndex, int length) 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; length = me.Length - startIndex;
} }
@ -632,30 +497,6 @@ public static partial class StringExtensions
return $"<pre>{me}</pre>"; return $"<pre>{me}</pre>";
} }
/// <summary>
/// 首字母小写
/// </summary>
public static string ToLowerCamelCase(this string me)
{
return string.IsNullOrWhiteSpace(me) ? me : string.Concat(me[0].ToString(CultureInfo.InvariantCulture).ToLowerInvariant(), me.AsSpan(1));
}
/// <summary>
/// 首字母大写
/// </summary>
public static string ToUpperCamelCase(this string me)
{
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>
/// 将连续多个空格替换成一个空格 /// 将连续多个空格替换成一个空格
/// </summary> /// </summary>
@ -667,31 +508,10 @@ public static partial class StringExtensions
return ret == me ? ret : ret.TrimSpaces(); 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;";
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> /// <summary>
/// url编码 /// url编码
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">字符串</param>
/// <returns>url编码后的字符串</returns> /// <returns>url编码后的字符串</returns>
public static string Url(this string me) public static string Url(this string me)
{ {
@ -701,7 +521,7 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// 解码url编码 /// 解码url编码
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">url编码后的字符串</param>
/// <returns>解码后的原始字符串</returns> /// <returns>解码后的原始字符串</returns>
public static string UrlDe(this string me) public static string UrlDe(this string me)
{ {
@ -711,21 +531,15 @@ public static partial class StringExtensions
/// <summary> /// <summary>
/// MD5 hmac编码 /// MD5 hmac编码
/// </summary> /// </summary>
/// <param name="me">me</param> /// <param name="me">字符串</param>
/// <param name="key">密钥</param> /// <param name="key">密钥</param>
/// <param name="e">字符串使用的编码</param> /// <param name="e">字符串使用的编码</param>
/// <returns>hash摘要的16进制文本形式无连字符小写</returns> /// <returns>hash摘要的16进制文本形式无连字符小写</returns>
private static string Md5Hmac(this string me, string key, Encoding e) private static string Md5Hmac(this string me, string key, Encoding e)
{ {
using var md5Hmac = new HMACMD5(e.GetBytes(key)); using var md5Hmac = new HMACMD5(e.GetBytes(key));
return BitConverter.ToString(md5Hmac.ComputeHash(e.GetBytes(me)))
#if NET9_0_OR_GREATER .Replace("-", string.Empty)
return Convert.ToHexStringLower(md5Hmac.ComputeHash(e.GetBytes(me))); .ToLower(CultureInfo.CurrentCulture);
#else
return BitConverter.ToString(md5Hmac.ComputeHash(e.GetBytes(me))).Replace("-", string.Empty).ToLower(CultureInfo.CurrentCulture);
#endif
} }
[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();
} }

9
src/GlobalUsings.cs Normal file
View File

@ -0,0 +1,9 @@
global using System.ComponentModel;
global using System.Data;
global using System.Data.Common;
global using System.Globalization;
global using System.Runtime.CompilerServices;
global using System.Text;
global using System.Text.RegularExpressions;
global using System.Web;
global using Microsoft.Extensions.Logging;

17
src/NSExt.csproj Normal file
View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
<PackageReference Include="MinVer" Version="4.3.0-beta.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<Import Project="../CodeQuality.props" />
</Project>

View File

@ -1,7 +0,0 @@
global using System;
global using System.ComponentModel;
global using System.Diagnostics;
global using System.Globalization;
global using System.Text;
global using System.Text.RegularExpressions;
global using NSExt.Languages;

View File

@ -1,19 +0,0 @@
using NSExt.Extensions;
using Xunit;
namespace NSExt;
/// <summary>
/// 所有测试用例
/// </summary>
public class AllTests
{
/// <summary>
/// IsJsonString
/// </summary>
[Fact]
public void IsJsonString()
{
Assert.True("{\"a\":\"b\"}".IsJsonString());
}
}

View File

@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<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.4">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<ProjectReference Include="../NSExt/NSExt.csproj"/>
</ItemGroup>
</Project>

View File

@ -1,26 +0,0 @@
namespace NSExt.Attributes;
/// <summary>
/// 指定本地化资源类型
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Field)]
public sealed class LocalizationAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="LocalizationAttribute" /> class.
/// </summary>
#pragma warning disable IDE0290
public LocalizationAttribute(Type resourceClass)
#pragma warning restore IDE0290
{
ResourceClass = resourceClass;
}
/// <summary>
/// Gets or sets 资源类型
/// </summary>
/// <value>
/// 资源类型
/// </value>
public Type ResourceClass { get; set; }
}

View File

@ -1,28 +0,0 @@
namespace NSExt.Attributes;
/// <summary>
/// 本地化资源描述特性
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Field)]
public sealed class ResourceDescriptionAttribute<T> : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="ResourceDescriptionAttribute{T}" /> class.
/// </summary>
#pragma warning disable IDE0290
public ResourceDescriptionAttribute(string resourceName)
#pragma warning restore IDE0290
{
ResourceName = resourceName;
}
/// <summary>
/// 资源名称
/// </summary>
public string ResourceName { get; }
/// <summary>
/// 资源对象
/// </summary>
public T ResourceObject { get; set; }
}

View File

@ -1,21 +0,0 @@
namespace NSExt.Constant;
#pragma warning disable SYSLIB1045
/// <summary>
/// 使用 RegexGenerator 新特性会生成重复key值的xmlComment导致出错
/// </summary>
internal static class Regexes
{
public static readonly Regex RegexBacksLantUnicode
= new(@"\\u([a-fA-F0-9]{4})", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static readonly Regex RegexHtmlTag = new("<[^>]*>", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static readonly Regex RegexMobile
= new(@"^(\d{3})\d{4}(\d{4})$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static readonly Regex RegexPercentUnicode
= new(@"\\u([a-fA-F0-9]{4})", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static readonly Regex RegexUpLetter = new("([A-Z])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
}

View File

@ -1,41 +0,0 @@
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using NSExt.Attributes;
namespace NSExt.Extensions;
/// <summary>
/// EnumExtensions
/// </summary>
public static class EnumExtensions
{
/// <summary>
/// 获取显示特性
/// </summary>
public static DisplayAttribute GetDisplay(this Enum me)
{
return me.GetAttributeOfType<DisplayAttribute>();
}
/// <summary>
/// 获取枚举的本地化资源描述
/// </summary>
public static string ResDesc<T>(this Enum e)
{
var typeOfEnum = e.GetType();
var typeOfField = typeOfEnum.GetField(Enum.GetName(typeOfEnum, e)!);
var resDescAttr = typeOfField!.GetCustomAttribute<ResourceDescriptionAttribute<T>>(true);
return resDescAttr is null
? Enum.GetName(typeOfEnum, e)
: typeof(T).GetProperty(resDescAttr.ResourceName)?.GetValue(null) as string;
}
/// <summary>
/// 通过类泛型类型获取特性
/// </summary>
private static T GetAttributeOfType<T>(this Enum me)
where T : Attribute
{
return me.GetType().GetMember(me.ToString())[0].GetCustomAttributes<T>(false).FirstOrDefault();
}
}

View File

@ -1,46 +0,0 @@
namespace NSExt.Extensions;
/// <summary>
/// EnumerableExtensions
/// </summary>
public static class EnumerableExtensions
{
/// <summary>
/// 异步累加器函数
/// </summary>
/// <exception cref="InvalidOperationException">InvalidOperationException</exception>
public static async Task<TSource> AggregateAsync<TSource>( //
this IEnumerable<TSource> source, Func<TSource, TSource, Task<TSource>> func)
{
using var e = source.GetEnumerator();
if (!e.MoveNext()) {
throw new InvalidOperationException("Sequence contains no elements");
}
var result = e.Current;
while (e.MoveNext()) {
result = await func(result, e.Current).ConfigureAwait(false);
}
return result;
}
/// <summary>
/// 将列表转成分隔符分隔的字符串
/// </summary>
public static string Join(this IEnumerable<object> me, string separator)
{
return string.Join(separator, me);
}
/// <summary>
/// 判断对象是否为null或不存在子元素如果为集合对象
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="me">me</param>
/// <returns>空则返回true</returns>
public static bool NullOrEmpty<T>(this IEnumerable<T> me)
{
return me?.Any() != true;
}
}

View File

@ -1,86 +0,0 @@
// ReSharper disable TemplateIsNotCompileTimeConstantProblem
using System.Runtime.CompilerServices;
using Microsoft.Extensions.Logging;
namespace NSExt.Extensions;
/// <summary>
/// LoggerExtensions
/// </summary>
public static class LoggerExtensions
{
private const string _MESSAGE_S_THREAD_ID_CALLER_NAME_CALLER_FILE_PATH_CALLER_LINE_NUMBER
= "{Message} <s:{CallerName}@{CallerFilePath}:{CallerLineNumber}>";
private static readonly Action<ILogger, string, string, string, string, Exception> _logDebug
= LoggerMessage.Define<string, string, string, string>(LogLevel.Debug, default
, _MESSAGE_S_THREAD_ID_CALLER_NAME_CALLER_FILE_PATH_CALLER_LINE_NUMBER);
private static readonly Action<ILogger, string, string, string, string, Exception> _logError
= LoggerMessage.Define<string, string, string, string>(LogLevel.Error, default
, _MESSAGE_S_THREAD_ID_CALLER_NAME_CALLER_FILE_PATH_CALLER_LINE_NUMBER);
private static readonly Action<ILogger, string, string, string, string, Exception> _logFatal
= LoggerMessage.Define<string, string, string, string>(LogLevel.Critical, default
, _MESSAGE_S_THREAD_ID_CALLER_NAME_CALLER_FILE_PATH_CALLER_LINE_NUMBER);
private static readonly Action<ILogger, string, string, string, string, Exception> _logInfo
= LoggerMessage.Define<string, string, string, string>(LogLevel.Information, default
, _MESSAGE_S_THREAD_ID_CALLER_NAME_CALLER_FILE_PATH_CALLER_LINE_NUMBER);
private static readonly Action<ILogger, string, string, string, string, Exception> _logWarn
= LoggerMessage.Define<string, string, string, string>(LogLevel.Warning, default
, _MESSAGE_S_THREAD_ID_CALLER_NAME_CALLER_FILE_PATH_CALLER_LINE_NUMBER);
/// <summary>
/// Debug
/// </summary>
public static void Debug(this ILogger me, object message, [CallerMemberName] string callerName = null
, [CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = 0)
{
_logDebug(me, message.ToString(), callerName, Path.GetFileName(callerFilePath)
, callerLineNumber.ToString(CultureInfo.InvariantCulture), null);
}
/// <summary>
/// Error
/// </summary>
public static void Error(this ILogger me, object message, [CallerMemberName] string callerName = null
, [CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = 0)
{
_logError(me, message.ToString(), callerName, Path.GetFileName(callerFilePath)
, callerLineNumber.ToString(CultureInfo.InvariantCulture), null);
}
/// <summary>
/// Fatal
/// </summary>
public static void Fatal(this ILogger me, object message, Exception ex = null
, [CallerMemberName] string callerName = null, [CallerFilePath] string callerFilePath = null
, [CallerLineNumber] int callerLineNumber = 0)
{
_logFatal(me, message.ToString(), callerName, Path.GetFileName(callerFilePath)
, callerLineNumber.ToString(CultureInfo.InvariantCulture), ex);
}
/// <summary>
/// Info
/// </summary>
public static void Info(this ILogger me, object message, [CallerMemberName] string callerName = null
, [CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = 0)
{
_logInfo(me, message.ToString(), callerName, Path.GetFileName(callerFilePath)
, callerLineNumber.ToString(CultureInfo.InvariantCulture), null);
}
/// <summary>
/// Warn
/// </summary>
public static void Warn(this ILogger me, object message, [CallerMemberName] string callerName = null
, [CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = 0)
{
_logWarn(me, message.ToString(), callerName, Path.GetFileName(callerFilePath)
, callerLineNumber.ToString(CultureInfo.InvariantCulture), null);
}
}

View File

@ -1,42 +0,0 @@
namespace NSExt.Extensions;
/// <summary>
/// LongExtensions
/// </summary>
public static class LongExtensions
{
/// <summary>
/// 判断枚举是否包含某个位
/// </summary>
public static bool HasFlag<T>(this long me, T flag)
where T : Enum
{
var val = (long)(object)flag;
return (me & val) == val;
}
/// <summary>
/// 生成随机数
/// </summary>
/// <param name="me">me</param>
public static long Rand(this long[] me)
{
return new Random(Guid.NewGuid().GetHashCode()).NextInt64(me[0], me[1]);
}
/// <summary>
/// 1970毫秒数转换成日期对象
/// </summary>
public static DateTime Time(this long msFrom1970)
{
return DateTime.UnixEpoch.AddMilliseconds(msFrom1970).ToLocalTime();
}
/// <summary>
/// ToString 的 Invariant 版本
/// </summary>
public static string ToInvString(this long me)
{
return me.ToString(CultureInfo.InvariantCulture);
}
}

View File

@ -1,30 +0,0 @@
using System.Text.Json;
namespace NSExt.Extensions;
/// <summary>
/// ObjectExtensions
/// </summary>
public static class ObjectExtensions
{
/// <summary>
/// 将一个对象序列化成json文本
/// </summary>
/// <param name="me">me</param>
/// <returns>json文本</returns>
public static string Json(this object me)
{
return JsonSerializer.Serialize(me);
}
/// <summary>
/// 将一个对象序列化成json文本
/// </summary>
/// <param name="me">me</param>
/// <param name="options">序列化选项</param>
/// <returns>json文本</returns>
public static string Json(this object me, JsonSerializerOptions options)
{
return JsonSerializer.Serialize(me, options);
}
}

View File

@ -1,19 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackageProjectUrl>https://github.com/nsnail/NSExt.git</PackageProjectUrl>
</PropertyGroup>
<Import Project="$(SolutionDir)/build/code.quality.props"/>
<Import Project="$(SolutionDir)/build/nuget.package.props"/>
<Import Project="$(SolutionDir)/build/copy.pkg.xml.comment.files.targets"/>
<Import Project="$(SolutionDir)/build/prebuild.targets"/>
<ItemGroup>
<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">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

9
stylecop.json Normal file
View File

@ -0,0 +1,9 @@
{
"$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
"settings": {
"indentation": {
"useTabs": false,
"indentationSize": 4
}
}
}