refactor: ♻️ 2.0 (#3)

This commit is contained in:
nsnail 2023-12-14 15:03:07 +08:00 committed by GitHub
parent 8c0dbcf1f4
commit cf2988b389
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
73 changed files with 1157 additions and 371 deletions

72
.commitlintrc.js Normal file
View File

@ -0,0 +1,72 @@
// .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: '',
defaultIssues: '',
defaultScope: '',
defaultSubject: ''
}
}

View File

@ -15,28 +15,6 @@ indent_size = 2
[*.cs]
dotnet_analyzer_diagnostic.severity = warning
dotnet_diagnostic.CA1200.severity = none
dotnet_diagnostic.CA1707.severity = none
dotnet_diagnostic.CA1716.severity = none
dotnet_diagnostic.IDE0005.severity = none
dotnet_diagnostic.IDE0008.severity = none
dotnet_diagnostic.IDE0010.severity = none
dotnet_diagnostic.IDE0055.severity = none
dotnet_diagnostic.IDE0160.severity = none
dotnet_diagnostic.IDE0270.severity = none
dotnet_diagnostic.RCS1141.severity = none
dotnet_diagnostic.RCS1142.severity = none
dotnet_diagnostic.RCS1181.severity = none
dotnet_diagnostic.RCS1186.severity = none
dotnet_diagnostic.S101.severity = none
dotnet_diagnostic.S1121.severity = none
dotnet_diagnostic.S1199.severity = none
dotnet_diagnostic.S125.severity = none
dotnet_diagnostic.S2094.severity = none
dotnet_diagnostic.S3925.severity = none
dotnet_diagnostic.S4663.severity = none
dotnet_diagnostic.SYSLIB1045.severity = none
# ReSharper properties
resharper_align_linq_query = true
@ -73,7 +51,6 @@ resharper_wrap_before_eq = true
resharper_wrap_chained_method_calls = chop_if_long
resharper_wrap_switch_expression = chop_if_long
# Microsoft .NET properties
csharp_indent_braces = false
csharp_new_line_before_open_brace = local_functions, methods, types

36
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,36 @@
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: 8.0.x
- working-directory: ./src/backend/NSExt
run: dotnet build -c Release -f net6.0
- working-directory: ./src/backend/NSExt
run: dotnet build -c Release -f net7.0
- working-directory: ./src/backend/NSExt
run: dotnet build -c Release -f net8.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
- run: dotnet nuget push ./dist/backend/NSExt/bin/Release/NSExt.${{ steps.get_version.outputs.VERSION }}.snupkg --skip-duplicate --api-key ${{ secrets.NUGET_TOKEN }} --source https://api.nuget.org/v3/index.json

9
.gitignore vendored
View File

@ -55,7 +55,7 @@ nunit-*.xml
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
BenchmarkNSExtNet.Artifacts/
# .NET Core
project.lock.json
@ -130,12 +130,12 @@ $tf/
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
*.NSExtSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
# NSExtCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
@ -400,6 +400,7 @@ FodyWeavers.xsd
# User Define
dist/
refs/
*.[Dd]esigner.cs
*.db
cache
/assets/res/Ln.resx

View File

@ -0,0 +1,30 @@
{
"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/**"
]
}
]
}
],
}

View File

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

11
CHANGELOG.md Normal file
View File

