├── .config └── dotnet-tools.json ├── .github ├── dependabot.yml └── workflows │ └── build.yml ├── .gitignore ├── Gazorator.sln ├── Gazorator.sln.DotSettings ├── LICENSE ├── appveyor.yml ├── assets ├── black-logo@2x.png ├── color-logo@2x.png ├── horizontal-logo.png └── white-logo@2x.png ├── build.ps1 ├── build.sh ├── global.json ├── readme.md ├── recipe.cake ├── sample └── Gazorator.Console │ ├── BindingProjectModel.cs │ ├── Gazorator.Console.csproj │ ├── MavenArtifactModel.cs │ ├── Model.cs │ ├── NuGetDependencyModel.cs │ ├── Program.cs │ └── Views │ ├── CakeIssues.cshtml │ ├── Sample.cshtml │ └── Xamarin.cshtml └── src ├── Directory.Build.targets ├── Gazorator.sln.DotSettings └── Gazorator ├── Extensions └── TypeExtensions.cs ├── Gazorator.cs ├── Gazorator.csproj ├── Razor ├── CSharpScriptDocumentClassifierPass.cs └── CSharpScriptRazorGenerator.cs └── Scripting ├── DynamicViewBag.cs ├── HtmlRenderer.cs ├── IRazorLiteral.cs ├── RazorContentGenerator.cs ├── RazorLiteral.cs └── RazorScriptHost.cs /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "cake.tool": { 6 | "version": "0.38.4", 7 | "commands": ["dotnet-cake"] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "nuget" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | ignore: 8 | - "Cake.Core" 9 | - package-ecosystem: "github-actions" 10 | directory: "/" 11 | schedule: 12 | interval: "daily" -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - develop 8 | - "release/**" 9 | - "hotfix/**" 10 | - "feature/**" 11 | paths-ignore: 12 | - "README.md" 13 | pull_request: 14 | 15 | jobs: 16 | build: 17 | runs-on: ${{ matrix.os }} 18 | strategy: 19 | matrix: 20 | os: [windows-latest, ubuntu-latest, macos-latest] 21 | 22 | steps: 23 | - uses: actions/checkout@v2.3.2 24 | with: 25 | sumbodules: true 26 | - name: Fetch all tags and branches 27 | run: git fetch --prune --unshallow 28 | - name: Cache Tools 29 | uses: actions/cache@v2.1.1 30 | with: 31 | path: tools 32 | key: ${{ runner.os }}-tools-${{ hashFiles('recipe.cake') }} 33 | - name: Build Addin 34 | uses: cake-build/cake-action@v1 35 | with: 36 | script-path: recipe.cake 37 | target: CI 38 | verbosity: Diagnostic 39 | cake-version: 0.38.4 40 | cake-bootstrap: true 41 | - name: Upload artifacts 42 | uses: actions/upload-artifact@v2.1.4 43 | with: 44 | name: ${{ matrix.os }}-artifacts 45 | path: | 46 | BuildArtifacts/report.html 47 | BuildArtifacts/packages/**/*.nupkg 48 | BuildArtifacts/**/coverlet/*.xml -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | .DS_Store 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | bld/ 24 | [Bb]in/ 25 | [Oo]bj/ 26 | [Ll]og/ 27 | 28 | # Visual Studio 2015 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # MSTest test Results 34 | [Tt]est[Rr]esult*/ 35 | [Bb]uild[Ll]og.* 36 | 37 | # NUNIT 38 | *.VisualState.xml 39 | TestResult.xml 40 | 41 | # Build Results of an ATL Project 42 | [Dd]ebugPS/ 43 | [Rr]eleasePS/ 44 | dlldata.c 45 | 46 | # .NET Core 47 | project.lock.json 48 | project.fragment.lock.json 49 | artifacts/ 50 | **/Properties/launchSettings.json 51 | 52 | *_i.c 53 | *_p.c 54 | *_i.h 55 | *.ilk 56 | *.meta 57 | *.obj 58 | *.pch 59 | *.pdb 60 | *.pgc 61 | *.pgd 62 | *.rsp 63 | *.sbr 64 | *.tlb 65 | *.tli 66 | *.tlh 67 | *.tmp 68 | *.tmp_proj 69 | *.log 70 | *.vspscc 71 | *.vssscc 72 | .builds 73 | *.pidb 74 | *.svclog 75 | *.scc 76 | 77 | # Chutzpah Test files 78 | _Chutzpah* 79 | 80 | # Visual C++ cache files 81 | ipch/ 82 | *.aps 83 | *.ncb 84 | *.opendb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | *.VC.db 89 | *.VC.VC.opendb 90 | 91 | # Visual Studio profiler 92 | *.psess 93 | *.vsp 94 | *.vspx 95 | *.sap 96 | 97 | # TFS 2012 Local Workspace 98 | $tf/ 99 | 100 | # Guidance Automation Toolkit 101 | *.gpState 102 | 103 | # ReSharper is a .NET coding add-in 104 | _ReSharper*/ 105 | *.[Rr]e[Ss]harper 106 | *.DotSettings.user 107 | 108 | # JustCode is a .NET coding add-in 109 | .JustCode 110 | 111 | # TeamCity is a build add-in 112 | _TeamCity* 113 | 114 | # DotCover is a Code Coverage Tool 115 | *.dotCover 116 | 117 | # Visual Studio code coverage results 118 | *.coverage 119 | *.coveragexml 120 | 121 | # NCrunch 122 | _NCrunch_* 123 | .*crunch*.local.xml 124 | nCrunchTemp_* 125 | 126 | # MightyMoose 127 | *.mm.* 128 | AutoTest.Net/ 129 | 130 | # Web workbench (sass) 131 | .sass-cache/ 132 | 133 | # Installshield output folder 134 | [Ee]xpress/ 135 | 136 | # DocProject is a documentation generator add-in 137 | DocProject/buildhelp/ 138 | DocProject/Help/*.HxT 139 | DocProject/Help/*.HxC 140 | DocProject/Help/*.hhc 141 | DocProject/Help/*.hhk 142 | DocProject/Help/*.hhp 143 | DocProject/Help/Html2 144 | DocProject/Help/html 145 | 146 | # Click-Once directory 147 | publish/ 148 | 149 | # Publish Web Output 150 | *.[Pp]ublish.xml 151 | *.azurePubxml 152 | # TODO: Comment the next line if you want to checkin your web deploy settings 153 | # but database connection strings (with potential passwords) will be unencrypted 154 | *.pubxml 155 | *.publishproj 156 | 157 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 158 | # checkin your Azure Web App publish settings, but sensitive information contained 159 | # in these scripts will be unencrypted 160 | PublishScripts/ 161 | 162 | # NuGet Packages 163 | *.nupkg 164 | # The packages folder can be ignored because of Package Restore 165 | **/packages/* 166 | # except build/, which is used as an MSBuild target. 167 | !**/packages/build/ 168 | # Uncomment if necessary however generally it will be regenerated when needed 169 | #!**/packages/repositories.config 170 | # NuGet v3's project.json files produces more ignorable files 171 | *.nuget.props 172 | *.nuget.targets 173 | 174 | # Microsoft Azure Build Output 175 | csx/ 176 | *.build.csdef 177 | 178 | # Microsoft Azure Emulator 179 | ecf/ 180 | rcf/ 181 | 182 | # Windows Store app package directories and files 183 | AppPackages/ 184 | BundleArtifacts/ 185 | Package.StoreAssociation.xml 186 | _pkginfo.txt 187 | 188 | # Visual Studio cache files 189 | # files ending in .cache can be ignored 190 | *.[Cc]ache 191 | # but keep track of directories ending in .cache 192 | !*.[Cc]ache/ 193 | 194 | # Others 195 | ClientBin/ 196 | ~$* 197 | *~ 198 | *.dbmdl 199 | *.dbproj.schemaview 200 | *.jfm 201 | *.pfx 202 | *.publishsettings 203 | orleans.codegen.cs 204 | 205 | # Since there are multiple workflows, uncomment next line to ignore bower_components 206 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 207 | #bower_components/ 208 | 209 | # RIA/Silverlight projects 210 | Generated_Code/ 211 | 212 | # Backup & report files from converting an old project file 213 | # to a newer Visual Studio version. Backup files are not needed, 214 | # because we have git ;-) 215 | _UpgradeReport_Files/ 216 | Backup*/ 217 | UpgradeLog*.XML 218 | UpgradeLog*.htm 219 | 220 | # SQL Server files 221 | *.mdf 222 | *.ldf 223 | *.ndf 224 | 225 | # Business Intelligence projects 226 | *.rdl.data 227 | *.bim.layout 228 | *.bim_*.settings 229 | 230 | # Microsoft Fakes 231 | FakesAssemblies/ 232 | 233 | # GhostDoc plugin setting file 234 | *.GhostDoc.xml 235 | 236 | # Node.js Tools for Visual Studio 237 | .ntvs_analysis.dat 238 | node_modules/ 239 | 240 | # Typescript v1 declaration files 241 | typings/ 242 | 243 | # Visual Studio 6 build log 244 | *.plg 245 | 246 | # Visual Studio 6 workspace options file 247 | *.opt 248 | 249 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 250 | *.vbw 251 | 252 | # Visual Studio LightSwitch build output 253 | **/*.HTMLClient/GeneratedArtifacts 254 | **/*.DesktopClient/GeneratedArtifacts 255 | **/*.DesktopClient/ModelManifest.xml 256 | **/*.Server/GeneratedArtifacts 257 | **/*.Server/ModelManifest.xml 258 | _Pvt_Extensions 259 | 260 | # Paket dependency manager 261 | .paket/paket.exe 262 | paket-files/ 263 | 264 | # FAKE - F# Make 265 | .fake/ 266 | 267 | # JetBrains Rider 268 | .idea/ 269 | *.sln.iml 270 | 271 | # CodeRush 272 | .cr/ 273 | 274 | # Python Tools for Visual Studio (PTVS) 275 | __pycache__/ 276 | *.pyc 277 | 278 | # Cake - Uncomment if you are using it 279 | # tools/** 280 | # !tools/packages.config 281 | 282 | # Telerik's JustMock configuration file 283 | *.jmconfig 284 | 285 | # BizTalk build output 286 | *.btp.cs 287 | *.btm.cs 288 | *.odx.cs 289 | *.xsd.cs 290 | 291 | #Cake (generated) 292 | [Tt]ools/ 293 | BuildArtifacts/ 294 | 295 | #VS Code 296 | .vscode/ 297 | .ionide 298 | .dotnet -------------------------------------------------------------------------------- /Gazorator.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27428.2011 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Gazorator", "src\Gazorator\Gazorator.csproj", "{DAC00C66-6160-44DD-8412-D38229026250}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sample", "sample", "{CFC49255-CEDC-49D7-AF18-7CEAE9970556}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F9A6DB59-9592-42D4-A498-B2D97CB6D2B5}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gazorator.Console", "sample\Gazorator.Console\Gazorator.Console.csproj", "{18AF6377-1AB4-483D-8231-FBE7B39AC250}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {DAC00C66-6160-44DD-8412-D38229026250}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {DAC00C66-6160-44DD-8412-D38229026250}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {DAC00C66-6160-44DD-8412-D38229026250}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {DAC00C66-6160-44DD-8412-D38229026250}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {18AF6377-1AB4-483D-8231-FBE7B39AC250}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {18AF6377-1AB4-483D-8231-FBE7B39AC250}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {18AF6377-1AB4-483D-8231-FBE7B39AC250}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {18AF6377-1AB4-483D-8231-FBE7B39AC250}.Release|Any CPU.Build.0 = Release|Any CPU 28 | EndGlobalSection 29 | GlobalSection(SolutionProperties) = preSolution 30 | HideSolutionNode = FALSE 31 | EndGlobalSection 32 | GlobalSection(NestedProjects) = preSolution 33 | {DAC00C66-6160-44DD-8412-D38229026250} = {F9A6DB59-9592-42D4-A498-B2D97CB6D2B5} 34 | {18AF6377-1AB4-483D-8231-FBE7B39AC250} = {CFC49255-CEDC-49D7-AF18-7CEAE9970556} 35 | EndGlobalSection 36 | GlobalSection(ExtensibilityGlobals) = postSolution 37 | SolutionGuid = {73C9CC56-8AA4-4274-A3A6-27C5795C119C} 38 | EndGlobalSection 39 | EndGlobal 40 | -------------------------------------------------------------------------------- /Gazorator.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | ExplicitlyExcluded -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Martin Björkström 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | #---------------------------------# 2 | # Build Image # 3 | #---------------------------------# 4 | image: Visual Studio 2019 5 | 6 | #---------------------------------# 7 | # Build Script # 8 | #---------------------------------# 9 | build_script: 10 | - ps: .\build.ps1 --target=CI 11 | 12 | #---------------------------------# 13 | # Tests 14 | #---------------------------------# 15 | test: off 16 | 17 | #---------------------------------# 18 | # Pull Requests # 19 | #---------------------------------# 20 | pull_requests: 21 | do_not_increment_build_number: true 22 | 23 | #---------------------------------# 24 | # General # 25 | #---------------------------------# 26 | skip_branch_with_pr: true 27 | 28 | #---------------------------------# 29 | # Branches to build # 30 | #---------------------------------# 31 | branches: 32 | # Allow-List 33 | only: 34 | - develop 35 | - master 36 | - /release/.*/ 37 | - /hotfix/.*/ 38 | 39 | #---------------------------------# 40 | # Build Cache # 41 | #---------------------------------# 42 | cache: 43 | - tools -> recipe.cake -------------------------------------------------------------------------------- /assets/black-logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjorkstromm/gazorator/b851d1067778d782f8257e6fcc42697c13831d16/assets/black-logo@2x.png -------------------------------------------------------------------------------- /assets/color-logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjorkstromm/gazorator/b851d1067778d782f8257e6fcc42697c13831d16/assets/color-logo@2x.png -------------------------------------------------------------------------------- /assets/horizontal-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjorkstromm/gazorator/b851d1067778d782f8257e6fcc42697c13831d16/assets/horizontal-logo.png -------------------------------------------------------------------------------- /assets/white-logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjorkstromm/gazorator/b851d1067778d782f8257e6fcc42697c13831d16/assets/white-logo@2x.png -------------------------------------------------------------------------------- /build.ps1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env pwsh 2 | $ErrorActionPreference = 'Stop' 3 | $DotNetInstallerUri = 'https://dot.net/v1/dotnet-install.ps1'; 4 | $DotNetUnixInstallerUri = 'https://dot.net/v1/dotnet-install.sh' 5 | $DotNetChannel = 'LTS' 6 | $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent 7 | 8 | [string] $DotNetVersion = '3.1.402' 9 | 10 | ########################################################################### 11 | # INSTALL .NET CORE CLI 12 | ########################################################################### 13 | 14 | $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1 15 | $env:DOTNET_CLI_TELEMETRY_OPTOUT = 1 16 | $env:DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX = 2 17 | 18 | Function Remove-PathVariable([string]$VariableToRemove) { 19 | $SplitChar = ';' 20 | if ($IsMacOS -or $IsLinux) { 21 | $SplitChar = ':' 22 | } 23 | 24 | $path = [Environment]::GetEnvironmentVariable("PATH", "User") 25 | if ($path -ne $null) { 26 | $newItems = $path.Split($SplitChar, [StringSplitOptions]::RemoveEmptyEntries) | Where-Object { "$($_)" -inotlike $VariableToRemove } 27 | [Environment]::SetEnvironmentVariable("PATH", [System.String]::Join($SplitChar, $newItems), "User") 28 | } 29 | 30 | $path = [Environment]::GetEnvironmentVariable("PATH", "Process") 31 | if ($path -ne $null) { 32 | $newItems = $path.Split($SplitChar, [StringSplitOptions]::RemoveEmptyEntries) | Where-Object { "$($_)" -inotlike $VariableToRemove } 33 | [Environment]::SetEnvironmentVariable("PATH", [System.String]::Join($SplitChar, $newItems), "Process") 34 | } 35 | } 36 | 37 | # Get .NET Core CLI path if installed. 38 | $FoundDotNetCliVersion = $null; 39 | if (Get-Command dotnet -ErrorAction SilentlyContinue) { 40 | $FoundDotNetCliVersion = dotnet --version; 41 | } 42 | 43 | if ($FoundDotNetCliVersion -ne $DotNetVersion) { 44 | $InstallPath = Join-Path $PSScriptRoot ".dotnet" 45 | if (!(Test-Path $InstallPath)) { 46 | New-Item -Path $InstallPath -ItemType Directory -Force | Out-Null; 47 | } 48 | 49 | if ($IsMacOS -or $IsLinux) { 50 | $ScriptPath = Join-Path $InstallPath 'dotnet-install.sh' 51 | (New-Object System.Net.WebClient).DownloadFile($DotNetUnixInstallerUri, $ScriptPath); 52 | & bash $ScriptPath --version "$DotNetVersion" --install-dir "$InstallPath" --channel "$DotNetChannel" --no-path 53 | 54 | Remove-PathVariable "$InstallPath" 55 | $env:PATH = "$($InstallPath):$env:PATH" 56 | } 57 | else { 58 | $ScriptPath = Join-Path $InstallPath 'dotnet-install.ps1' 59 | (New-Object System.Net.WebClient).DownloadFile($DotNetInstallerUri, $ScriptPath); 60 | & $ScriptPath -Channel $DotNetChannel -Version $DotNetVersion -InstallDir $InstallPath; 61 | 62 | Remove-PathVariable "$InstallPath" 63 | $env:PATH = "$InstallPath;$env:PATH" 64 | } 65 | $env:DOTNET_ROOT = $InstallPath 66 | } 67 | 68 | ########################################################################### 69 | # RUN BUILD SCRIPT 70 | ########################################################################### 71 | 72 | $SCRIPT_NAME = "recipe.cake" 73 | 74 | Write-Host "Restoring .NET Core tools" 75 | dotnet tool restore 76 | if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } 77 | 78 | Write-Host "Bootstrapping Cake" 79 | dotnet cake $SCRIPT_NAME --bootstrap 80 | if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } 81 | 82 | Write-Host "Running Build" 83 | dotnet cake $SCRIPT_NAME @args 84 | if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Define varibles 4 | SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 5 | DOTNET_VERSION="3.1.402" 6 | 7 | ########################################################################### 8 | # INSTALL .NET CORE CLI 9 | ########################################################################### 10 | 11 | export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 12 | export DOTNET_CLI_TELEMETRY_OPTOUT=1 13 | export DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER=0 14 | export DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX=2 15 | 16 | DOTNET_INSTALLED_VERSION=$(dotnet --version 2>&1) 17 | 18 | if [ "$DOTNET_VERSION" != "$DOTNET_INSTALLED_VERSION" ]; then 19 | echo "Installing .NET CLI..." 20 | if [ ! -d "$SCRIPT_DIR/.dotnet" ]; then 21 | mkdir "$SCRIPT_DIR/.dotnet" 22 | fi 23 | curl -Lsfo "$SCRIPT_DIR/.dotnet/dotnet-install.sh" https://dot.net/v1/dotnet-install.sh 24 | bash "$SCRIPT_DIR/.dotnet/dotnet-install.sh" --version $DOTNET_VERSION --install-dir .dotnet --no-path 25 | export PATH="$SCRIPT_DIR/.dotnet":$PATH 26 | export DOTNET_ROOT="$SCRIPT_DIR/.dotnet" 27 | fi 28 | 29 | ########################################################################### 30 | # RUN BUILD SCRIPT 31 | ########################################################################### 32 | 33 | SCRIPT_NAME="recipe.cake" 34 | 35 | echo "Restoring .NET Core tools" 36 | dotnet tool restore 37 | 38 | echo "Bootstrapping Cake" 39 | dotnet cake $SCRIPT_NAME --bootstrap 40 | 41 | echo "Running Build" 42 | dotnet cake $SCRIPT_NAME "$@" -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "3.1.402", 4 | "rollForward": "latestPatch", 5 | "allowPrerelease": false 6 | } 7 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Gazorator 2 | 3 | ![gazorator logo](./assets/horizontal-logo.png) 4 | 5 | Gazorator is a `dotnet` library that empowers developers to generate XML based outputs using the power of the Razor View Engine. 6 | 7 | Supported output formats include: 8 | 9 | - HTML 10 | - XML 11 | - XAML 12 | 13 | ## Sample 14 | 15 | There are three parts to running Gazorator: 16 | 17 | 1. The **Template** 18 | 2. The **Model** or data 19 | 3. The **Output**. 20 | 21 | ### Template 22 | 23 | Templates can be any XML based language, and Razor syntax is recommended due to its flexibility. Templates are required to `inherit` from the type `Gazorator.Scripting.RazorScriptHost`. 24 | 25 | ```html 26 | @inherits Gazorator.Scripting.RazorScriptHost 27 | @{ var helloWorld = ""Hello World!""; } 28 | @{ var year = DateTime.Now.Year; } 29 | 30 | 31 | 32 | 33 | Add Numbers 34 | 35 | 48 | 49 | 50 |
51 |

@helloWorld

52 |

It's year @year!

53 |

@Model.MyProperty

54 | @foreach (var x in Model.Values) 55 | { 56 |

@x

57 | } 58 | @Html.Raw(""

Output some html!

"") 59 |
60 | 61 | 62 | ``` 63 | 64 | ### Models 65 | 66 | Similar to Razor Views, Gazorator templates can take a view model. Here we see the usage of `WithModel` passing in a value. 67 | 68 | ```c# 69 | using var writer = new StringWriter(); 70 | await Gazorator.Default 71 | .WithOutput(writer) 72 | .WithModel(new Model 73 | { 74 | MyProperty = 1234, 75 | Values = new List {1, 2, 3, 4} 76 | }) 77 | .ProcessTemplateAsync(template); 78 | ``` 79 | 80 | ### Output 81 | 82 | We can write the output to an instance of `TextWriter`. 83 | 84 | ## License 85 | 86 | MIT License 87 | 88 | Copyright (c) 2018 Martin Björkström 89 | 90 | Permission is hereby granted, free of charge, to any person obtaining a copy 91 | of this software and associated documentation files (the "Software"), to deal 92 | in the Software without restriction, including without limitation the rights 93 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 94 | copies of the Software, and to permit persons to whom the Software is 95 | furnished to do so, subject to the following conditions: 96 | 97 | The above copyright notice and this permission notice shall be included in all 98 | copies or substantial portions of the Software. 99 | 100 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 101 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 102 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 103 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 104 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 105 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 106 | SOFTWARE. 107 | -------------------------------------------------------------------------------- /recipe.cake: -------------------------------------------------------------------------------- 1 | #load nuget:?package=Cake.Recipe&version=2.0.0 2 | 3 | Environment.SetVariableNames(); 4 | 5 | BuildParameters.SetParameters(context: Context, 6 | buildSystem: BuildSystem, 7 | sourceDirectoryPath: "./src", 8 | solutionFilePath: "./Gazorator.sln", 9 | title: "Gazorator", 10 | repositoryOwner: "mholo65", 11 | repositoryName: "gazorator", 12 | appVeyorAccountName: "mholo65", 13 | shouldRunDupFinder: false, 14 | shouldRunInspectCode: false, 15 | shouldRunDotNetCorePack: true, 16 | shouldUseDeterministicBuilds: true); 17 | 18 | BuildParameters.PrintParameters(Context); 19 | 20 | ToolSettings.SetToolSettings(context: Context, 21 | dupFinderExcludePattern: new string[] { 22 | BuildParameters.RootDirectoryPath + "/src/Gazorator/**/*.AssemblyInfo.cs"}); 23 | 24 | Build.RunDotNetCore(); 25 | -------------------------------------------------------------------------------- /sample/Gazorator.Console/BindingProjectModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace AndroidBinderator 5 | { 6 | public class BindingProjectModel 7 | { 8 | public string Id { get; private set; } = Guid.NewGuid().ToString().ToUpperInvariant(); 9 | 10 | public string Name { get; set; } = string.Empty; 11 | 12 | public string MavenGroupId { get; set; } = string.Empty; 13 | 14 | public List MavenArtifacts { get; set; } = new List(); 15 | 16 | public string NuGetPackageId { get; set; } = string.Empty; 17 | public string NuGetVersion { get; set; } = string.Empty; 18 | 19 | public string AssemblyName { get; set; } = string.Empty; 20 | 21 | public List NuGetDependencies { get; set; } = new List(); 22 | 23 | public List ProjectReferences { get; set; } = new List(); 24 | } 25 | } -------------------------------------------------------------------------------- /sample/Gazorator.Console/Gazorator.Console.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp2.1 6 | latest 7 | 8 | 9 | 10 | 11 | runtime; build; native; contentfiles; analyzers; buildtransitive 12 | all 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | PreserveNewest 24 | 25 | 26 | PreserveNewest 27 | 28 | 29 | PreserveNewest 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /sample/Gazorator.Console/MavenArtifactModel.cs: -------------------------------------------------------------------------------- 1 | namespace AndroidBinderator 2 | { 3 | public class MavenArtifactModel 4 | { 5 | public string MavenGroupId { get; set; } = string.Empty; 6 | public string MavenArtifactId { get; set; } = string.Empty; 7 | public string MavenArtifactVersion { get; set; } = string.Empty; 8 | public string MavenArtifactPackaging { get; set; } = string.Empty; 9 | 10 | public string DownloadedArtifact { get; set; } = string.Empty; 11 | public string ProguardFile { get; set; } = string.Empty; 12 | } 13 | } -------------------------------------------------------------------------------- /sample/Gazorator.Console/Model.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Gazorator.Console 4 | { 5 | public class Model 6 | { 7 | public int MyProperty { get; set; } 8 | 9 | public List Values { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /sample/Gazorator.Console/NuGetDependencyModel.cs: -------------------------------------------------------------------------------- 1 | namespace AndroidBinderator 2 | { 3 | public class NuGetDependencyModel 4 | { 5 | public bool IsProjectReference { get; set; } 6 | 7 | public string NuGetPackageId { get; set; } = string.Empty; 8 | public string NuGetVersion { get; set; } = string.Empty; 9 | 10 | public MavenArtifactModel MavenArtifact { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /sample/Gazorator.Console/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Threading.Tasks; 5 | using AndroidBinderator; 6 | using System.Linq; 7 | using System.Xml.Linq; 8 | 9 | namespace Gazorator.Console 10 | { 11 | class Program 12 | { 13 | private const string template = @" 14 | @inherits Gazorator.Scripting.RazorScriptHost 15 | @{ var helloWorld = ""Hello World!""; } 16 | @{ var year = DateTime.Now.Year; } 17 | 18 | 19 | 20 | 21 | Add Numbers 22 | 23 | 36 | 37 | 38 |
39 |

@helloWorld

40 |

It's year @year!

41 |

@Model.MyProperty

42 | @foreach (var x in Model.Values) 43 | { 44 |

@x

45 | } 46 | @Html.Raw(""

Output some html!

"") 47 |
48 | 49 | "; 50 | static async Task Main(string[] args) 51 | { 52 | using (var writer = new StringWriter()) 53 | { 54 | // Gazorator.Default 55 | // .WithOutput(writer) 56 | // .WithModel(new Model 57 | // { 58 | // MyProperty = 1234, 59 | // Values = new List { 1, 2, 3, 4 } 60 | // }).ProcessAsync("./Views/Sample.cshtml").Wait(); 61 | 62 | // await Gazorator.Default 63 | // .WithOutput(writer) 64 | // // .WithModel(new BindingProjectModel()) 65 | // // .WithReferences(typeof(XDocument).Assembly) 66 | // //.ProcessAsync("./Views/Xamarin.cshtml") 67 | // .WithModel(new Model 68 | // { 69 | // MyProperty = 1234, 70 | // Values = new List {1, 2, 3, 4} 71 | // }) 72 | // .ProcessTemplateAsync(template); 73 | 74 | var issue = new Cake.Issues.Issue( 75 | "id", 76 | "path", 77 | "projectName", 78 | "affectedPath", 79 | 1, 80 | 2, 81 | 1, 82 | 2, 83 | "text", 84 | "html", 85 | "markdown", 86 | 1, 87 | "prio", 88 | "rule", 89 | new Uri("http://example.com"), 90 | "run", 91 | "providerType", 92 | "providerName"); 93 | 94 | await Gazorator.Default 95 | .WithOutput(writer) 96 | .WithModel(new [] { issue } 97 | .AsEnumerable() 98 | .Cast()) 99 | .WithReferences( 100 | typeof(Cake.Issues.IIssue).Assembly, 101 | typeof(Cake.Issues.Reporting.IIssueReportFormat).Assembly, 102 | typeof(Cake.Issues.Reporting.Generic.DevExtremeTheme).Assembly, 103 | typeof(Cake.Core.IO.FilePath).Assembly 104 | ) 105 | // .WithViewBag(ViewBag => 106 | // { 107 | // ViewBag.Title = "Foo"; 108 | // }) 109 | .WithViewBag(new Dictionary 110 | { 111 | ["Title"] = "FooBar" 112 | }) 113 | .ProcessAsync("./Views/CakeIssues.cshtml"); 114 | 115 | System.Console.WriteLine(writer.ToString()); 116 | } 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /sample/Gazorator.Console/Views/CakeIssues.cshtml: -------------------------------------------------------------------------------- 1 | @inherits Gazorator.Scripting.RazorScriptHost> 2 | 3 | @using System.Collections.Generic 4 | @using System.Linq 5 | @using Cake.Issues.Serialization 6 | @using Cake.Issues.Reporting.Generic 7 | 8 | 9 | 10 | @{ 11 | // Read options and apply default values. 12 | var title = ViewBagHelper.ValueOrDefault(ViewBag.Title, "Issues Report"); 13 | DevExtremeTheme theme = ViewBagHelper.ValueOrDefault(ViewBag.Theme, DevExtremeTheme.Light); 14 | bool showHeader = ViewBagHelper.ValueOrDefault(ViewBag.ShowHeader, true); 15 | bool enableSearching = ViewBagHelper.ValueOrDefault(ViewBag.EnableSearching, true); 16 | bool enableGrouping = ViewBagHelper.ValueOrDefault(ViewBag.EnableGrouping, true); 17 | bool enableFiltering = ViewBagHelper.ValueOrDefault(ViewBag.EnableFiltering, true); 18 | bool enableExporting = ViewBagHelper.ValueOrDefault(ViewBag.EnableExporting, false); 19 | string exportFileName = ViewBagHelper.ValueOrDefault(ViewBag.JQueryVersion, "issue-report"); 20 | bool providerTypeVisible = ViewBagHelper.ValueOrDefault(ViewBag.ProviderTypeVisible, false); 21 | ColumnSortOrder providerTypeSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.ProviderTypeSortOder, ColumnSortOrder.Ascending); 22 | bool providerNameVisible = ViewBagHelper.ValueOrDefault(ViewBag.ProviderNameVisible, true); 23 | ColumnSortOrder providerNameSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.ProviderNameSortOder, ColumnSortOrder.Ascending); 24 | bool priorityVisible = ViewBagHelper.ValueOrDefault(ViewBag.PriorityVisible, false); 25 | ColumnSortOrder prioritySortOrder = ViewBagHelper.ValueOrDefault(ViewBag.PrioritySortOrder, ColumnSortOrder.Descending); 26 | bool priorityNameVisible = ViewBagHelper.ValueOrDefault(ViewBag.PriorityNameVisible, true); 27 | ColumnSortOrder priorityNameSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.PriorityNameSortOrder, ColumnSortOrder.Descending); 28 | bool projectPathVisible = ViewBagHelper.ValueOrDefault(ViewBag.ProjectPathVisible, false); 29 | ColumnSortOrder projectPathSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.ProjectPathSortOder, ColumnSortOrder.Ascending); 30 | bool projectNameVisible = ViewBagHelper.ValueOrDefault(ViewBag.ProjectNameVisible, true); 31 | ColumnSortOrder projectNameSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.ProjectNameSortOder, ColumnSortOrder.Ascending); 32 | bool filePathVisible = ViewBagHelper.ValueOrDefault(ViewBag.FilePathVisible, false); 33 | ColumnSortOrder filePathSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.FilePathSortOder, ColumnSortOrder.Ascending); 34 | bool fileDirectoryVisible = ViewBagHelper.ValueOrDefault(ViewBag.FileDirectoryVisible, true); 35 | ColumnSortOrder fileDirectorySortOrder = ViewBagHelper.ValueOrDefault(ViewBag.FileDirectorySortOder, ColumnSortOrder.Ascending); 36 | bool fileNameVisible = ViewBagHelper.ValueOrDefault(ViewBag.FileNameVisible, true); 37 | ColumnSortOrder fileNameSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.FileNameSortOder, ColumnSortOrder.Ascending); 38 | bool lineVisible = ViewBagHelper.ValueOrDefault(ViewBag.LineVisible, true); 39 | ColumnSortOrder lineSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.LineSortOder, ColumnSortOrder.Ascending); 40 | bool ruleVisible = ViewBagHelper.ValueOrDefault(ViewBag.RuleVisible, true); 41 | ColumnSortOrder ruleSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.RuleSortOder, ColumnSortOrder.Ascending); 42 | bool ruleUrlVisible = ViewBagHelper.ValueOrDefault(ViewBag.RuleUrlVisible, false); 43 | ColumnSortOrder ruleUrlSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.RuleUrlSortOder, ColumnSortOrder.Ascending); 44 | bool messageVisible = ViewBagHelper.ValueOrDefault(ViewBag.MessageVisible, true); 45 | ColumnSortOrder messageSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.MessageSortOder, ColumnSortOrder.Ascending); 46 | var groupedColumns = ViewBagHelper.ValueOrDefault(ViewBag.GroupedColumns, new List { ReportColumn.ProviderName }); 47 | var sortedColumns = ViewBagHelper.ValueOrDefault(ViewBag.SortedColumns, new List { ReportColumn.PriorityName, ReportColumn.ProjectName, ReportColumn.FileDirectory, ReportColumn.FileName, ReportColumn.Line }); 48 | FileLinkSettings fileLinkSettings = ViewBagHelper.ValueOrDefault(ViewBag.FileLinkSettings, new FileLinkSettings()); 49 | IdeIntegrationSettings ideIntegrationSettings = ViewBagHelper.ValueOrDefault(ViewBag.IdeIntegrationSettings, null); 50 | List additionalColumns = ViewBagHelper.ValueOrDefault(ViewBag.AdditionalColumns, new List()); 51 | string jQueryLocation = ViewBagHelper.ValueOrDefault(ViewBag.JQueryLocation, "https://ajax.aspnetcdn.com/ajax/jquery/"); 52 | string jQueryVersion = ViewBagHelper.ValueOrDefault(ViewBag.JQueryVersion, "3.4.1"); 53 | string JSZipLocation = ViewBagHelper.ValueOrDefault(ViewBag.JSZipLocation, "https://cdnjs.cloudflare.com/ajax/libs/jszip/3.2.2/"); 54 | string devExtremeLocation = ViewBagHelper.ValueOrDefault(ViewBag.DevExtremeLocation, "https://cdn3.devexpress.com/jslib/"); 55 | string devExtremeVersion = ViewBagHelper.ValueOrDefault(ViewBag.DevExtremeVersion, "19.2.5"); 56 | } 57 | 58 | @{ 59 | // Prepare issues. 60 | var issues = 61 | from issue in Model 62 | select 63 | issue.GetExpandoObject( 64 | addProviderType: providerTypeVisible, 65 | addProviderName: providerNameVisible, 66 | addPriority: priorityVisible || priorityNameVisible, 67 | addPriorityName: priorityNameVisible, 68 | addProjectPath: projectPathVisible, 69 | addProjectName: projectNameVisible, 70 | addFilePath: filePathVisible || ideIntegrationSettings != null, 71 | addFileDirectory: fileDirectoryVisible, 72 | addFileName: fileNameVisible, 73 | addLine: lineVisible || ideIntegrationSettings != null, 74 | addRule: ruleVisible, 75 | addRuleUrl: ruleVisible || ruleUrlVisible, 76 | addMessageHtml: messageVisible, 77 | fileLinkSettings: fileLinkSettings, 78 | additionalValues: additionalColumns.ToDictionary(x => x.Id, x => x.ValueRetriever)); 79 | 80 | if (!jQueryLocation.EndsWith("/")) 81 | { 82 | jQueryLocation += "/"; 83 | } 84 | 85 | if (!devExtremeLocation.EndsWith("/")) 86 | { 87 | devExtremeLocation += "/"; 88 | } 89 | } 90 | 91 | 92 | 93 | 94 | @title 95 | 96 | @* DevExtreme dependencies *@ 97 | 98 | @if (enableExporting) 99 | { 100 | 101 | } 102 | @* DevExtreme themes *@ 103 | 104 | 105 | @* DevExtreme library *@ 106 | 107 | @* Additional JavaScript for IDE integration *@ 108 | @if (ideIntegrationSettings != null && !string.IsNullOrWhiteSpace(ideIntegrationSettings.JavaScript)) 109 | { 110 | 113 | } 114 | 115 | 131 | 132 | 133 | @if (showHeader) 134 | { 135 |

@title

136 | } 137 | 138 |
139 |
140 |
141 | 142 | 145 | 146 | 548 | 549 | -------------------------------------------------------------------------------- /sample/Gazorator.Console/Views/Sample.cshtml: -------------------------------------------------------------------------------- 1 | @inherits Gazorator.Scripting.RazorScriptHost 2 | @{ var helloWorld = "Hello World!"; } 3 | @{ var year = DateTime.Now.Year; } 4 | 5 | 6 | 7 | 8 | Add Numbers 9 | 10 | 23 | 24 | 25 |
26 |

