add version 0.0.1
This commit is contained in:
36
.devcontainer/devcontainer.json
Normal file
36
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||||
|
// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet
|
||||||
|
{
|
||||||
|
"name": "C# (.NET)",
|
||||||
|
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||||
|
"image": "mcr.microsoft.com/devcontainers/dotnet:0-6.0",
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/nix:1": {}
|
||||||
|
},
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"formulahendry.dotnet-test-explorer",
|
||||||
|
"jnoortheen.nix-ide",
|
||||||
|
"eamodio.gitlens"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||||
|
// "features": {},
|
||||||
|
|
||||||
|
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||||
|
// "forwardPorts": [5000, 5001],
|
||||||
|
// "portsAttributes": {
|
||||||
|
// "5001": {
|
||||||
|
// "protocol": "https"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Use 'postCreateCommand' to run commands after the container is created.
|
||||||
|
"postCreateCommand": "nix-env -i nixpkgs-fmt"
|
||||||
|
|
||||||
|
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||||
|
// "remoteUser": "root"
|
||||||
|
}
|
||||||
478
.gitignore
vendored
Normal file
478
.gitignore
vendored
Normal file
@@ -0,0 +1,478 @@
|
|||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# Tye
|
||||||
|
.tye/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.tlog
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
||||||
|
*.vbp
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
||||||
|
*.dsw
|
||||||
|
*.dsp
|
||||||
|
|
||||||
|
# Visual Studio 6 technical files
|
||||||
|
*.ncb
|
||||||
|
*.aps
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# Visual Studio History (VSHistory) files
|
||||||
|
.vshistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
# VS Code files for those working on multiple tools
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# Windows Installer files from build outputs
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
*.sln.iml
|
||||||
|
|
||||||
|
##
|
||||||
|
## Visual studio for Mac
|
||||||
|
##
|
||||||
|
|
||||||
|
|
||||||
|
# globs
|
||||||
|
Makefile.in
|
||||||
|
*.userprefs
|
||||||
|
*.usertasks
|
||||||
|
config.make
|
||||||
|
config.status
|
||||||
|
aclocal.m4
|
||||||
|
install-sh
|
||||||
|
autom4te.cache/
|
||||||
|
*.tar.gz
|
||||||
|
tarballs/
|
||||||
|
test-results/
|
||||||
|
|
||||||
|
# Mac bundle stuff
|
||||||
|
*.dmg
|
||||||
|
*.app
|
||||||
|
|
||||||
|
# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
|
||||||
|
# General
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
|
||||||
|
# Windows thumbnail cache files
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
|
||||||
|
# Dump file
|
||||||
|
*.stackdump
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
[Dd]esktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
||||||
|
result
|
||||||
40
.vscode/launch.json
vendored
Normal file
40
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
|
||||||
|
{
|
||||||
|
// Use IntelliSense to find out which attributes exist for C# debugging
|
||||||
|
// Use hover for the description of the existing attributes
|
||||||
|
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
|
||||||
|
"name": "Launch Example App",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "build",
|
||||||
|
// If you have changed target frameworks, make sure to update the program path.
|
||||||
|
"program": "${workspaceFolder}/example/Example.App/bin/Debug/net6.0/Example.App.dll",
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}/example/Example.App",
|
||||||
|
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
||||||
|
"console": "internalConsole",
|
||||||
|
"stopAtEntry": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Update Resources.cs",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "build",
|
||||||
|
"program": "${workspaceFolder}/ResourceString.Net.App.Console/bin/Debug/net6.0/ResourceString.Net.App.Console.dll",
|
||||||
|
"args": [
|
||||||
|
"${workspaceFolder}/ResourceString.Net.Logic/Properties/Resources.resx"
|
||||||
|
],
|
||||||
|
"cwd": "${workspaceFolder}/ResourceString.Net.App.Console",
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"stopAtEntry": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": ".NET Core Attach",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "attach"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"dotnet-test-explorer.testProjectPath": "**/*Tests.csproj"
|
||||||
|
}
|
||||||
41
.vscode/tasks.json
vendored
Normal file
41
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "build",
|
||||||
|
"command": "nix",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"--experimental-features",
|
||||||
|
"nix-command flakes",
|
||||||
|
"run",
|
||||||
|
".#devTasks.buildAllAssemblies"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "publish",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"publish",
|
||||||
|
"${workspaceFolder}/example/Example.App/Example.App.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "watch",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"watch",
|
||||||
|
"run",
|
||||||
|
"--project",
|
||||||
|
"${workspaceFolder}/example/Example.App/Example.App.csproj"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 stubbfel
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
240
Readme.md
240
Readme.md
@@ -0,0 +1,240 @@
|
|||||||
|
# ResourceString.Net
|
||||||
|
|
||||||
|
## What is ResourceString.Net?
|
||||||
|
|
||||||
|
ResourceString.Net is a powerful .NET library that allows you to work with string resources in a type-safe manner.
|
||||||
|
It leverages the `resx` file in your project and utilizes a [c# source code generator](https://learn.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/source-generators-overview) to create a comprehensive API.
|
||||||
|
With ResourceString.Net, you can handle resource strings as "multi-language strings" (see [The ResourceString-Classes](#the-resourcestring-classes)) instead of built-in strings.
|
||||||
|
This provides the ability to switch languages during runtime without the need to rerun string factory methods.
|
||||||
|
Additionally, ResourceString.Net ensures that formatted strings have methods with the correct number of expected parameters.
|
||||||
|
|
||||||
|
## Installation and Setup Instructions
|
||||||
|
|
||||||
|
To incorporate ResourceString.Net into your .NET application, follow these simple steps:
|
||||||
|
|
||||||
|
1. Install the NuGet package by executing the following command in the NuGet package manager or the dotnet CLI:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dotnet add package ResourceString.Net
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Once the package is installed, you can start using the APIs in your application.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
To quickly get started with ResourceString.Net, follow the steps below:
|
||||||
|
|
||||||
|
1. Run the following script to create a new project and a resource file:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dotnet new console --name MyTestConsoleApp
|
||||||
|
cd MyTestConsoleApp
|
||||||
|
|
||||||
|
dotnet add package "System.Resources.Extensions"
|
||||||
|
dotnet add package "ResourceString.Net"
|
||||||
|
|
||||||
|
echo "<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<root>
|
||||||
|
<data name='Greetings'>
|
||||||
|
<value>Hello {0}</value>
|
||||||
|
<comment>0 = name</comment>
|
||||||
|
</data>
|
||||||
|
<data name='World' type='System.String'>
|
||||||
|
<value>World</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
|
" > Resources.resx
|
||||||
|
|
||||||
|
echo "var message = MyTestConsoleApp.Resources.Greetings.From(
|
||||||
|
MyTestConsoleApp.Resources.World
|
||||||
|
);
|
||||||
|
|
||||||
|
Console.WriteLine(message.Value);
|
||||||
|
" > Program.cs
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Add the following `PropertyGroup` to the `MyTestConsoleApp.csproj` file to enable ResourceString.Net to handle the project's resource file:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<PropertyGroup>
|
||||||
|
<AdditionalFileItemNames>$(AdditionalFileItemNames);EmbeddedResource</AdditionalFileItemNames>
|
||||||
|
</PropertyGroup>
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Run the project using the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dotnet run
|
||||||
|
# Expected output: Hello World
|
||||||
|
```
|
||||||
|
|
||||||
|
During compile time, the ResourceString.Net source code generator will automatically add the following code to the `MyTestConsoleApp.csproj` project:
|
||||||
|
|
||||||
|
```cs
|
||||||
|
using ResourceString.Net.Contract;
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Resources;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace MyTestConsoleApp
|
||||||
|
{
|
||||||
|
internal static class Resources
|
||||||
|
{
|
||||||
|
|
||||||
|
#region ResourceManager
|
||||||
|
|
||||||
|
private static readonly Type _Type = typeof(Resources);
|
||||||
|
|
||||||
|
private static readonly Lazy<ResourceManager> _ResourceManager = new Lazy<ResourceManager>(
|
||||||
|
() => new ResourceManager(_Type.FullName ?? string.Empty, _Type.Assembly),
|
||||||
|
LazyThreadSafetyMode.PublicationOnly
|
||||||
|
);
|
||||||
|
|
||||||
|
public static ResourceManager ResourceManager => _ResourceManager.Value;
|
||||||
|
|
||||||
|
#endregion // ResourceManager
|
||||||
|
|
||||||
|
|
||||||
|
internal static class Greetings
|
||||||
|
{
|
||||||
|
private static readonly Lazy<IResourceString> LazyFormat = new Lazy<IResourceString>(
|
||||||
|
() => new ResourceManagerString("Greetings", ResourceManager, CultureInfo.CurrentCulture),
|
||||||
|
LazyThreadSafetyMode.PublicationOnly
|
||||||
|
);
|
||||||
|
|
||||||
|
public static IResourceString Format => LazyFormat.Value;
|
||||||
|
|
||||||
|
public static IResourceString From(IResourceString name) => new FormattedResourceString(
|
||||||
|
Format,
|
||||||
|
name
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#region World
|
||||||
|
|
||||||
|
private static readonly Lazy<IResourceString> LazyWorld = new Lazy<IResourceString>(
|
||||||
|
() => new ResourceManagerString("World", ResourceManager, CultureInfo.CurrentCulture),
|
||||||
|
LazyThreadSafetyMode.PublicationOnly
|
||||||
|
);
|
||||||
|
|
||||||
|
public static IResourceString World => LazyWorld.Value;
|
||||||
|
|
||||||
|
#endregion // World
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## The ResourceString-Classes
|
||||||
|
|
||||||
|
### IResourceString
|
||||||
|
|
||||||
|
- Interface that defines the contract for resource strings.
|
||||||
|
- Contains properties: `Value`, representing the string value, and `GetValue(CultureInfo cultureInfo)`, for retrieving the value for a specific `CultureInfo`.
|
||||||
|
|
||||||
|
### FormattedResourceString
|
||||||
|
|
||||||
|
- Implements the `IResourceString` interface.
|
||||||
|
- Represents a resource string with placeholders for parameters.
|
||||||
|
- Allows for dynamic formatting of the string by providing a format and an array of parameters.
|
||||||
|
- Formats the string by replacing the placeholders with the parameter values.
|
||||||
|
|
||||||
|
### JoinedResourceString
|
||||||
|
|
||||||
|
- Implements the `IResourceString` interface.
|
||||||
|
- Represents a resource string that joins multiple elements with a separator.
|
||||||
|
- Useful for constructing strings that involve concatenating multiple resource strings or literal strings together.
|
||||||
|
- Allows customization of the separator between the elements.
|
||||||
|
|
||||||
|
### LiteralString
|
||||||
|
|
||||||
|
- Implements the `IResourceString` interface.
|
||||||
|
- Represents a literal string resource.
|
||||||
|
- Provides the actual string value as-is without any formatting or localization.
|
||||||
|
- Can be used for static, non-localized strings.
|
||||||
|
|
||||||
|
### ResourceManagerString
|
||||||
|
|
||||||
|
- Implements the `IResourceString` interface.
|
||||||
|
- Represents a resource string retrieved from a `ResourceManager`.
|
||||||
|
- Provides access to resource strings stored in `resx` files or other resource sources.
|
||||||
|
- Handles retrieving the localized value for the specified `CultureInfo`.
|
||||||
|
|
||||||
|
Great! Based on the provided code for the console app `ResourceString.Net.App.Console`, let's enhance the Readme.md file to include instructions on how to use the console app and generate a C# class based on a given resource file.
|
||||||
|
|
||||||
|
## Console App: ResourceString.Net.App.Console
|
||||||
|
|
||||||
|
The ResourceString.Net project also provide a console app, `ResourceString.Net.App.Console`, which allows you to generate a C# class based on a given resource file. This can be useful for automating the creation of resource classes in your projects without usage of the `source generator`.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
To use the console app, follow these steps:
|
||||||
|
|
||||||
|
1. Build the console app from this source repository
|
||||||
|
2. Open a command prompt or terminal.
|
||||||
|
3. Navigate to the directory where the `ResourceString.Net.App.Console` executable is located.
|
||||||
|
|
||||||
|
#### Syntax
|
||||||
|
|
||||||
|
```
|
||||||
|
ResourceString.Net.App.Console <sourceFile> [namespaceString] [className]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
- `<sourceFile>`: Required. The path to the resource file (e.g., `Resources.resx`) that you want to generate the C# class from.
|
||||||
|
- `[namespaceString]` (optional): The namespace for the generated C# class. If not provided, the default value is `"Properties"`.
|
||||||
|
- `[className]` (optional): The name of the generated C# class. If not provided, the default value is `"Resources"`.
|
||||||
|
|
||||||
|
#### Examples
|
||||||
|
|
||||||
|
Here are some examples of how to use the console app:
|
||||||
|
|
||||||
|
- Generate a C# class named `Resources.cs` in the `"Properties"` namespace based on the `Resources.resx` file:
|
||||||
|
|
||||||
|
```
|
||||||
|
ResourceString.Net.App.Console Resources.resx
|
||||||
|
```
|
||||||
|
|
||||||
|
- Generate a C# class named `MyResources.cs` in the `"MyNamespace"` namespace based on the `MyResources.resx` file:
|
||||||
|
|
||||||
|
```
|
||||||
|
ResourceString.Net.App.Console MyResources.resx MyNamespace MyResources
|
||||||
|
```
|
||||||
|
|
||||||
|
### Output
|
||||||
|
|
||||||
|
The console app will generate the C# class code based on the provided resource file and output it to the console.
|
||||||
|
You can redirect the output to a file if desired.
|
||||||
|
|
||||||
|
## Third party packages
|
||||||
|
|
||||||
|
| Package | Version |
|
||||||
|
| ------------------------------------- | ------- |
|
||||||
|
| Fody | 6.7.0 |
|
||||||
|
| ILMerge.Fody | 1.24.0 |
|
||||||
|
| Microsoft.CodeAnalysis.Analyzers | 3.3.4 |
|
||||||
|
| Microsoft.CodeAnalysis.CSharp | 4.3.0 |
|
||||||
|
| NETStandard.Library (Auto-referenced) | 2.0.3 |
|
||||||
|
| LanguageExt.Core | 4.4.3 |
|
||||||
|
| System.Resources.Extensions | 7.0.0 |
|
||||||
|
|
||||||
|
## Development Notes
|
||||||
|
|
||||||
|
Here are some useful aliases for running Nix commands with experimental features:
|
||||||
|
|
||||||
|
- `nixe`: This alias runs the `nix` command with the experimental feature flag `nix-command flakes`.
|
||||||
|
- `nulock`: This alias runs the `nixe` command with the argument `run .#devTasks.updateNugetLock`, which updates the NuGet lock file.
|
||||||
|
- `fllock`: This alias runs the `nixe` command with the argument `run .#devTasks.updateFlakeLock`, which updates the Flake lock file.
|
||||||
|
- `ulock`: This alias combines the `nulock` and `fllock` aliases to update both the NuGet and Flake lock files.
|
||||||
|
|
||||||
|
To load the `alias.sh` source file from the current folder, use the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
source ./alias.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
By executing the command above, you'll make the aliases available for use in the current terminal session.
|
||||||
|
|||||||
18
ResourceString.Net.App.Console/Program.cs
Normal file
18
ResourceString.Net.App.Console/Program.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using ResourceString.Net.Logic.Factories;
|
||||||
|
using ResourceString.Net.Logic.Parsers.Resx;
|
||||||
|
|
||||||
|
var sourceFile = args.First();
|
||||||
|
var namespaceString = args.Skip(1).FirstOrDefault() ?? "Properties";
|
||||||
|
var className = args.Skip(2).FirstOrDefault() ?? "Resources";
|
||||||
|
|
||||||
|
var result = Parser.TryParse(System.IO.File.ReadAllText(sourceFile)).Match(
|
||||||
|
Some: v => CodeSnippetFactory.CreateResourceClassCodeSnippet(
|
||||||
|
namespaceString,
|
||||||
|
className,
|
||||||
|
CodeSnippetFactory.CreateResourceMangerMemberCodeSnippet(className),
|
||||||
|
v.Resources
|
||||||
|
),
|
||||||
|
None: () => throw new InvalidOperationException()
|
||||||
|
);
|
||||||
|
|
||||||
|
Console.WriteLine(result.Value.Trim());
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<PackAsTool>true</PackAsTool>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\ResourceString.Net.Logic\ResourceString.Net.Logic.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
35
ResourceString.Net.Contract/FormattedResourceString.cs
Normal file
35
ResourceString.Net.Contract/FormattedResourceString.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace ResourceString.Net.Contract
|
||||||
|
{
|
||||||
|
public class FormattedResourceString : IResourceString
|
||||||
|
{
|
||||||
|
public IResourceString Format { get; }
|
||||||
|
|
||||||
|
public IEnumerable<IResourceString> Parameters { get; }
|
||||||
|
|
||||||
|
public string Value => GetValue(CultureInfo.CurrentCulture);
|
||||||
|
|
||||||
|
public FormattedResourceString(
|
||||||
|
IResourceString format,
|
||||||
|
params IResourceString[] parameters)
|
||||||
|
{
|
||||||
|
Format = format ?? new JoinedResourceString(
|
||||||
|
LiteralString.Factory(","),
|
||||||
|
parameters.Select(((p, idx) => LiteralString.Factory("{" + idx + "}"))).ToArray()
|
||||||
|
);
|
||||||
|
|
||||||
|
Parameters = parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetValue(CultureInfo cultureInfo)
|
||||||
|
{
|
||||||
|
var format = Format.GetValue(cultureInfo);
|
||||||
|
var parameterStrings = Parameters.Select(p => p.GetValue(cultureInfo));
|
||||||
|
return string.Format(format, parameterStrings.ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
13
ResourceString.Net.Contract/IResourceString.cs
Normal file
13
ResourceString.Net.Contract/IResourceString.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace ResourceString.Net.Contract
|
||||||
|
{
|
||||||
|
public interface IResourceString
|
||||||
|
{
|
||||||
|
|
||||||
|
string Value { get; }
|
||||||
|
|
||||||
|
string GetValue(CultureInfo cultureInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
35
ResourceString.Net.Contract/JoinedResourceString.cs
Normal file
35
ResourceString.Net.Contract/JoinedResourceString.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace ResourceString.Net.Contract
|
||||||
|
{
|
||||||
|
|
||||||
|
public class JoinedResourceString : IResourceString
|
||||||
|
{
|
||||||
|
public IResourceString Separator { get; }
|
||||||
|
|
||||||
|
public IEnumerable<IResourceString> Elements { get; }
|
||||||
|
|
||||||
|
public string Value => GetValue(CultureInfo.CurrentCulture);
|
||||||
|
|
||||||
|
public JoinedResourceString(
|
||||||
|
IResourceString separator,
|
||||||
|
params IResourceString[] elements)
|
||||||
|
{
|
||||||
|
Separator = separator ?? new LiteralString(
|
||||||
|
() => ","
|
||||||
|
);
|
||||||
|
|
||||||
|
Elements = elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetValue(CultureInfo cultureInfo)
|
||||||
|
{
|
||||||
|
var separator = Separator.GetValue(cultureInfo);
|
||||||
|
var elementsStrings = Elements.Select(p => p.GetValue(cultureInfo));
|
||||||
|
return string.Join(separator, elementsStrings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
30
ResourceString.Net.Contract/LiteralString.cs
Normal file
30
ResourceString.Net.Contract/LiteralString.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace ResourceString.Net.Contract
|
||||||
|
{
|
||||||
|
public class LiteralString : IResourceString
|
||||||
|
{
|
||||||
|
private Lazy<string> m_Value;
|
||||||
|
|
||||||
|
public string Value => m_Value.Value;
|
||||||
|
|
||||||
|
public static IResourceString Empty { get; } = Factory(string.Empty);
|
||||||
|
public static IResourceString Factory(string source)
|
||||||
|
{
|
||||||
|
return new LiteralString(() => source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiteralString(Func<string> factory)
|
||||||
|
{
|
||||||
|
m_Value = new Lazy<string>(
|
||||||
|
() => factory?.Invoke() ?? string.Empty,
|
||||||
|
LazyThreadSafetyMode.PublicationOnly
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetValue(CultureInfo _) => Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
33
ResourceString.Net.Contract/ResourceManagerString.cs
Normal file
33
ResourceString.Net.Contract/ResourceManagerString.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Resources;
|
||||||
|
|
||||||
|
namespace ResourceString.Net.Contract
|
||||||
|
{
|
||||||
|
public class ResourceManagerString : IResourceString
|
||||||
|
{
|
||||||
|
private readonly CultureInfo m_Culture;
|
||||||
|
|
||||||
|
public string Id { get; }
|
||||||
|
|
||||||
|
public ResourceManager Manager { get; }
|
||||||
|
|
||||||
|
public string Value => GetValue(m_Culture);
|
||||||
|
|
||||||
|
public ResourceManagerString(
|
||||||
|
string id,
|
||||||
|
ResourceManager manager,
|
||||||
|
CultureInfo cultureInfo)
|
||||||
|
{
|
||||||
|
Id = id ?? string.Empty;
|
||||||
|
Manager = manager ?? throw new ArgumentNullException(nameof(manager));
|
||||||
|
m_Culture = cultureInfo ?? CultureInfo.CurrentCulture;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetValue(CultureInfo cultureInfo)
|
||||||
|
{
|
||||||
|
return Manager.GetString(Id, cultureInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
106
ResourceString.Net.Logic.Tests/LogicResourcesTests.cs
Normal file
106
ResourceString.Net.Logic.Tests/LogicResourcesTests.cs
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
using ResourceString.Net.Logic.Factories;
|
||||||
|
|
||||||
|
namespace ResourceString.Net.Logic.Tests;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class LogicResourcesTests
|
||||||
|
{
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Test_Get_ResourceStringMembers()
|
||||||
|
{
|
||||||
|
var rm = Properties.Resources.ResourceManager;
|
||||||
|
Assert.AreEqual(
|
||||||
|
new FormattedResourceString(
|
||||||
|
Properties.Resources.ResourceStringMembers.Format,
|
||||||
|
LiteralString.Factory("ResourceStringMembers"),
|
||||||
|
LiteralString.Factory("ResourceManager")
|
||||||
|
).Value,
|
||||||
|
string.Format(
|
||||||
|
rm.GetString("ResourceStringMembers") ?? string.Empty,
|
||||||
|
"ResourceStringMembers",
|
||||||
|
"ResourceManager"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Test_Get_ResourceFormatClassMembers()
|
||||||
|
{
|
||||||
|
var rm = Properties.Resources.ResourceManager;
|
||||||
|
Assert.AreEqual(
|
||||||
|
new FormattedResourceString(
|
||||||
|
Properties.Resources.ResourceFormatClassMembers.Format,
|
||||||
|
LiteralString.Factory("ResourceFormatClassMembers"),
|
||||||
|
LiteralString.Factory("ResourceManager"),
|
||||||
|
LiteralString.Factory("Format")
|
||||||
|
).Value,
|
||||||
|
string.Format(
|
||||||
|
rm.GetString("ResourceFormatClassMembers") ?? string.Empty,
|
||||||
|
"ResourceFormatClassMembers",
|
||||||
|
"ResourceManager",
|
||||||
|
"Format"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Test_Get_ResourceFormatClassFromMethod()
|
||||||
|
{
|
||||||
|
var rm = Properties.Resources.ResourceManager;
|
||||||
|
Assert.AreEqual(
|
||||||
|
new FormattedResourceString(
|
||||||
|
Properties.Resources.ResourceFormatClassFromMethod.Format,
|
||||||
|
LiteralString.Factory("IResourceString name"),
|
||||||
|
LiteralString.Factory("name")
|
||||||
|
).Value,
|
||||||
|
string.Format(
|
||||||
|
rm.GetString("ResourceFormatClassFromMethod") ?? string.Empty,
|
||||||
|
"IResourceString name",
|
||||||
|
"name"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Test_Get_ResourceManagerMemberTemplate()
|
||||||
|
{
|
||||||
|
var rm = Properties.Resources.ResourceManager;
|
||||||
|
Assert.AreEqual(
|
||||||
|
CodeSnippetFactory.CreateResourceMangerMemberCodeSnippet(
|
||||||
|
"Resources"
|
||||||
|
).Value,
|
||||||
|
string.Format(
|
||||||
|
rm.GetString("ResourceManagerMemberTemplate") ?? string.Empty,
|
||||||
|
"Resources"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Test_Get_ResourcesClassTemplate()
|
||||||
|
{
|
||||||
|
var rm = Properties.Resources.ResourceManager;
|
||||||
|
|
||||||
|
var rmSnippet = CodeSnippetFactory.CreateResourceMangerMemberCodeSnippet(
|
||||||
|
"Resources"
|
||||||
|
);
|
||||||
|
|
||||||
|
Assert.AreEqual(
|
||||||
|
CodeSnippetFactory.CreateResourceClassCodeSnippet(
|
||||||
|
"ResourceString.Net.Logic.Properties",
|
||||||
|
"Resources",
|
||||||
|
rmSnippet,
|
||||||
|
Enumerable.Empty<IResourceString>()
|
||||||
|
).Value,
|
||||||
|
string.Format(
|
||||||
|
rm.GetString("ResourcesClassTemplate") ?? string.Empty,
|
||||||
|
"ResourceString.Net.Logic.Properties",
|
||||||
|
"Resources",
|
||||||
|
rmSnippet.Value,
|
||||||
|
string.Empty
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
|
||||||
|
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
|
||||||
|
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
|
||||||
|
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\ResourceString.Net.Logic\ResourceString.Net.Logic.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
192
ResourceString.Net.Logic.Tests/ResxFileTests.cs
Normal file
192
ResourceString.Net.Logic.Tests/ResxFileTests.cs
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
using ResourceString.Net.Logic.DomainObjects.Resx;
|
||||||
|
using ResourceString.Net.Logic.Factories;
|
||||||
|
using ResourceString.Net.Logic.Parsers.Resx;
|
||||||
|
|
||||||
|
namespace ResourceString.Net.Logic.Tests;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class ResxFileTests
|
||||||
|
{
|
||||||
|
private readonly string validXml = @$"<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<root>
|
||||||
|
<data name='Test1'>
|
||||||
|
<value>Value1</value>
|
||||||
|
<comment>This is a greeting message.</comment>
|
||||||
|
</data>
|
||||||
|
<data name='Test2' type='{typeof(string).FullName}'>
|
||||||
|
<value>{{2}}Value2{{0}}{{{{1}}}}</value>
|
||||||
|
<comment>2 = prefix</comment>
|
||||||
|
</data>
|
||||||
|
<data name='Test3' type='{typeof(byte[]).FullName}'>
|
||||||
|
<value>0xDEADBEEF</value>
|
||||||
|
</data>
|
||||||
|
</root>";
|
||||||
|
|
||||||
|
private const string expectedClass = @"
|
||||||
|
using ResourceString.Net.Contract;
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Resources;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace TestNameSpace
|
||||||
|
{
|
||||||
|
internal static class TestResourceClass
|
||||||
|
{
|
||||||
|
|
||||||
|
#region ResourceManager
|
||||||
|
|
||||||
|
private static readonly Type _Type = typeof(ResourceManager);
|
||||||
|
|
||||||
|
private static readonly Lazy<ResourceManager> _ResourceManager = new Lazy<ResourceManager>(
|
||||||
|
() => new ResourceManager(_Type.FullName ?? string.Empty, _Type.Assembly),
|
||||||
|
LazyThreadSafetyMode.PublicationOnly
|
||||||
|
);
|
||||||
|
|
||||||
|
public static ResourceManager ResourceManager => _ResourceManager.Value;
|
||||||
|
|
||||||
|
#endregion // ResourceManager
|
||||||
|
|
||||||
|
|
||||||
|
#region Test1
|
||||||
|
|
||||||
|
private static readonly Lazy<IResourceString> LazyTest1 = new Lazy<IResourceString>(
|
||||||
|
() => new ResourceManagerString(""Test1"", ResourceManager, CultureInfo.CurrentCulture),
|
||||||
|
LazyThreadSafetyMode.PublicationOnly
|
||||||
|
);
|
||||||
|
|
||||||
|
public static IResourceString Test1 => LazyTest1.Value;
|
||||||
|
|
||||||
|
#endregion // Test1
|
||||||
|
|
||||||
|
internal static class Test2
|
||||||
|
{
|
||||||
|
private static readonly Lazy<IResourceString> LazyFormat = new Lazy<IResourceString>(
|
||||||
|
() => new ResourceManagerString(""Test2"", ResourceManager, CultureInfo.CurrentCulture),
|
||||||
|
LazyThreadSafetyMode.PublicationOnly
|
||||||
|
);
|
||||||
|
|
||||||
|
public static IResourceString Format => LazyFormat.Value;
|
||||||
|
|
||||||
|
public static IResourceString From(IResourceString prefix, IResourceString p1) => new FormattedResourceString(
|
||||||
|
Format,
|
||||||
|
prefix,
|
||||||
|
p1
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}";
|
||||||
|
|
||||||
|
private readonly string emptyXml = @"<?xml version='1.0' encoding='utf-8'?><root></root>";
|
||||||
|
|
||||||
|
private readonly string invalidXml = @"<?xml version='1.0' encoding='utf-8'?><root></data>";
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Test_TryParse_ValidXml()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedData = new[] {
|
||||||
|
("Test1", "Value1", string.Empty, "This is a greeting message."),
|
||||||
|
("Test2", "{2}Value2{0}{{1}}", typeof(string).FullName, "2 = prefix"),
|
||||||
|
("Test3", "0xDEADBEEF", typeof(byte[]).FullName, string.Empty)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = Parser.TryParse(validXml).Match(
|
||||||
|
Some: v => v.Resources,
|
||||||
|
None: () => throw new InvalidOperationException()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
CollectionAssert.AreEqual(
|
||||||
|
expectedData,
|
||||||
|
result.Select(i => (
|
||||||
|
i.Name,
|
||||||
|
i.Value,
|
||||||
|
i.Type.IfNone(string.Empty),
|
||||||
|
i.Comment.IfNone(string.Empty)
|
||||||
|
)).ToList()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Test_TryParse_EmptyXml()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedData = Enumerable.Empty<Resource>();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var isSome = Parser.TryParse(emptyXml).Match(
|
||||||
|
Some: _ => true,
|
||||||
|
None: () => false
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsFalse(isSome);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Test_TryParse_InValidXml()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedData = Enumerable.Empty<Resource>();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var isSome = Parser.TryParse(invalidXml).Match(
|
||||||
|
Some: _ => true,
|
||||||
|
None: () => false
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsFalse(isSome);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Test_ToMemberString()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
var result = Parser.TryParse(validXml).Match(
|
||||||
|
Some: v => CodeSnippetFactory.CreateMemberCodeSnippets(v.Resources),
|
||||||
|
None: () => throw new InvalidOperationException()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.AreEqual(2, result.Count());
|
||||||
|
|
||||||
|
Assert.AreEqual(
|
||||||
|
"#region Test1",
|
||||||
|
result.Select(i => i.Value.Substring(0, 25).Trim()).ToList()[0]
|
||||||
|
);
|
||||||
|
|
||||||
|
Assert.AreEqual(
|
||||||
|
"internal static class Test2",
|
||||||
|
result.Select(i => i.Value.Substring(0, 45).Trim()).ToList()[1]
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Test_ToClassString()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
var result = Parser.TryParse(validXml).Match(
|
||||||
|
Some: v => CodeSnippetFactory.CreateResourceClassCodeSnippet(
|
||||||
|
"TestNameSpace",
|
||||||
|
"TestResourceClass",
|
||||||
|
CodeSnippetFactory.CreateResourceMangerMemberCodeSnippet("ResourceManager"),
|
||||||
|
v.Resources
|
||||||
|
),
|
||||||
|
None: () => throw new InvalidOperationException()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.AreEqual(
|
||||||
|
expectedClass.Trim(),
|
||||||
|
result.Value.Trim()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
4
ResourceString.Net.Logic.Tests/Usings.cs
Normal file
4
ResourceString.Net.Logic.Tests/Usings.cs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
global using LanguageExt;
|
||||||
|
global using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
global using ResourceString.Net.Contract;
|
||||||
|
global using ResourceString.Net.Logic;
|
||||||
16
ResourceString.Net.Logic/DomainObjects/Resx/File.cs
Normal file
16
ResourceString.Net.Logic/DomainObjects/Resx/File.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace ResourceString.Net.Logic.DomainObjects.Resx;
|
||||||
|
|
||||||
|
internal record File
|
||||||
|
{
|
||||||
|
public File(IEnumerable<Resource> resources)
|
||||||
|
{
|
||||||
|
Resources = new Seq<Resource>(
|
||||||
|
resources?.Where(o => o != null) ?? Enumerable.Empty<Resource>()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Resource> Resources { get; }
|
||||||
|
}
|
||||||
18
ResourceString.Net.Logic/DomainObjects/Resx/Resource.cs
Normal file
18
ResourceString.Net.Logic/DomainObjects/Resx/Resource.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
namespace ResourceString.Net.Logic.DomainObjects.Resx;
|
||||||
|
|
||||||
|
internal record Resource
|
||||||
|
{
|
||||||
|
public Resource(string name, string value)
|
||||||
|
{
|
||||||
|
Name = name ?? string.Empty;
|
||||||
|
Value = value ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get;}
|
||||||
|
|
||||||
|
public Option<string> Type { get; init;}
|
||||||
|
|
||||||
|
public Option<string> Comment { get; init;}
|
||||||
|
|
||||||
|
public string Value { get; }
|
||||||
|
}
|
||||||
126
ResourceString.Net.Logic/Factories/CodeSnippetFactory.cs
Normal file
126
ResourceString.Net.Logic/Factories/CodeSnippetFactory.cs
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
using ResourceString.Net.Logic.DomainObjects.Resx;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace ResourceString.Net.Logic.Factories;
|
||||||
|
|
||||||
|
internal static class CodeSnippetFactory
|
||||||
|
{
|
||||||
|
public static IResourceString CreateResourceMangerMemberCodeSnippet(string typeName)
|
||||||
|
{
|
||||||
|
return Properties.Resources.ResourceManagerMemberTemplate.From(
|
||||||
|
LiteralString.Factory(typeName)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<IResourceString> CreateMemberCodeSnippets(IEnumerable<Resource> resources)
|
||||||
|
{
|
||||||
|
return CreateMemberCodeSnippets(
|
||||||
|
resources,
|
||||||
|
Properties.Resources.DefaultPropertyName_ResourceManager
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<IResourceString> CreateMemberCodeSnippets(
|
||||||
|
IEnumerable<Resource> resources,
|
||||||
|
IResourceString resourceManagerName
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (resources is null)
|
||||||
|
{
|
||||||
|
return Enumerable.Empty<IResourceString>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var stringResourses = resources.Where(r => r.Type.Match(
|
||||||
|
v => typeof(string).IsAssignableFrom(Type.GetType(v.Trim(), false, true)),
|
||||||
|
() => true
|
||||||
|
));
|
||||||
|
|
||||||
|
return stringResourses.Select(r =>
|
||||||
|
{
|
||||||
|
var openBraces = r.Value
|
||||||
|
.Replace("{{", string.Empty)
|
||||||
|
.Replace("{{", string.Empty)
|
||||||
|
.Split('{')
|
||||||
|
.Skip(1)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
if (openBraces.Any())
|
||||||
|
{
|
||||||
|
var formatNames = new System.Collections.Generic.HashSet<string>(
|
||||||
|
openBraces.Select(b => b.Split('}').First())
|
||||||
|
);
|
||||||
|
|
||||||
|
var resolveParameterNames = r.Comment.Match(
|
||||||
|
c => c.Split(',')
|
||||||
|
.Select(str => str.Split('='))
|
||||||
|
.Where(parts => parts.Count() == 2)
|
||||||
|
.Select(parts => (
|
||||||
|
parts.First().Trim().Trim('{', '}').Split(' ').First(),
|
||||||
|
parts.Last().Trim().Split(' ').First()
|
||||||
|
)).Where(t => uint.TryParse(t.Item1, out var _))
|
||||||
|
.GroupBy(t => t.Item1)
|
||||||
|
.ToDictionary(k => k.Key, v => v.First().Item2),
|
||||||
|
() => new Dictionary<string, string>()
|
||||||
|
);
|
||||||
|
|
||||||
|
var parameterNames = formatNames.Select(
|
||||||
|
n => resolveParameterNames.TryGetValue(n.Trim(), out var paramName)
|
||||||
|
? paramName.Substring(0, 1).ToLower() + paramName.Substring(1)
|
||||||
|
: uint.TryParse(n, out var value) ? $"p{value + 1}" : n
|
||||||
|
).ToArray();
|
||||||
|
|
||||||
|
var from = Properties.Resources.ResourceFormatClassFromMethod.From(
|
||||||
|
new JoinedResourceString(
|
||||||
|
LiteralString.Factory(", "),
|
||||||
|
parameterNames.Select(n => LiteralString.Factory($"{nameof(IResourceString)} {n}")).ToArray()
|
||||||
|
),
|
||||||
|
new JoinedResourceString(
|
||||||
|
LiteralString.Factory($",{System.Environment.NewLine} "),
|
||||||
|
parameterNames.Select(n => LiteralString.Factory($"{n}")).ToArray()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return Properties.Resources.ResourceFormatClassMembers.From(
|
||||||
|
LiteralString.Factory(r.Name), resourceManagerName, from
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Properties.Resources.ResourceStringMembers.From(
|
||||||
|
LiteralString.Factory(r.Name), resourceManagerName
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IResourceString CreateResourceClassCodeSnippet(
|
||||||
|
string namespaceString,
|
||||||
|
string resourceClassName,
|
||||||
|
IResourceString resourceManagerSnippet,
|
||||||
|
IEnumerable<IResourceString> memberSnippets
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return Properties.Resources.ResourcesClassTemplate.From(
|
||||||
|
LiteralString.Factory(namespaceString),
|
||||||
|
LiteralString.Factory(resourceClassName),
|
||||||
|
resourceManagerSnippet,
|
||||||
|
new JoinedResourceString(
|
||||||
|
LiteralString.Empty,
|
||||||
|
memberSnippets?.ToArray() ?? Array.Empty<IResourceString>()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IResourceString CreateResourceClassCodeSnippet(
|
||||||
|
string namespaceString,
|
||||||
|
string resourceClassName,
|
||||||
|
IResourceString resourceManagerSnippet,
|
||||||
|
IEnumerable<Resource> resources
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return CreateResourceClassCodeSnippet(
|
||||||
|
namespaceString,
|
||||||
|
resourceClassName,
|
||||||
|
resourceManagerSnippet,
|
||||||
|
CreateMemberCodeSnippets(resources)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
3
ResourceString.Net.Logic/IsExternalInit.cs
Normal file
3
ResourceString.Net.Logic/IsExternalInit.cs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
namespace System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
internal static class IsExternalInit { }
|
||||||
44
ResourceString.Net.Logic/Parsers/Resx/Parser.cs
Normal file
44
ResourceString.Net.Logic/Parsers/Resx/Parser.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using ResourceString.Net.Logic.DomainObjects.Resx;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Xml;
|
||||||
|
|
||||||
|
namespace ResourceString.Net.Logic.Parsers.Resx;
|
||||||
|
|
||||||
|
internal static class Parser
|
||||||
|
{
|
||||||
|
public static Option<File> TryParse(string xmlString)
|
||||||
|
{
|
||||||
|
var doc = new XmlDocument();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
doc.LoadXml(xmlString);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return Option<File>.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
var resources = doc.SelectNodes("descendant::data").OfType<XmlElement>().Select((i, _) =>
|
||||||
|
{
|
||||||
|
var name = i.GetAttribute("name");
|
||||||
|
var type = i.GetAttribute("type");
|
||||||
|
var comment = i.SelectSingleNode("descendant::comment")?.InnerXml ?? string.Empty;
|
||||||
|
var value = i.SelectSingleNode("descendant::value")?.InnerXml ?? string.Empty;
|
||||||
|
|
||||||
|
return new Resource(name, value)
|
||||||
|
{
|
||||||
|
Type = string.IsNullOrWhiteSpace(type)
|
||||||
|
? Option<string>.None
|
||||||
|
: Option<string>.Some(type),
|
||||||
|
Comment = string.IsNullOrWhiteSpace(comment)
|
||||||
|
? Option<string>.None
|
||||||
|
: Option<string>.Some(comment)
|
||||||
|
};
|
||||||
|
}).ToArray();
|
||||||
|
|
||||||
|
return resources.Any()
|
||||||
|
? Option<File>.Some(new File(resources))
|
||||||
|
: Option<File>.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
125
ResourceString.Net.Logic/Properties/Resources.cs
Normal file
125
ResourceString.Net.Logic/Properties/Resources.cs
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
using ResourceString.Net.Contract;
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Resources;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace ResourceString.Net.Logic.Properties
|
||||||
|
{
|
||||||
|
internal static class Resources
|
||||||
|
{
|
||||||
|
|
||||||
|
#region ResourceManager
|
||||||
|
|
||||||
|
private static readonly Type _Type = typeof(Resources);
|
||||||
|
|
||||||
|
private static readonly Lazy<ResourceManager> _ResourceManager = new Lazy<ResourceManager>(
|
||||||
|
() => new ResourceManager(_Type.FullName ?? string.Empty, _Type.Assembly),
|
||||||
|
LazyThreadSafetyMode.PublicationOnly
|
||||||
|
);
|
||||||
|
|
||||||
|
public static ResourceManager ResourceManager => _ResourceManager.Value;
|
||||||
|
|
||||||
|
#endregion // ResourceManager
|
||||||
|
|
||||||
|
|
||||||
|
internal static class ResourceStringMembers
|
||||||
|
{
|
||||||
|
private static readonly Lazy<IResourceString> LazyFormat = new Lazy<IResourceString>(
|
||||||
|
() => new ResourceManagerString("ResourceStringMembers", ResourceManager, CultureInfo.CurrentCulture),
|
||||||
|
LazyThreadSafetyMode.PublicationOnly
|
||||||
|
);
|
||||||
|
|
||||||
|
public static IResourceString Format => LazyFormat.Value;
|
||||||
|
|
||||||
|
public static IResourceString From(IResourceString resourceId, IResourceString resourceManagerPropertyName) => new FormattedResourceString(
|
||||||
|
Format,
|
||||||
|
resourceId,
|
||||||
|
resourceManagerPropertyName
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class ResourceFormatClassMembers
|
||||||
|
{
|
||||||
|
private static readonly Lazy<IResourceString> LazyFormat = new Lazy<IResourceString>(
|
||||||
|
() => new ResourceManagerString("ResourceFormatClassMembers", ResourceManager, CultureInfo.CurrentCulture),
|
||||||
|
LazyThreadSafetyMode.PublicationOnly
|
||||||
|
);
|
||||||
|
|
||||||
|
public static IResourceString Format => LazyFormat.Value;
|
||||||
|
|
||||||
|
public static IResourceString From(IResourceString resourceId, IResourceString resourceManagerPropertyName, IResourceString fromMethodDefinition) => new FormattedResourceString(
|
||||||
|
Format,
|
||||||
|
resourceId,
|
||||||
|
resourceManagerPropertyName,
|
||||||
|
fromMethodDefinition
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class ResourceFormatClassFromMethod
|
||||||
|
{
|
||||||
|
private static readonly Lazy<IResourceString> LazyFormat = new Lazy<IResourceString>(
|
||||||
|
() => new ResourceManagerString("ResourceFormatClassFromMethod", ResourceManager, CultureInfo.CurrentCulture),
|
||||||
|
LazyThreadSafetyMode.PublicationOnly
|
||||||
|
);
|
||||||
|
|
||||||
|
public static IResourceString Format => LazyFormat.Value;
|
||||||
|
|
||||||
|
public static IResourceString From(IResourceString fromMethodSignature, IResourceString parameterNames) => new FormattedResourceString(
|
||||||
|
Format,
|
||||||
|
fromMethodSignature,
|
||||||
|
parameterNames
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class ResourcesClassTemplate
|
||||||
|
{
|
||||||
|
private static readonly Lazy<IResourceString> LazyFormat = new Lazy<IResourceString>(
|
||||||
|
() => new ResourceManagerString("ResourcesClassTemplate", ResourceManager, CultureInfo.CurrentCulture),
|
||||||
|
LazyThreadSafetyMode.PublicationOnly
|
||||||
|
);
|
||||||
|
|
||||||
|
public static IResourceString Format => LazyFormat.Value;
|
||||||
|
|
||||||
|
public static IResourceString From(IResourceString ns, IResourceString className, IResourceString resourceManagerRegion, IResourceString resourceRegions) => new FormattedResourceString(
|
||||||
|
Format,
|
||||||
|
ns,
|
||||||
|
className,
|
||||||
|
resourceManagerRegion,
|
||||||
|
resourceRegions
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class ResourceManagerMemberTemplate
|
||||||
|
{
|
||||||
|
private static readonly Lazy<IResourceString> LazyFormat = new Lazy<IResourceString>(
|
||||||
|
() => new ResourceManagerString("ResourceManagerMemberTemplate", ResourceManager, CultureInfo.CurrentCulture),
|
||||||
|
LazyThreadSafetyMode.PublicationOnly
|
||||||
|
);
|
||||||
|
|
||||||
|
public static IResourceString Format => LazyFormat.Value;
|
||||||
|
|
||||||
|
public static IResourceString From(IResourceString resourceManagerTypeName) => new FormattedResourceString(
|
||||||
|
Format,
|
||||||
|
resourceManagerTypeName
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#region DefaultPropertyName_ResourceManager
|
||||||
|
|
||||||
|
private static readonly Lazy<IResourceString> LazyDefaultPropertyName_ResourceManager = new Lazy<IResourceString>(
|
||||||
|
() => new ResourceManagerString("DefaultPropertyName_ResourceManager", ResourceManager, CultureInfo.CurrentCulture),
|
||||||
|
LazyThreadSafetyMode.PublicationOnly
|
||||||
|
);
|
||||||
|
|
||||||
|
public static IResourceString DefaultPropertyName_ResourceManager => LazyDefaultPropertyName_ResourceManager.Value;
|
||||||
|
|
||||||
|
#endregion // DefaultPropertyName_ResourceManager
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
81
ResourceString.Net.Logic/Properties/Resources.resx
Normal file
81
ResourceString.Net.Logic/Properties/Resources.resx
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<data name="ResourceStringMembers" xml:space="preserve">
|
||||||
|
<value>
|
||||||
|
#region {0}
|
||||||
|
|
||||||
|
private static readonly Lazy<IResourceString> Lazy{0} = new Lazy<IResourceString>(
|
||||||
|
() => new ResourceManagerString("{0}", {1}, CultureInfo.CurrentCulture),
|
||||||
|
LazyThreadSafetyMode.PublicationOnly
|
||||||
|
);
|
||||||
|
|
||||||
|
public static IResourceString {0} => Lazy{0}.Value;
|
||||||
|
|
||||||
|
#endregion // {0}
|
||||||
|
</value>
|
||||||
|
<comment>0 = ResourceId, 1 = ResourceManagerPropertyName</comment>
|
||||||
|
</data>
|
||||||
|
<data name="ResourceFormatClassMembers" xml:space="preserve">
|
||||||
|
<value>
|
||||||
|
internal static class {0}
|
||||||
|
{{
|
||||||
|
private static readonly Lazy<IResourceString> LazyFormat = new Lazy<IResourceString>(
|
||||||
|
() => new ResourceManagerString("{0}", {1}, CultureInfo.CurrentCulture),
|
||||||
|
LazyThreadSafetyMode.PublicationOnly
|
||||||
|
);
|
||||||
|
|
||||||
|
public static IResourceString Format => LazyFormat.Value;
|
||||||
|
{2}
|
||||||
|
}}
|
||||||
|
</value>
|
||||||
|
<comment>0 = ResourceId, 1 = ResourceManagerPropertyName, 2 = FromMethodDefinition</comment>
|
||||||
|
</data>
|
||||||
|
<data name="ResourceFormatClassFromMethod" xml:space="preserve">
|
||||||
|
<value>
|
||||||
|
public static IResourceString From({0}) => new FormattedResourceString(
|
||||||
|
Format,
|
||||||
|
{1}
|
||||||
|
);
|
||||||
|
</value>
|
||||||
|
<comment>0 = FromMethodSignature, 1 = ParameterNames</comment>
|
||||||
|
</data>
|
||||||
|
<data name="ResourcesClassTemplate" xml:space="preserve">
|
||||||
|
<value>
|
||||||
|
using ResourceString.Net.Contract;
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Resources;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace {0}
|
||||||
|
{{
|
||||||
|
internal static class {1}
|
||||||
|
{{
|
||||||
|
{2}
|
||||||
|
{3}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
</value>
|
||||||
|
<comment>0 = ns, 1 = ClassName, 2 = ResourceManagerRegion, 3 = ResourceRegions</comment>
|
||||||
|
</data>
|
||||||
|
<data name="ResourceManagerMemberTemplate" xml:space="preserve">
|
||||||
|
<value>
|
||||||
|
#region ResourceManager
|
||||||
|
|
||||||
|
private static readonly Type _Type = typeof({0});
|
||||||
|
|
||||||
|
private static readonly Lazy<ResourceManager> _ResourceManager = new Lazy<ResourceManager>(
|
||||||
|
() => new ResourceManager(_Type.FullName ?? string.Empty, _Type.Assembly),
|
||||||
|
LazyThreadSafetyMode.PublicationOnly
|
||||||
|
);
|
||||||
|
|
||||||
|
public static ResourceManager ResourceManager => _ResourceManager.Value;
|
||||||
|
|
||||||
|
#endregion // ResourceManager
|
||||||
|
</value>
|
||||||
|
<comment>0 = ResourceManagerTypeName</comment>
|
||||||
|
</data>
|
||||||
|
<data name="DefaultPropertyName_ResourceManager">
|
||||||
|
<value>ResourceManager</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
29
ResourceString.Net.Logic/ResourceString.Net.Logic.csproj
Normal file
29
ResourceString.Net.Logic/ResourceString.Net.Logic.csproj
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="LanguageExt.Core" Version="4.4.3" />
|
||||||
|
<PackageReference Include="System.Resources.Extensions" Version="7.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\ResourceString.Net.Contract\ResourceString.Net.Contract.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
||||||
|
<_Parameter1>$(MSBuildProjectName).Tests</_Parameter1>
|
||||||
|
</AssemblyAttribute>
|
||||||
|
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
||||||
|
<_Parameter1>ResourceString.Net.App.Console</_Parameter1>
|
||||||
|
</AssemblyAttribute>
|
||||||
|
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
||||||
|
<_Parameter1>ResourceString.Net</_Parameter1>
|
||||||
|
</AssemblyAttribute>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
4
ResourceString.Net.Logic/Usings.cs
Normal file
4
ResourceString.Net.Logic/Usings.cs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
global using LanguageExt;
|
||||||
|
|
||||||
|
global using ResourceString.Net.Contract;
|
||||||
|
|
||||||
3
ResourceString.Net/FodyWeavers.xml
Normal file
3
ResourceString.Net/FodyWeavers.xml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||||
|
<ILMerge FullImport='true' HideImportedTypes='false' IncludeAssemblies='ResourceString.Net*|LanguageExt*'/>
|
||||||
|
</Weavers>
|
||||||
50
ResourceString.Net/Generator.cs
Normal file
50
ResourceString.Net/Generator.cs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using ResourceString.Net.Logic.Factories;
|
||||||
|
using ResourceString.Net.Logic.Parsers.Resx;
|
||||||
|
|
||||||
|
namespace ResourceString.Net;
|
||||||
|
|
||||||
|
[Generator]
|
||||||
|
public class Generator : IIncrementalGenerator
|
||||||
|
{
|
||||||
|
public void Initialize(IncrementalGeneratorInitializationContext initContext)
|
||||||
|
{
|
||||||
|
// find all additional files that end with .txt
|
||||||
|
var resxFiles = initContext.AdditionalTextsProvider.Where(static file => file.Path.EndsWith(".resx"));
|
||||||
|
var assemblies = initContext.CompilationProvider.Select(static (c, _) => c.Assembly);
|
||||||
|
|
||||||
|
// read their contents and save their name
|
||||||
|
var config = resxFiles.Combine(assemblies).Select(
|
||||||
|
(t, cancellationToken) => (
|
||||||
|
name: System.IO.Path.GetFileNameWithoutExtension(t.Left.Path),
|
||||||
|
content: t.Left.GetText(cancellationToken)!.ToString(),
|
||||||
|
assembly: t.Right,
|
||||||
|
path: t.Left.Path
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// generate a class that contains their values as const strings
|
||||||
|
initContext.RegisterSourceOutput(config, (spc, t) =>
|
||||||
|
{
|
||||||
|
Parser.TryParse(t.content).IfSome(v =>
|
||||||
|
{
|
||||||
|
var relativeNamespace = System.IO.Path.GetDirectoryName(t.path).Substring(
|
||||||
|
System.IO.Path.GetDirectoryName(t.assembly.Locations[0].GetLineSpan().Path).Length
|
||||||
|
).Trim(System.IO.Path.DirectorySeparatorChar).Replace(System.IO.Path.DirectorySeparatorChar, '.');
|
||||||
|
|
||||||
|
var ns = string.IsNullOrWhiteSpace(relativeNamespace)
|
||||||
|
? t.assembly.Name
|
||||||
|
: $"{t.assembly.Name}.{relativeNamespace}";
|
||||||
|
|
||||||
|
var snippet = CodeSnippetFactory.CreateResourceClassCodeSnippet(
|
||||||
|
ns,
|
||||||
|
t.name,
|
||||||
|
CodeSnippetFactory.CreateResourceMangerMemberCodeSnippet(t.name),
|
||||||
|
v.Resources
|
||||||
|
);
|
||||||
|
|
||||||
|
spc.AddSource(ns + t.name, snippet.Value);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
41
ResourceString.Net/ResourceString.Net.csproj
Normal file
41
ResourceString.Net/ResourceString.Net.csproj
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||||
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
|
<Authors>stubbfel</Authors>
|
||||||
|
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
||||||
|
<PackageTags>generator</PackageTags>
|
||||||
|
<NoPackageAnalysis>true</NoPackageAnalysis>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!-- It puts the dll in the expected folder of the NuGet package to be recognized as a C# analyzer -->
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Fody" Version="6.7.0">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="ILMerge.Fody" Version="1.24.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.3.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\ResourceString.Net.Logic\ResourceString.Net.Logic.csproj">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
48
ResourceString.Net/deps.nix
Normal file
48
ResourceString.Net/deps.nix
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
{ fetchNuGet }: [
|
||||||
|
(fetchNuGet { pname = "Fody"; version = "6.7.0"; sha256 = "0fv0zrffa296qjyi11yk31vfqh6gm1nxsx8g5zz380jcsrilnp3h"; })
|
||||||
|
(fetchNuGet { pname = "ILMerge.Fody"; version = "1.24.0"; sha256 = "1gibwcl8ngbvwlcqzd9clysrhsjb8g4gwry7n8ifw1mrw7sjjk6x"; })
|
||||||
|
(fetchNuGet { pname = "LanguageExt.Core"; version = "4.4.3"; sha256 = "1pd7wx4c21v56y6i75sxbs990mjrs6bp9h8c48a5w79s1zpbinw5"; })
|
||||||
|
(fetchNuGet { pname = "Microsoft.Bcl.AsyncInterfaces"; version = "7.0.0"; sha256 = "1waiggh3g1cclc81gmjrqbh128kwfjky3z79ma4bd2ms9pa3gvfm"; })
|
||||||
|
(fetchNuGet { pname = "Microsoft.CodeAnalysis.Analyzers"; version = "3.3.4"; sha256 = "0wd6v57p53ahz5z9zg4iyzmy3src7rlsncyqpcag02jjj1yx6g58"; })
|
||||||
|
(fetchNuGet { pname = "Microsoft.CodeAnalysis.Common"; version = "4.3.0"; sha256 = "0qpxygiq53v2d2wl6hccnkjf1lhlxjh4q3w5b6d23aq9pw5qj626"; })
|
||||||
|
(fetchNuGet { pname = "Microsoft.CodeAnalysis.CSharp"; version = "4.3.0"; sha256 = "0m9qqn391ayfi1ffkzvhpij790hs96q6dbhzfkj2ahvw6qx47b30"; })
|
||||||
|
(fetchNuGet { pname = "Microsoft.CSharp"; version = "4.7.0"; sha256 = "0gd67zlw554j098kabg887b5a6pq9kzavpa3jjy5w53ccjzjfy8j"; })
|
||||||
|
(fetchNuGet { pname = "Microsoft.NETCore.Platforms"; version = "1.1.0"; sha256 = "08vh1r12g6ykjygq5d3vq09zylgb84l63k49jc4v8faw9g93iqqm"; })
|
||||||
|
(fetchNuGet { pname = "Microsoft.NETCore.Targets"; version = "1.1.0"; sha256 = "193xwf33fbm0ni3idxzbr5fdq3i2dlfgihsac9jj7whj0gd902nh"; })
|
||||||
|
(fetchNuGet { pname = "NETStandard.Library"; version = "2.0.3"; sha256 = "1fn9fxppfcg4jgypp2pmrpr6awl3qz1xmnri0cygpkwvyx27df1y"; })
|
||||||
|
(fetchNuGet { pname = "System.Buffers"; version = "4.5.1"; sha256 = "04kb1mdrlcixj9zh1xdi5as0k0qi8byr5mi3p3jcxx72qz93s2y3"; })
|
||||||
|
(fetchNuGet { pname = "System.Collections"; version = "4.3.0"; sha256 = "19r4y64dqyrq6k4706dnyhhw7fs24kpp3awak7whzss39dakpxk9"; })
|
||||||
|
(fetchNuGet { pname = "System.Collections.Immutable"; version = "6.0.0"; sha256 = "1js98kmjn47ivcvkjqdmyipzknb9xbndssczm8gq224pbaj1p88c"; })
|
||||||
|
(fetchNuGet { pname = "System.Diagnostics.Contracts"; version = "4.3.0"; sha256 = "1gxawcr4d2y5jmc6y7iv8c1q83hm22f6savcvspvhmpl974jigib"; })
|
||||||
|
(fetchNuGet { pname = "System.Diagnostics.Debug"; version = "4.3.0"; sha256 = "00yjlf19wjydyr6cfviaph3vsjzg3d5nvnya26i2fvfg53sknh3y"; })
|
||||||
|
(fetchNuGet { pname = "System.Globalization"; version = "4.3.0"; sha256 = "1cp68vv683n6ic2zqh2s1fn4c2sd87g5hpp6l4d4nj4536jz98ki"; })
|
||||||
|
(fetchNuGet { pname = "System.IO"; version = "4.3.0"; sha256 = "05l9qdrzhm4s5dixmx68kxwif4l99ll5gqmh7rqgw554fx0agv5f"; })
|
||||||
|
(fetchNuGet { pname = "System.Linq"; version = "4.3.0"; sha256 = "1w0gmba695rbr80l1k2h4mrwzbzsyfl2z4klmpbsvsg5pm4a56s7"; })
|
||||||
|
(fetchNuGet { pname = "System.Linq.Expressions"; version = "4.3.0"; sha256 = "0ky2nrcvh70rqq88m9a5yqabsl4fyd17bpr63iy2mbivjs2nyypv"; })
|
||||||
|
(fetchNuGet { pname = "System.Linq.Queryable"; version = "4.3.0"; sha256 = "0vidv9cjwy8scabxd33mm4zl5vql695rz56ydc42m9b731xi2ahj"; })
|
||||||
|
(fetchNuGet { pname = "System.Memory"; version = "4.5.4"; sha256 = "14gbbs22mcxwggn0fcfs1b062521azb9fbb7c113x0mq6dzq9h6y"; })
|
||||||
|
(fetchNuGet { pname = "System.Memory"; version = "4.5.5"; sha256 = "08jsfwimcarfzrhlyvjjid61j02irx6xsklf32rv57x2aaikvx0h"; })
|
||||||
|
(fetchNuGet { pname = "System.Numerics.Vectors"; version = "4.4.0"; sha256 = "0rdvma399070b0i46c4qq1h2yvjj3k013sqzkilz4bz5cwmx1rba"; })
|
||||||
|
(fetchNuGet { pname = "System.ObjectModel"; version = "4.3.0"; sha256 = "191p63zy5rpqx7dnrb3h7prvgixmk168fhvvkkvhlazncf8r3nc2"; })
|
||||||
|
(fetchNuGet { pname = "System.Reflection"; version = "4.3.0"; sha256 = "0xl55k0mw8cd8ra6dxzh974nxif58s3k1rjv1vbd7gjbjr39j11m"; })
|
||||||
|
(fetchNuGet { pname = "System.Reflection.Emit"; version = "4.7.0"; sha256 = "121l1z2ypwg02yz84dy6gr82phpys0njk7yask3sihgy214w43qp"; })
|
||||||
|
(fetchNuGet { pname = "System.Reflection.Emit.ILGeneration"; version = "4.3.0"; sha256 = "0w1n67glpv8241vnpz1kl14sy7zlnw414aqwj4hcx5nd86f6994q"; })
|
||||||
|
(fetchNuGet { pname = "System.Reflection.Emit.ILGeneration"; version = "4.7.0"; sha256 = "0l8jpxhpgjlf1nkz5lvp61r4kfdbhr29qi8aapcxn3izd9wd0j8r"; })
|
||||||
|
(fetchNuGet { pname = "System.Reflection.Emit.Lightweight"; version = "4.7.0"; sha256 = "0mbjfajmafkca47zr8v36brvknzks5a7pgb49kfq2d188pyv6iap"; })
|
||||||
|
(fetchNuGet { pname = "System.Reflection.Extensions"; version = "4.3.0"; sha256 = "02bly8bdc98gs22lqsfx9xicblszr2yan7v2mmw3g7hy6miq5hwq"; })
|
||||||
|
(fetchNuGet { pname = "System.Reflection.Metadata"; version = "5.0.0"; sha256 = "17qsl5nanlqk9iz0l5wijdn6ka632fs1m1fvx18dfgswm258r3ss"; })
|
||||||
|
(fetchNuGet { pname = "System.Reflection.Primitives"; version = "4.3.0"; sha256 = "04xqa33bld78yv5r93a8n76shvc8wwcdgr1qvvjh959g3rc31276"; })
|
||||||
|
(fetchNuGet { pname = "System.Reflection.TypeExtensions"; version = "4.3.0"; sha256 = "0y2ssg08d817p0vdag98vn238gyrrynjdj4181hdg780sif3ykp1"; })
|
||||||
|
(fetchNuGet { pname = "System.Resources.Extensions"; version = "7.0.0"; sha256 = "0d5gk5g5qqkwa728jwx9yabgjvgywsy6k8r5vgqv2dmlvjrqflb4"; })
|
||||||
|
(fetchNuGet { pname = "System.Resources.ResourceManager"; version = "4.3.0"; sha256 = "0sjqlzsryb0mg4y4xzf35xi523s4is4hz9q4qgdvlvgivl7qxn49"; })
|
||||||
|
(fetchNuGet { pname = "System.Runtime"; version = "4.3.0"; sha256 = "066ixvgbf2c929kgknshcxqj6539ax7b9m570cp8n179cpfkapz7"; })
|
||||||
|
(fetchNuGet { pname = "System.Runtime.CompilerServices.Unsafe"; version = "4.5.3"; sha256 = "1afi6s2r1mh1kygbjmfba6l4f87pi5sg13p4a48idqafli94qxln"; })
|
||||||
|
(fetchNuGet { pname = "System.Runtime.CompilerServices.Unsafe"; version = "6.0.0"; sha256 = "0qm741kh4rh57wky16sq4m0v05fxmkjjr87krycf5vp9f0zbahbc"; })
|
||||||
|
(fetchNuGet { pname = "System.Runtime.Extensions"; version = "4.3.0"; sha256 = "1ykp3dnhwvm48nap8q23893hagf665k0kn3cbgsqpwzbijdcgc60"; })
|
||||||
|
(fetchNuGet { pname = "System.Text.Encoding"; version = "4.3.0"; sha256 = "1f04lkir4iladpp51sdgmis9dj4y8v08cka0mbmsy0frc9a4gjqr"; })
|
||||||
|
(fetchNuGet { pname = "System.Text.Encoding.CodePages"; version = "6.0.0"; sha256 = "0gm2kiz2ndm9xyzxgi0jhazgwslcs427waxgfa30m7yqll1kcrww"; })
|
||||||
|
(fetchNuGet { pname = "System.Threading"; version = "4.3.0"; sha256 = "0rw9wfamvhayp5zh3j7p1yfmx9b5khbf4q50d8k5rk993rskfd34"; })
|
||||||
|
(fetchNuGet { pname = "System.Threading.Tasks"; version = "4.3.0"; sha256 = "134z3v9abw3a6jsw17xl3f6hqjpak5l682k2vz39spj4kmydg6k7"; })
|
||||||
|
(fetchNuGet { pname = "System.Threading.Tasks.Extensions"; version = "4.5.4"; sha256 = "0y6ncasgfcgnjrhynaf0lwpkpkmv4a07sswwkwbwb5h7riisj153"; })
|
||||||
|
(fetchNuGet { pname = "System.ValueTuple"; version = "4.5.0"; sha256 = "00k8ja51d0f9wrq4vv5z2jhq8hy31kac2rg0rv06prylcybzl8cy"; })
|
||||||
|
]
|
||||||
6
alias.sh
Normal file
6
alias.sh
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/env sh
|
||||||
|
|
||||||
|
alias nixe='nix --experimental-features "nix-command flakes"'
|
||||||
|
alias nulock='nixe run .#devTasks.updateNugetLock'
|
||||||
|
alias fllock='nixe run .#devTasks.updateFlakeLock'
|
||||||
|
alias ulock='nulock && fllock'
|
||||||
23
example/Example.App/Example.App.csproj
Normal file
23
example/Example.App/Example.App.csproj
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\ResourceString.Net\ResourceString.Net.csproj" OutputItemType="Analyzer" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<AdditionalFileItemNames>$(AdditionalFileItemNames);EmbeddedResource</AdditionalFileItemNames>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="System.Resources.Extensions" Version="7.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
22
example/Example.App/Program.cs
Normal file
22
example/Example.App/Program.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
namespace Test
|
||||||
|
{
|
||||||
|
|
||||||
|
internal class Program
|
||||||
|
{
|
||||||
|
private static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Hello");
|
||||||
|
|
||||||
|
var foo = Example.App.Resources.Test1;
|
||||||
|
Console.WriteLine(foo.Value);
|
||||||
|
|
||||||
|
var bar = Example.App.Properties.SubProperties.Properties.Test2.From(
|
||||||
|
ResourceString.Net.Contract.LiteralString.Factory("1"),
|
||||||
|
ResourceString.Net.Contract.LiteralString.Factory("2")
|
||||||
|
);
|
||||||
|
|
||||||
|
Console.WriteLine(bar.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
14
example/Example.App/Properties/SubProperties/Properties.resx
Normal file
14
example/Example.App/Properties/SubProperties/Properties.resx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<root>
|
||||||
|
<data name='Test1'>
|
||||||
|
<value>Value1</value>
|
||||||
|
<comment>This is a greeting message.</comment>
|
||||||
|
</data>
|
||||||
|
<data name='Test2' type='System.String'>
|
||||||
|
<value>{1}Value2{0}{{2}}</value>
|
||||||
|
<comment>2 = prefix</comment>
|
||||||
|
</data>
|
||||||
|
<data name='Test3' type='System.Byte[]'>
|
||||||
|
<value>0xDEADBEEF</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
14
example/Example.App/Resources.resx
Normal file
14
example/Example.App/Resources.resx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<root>
|
||||||
|
<data name='Test1'>
|
||||||
|
<value>Value1</value>
|
||||||
|
<comment>This is a greeting message.</comment>
|
||||||
|
</data>
|
||||||
|
<data name='Test2' type='System.String'>
|
||||||
|
<value>{1}Value2{0}{{2}}</value>
|
||||||
|
<comment>2 = prefix</comment>
|
||||||
|
</data>
|
||||||
|
<data name='Test3' type='System.Byte[]'>
|
||||||
|
<value>0xDEADBEEF</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
26
flake.lock
generated
Normal file
26
flake.lock
generated
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1684364070,
|
||||||
|
"narHash": "sha256-+bmqPSEQBePWwmfwxUX8kvJLyg8OM9mRKnDi5qB+m1s=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "2e6eb88c9ab70147e6087d37c833833fd4a907e5",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"id": "nixpkgs",
|
||||||
|
"ref": "nixos-22.11-small",
|
||||||
|
"type": "indirect"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
158
flake.nix
Normal file
158
flake.nix
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
{
|
||||||
|
description = "";
|
||||||
|
inputs.nixpkgs.url = "nixpkgs/nixos-22.11-small";
|
||||||
|
outputs = { self, nixpkgs }:
|
||||||
|
let
|
||||||
|
name = "ResourceString.Net";
|
||||||
|
version = "0.0.1";
|
||||||
|
supportedSystems =
|
||||||
|
[ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ];
|
||||||
|
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
|
||||||
|
nixpkgsFor = forAllSystems (system: import nixpkgs { inherit system; });
|
||||||
|
scripts = forAllSystems (system: {
|
||||||
|
updateFlakeLockFile = nixpkgsFor.${system}.writeScript "update_flake_lock.sh" ''
|
||||||
|
nix --experimental-features 'nix-command flakes' flake lock --update-input nixpkgs
|
||||||
|
nix --experimental-features 'nix-command flakes' build
|
||||||
|
'';
|
||||||
|
|
||||||
|
updateNugetLockFile = nixpkgsFor.${system}.writeScript "update_nuget_lock.sh" ''
|
||||||
|
temp_package_folder=$(mktemp -d)
|
||||||
|
dotnet restore ResourceString.Net --packages "$temp_package_folder"
|
||||||
|
${nixpkgsFor.${system}.nuget-to-nix}/bin/nuget-to-nix "$temp_package_folder" > ResourceString.Net/deps.nix
|
||||||
|
rm -rf "$temp_package_folder"
|
||||||
|
'';
|
||||||
|
|
||||||
|
autoTag = nixpkgsFor.${system}.writeScript "auto_tag.sh" ''
|
||||||
|
git tag --force v${version}
|
||||||
|
git push origin v${version}
|
||||||
|
'';
|
||||||
|
updateLogicResourceFile = nixpkgsFor.${system}.writeScript "update_logic_resource_file.sh" ''
|
||||||
|
dotnet run --project ResourceString.Net.App.Console ResourceString.Net.Logic/Properties/Resources.resx ResourceString.Net.Logic.Properties > ResourceString.Net.Logic/Properties/Resources.cs.tmp
|
||||||
|
mv ResourceString.Net.Logic/Properties/Resources.cs.tmp ResourceString.Net.Logic/Properties/Resources.cs
|
||||||
|
'';
|
||||||
|
runAllTests = nixpkgsFor.${system}.writeScript "run_all_tests.sh" ''
|
||||||
|
dotnet test *.Tests
|
||||||
|
'';
|
||||||
|
buildAllAssemblies = nixpkgsFor.${system}.writeScript "build_all_assemblies.sh" ''
|
||||||
|
# Find all .csproj files below the current folder
|
||||||
|
csproj_files=$(find . -name '*.csproj')
|
||||||
|
|
||||||
|
# Create a temporary file to store the number of dependencies for each project
|
||||||
|
temp_file=$(mktemp)
|
||||||
|
|
||||||
|
# Loop through each .csproj file and count its number of ResourceString dependencies
|
||||||
|
for file in $csproj_files
|
||||||
|
do
|
||||||
|
count=$(cat "$file" | grep -c "<ProjectReference.*ResourceString")
|
||||||
|
depth=$(echo "$file" | tr -cd '/' | wc -c)
|
||||||
|
dot_count=$(echo "$file" | tr -cd '.' | wc -c)
|
||||||
|
echo "$depth $count $dot_count $file" >> "$temp_file"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Sort the projects by their count of dependencies and path depth, in ascending order
|
||||||
|
sorted_projects=$(sort -nk1 -nk2 -nk3 -t' ' "$temp_file" | awk '{print $4}')
|
||||||
|
|
||||||
|
# Loop through the sorted projects and build them
|
||||||
|
while read -r file
|
||||||
|
do
|
||||||
|
echo "Building project: $file"
|
||||||
|
dotnet build "$file"
|
||||||
|
done << EOF
|
||||||
|
$sorted_projects
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Remove the temporary file
|
||||||
|
rm "$temp_file"
|
||||||
|
|
||||||
|
'';
|
||||||
|
|
||||||
|
cleanAllAssemblies = nixpkgsFor.${system}.writeScript "clean_all_assemblies.sh" ''
|
||||||
|
csproj_files=$(find . -name '*.csproj')
|
||||||
|
for file in $csproj_files
|
||||||
|
do
|
||||||
|
dotnet clean "$file"
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
runDefaultApp = nixpkgsFor.${system}.writeScript "run_default_app.sh" ''
|
||||||
|
dotnet run --project ResourceString.Net.App.Console $@
|
||||||
|
'';
|
||||||
|
createNugetPackage = nixpkgsFor.${system}.writeScript "run_default_app.sh" ''
|
||||||
|
dotnet run --project ResourceString.Net.App.Console $@
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
|
||||||
|
in
|
||||||
|
rec {
|
||||||
|
packages = forAllSystems (system: {
|
||||||
|
default = nixpkgsFor.${system}.buildDotnetModule {
|
||||||
|
pname = name;
|
||||||
|
version = version;
|
||||||
|
|
||||||
|
src = self;
|
||||||
|
|
||||||
|
projectFile = [
|
||||||
|
"ResourceString.Net/ResourceString.Net.csproj"
|
||||||
|
"ResourceString.Net.App.Console/ResourceString.Net.App.Console.csproj"
|
||||||
|
"example/Example.App/Example.App.csproj"
|
||||||
|
];
|
||||||
|
|
||||||
|
nugetDeps = ./ResourceString.Net/deps.nix;
|
||||||
|
projectReferences = [ ];
|
||||||
|
|
||||||
|
dotnet-sdk = nixpkgsFor.${system}.dotnet-sdk;
|
||||||
|
dotnet-runtime = nixpkgsFor.${system}.dotnet-runtime;
|
||||||
|
executables = [ "ResourceString.Net.App.Console" "Example.App" ];
|
||||||
|
packNupkg = true;
|
||||||
|
runtimeDeps = [ ];
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
apps = forAllSystems (system: {
|
||||||
|
default = {
|
||||||
|
type = "app";
|
||||||
|
program = "${scripts.${system}.runDefaultApp}";
|
||||||
|
};
|
||||||
|
devTasks = {
|
||||||
|
updateFlakeLock = {
|
||||||
|
type = "app";
|
||||||
|
program = "${scripts.${system}.updateFlakeLockFile}";
|
||||||
|
};
|
||||||
|
updateNugetLock = {
|
||||||
|
type = "app";
|
||||||
|
program = "${scripts.${system}.updateNugetLockFile}";
|
||||||
|
};
|
||||||
|
autoTag = {
|
||||||
|
type = "app";
|
||||||
|
program = "${scripts.${system}.autoTag}";
|
||||||
|
};
|
||||||
|
updateLogicResourceFile = {
|
||||||
|
type = "app";
|
||||||
|
program = "${scripts.${system}.updateLogicResourceFile}";
|
||||||
|
};
|
||||||
|
runAllTests = {
|
||||||
|
type = "app";
|
||||||
|
program = "${scripts.${system}.runAllTests}";
|
||||||
|
};
|
||||||
|
buildAllAssemblies = {
|
||||||
|
type = "app";
|
||||||
|
program = "${scripts.${system}.buildAllAssemblies}";
|
||||||
|
};
|
||||||
|
cleanAllAssemblies = {
|
||||||
|
type = "app";
|
||||||
|
program = "${scripts.${system}.cleanAllAssemblies}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
devShells = forAllSystems (system: {
|
||||||
|
default = nixpkgsFor.${system}.mkShell {
|
||||||
|
name = "dev-shell";
|
||||||
|
packages =
|
||||||
|
[ nixpkgsFor.${system}.dotnet-sdk nixpkgsFor.${system}.nixfmt ];
|
||||||
|
shellHook = ''
|
||||||
|
alias nixe="nix --experimental-features 'nix-command flakes'"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user