@ -0,0 +1,11 @@
# 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.0.0 (2023-12-14)
### Features
* ++ ([e41652d](https://github.com/nsnail/NSExt/commit/e41652d553beda7a2eb1600da4795e07f4260330))
* 增加一些扩展方法 ([1f26d0f](https://github.com/nsnail/NSExt/commit/1f26d0f28098f7ee98a9a5482096aecd53b85e04))

View File

@ -1,26 +1,36 @@
<!-- 注意此文件名大小写不可变更 -->
<Project>
<PropertyGroup>
<!-- $(XXX) 定义有顺序 排序请注意-->
<SolutionDir>$(MSBuildThisFileDirectory)</SolutionDir>
</PropertyGroup>
<Import Project="$(SolutionDir)/build/minver.targets"/>
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Authors>nsnail</Authors>
<BaseIntermediateOutputPath>$(SolutionDir)/dist/$(MSBuildProjectName)/obj</BaseIntermediateOutputPath>
<BaseOutputPath>$(SolutionDir)/dist/$(MSBuildProjectName)/bin</BaseOutputPath>
<BaseIntermediateOutputPath>$(SolutionDir)/dist/backend/$(MSBuildProjectName)/obj</BaseIntermediateOutputPath>
<BaseOutputPath>$(SolutionDir)/dist/backend/$(MSBuildProjectName)/bin</BaseOutputPath>
<Copyright>© 2006-2023 nsnail</Copyright>
<Description>A .NET extension function library</Description>
<Description>The NSExt is a .NET extension function library</Description>
<EnableBaseIntermediateOutputPathMismatchWarning>false</EnableBaseIntermediateOutputPathMismatchWarning>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>preview</LangVersion>
<MinVerDefaultPreReleaseIdentifiers>beta</MinVerDefaultPreReleaseIdentifiers>
<MinVerTagPrefix>v</MinVerTagPrefix>
<NoWarn>CA1707;IDE0005;IDE0008;IDE0010;IDE0028;IDE0055;IDE0160;IDE0300;IDE0305;RCS1141;RCS1142;RCS1181;S101;S1121;S1135;S125;S2094;S3604;S4663;SYSLIB1045;SA1010;RCS1123;SA1407;IDE0048;S1075;S3928</NoWarn>
<Product>NSExt</Product>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/nsnail/NSExt.git</RepositoryUrl>
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
<Title>$(AssemblyName)</Title>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MinVer" Version="5.0.0-alpha.1">
<PackageReference Include="MinVer" Version="5.0.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>

View File

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

View File

@ -3,38 +3,66 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C84EB5A0-37AD-4B17-A51E-E36888C4441E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "backend", "backend", "{4DAF9366-855F-46BB-AE4C-660C92FA0697}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "meta", "meta", "{5198A03D-0CAC-4828-A807-34A693F73859}"
ProjectSection(SolutionItems) = preProject
.commitlintrc.js = .commitlintrc.js
.editorconfig = .editorconfig
.gitattributes = .gitattributes
.gitignore = .gitignore
.tgitconfig = .tgitconfig
build.cake = build.cake
code.cleanup.full.ps1 = code.cleanup.full.ps1
code.quality.props = code.quality.props
Directory.Build.props = Directory.Build.props
dot.clean.cmd = dot.clean.cmd
dotnet-tools.json = dotnet-tools.json
git.pr.ps1 = git.pr.ps1
git.rc.ps1 = git.rc.ps1
global.json = global.json
image.optimize.csx = image.optimize.csx
key.snk = key.snk
LICENSE = LICENSE
logo.png = logo.png
NSExt.sln.DotSettings = NSExt.sln.DotSettings
nuget.config = nuget.config
packable.props = packable.props
NuGet.Config = NuGet.Config
package.json = package.json
README.md = README.md
README.zh-CN.md = README.zh-CN.md
stylecop.analyzers.ruleset = stylecop.analyzers.ruleset
stylecop.json = stylecop.json
sync.metafiles.csx = sync.metafiles.csx
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NSExt.Tests", "src\NSExt.Tests\NSExt.Tests.csproj", "{557FBEF6-E6D5-4531-86DF-D772A10E2261}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{BB0B25C9-0901-4923-913F-00F9A6B352A5}"
ProjectSection(SolutionItems) = preProject
clean.ln.csx = scripts/clean.ln.csx
code.clean.csx = scripts/code.clean.csx
code.clean.ps1 = scripts/code.clean.ps1
gen.cs.tt = scripts/gen.cs.tt
gen.ln.cmd = scripts/gen.ln.cmd
gen.resx.tt = scripts/gen.resx.tt
git.pr.ps1 = scripts/git.pr.ps1
git.rc.ps1 = scripts/git.rc.ps1
image.optimize.csx = scripts/image.optimize.csx
install.as.tpl.ps1 = scripts/install.as.tpl.ps1
rename.csx = scripts/rename.csx
resharper.full.ps1 = scripts/resharper.full.ps1
switcher.nsext.json = scripts/switcher.nsext.json
switcher.ps1 = scripts/switcher.ps1
sync.sln.files.csx = scripts/sync.sln.files.csx
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NSExt", "src\NSExt\NSExt.csproj", "{BA0982BE-6E57-4AAF-9778-F9B2EB46F505}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{1129FE25-466B-4F4F-85FC-3752664245E1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{3C6F049E-3EE8-4D66-9AFF-E8A369032487}"
ProjectSection(SolutionItems) = preProject
ci.yml = .github/workflows/ci.yml
EndProjectSection
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
prebuild.targets = build/prebuild.targets
stylecop.analyzers.ruleset = build/stylecop.analyzers.ruleset
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NSExt", "src\backend\NSExt\NSExt.csproj", "{1E62C322-EE42-4699-A6F1-791C53EFA62D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NSExt.Tests", "src\backend\NSExt.Tests\NSExt.Tests.csproj", "{00604162-C444-478B-B773-3AB23C856CA7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -45,13 +73,19 @@ Global
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{557FBEF6-E6D5-4531-86DF-D772A10E2261}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{557FBEF6-E6D5-4531-86DF-D772A10E2261}.Debug|Any CPU.Build.0 = Debug|Any CPU
{557FBEF6-E6D5-4531-86DF-D772A10E2261}.Release|Any CPU.ActiveCfg = Release|Any CPU
{557FBEF6-E6D5-4531-86DF-D772A10E2261}.Release|Any CPU.Build.0 = Release|Any CPU
{BA0982BE-6E57-4AAF-9778-F9B2EB46F505}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BA0982BE-6E57-4AAF-9778-F9B2EB46F505}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BA0982BE-6E57-4AAF-9778-F9B2EB46F505}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BA0982BE-6E57-4AAF-9778-F9B2EB46F505}.Release|Any CPU.Build.0 = Release|Any CPU
{1E62C322-EE42-4699-A6F1-791C53EFA62D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1E62C322-EE42-4699-A6F1-791C53EFA62D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E62C322-EE42-4699-A6F1-791C53EFA62D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E62C322-EE42-4699-A6F1-791C53EFA62D}.Release|Any CPU.Build.0 = Release|Any CPU
{00604162-C444-478B-B773-3AB23C856CA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{00604162-C444-478B-B773-3AB23C856CA7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{00604162-C444-478B-B773-3AB23C856CA7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{00604162-C444-478B-B773-3AB23C856CA7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{4DAF9366-855F-46BB-AE4C-660C92FA0697} = {C84EB5A0-37AD-4B17-A51E-E36888C4441E}
{3C6F049E-3EE8-4D66-9AFF-E8A369032487} = {1129FE25-466B-4F4F-85FC-3752664245E1}
{1E62C322-EE42-4699-A6F1-791C53EFA62D} = {4DAF9366-855F-46BB-AE4C-660C92FA0697}
{00604162-C444-478B-B773-3AB23C856CA7} = {4DAF9366-855F-46BB-AE4C-660C92FA0697}
EndGlobalSection
EndGlobal

View File

@ -1,34 +1,57 @@
<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">
<s:String x:Key="/Default/CodeEditing/GenerateMemberBody/DocumentationGenerationKind/@EntryValue">Inherit</s:String>
<s:Boolean x:Key="/Default/CodeEditing/TypingAssist/SkipClosingBracesOnTabInStringLiterals/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=AssignmentInConditionalExpression/@EntryIndexedValue">DO_NOT_SHOW</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>
<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/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:Boolean
x:Key="/Default/CodeEditing/TypingAssist/SkipClosingBracesOnTabInStringLiterals/@EntryValue">True</s:Boolean>
<s:Boolean
x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Ett/@EntryIndexedValue">True</s:Boolean>
<s:String
x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=AssignmentInConditionalExpression/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=LocalizableElement/@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>
<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/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</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/CodeFormatting/CSharpFormat/PLACE_RECORD_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</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/Abbreviations/=ID/@EntryIndexedValue">ID</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IOS/@EntryIndexedValue">IOS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IP/@EntryIndexedValue">IP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
<s:String
x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CustomTools/CustomToolsData/@EntryValue"></s:String>
<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_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<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_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/ReSpeller/ReSpellerEnabled/@EntryValue">True</s:Boolean>
<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/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_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_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_WHILE/@EntryValue">Required</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/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="AA_BB" /&gt;</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/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;</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/CSharpFileLayoutPatterns/Pattern/@EntryValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;
&lt;Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"&gt;
@ -80,7 +103,6 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Haojia/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=hongbao/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=inte/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Lant/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=logourl/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Meituan/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=miaosha/@EntryIndexedValue">True</s:Boolean>

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,117 +0,0 @@
var target = Argument("target", "Default");
var configuration = Argument("configuration", "Release");
var framework = Argument("framework", "net7.0");
////////////////////////////////////////////////////////////////
// Tasks
Task("Clean")
.Does(context =>
{
context.CleanDirectory("./dist");
});
Task("Build")
.IsDependentOn("Clean")
.Does(context =>
{
DotNetPublish("./src/NSExt/NSExt.csproj", new DotNetPublishSettings {
Configuration = configuration,
Framework = framework,
});
});
// 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("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("Build")
.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("./dist/NSExt/bin/Release/*.*"))
{
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("Build");
////////////////////////////////////////////////////////////////
// Execution
RunTarget(target)

View File

@ -1,8 +1,8 @@
<Project>
<PropertyGroup>
<CodeAnalysisRuleSet>$(SolutionDir)/stylecop.analyzers.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRuleSet>$(SolutionDir)/build/stylecop.analyzers.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<PropertyGroup>
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<MSBuildTreatWarningsAsErrors>true</MSBuildTreatWarningsAsErrors>
@ -15,11 +15,15 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Roslynator.Analyzers" Version="4.5.0">
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.9.1-alpha">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.11.0.78383">
<PackageReference Include="Roslynator.Analyzers" Version="4.7.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.15.0.81779">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

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

11
build/minver.targets Normal file
View File

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

24
build/prebuild.targets Normal file
View File

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

View File

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

182
docs/CONTRIBUTING.md Normal file
View File

@ -0,0 +1,182 @@
# 约定式提交 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

226
docs/SEMVER.md Normal file
View File

@ -0,0 +1,226 @@
语义化版本 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,3 +0,0 @@
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

@ -2,22 +2,10 @@
"version": 1,
"isRoot": true,
"tools": {
"cake.tool": {
"version": "3.1.0",
"dotnet-t4": {
"version": "2.3.1",
"commands": [
"dotnet-cake"
]
},
"dotnet-script": {
"version": "1.4.0",
"commands": [
"dotnet-script"
]
},
"jetbrains.resharper.globaltools": {
"version": "2023.2.0",
"commands": [
"jb"
"t4"
]
}
}

View File

@ -1,26 +0,0 @@
$types = @{
'1' = @('FEA', '新增特性')
'2' = @('REF', '项目重构')
'3' = @('FIX', '缺陷修复')
'4' = @('PER', '性能优化')
'5' = @('RVT', '还原变更')
'6' = @('FMT', '格式整理')
'7' = @('DOC', '文档变更')
'8' = @('TST', '单元测试')
'9' = @('BLD', '工程构建')
}
git add ./
$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 commit -m "[$($types[$prefix][0])] $(($(Read-Host '是否跳过自动构建Y/n') -eq 'n') ? '': '[SKIP CI] ')$(Read-Host '请输入提交消息')"
$branch = $(git branch --show-current)
& './dot.clean.cmd'
git add ./
git commit --amend --no-edit
git pull
git push --set-upstream origin $branch
Start-Process -FilePath "https://github.com/nsnail/NSExt/compare/main...$branch"
Pause

View File

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

View File

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

View File

@ -1,18 +0,0 @@
<Project>
<PropertyGroup>
<AssemblyOriginatorKeyFile>../../key.snk</AssemblyOriginatorKeyFile>
<DelaySign>false</DelaySign>
<EmbedAllSources>true</EmbedAllSources>
<EmbedUntrackedSource>true</EmbedUntrackedSource>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<IncludeSymbols>true</IncludeSymbols>
<IsPackable>true</IsPackable>
<PackageIcon>logo.png</PackageIcon>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/nsnail/NSExt.git</PackageProjectUrl>
<PackageTags>extensions</PackageTags>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<SignAssembly>true</SignAssembly>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
</Project>

14
package.json Normal file
View File

@ -0,0 +1,14 @@
{
"version": "2.0.0",
"devDependencies": {
"cz-git": "^1.7.1",
"commitizen": "^4.3.0",
"prettier": "^3.1.0",
"standard-version": "^9.5.0"
},
"config": {
"commitizen": {
"path": "node_modules/cz-git"
}
}
}

View File

@ -1,6 +0,0 @@
Remove-Item ./dist -Recurse -Force -Confirm:$false
dotnet build -c Release
$apikey = Read-Host -Prompt "nuget apikey"
foreach ($file in Get-ChildItem -Path ./dist/NSExt/bin/Release | Where-Object { $_.Name -match "nupkg" }) {
dotnet nuget push $file --skip-duplicate --api-key $apikey --source https://api.nuget.org/v3/index.json
}

26
scripts/clean.ln.csx Normal file
View File

@ -0,0 +1,26 @@
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);
}

44
scripts/code.clean.csx Normal file
View File

@ -0,0 +1,44 @@
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;
}

4
scripts/code.clean.ps1 Normal file
View File

@ -0,0 +1,4 @@
dotnet 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 ../

77
scripts/gen.cs.tt Normal file
View File

@ -0,0 +1,77 @@
<#@ template language="C#" #>
<#@ assembly name="System.Xml" #>
<#@ output encoding="utf-8" extension="Designer.cs" #>
//------------------------------------------------------------------------------
// <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")]
[System.Diagnostics.DebuggerNonUserCode]
[System.Runtime.CompilerServices.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 System.Xml.XmlDocument();
xml.Load("../assets/res/Ln.resx");
foreach (System.Xml.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);
<#
}
#>
}

2
scripts/gen.ln.cmd Normal file
View File

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

39
scripts/gen.resx.tt Normal file
View File

@ -0,0 +1,39 @@
<#@ template language="C#" #>
<#@ output encoding="utf-8" extension="resx" #>
<?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 System.Text.RegularExpressions.Regex(@"^\d", System.Text.RegularExpressions.RegexOptions.Compiled);
foreach (var file in System.IO.Directory.GetFiles("../assets/res/", "*.ln"))
{
foreach (var line in System.IO.File.ReadLines(file))
{
#>
<data name="<#= regex.IsMatch(line) ? "_" : "" #><#= line #>" xml:space="preserve"><value><#= line #></value></data>
<#
}
}
#>
</root>

11
scripts/git.pr.ps1 Normal file
View File

@ -0,0 +1,11 @@
$branch = $( git branch --show-current )
git add ../
./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
./git.rc.ps1

View File

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

View File

@ -7,7 +7,7 @@
var files = Directory
.EnumerateFiles(
"./",
"../",
"*.png",
new EnumerationOptions
{
@ -37,7 +37,7 @@ files = new[] { "*.jpg", "*.jpeg" }
.SelectMany(
x =>
Directory.EnumerateFiles(
"./",
"../",
x,
new EnumerationOptions
{

View File

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

27
scripts/rename.csx Normal file
View File

@ -0,0 +1,27 @@
#r "nuget: NSExt, 1.1.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

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

View File

@ -0,0 +1,17 @@
{
"solution": "NSExt.sln",
"mappings": {
"NSExt": "../refs/ns-ext/src/NSExt/NSExt.csproj"
},
"restore": [
{
"name": "NSExt",
"packages": [
{
"packageName": "NSExt",
"version": "1.1.0"
}
]
}
]
}

27
scripts/switcher.ps1 Normal file
View File

@ -0,0 +1,27 @@
# https://github.com/RicoSuter/DNT#switch-to-projects
$targets = @{
'1' = 'switch-to-projects'
'2' = 'switch-to-packages'
}
$key = ''
while ($null -eq $targets[$key])
{
$key = 读取-Host '请选择1切换到项目引用 2切换到Nuget包引用'
}
$files = Get-ChildItem Switcher.*.json
$file = 9999
while ($null -eq $files[[int]$file - 1])
{
$i = 0
Write-Host '请选择要切换的配置文件文件'
foreach ($file in $files)
{
$i++
Write-Host $i $file.Name
}
$file = 读取-Host
}
$file = [int]$file - 1
Copy-Item $files[$file] 'switcher.json' -Force
dotnet dnt $targets[$key] ../NSExt.sln
Remove-Item switcher.json

View File

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

View File

@ -1,9 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0-preview-23424-02"/>
<PackageReference Include="xunit" Version="2.5.2-pre.2"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\NSExt\NSExt.csproj"/>
</ItemGroup>
</Project>

View File

@ -1,36 +0,0 @@
namespace NSExt.Tests;
/// <summary>
/// 测试用例
/// </summary>
public class TestCase
{
// private readonly ITestOutputHelper _testOutputHelper;
//
// public TestCase(ITestOutputHelper testOutputHelper)
// {
// _testOutputHelper = testOutputHelper;
// }
//
// public enum MyEnum1
// {
// [ResourceDescription<TestCase>(nameof(Description))]
// Online = 1
//
// , Offline = 2
// }
//
// public static string Description { get; set; } = "123";
//
// /// <summary>
// /// Case1
// /// </summary>
// [Fact]
// public void Case1()
// {
// var test = MyEnum1.Online.ResDesc<TestCase>();
//
// _testOutputHelper.WriteLine(test);
// Assert.True(test is not null);
// }
}

View File

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

View File

@ -1,10 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="../../code.quality.props"/>
<Import Project="../../packable.props"/>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0"/>
</ItemGroup>
<ItemGroup>
<None Include="../../logo.png" Pack="true" PackagePath=""/>
</ItemGroup>
</Project>

View File

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

View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<PackageReference Include="xunit" Version="2.6.3"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<ProjectReference Include="../NSExt/NSExt.csproj"/>
</ItemGroup>
</Project>

View File

@ -1,3 +1,6 @@
using System.Data;
using System.Data.Common;
namespace NSExt.Extensions;
/// <summary>

View File

@ -1,5 +1,8 @@
// ReSharper disable TemplateIsNotCompileTimeConstantProblem
using System.Runtime.CompilerServices;
using Microsoft.Extensions.Logging;
namespace NSExt.Extensions;
/// <summary>

View File

@ -4,6 +4,7 @@
#pragma warning disable CA1720
using System.Security.Cryptography;
using System.Text.Json;
using System.Web;
using NSExt.Constant;
namespace NSExt.Extensions;
@ -141,7 +142,9 @@ public static class StringExtensions
/// <returns>转换后的日期对象</returns>
public static DateTime DateTimeTry(this string me, DateTime def)
{
return !System.DateTime.TryParse(me, CultureInfo.InvariantCulture, out var ret) ? def : ret;
return !System.DateTime.TryParse(me, CultureInfo.InvariantCulture, DateTimeStyles.None, out var ret)
? def
: ret;
}
/// <summary>

View File

@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyOriginatorKeyFile>../../../key.snk</AssemblyOriginatorKeyFile>
<DelaySign>false</DelaySign>
<EmbedAllSources>true</EmbedAllSources>
<EmbedUntrackedSource>true</EmbedUntrackedSource>
<IncludeSymbols>true</IncludeSymbols>
<IsPackable>true</IsPackable>
<PackageIcon>logo.png</PackageIcon>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/nsnail/NSExt.git</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageTags>extensions</PackageTags>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<RootNamespace>NSExt</RootNamespace>
<SignAssembly>true</SignAssembly>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
<Import Project="$(SolutionDir)/build/code.quality.props"/>
<Import Project="$(SolutionDir)/build/copy.pkg.xml.comment.files.targets"/>
<Import Project="$(SolutionDir)/build/prebuild.targets"/>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0"/>
</ItemGroup>
<ItemGroup>
<None Include="../../../assets/logo.png" Pack="true" PackagePath="/"/>
<None Include="../../../README.md" Pack="true" PackagePath="/"/>
<None Update="*.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

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

View File

@ -1,20 +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}"
{{'\t'}}ProjectSection(SolutionItems) = preProject
{{string.Join('\n',
Directory.GetFiles(@"./", "*").Where(x => !x.EndsWith(".sln") && !x.EndsWith(".user"))
.Select(x=>$"\t\t{Path.GetFileName(x)} = {Path.GetFileName(x)}")
)}}
{{'\t'}}EndProject
"""
);
Console.WriteLine(content);
File.WriteAllText(slnFile, content);