@helloWorld

27 |

It's year @year!

28 |

@Model.MyProperty

29 | @foreach (var x in Model.Values) 30 | { 31 |

@x

32 | } 33 | @Html.Raw("

Output some html!

") 34 |
35 | 36 | -------------------------------------------------------------------------------- /sample/Gazorator.Console/Views/Xamarin.cshtml: -------------------------------------------------------------------------------- 1 | @inherits Gazorator.Scripting.RazorScriptHost 2 | @using System.Linq 3 | @using System.Xml.Linq 4 | 5 | 6 | 7 | MonoAndroid90 8 | true 9 | @if (!string.IsNullOrEmpty(Model.AssemblyName)) 10 | { 11 | @(Model.AssemblyName) 12 | } 13 | else 14 | { 15 | @(Model.NuGetPackageId) 16 | } 17 | Resources 18 | Assets 19 | False 20 | True 21 | Resources\Resource.designer.cs 22 | 23 | 24 | 25 | @(Model.NuGetPackageId) 26 | Xamarin Android Support Library - @(Model.Name) 27 | Xamarin.Android bindings for Android Support Library - @(Model.Name) 28 | Xamarin.Android bindings for Android Support Library - @(Model.Name) 29 | Xamarin Android Xamarin.Android Support 30 | Xamarin Inc. 31 | Xamarin Inc. 32 | © Microsoft Corporation. All rights reserved. 33 | https://go.microsoft.com/fwlink/?linkid=865352 34 | https://go.microsoft.com/fwlink/?linkid=865381 35 | https://raw.githubusercontent.com/xamarin/AndroidSupportComponents/master/icons/@(Model.Name)_128x128.png 36 | @(Model.NuGetVersion) 37 | true 38 | 39 | 40 | 41 | class-parse 42 | XAJavaInterop1 43 | 44 | 45 | 46 | @foreach (var art in @Model.MavenArtifacts) 47 | { 48 | 49 | } 50 | 51 | 52 | @* 53 | @foreach (var art in @Model.MavenArtifacts) { 54 | 55 | } 56 | *@ 57 | 58 | 59 | 60 | @foreach (var art in @Model.MavenArtifacts) 61 | { 62 | <_AndroidDocumentationPath Include="..\..\externals\@(art.MavenGroupId)\@(art.MavenArtifactId)-paramnames.txt" Condition="Exists('..\..\..\externals\@(art.MavenGroupId)\@(art.MavenArtifactId)-paramnames.txt')" /> 63 | } 64 | 65 | 66 | 67 | 68 | 69 | 70 | @if (@Model.MavenArtifacts.Count > 0) 71 | { 72 | 73 | @foreach (var art in @Model.MavenArtifacts) 74 | { 75 | if (art.ProguardFile != null) 76 | { 77 | 78 | } 79 | } 80 | 81 | } 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | Additions/%(RecursiveDir)/%(Filename)%(Extension) 92 | 93 | 94 | 95 | 96 | 97 | Transforms/Metadata.common.xml 98 | 99 | 100 | Transforms/%(RecursiveDir)/%(Filename)%(Extension) 101 | 102 | 103 | 104 | 105 | @foreach (var art in @Model.MavenArtifacts) 106 | { 107 | if (art.MavenArtifactPackaging == "aar") 108 | { 109 | 110 | } 111 | } 112 | 113 | 114 | 115 | @if (@Model.MavenArtifacts.Count > 0) 116 | { 117 | 118 | @foreach (var art in @Model.MavenArtifacts) 119 | { 120 | if (art.MavenArtifactPackaging == "aar") 121 | { 122 | 123 | 124 | 126 | } 127 | else 128 | { 129 | 130 | } 131 | } 132 | 133 | } 134 | 135 | 136 | 137 | @foreach (var dep in @Model.NuGetDependencies) 138 | { 139 | if (dep.IsProjectReference) 140 | { 141 | 142 | } 143 | } 144 | 145 | @if (@Model.NuGetPackageId == "Xamarin.Android.Support.Transition") 146 | { 147 | 148 | } 149 | 150 | 151 | 152 | 153 | 154 | @foreach (var dep in @Model.NuGetDependencies) 155 | { 156 | if (!dep.IsProjectReference) 157 | { 158 | 159 | } 160 | } 161 | 162 | 163 | @if (@Model.NuGetPackageId == "Xamarin.Android.Support.Annotations") 164 | { 165 | 166 | 167 | 168 | } 169 | 170 | @if (@Model.NuGetPackageId == "Xamarin.Android.Support.Vector.Drawable") 171 | { 172 | 173 | 174 | 175 | } 176 | 177 | @if (@Model.NuGetPackageId == "Xamarin.Android.Support.v4") 178 | { 179 | 180 | 181 | 182 | $(MSBuildProjectDirectory)/../../tools/microsoft.dotnet.buildtools.genapi.1.0.0-beta-00081/Microsoft.DotNet.BuildTools.GenAPI/tools/GenAPI.exe 183 | 184 | 185 | 186 | @foreach (var dep in @Model.NuGetDependencies) 187 | { 188 | if (dep.IsProjectReference) 189 | { 190 | 191 | "$(IntermediateOutputPath)/@(dep.NuGetPackageId).dll" 192 | ./Additions/@(dep.NuGetPackageId).cs 193 | 194 | } 195 | } 196 | 197 | 198 | 199 | 203 | 204 | 205 | 206 | } 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /src/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | true 10 | true 11 | $([System.IO.Path]::Combine('$(IntermediateOutputPath)','$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension)')) 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 24 | 25 | <_LocalTopLevelSourceRoot Include="@(SourceRoot)" Condition="'%(SourceRoot.NestedRoot)' == ''"/> 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Gazorator.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | ExplicitlyExcluded -------------------------------------------------------------------------------- /src/Gazorator/Extensions/TypeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Gazorator.Extensions 4 | { 5 | internal static class TypeExtensions 6 | { 7 | public static bool IsNullable(this Type type) 8 | { 9 | return !type.IsValueType || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Gazorator/Gazorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Dynamic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Threading.Tasks; 8 | using Gazorator.Razor; 9 | using Gazorator.Scripting; 10 | 11 | namespace Gazorator 12 | { 13 | public abstract class Gazorator 14 | { 15 | protected TextWriter Output { get; } 16 | protected IEnumerable References { get; } = new List(); 17 | protected Action ConfigureViewBag { get; } 18 | protected IEnumerable> ViewBag { get; } 19 | 20 | protected Gazorator(TextWriter output = null, Action configureViewBag = null, params Assembly[] references) 21 | { 22 | Output = output ?? TextWriter.Null; 23 | ConfigureViewBag = configureViewBag; 24 | References = new List(references); 25 | } 26 | 27 | protected Gazorator(TextWriter output = null, IEnumerable> viewBag = null, params Assembly[] references) 28 | { 29 | Output = output ?? TextWriter.Null; 30 | ViewBag = viewBag; 31 | References = new List(references); 32 | } 33 | 34 | public static Gazorator Default => new DefaultGazorator(TextWriter.Null, configureViewBag: null); 35 | 36 | public Gazorator WithModel(TModel model) 37 | { 38 | return new Gazorator(Output, model, ConfigureViewBag, References.ToArray()); 39 | } 40 | 41 | public Gazorator WithOutput(TextWriter output) 42 | { 43 | return new DefaultGazorator(output, ConfigureViewBag, References.ToArray()); 44 | } 45 | 46 | public Gazorator WithReferences(params Assembly[] references) 47 | { 48 | return new DefaultGazorator(Output, ConfigureViewBag, references); 49 | } 50 | 51 | public Gazorator WithViewBag(Action configureViewBag) 52 | { 53 | return new DefaultGazorator(Output, configureViewBag, References.ToArray()); 54 | } 55 | 56 | public Gazorator WithViewBag(IEnumerable> viewBag) 57 | { 58 | return new DefaultGazorator(Output, viewBag, References.ToArray()); 59 | } 60 | 61 | public virtual Task ProcessAsync(string filePath) 62 | { 63 | var razorGenerator = new CSharpScriptRazorGenerator(Path.GetDirectoryName(filePath)); 64 | var csharpScript = razorGenerator.Generate(filePath); 65 | 66 | var viewBag = new DynamicViewBag(ViewBag); 67 | ConfigureViewBag?.Invoke(viewBag); 68 | 69 | var razorContentGenerator = new RazorContentGenerator(Output, References, viewBag); 70 | return razorContentGenerator.Generate(csharpScript); 71 | } 72 | 73 | public virtual async Task ProcessTemplateAsync(string template) 74 | { 75 | var tempFile = Path.GetTempFileName(); 76 | try 77 | { 78 | using (var stream = File.OpenWrite(tempFile)) 79 | using (var writer = new StreamWriter(stream)) 80 | { 81 | await writer.WriteAsync(template); 82 | } 83 | 84 | await ProcessAsync(tempFile); 85 | } 86 | finally 87 | { 88 | if (File.Exists(tempFile)) 89 | { 90 | File.Delete(tempFile); 91 | } 92 | } 93 | } 94 | 95 | private sealed class DefaultGazorator : Gazorator 96 | { 97 | public DefaultGazorator(TextWriter output = null, Action configureViewBag = null, params Assembly[] references) : base(output, configureViewBag, references) 98 | { 99 | } 100 | 101 | public DefaultGazorator(TextWriter output = null, IEnumerable> viewbag = null, params Assembly[] references) : base(output, viewbag, references) 102 | { 103 | } 104 | } 105 | } 106 | 107 | public sealed class Gazorator : Gazorator 108 | { 109 | private readonly TModel _model; 110 | 111 | internal Gazorator(TextWriter output, TModel model, Action configureViewBag, params Assembly[] references) 112 | : base(output, configureViewBag, references) 113 | { 114 | _model = model; 115 | } 116 | 117 | internal Gazorator(TextWriter output, TModel model, IEnumerable> viewBag, params Assembly[] references) 118 | : base(output, viewBag, references) 119 | { 120 | _model = model; 121 | } 122 | 123 | public new Gazorator WithOutput(TextWriter output) 124 | { 125 | return new Gazorator(output, _model, ConfigureViewBag, References.ToArray()); 126 | } 127 | 128 | public new Gazorator WithReferences(params Assembly[] references) 129 | { 130 | return new Gazorator(Output, _model, ConfigureViewBag, references); 131 | } 132 | 133 | public new Gazorator WithViewBag(Action configureViewBag) 134 | { 135 | return new Gazorator(Output, _model, configureViewBag, References.ToArray()); 136 | } 137 | 138 | public new Gazorator WithViewBag(IEnumerable> viewBag) 139 | { 140 | return new Gazorator(Output, _model, viewBag, References.ToArray()); 141 | } 142 | 143 | public override Task ProcessAsync(string filePath) 144 | { 145 | var razorGenerator = new CSharpScriptRazorGenerator(Path.GetDirectoryName(filePath)); 146 | var csharpScript = razorGenerator.Generate(filePath); 147 | 148 | var viewBag = new DynamicViewBag(ViewBag); 149 | ConfigureViewBag?.Invoke(viewBag); 150 | 151 | var razorContentGenerator = new RazorContentGenerator(_model, Output, References, viewBag); 152 | return razorContentGenerator.Generate(csharpScript); 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/Gazorator/Gazorator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 0.1.0 6 | Gazorator 7 | Gazorator 8 | mholo65 9 | Enables Razor outside ASP.NET 10 | 2018 Martin Björkström 11 | https://github.com/mholo65/gazorator/blob/develop/LICENSE 12 | https://github.com/mholo65/gazorator 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | all 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/Gazorator/Razor/CSharpScriptDocumentClassifierPass.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Microsoft.AspNetCore.Razor.Language; 3 | using Microsoft.AspNetCore.Razor.Language.Intermediate; 4 | 5 | namespace Gazorator.Razor 6 | { 7 | internal sealed class CSharpScriptDocumentClassifierPass : DocumentClassifierPassBase 8 | { 9 | public override int Order => DefaultFeatureOrder; 10 | 11 | protected override string DocumentKind => "default"; 12 | 13 | protected override bool IsMatch(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) 14 | { 15 | return true; 16 | } 17 | 18 | protected override void OnDocumentStructureCreated( 19 | RazorCodeDocument codeDocument, 20 | NamespaceDeclarationIntermediateNode @namespace, 21 | ClassDeclarationIntermediateNode @class, 22 | MethodDeclarationIntermediateNode method) 23 | { 24 | var documentNode = codeDocument.GetDocumentIntermediateNode(); 25 | 26 | foreach (var @using in @namespace.Children.OfType()) 27 | { 28 | documentNode.Children.Add(@using); 29 | } 30 | foreach (var child in method.Children) 31 | { 32 | documentNode.Children.Add(child); 33 | } 34 | 35 | documentNode.Children.Remove(@namespace); 36 | 37 | return; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Gazorator/Razor/CSharpScriptRazorGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.AspNetCore.Razor.Language; 4 | using Microsoft.AspNetCore.Razor.Language.Extensions; 5 | 6 | namespace Gazorator.Razor 7 | { 8 | internal sealed class CSharpScriptRazorGenerator 9 | { 10 | private readonly RazorProjectEngine _projectEngine; 11 | 12 | public CSharpScriptRazorGenerator(string directoryRoot) 13 | { 14 | var fileSystem = RazorProjectFileSystem.Create(directoryRoot); 15 | var projectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, fileSystem, builder => 16 | { 17 | // Register directives. 18 | SectionDirective.Register(builder); 19 | 20 | // We replace the default document classifier, because we can't have namespace declaration ins script. 21 | var defaultDocumentClassifier = builder.Features 22 | .OfType() 23 | .FirstOrDefault(x => x.Order == 1000); 24 | builder.Features.Remove(defaultDocumentClassifier); 25 | builder.Features.Add(new CSharpScriptDocumentClassifierPass()); 26 | }); 27 | 28 | _projectEngine = projectEngine; 29 | } 30 | 31 | public string Generate(string filePath) 32 | { 33 | var razorItem = _projectEngine.FileSystem.GetItem(filePath); 34 | var codeDocument = _projectEngine.Process(razorItem); 35 | var csharpDocument = codeDocument.GetCSharpDocument(); 36 | 37 | if (csharpDocument.Diagnostics.Any()) 38 | { 39 | var diagnostics = string.Join(Environment.NewLine, csharpDocument.Diagnostics); 40 | throw new InvalidOperationException($"One or more parse errors encountered. This will not prevent the generator from continuing: {Environment.NewLine}{diagnostics}."); 41 | } 42 | 43 | return csharpDocument.GeneratedCode; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Gazorator/Scripting/DynamicViewBag.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Dynamic; 4 | using System.Linq; 5 | 6 | namespace Gazorator.Scripting 7 | { 8 | public class DynamicViewBag : DynamicObject 9 | { 10 | private readonly IDictionary _properties; 11 | 12 | public DynamicViewBag(IEnumerable> properties = null) 13 | { 14 | _properties = properties?.ToDictionary(x => x.Key, x => x.Value) 15 | ?? new Dictionary(); 16 | } 17 | 18 | public override bool TryGetMember(GetMemberBinder binder, out object result) 19 | { 20 | if (!_properties.TryGetValue(binder.Name, out result)) 21 | { 22 | result = GetDefault(binder.ReturnType); 23 | } 24 | 25 | return true; 26 | } 27 | 28 | public override bool TrySetMember(SetMemberBinder binder, object value) 29 | { 30 | _properties[binder.Name] = value; 31 | return true; 32 | } 33 | 34 | private static object GetDefault(Type type) 35 | => type.IsValueType ? Activator.CreateInstance(type) : null; 36 | } 37 | } -------------------------------------------------------------------------------- /src/Gazorator/Scripting/HtmlRenderer.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace Gazorator.Scripting 4 | { 5 | public class HtmlRenderer 6 | { 7 | public IRazorLiteral Raw(string content) 8 | { 9 | return new RazorLiteral(content); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/Gazorator/Scripting/IRazorLiteral.cs: -------------------------------------------------------------------------------- 1 | namespace Gazorator.Scripting 2 | { 3 | public interface IRazorLiteral 4 | { 5 | string Render(); 6 | } 7 | } -------------------------------------------------------------------------------- /src/Gazorator/Scripting/RazorContentGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Dynamic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Threading.Tasks; 8 | using Gazorator.Extensions; 9 | using Microsoft.CodeAnalysis; 10 | using Microsoft.CodeAnalysis.CSharp.Scripting; 11 | using Microsoft.CodeAnalysis.Scripting; 12 | 13 | namespace Gazorator.Scripting 14 | { 15 | internal abstract class RazorContentGeneratorBase 16 | { 17 | private IReadOnlyCollection _references; 18 | protected readonly DynamicViewBag _viewBag; 19 | 20 | protected RazorContentGeneratorBase(IEnumerable references, DynamicViewBag viewBag) 21 | { 22 | _references = new List(references); 23 | _viewBag = viewBag; 24 | } 25 | 26 | public Task Generate(string csharpScript) 27 | { 28 | var options = ScriptOptions.Default 29 | .WithReferences(GetMetadataReferences()) 30 | .WithImports("System") 31 | .WithMetadataResolver(ScriptMetadataResolver.Default); 32 | 33 | var roslynScript = CSharpScript.Create(csharpScript, options, GetGlobalsType()); 34 | 35 | var compilation = roslynScript.GetCompilation(); 36 | var diagnostics = compilation.GetDiagnostics().Where(d => d.Severity == DiagnosticSeverity.Error); 37 | 38 | if (diagnostics.Any()) 39 | { 40 | var errorMessages = string.Join(Environment.NewLine, diagnostics.Select(x => x.ToString())); 41 | throw new InvalidOperationException($"Error(s) occurred when compiling build script:{Environment.NewLine}{errorMessages}"); 42 | } 43 | 44 | return roslynScript.RunAsync(GetGlobalsObject()); 45 | } 46 | 47 | protected virtual IEnumerable GetMetadataReferences() 48 | { 49 | yield return MetadataReference.CreateFromFile(typeof(Action).Assembly.Location); // mscorlib or System.Private.Core 50 | yield return MetadataReference.CreateFromFile(typeof(IQueryable).Assembly.Location); // System.Core or System.Linq.Expressions 51 | yield return MetadataReference.CreateFromFile(typeof(Uri).Assembly.Location); // System 52 | yield return MetadataReference.CreateFromFile(typeof(System.Xml.XmlReader).Assembly.Location); // System.Xml 53 | yield return MetadataReference.CreateFromFile(typeof(System.Xml.Linq.XDocument).Assembly.Location); // System.Xml.Linq 54 | yield return MetadataReference.CreateFromFile(typeof(System.Data.DataTable).Assembly.Location); // System.Data 55 | yield return MetadataReference.CreateFromFile(typeof(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo).Assembly.Location); // dynamic 56 | 57 | var entryAssembly = Assembly.GetEntryAssembly(); 58 | if (entryAssembly != null) 59 | { 60 | if (entryAssembly.Location != null) 61 | { 62 | yield return MetadataReference.CreateFromFile(entryAssembly.Location); 63 | } 64 | 65 | foreach (var reference in entryAssembly.GetReferencedAssemblies()) 66 | { 67 | var referencedAssembly = Assembly.Load(reference); 68 | if (referencedAssembly.Location != null) 69 | { 70 | yield return MetadataReference.CreateFromFile(referencedAssembly.Location); 71 | } 72 | } 73 | } 74 | 75 | foreach (var reference in _references.Where(r => r.Location != null)) 76 | { 77 | yield return MetadataReference.CreateFromFile(reference.Location); 78 | } 79 | } 80 | 81 | protected abstract Type GetGlobalsType(); 82 | 83 | protected abstract RazorScriptHostBase GetGlobalsObject(); 84 | } 85 | 86 | internal sealed class RazorContentGenerator : RazorContentGeneratorBase 87 | { 88 | private readonly TextWriter _textWriter; 89 | 90 | public RazorContentGenerator(TextWriter textWriter, IEnumerable references, DynamicViewBag viewBag) : base(references, viewBag) 91 | { 92 | _textWriter = textWriter ?? throw new ArgumentNullException(nameof(textWriter)); 93 | } 94 | 95 | protected override RazorScriptHostBase GetGlobalsObject() 96 | { 97 | return new RazorScriptHost(_textWriter, _viewBag); 98 | } 99 | 100 | protected override Type GetGlobalsType() 101 | { 102 | return typeof(RazorScriptHost); 103 | } 104 | } 105 | 106 | internal sealed class RazorContentGenerator : RazorContentGeneratorBase 107 | { 108 | private readonly TextWriter _textWriter; 109 | private readonly TModel _model; 110 | private readonly bool _isDynamicAssembly; 111 | 112 | public RazorContentGenerator(TModel model, TextWriter textWriter, IEnumerable references, DynamicViewBag viewBag) : base(references, viewBag) 113 | { 114 | _textWriter = textWriter ?? throw new ArgumentNullException(nameof(textWriter)); 115 | if (typeof(TModel).IsNullable() && model == null) 116 | { 117 | throw new ArgumentNullException(nameof(model)); 118 | } 119 | if (typeof(TModel).IsNotPublic) 120 | { 121 | throw new ArgumentException($"{typeof(TModel).GetType().FullName} must be public."); 122 | } 123 | _model = model; 124 | _isDynamicAssembly = typeof(TModel).Assembly.IsDynamic || 125 | string.IsNullOrEmpty(typeof(TModel).Assembly.Location); 126 | } 127 | 128 | protected override IEnumerable GetMetadataReferences() 129 | { 130 | return _isDynamicAssembly ? 131 | base.GetMetadataReferences() : 132 | base.GetMetadataReferences() 133 | .Append(MetadataReference.CreateFromFile(typeof(TModel).Assembly.Location)); 134 | } 135 | 136 | protected override RazorScriptHostBase GetGlobalsObject() 137 | { 138 | return _isDynamicAssembly ? 139 | new RazorScriptHostDynamic(ToExpandoObject(_model), _textWriter, _viewBag): 140 | new RazorScriptHost(_model, _textWriter, _viewBag) as RazorScriptHostBase; 141 | } 142 | 143 | protected override Type GetGlobalsType() 144 | { 145 | return _isDynamicAssembly ? 146 | typeof(RazorScriptHostDynamic) : 147 | typeof(RazorScriptHost); 148 | } 149 | 150 | private static ExpandoObject ToExpandoObject(TModel model) 151 | { 152 | IDictionary expando = new ExpandoObject(); 153 | 154 | foreach(var property in typeof(TModel).GetProperties()) 155 | { 156 | expando.Add(property.Name, property.GetValue(model)); 157 | } 158 | 159 | return (ExpandoObject)expando; 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/Gazorator/Scripting/RazorLiteral.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Gazorator.Scripting 4 | { 5 | internal sealed class RazorLiteral : IRazorLiteral 6 | { 7 | private string Content { get; } 8 | 9 | string IRazorLiteral.Render() 10 | { 11 | return Content; 12 | } 13 | 14 | internal RazorLiteral(string content) 15 | { 16 | Content = content ?? throw new ArgumentNullException(nameof(content)); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/Gazorator/Scripting/RazorScriptHost.cs: -------------------------------------------------------------------------------- 1 | using Gazorator.Extensions; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Dynamic; 5 | using System.Globalization; 6 | using System.IO; 7 | using System.Text.Encodings.Web; 8 | 9 | namespace Gazorator.Scripting 10 | { 11 | // See https://github.com/aspnet/Common/blob/master/shared/Microsoft.Extensions.RazorViews.Sources/BaseView.cs 12 | public abstract class RazorScriptHostBase 13 | { 14 | public dynamic ViewBag { get; } 15 | 16 | public HtmlRenderer Html { get; } 17 | 18 | protected TextWriter Output { get; } 19 | 20 | protected virtual HtmlEncoder HtmlEncoder { get; } = HtmlEncoder.Default; 21 | 22 | public RazorScriptHostBase(TextWriter output, DynamicViewBag viewBag) 23 | { 24 | Output = output ?? throw new ArgumentNullException(nameof(output)); 25 | Html = new HtmlRenderer(); 26 | ViewBag = viewBag; 27 | } 28 | 29 | public virtual void WriteLiteral(object value) 30 | { 31 | WriteLiteral(Convert.ToString(value, CultureInfo.InvariantCulture)); 32 | } 33 | 34 | public virtual void WriteLiteral(string value) 35 | { 36 | if (!string.IsNullOrEmpty(value)) 37 | { 38 | Output.Write(value); 39 | } 40 | } 41 | 42 | public virtual void Write(string value) 43 | { 44 | if (value == null) 45 | { 46 | return; 47 | } 48 | 49 | WriteLiteral(HtmlEncoder.Encode(value)); 50 | } 51 | 52 | public virtual void Write(object value) 53 | { 54 | if (value is IRazorLiteral element) 55 | { 56 | WriteLiteral(element.Render()); 57 | return; 58 | } 59 | 60 | Write(Convert.ToString(value, CultureInfo.InvariantCulture)); 61 | } 62 | 63 | private string AttributeEnding { get; set; } 64 | private List AttributeValues { get; set; } 65 | 66 | public virtual void BeginWriteAttribute(string name, string prefix, int prefixOffset, string suffix, int suffixOffset, int attributeValuesCount) 67 | { 68 | Output.Write(prefix); 69 | AttributeEnding = suffix; 70 | } 71 | 72 | public void WriteAttributeValue(string prefix, int prefixOffset, object value, int valueOffset, int valueLength, bool isLiteral) 73 | { 74 | if (AttributeValues == null) 75 | { 76 | AttributeValues = new List(); 77 | } 78 | 79 | AttributeValues.Add(value.ToString()); 80 | } 81 | 82 | public virtual void EndWriteAttribute() 83 | { 84 | var attributes = string.Join(" ", AttributeValues); 85 | Output.Write(attributes); 86 | AttributeValues = null; 87 | 88 | Output.Write(AttributeEnding); 89 | AttributeEnding = null; 90 | } 91 | } 92 | 93 | public sealed class RazorScriptHost : RazorScriptHostBase 94 | { 95 | public RazorScriptHost(TextWriter output, DynamicViewBag viewBag) : base(output, viewBag) 96 | { 97 | } 98 | } 99 | 100 | public sealed class RazorScriptHost : RazorScriptHostBase 101 | { 102 | public RazorScriptHost(TModel model, TextWriter output, DynamicViewBag viewBag) : base(output, viewBag) 103 | { 104 | if (typeof(TModel).IsNullable() && model == null) 105 | { 106 | throw new ArgumentNullException(nameof(model)); 107 | } 108 | Model = model; 109 | } 110 | 111 | public TModel Model { get; } 112 | } 113 | 114 | public sealed class RazorScriptHostDynamic : RazorScriptHostBase 115 | { 116 | private readonly ExpandoObject _model; 117 | 118 | public RazorScriptHostDynamic(ExpandoObject model, TextWriter output, DynamicViewBag viewBag) : base(output, viewBag) 119 | { 120 | _model = model ?? throw new ArgumentNullException(nameof(model)); 121 | } 122 | 123 | public dynamic Model => _model; 124 | } 125 | } 126 | --------------------------------------------------------------------------------