Full Code of microsoft/RulesEngine for AI

main 89f9bcd1f94f cached
123 files
359.4 KB
79.3k tokens
353 symbols
1 requests
Download .txt
Showing preview only (391K chars total). Download the full file or copy to clipboard to get everything.
Repository: microsoft/RulesEngine
Branch: main
Commit: 89f9bcd1f94f
Files: 123
Total size: 359.4 KB

Directory structure:
gitextract_4_4zshmg/

├── .config/
│   └── dotnet-tools.json
├── .devcontainer/
│   └── devcontainer.json
├── .editorconfig
├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       ├── codeql-analysis.yml
│       └── dotnetcore-build.yml
├── .gitignore
├── .vscode/
│   ├── launch.json
│   ├── settings.json
│   └── tasks.json
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── RulesEngine.sln
├── SECURITY.md
├── benchmark/
│   └── RulesEngineBenchmark/
│       ├── Program.cs
│       ├── RulesEngineBenchmark.csproj
│       └── Workflows/
│           ├── Discount.json
│           └── NestedInputDemo.json
├── demo/
│   ├── DemoApp/
│   │   ├── BasicDemo.cs
│   │   ├── DemoApp.csproj
│   │   ├── EFDemo.cs
│   │   ├── JSONDemo.cs
│   │   ├── NestedInputDemo.cs
│   │   ├── Program.cs
│   │   └── Workflows/
│   │       ├── Discount.json
│   │       └── NestedInputDemo.json
│   └── DemoApp.EFDataExample/
│       ├── DemoApp.EFDataExample.csproj
│       ├── RulesEngineContext.cs
│       └── RulesEngineDemoContext.cs
├── deployment/
│   └── build-signed.ps1
├── docs/
│   ├── Getting-Started.md
│   ├── Home.md
│   ├── Introduction.md
│   ├── Use-Case.md
│   ├── _Sidebar.md
│   ├── _config.yml
│   └── index.md
├── global.json
├── schema/
│   ├── workflow-list-schema.json
│   └── workflow-schema.json
├── scripts/
│   ├── check-coverage.ps1
│   └── generate-coverage-report.ps1
├── signing/
│   └── RulesEngine-publicKey.snk
├── src/
│   └── RulesEngine/
│       ├── Actions/
│       │   ├── ActionBase.cs
│       │   ├── ActionContext.cs
│       │   ├── ActionFactory.cs
│       │   ├── EvaluateRuleAction.cs
│       │   └── ExpressionOutputAction.cs
│       ├── CustomTypeProvider.cs
│       ├── Exceptions/
│       │   ├── ExpressionParserException.cs
│       │   ├── RuleException.cs
│       │   ├── RuleValidationException.cs
│       │   └── ScopedParamException.cs
│       ├── ExpressionBuilders/
│       │   ├── LambdaExpressionBuilder.cs
│       │   ├── RuleExpressionBuilderBase.cs
│       │   └── RuleExpressionParser.cs
│       ├── Extensions/
│       │   ├── EnumerableExtensions.cs
│       │   └── ListofRuleResultTreeExtension.cs
│       ├── HelperFunctions/
│       │   ├── Constants.cs
│       │   ├── ExpressionUtils.cs
│       │   ├── Helpers.cs
│       │   ├── MemCache.cs
│       │   └── Utils.cs
│       ├── Interfaces/
│       │   └── IRulesEngine.cs
│       ├── Models/
│       │   ├── ActionInfo.cs
│       │   ├── ActionResult.cs
│       │   ├── ActionRuleResult.cs
│       │   ├── ReSettings.cs
│       │   ├── Rule.cs
│       │   ├── RuleActions.cs
│       │   ├── RuleDelegate.cs
│       │   ├── RuleErrorType.cs
│       │   ├── RuleExpressionParameter.cs
│       │   ├── RuleExpressionType.cs
│       │   ├── RuleParameter.cs
│       │   ├── RuleResultTree.cs
│       │   ├── ScopedParam.cs
│       │   └── Workflow.cs
│       ├── Properties/
│       │   └── AssemblyInfo.cs
│       ├── RuleCompiler.cs
│       ├── RuleExpressionBuilderFactory.cs
│       ├── RulesCache.cs
│       ├── RulesEngine.cs
│       ├── RulesEngine.csproj
│       └── Validators/
│           ├── RuleValidator.cs
│           └── WorkflowRulesValidator.cs
└── test/
    └── RulesEngine.UnitTest/
        ├── ActionTests/
        │   ├── ActionContextTests.cs
        │   ├── CustomActionTest.cs
        │   ├── MockClass/
        │   │   └── ReturnContextAction.cs
        │   └── RulesEngineWithActionsTests.cs
        ├── BusinessRuleEngineTest.cs
        ├── CaseSensitiveTests.cs
        ├── CustomTypeProviderTests.cs
        ├── EmptyRulesTest.cs
        ├── ExpressionUtilsTest.cs
        ├── LambdaExpressionBuilderTest.cs
        ├── ListofRuleResultTreeExtensionTest.cs
        ├── NestedRulesTest.cs
        ├── ParameterNameChangeTest.cs
        ├── RuleCompilerTest.cs
        ├── RuleExpressionBuilderFactoryTest.cs
        ├── RuleExpressionParserTests/
        │   └── RuleExpressionParserTests.cs
        ├── RuleParameterTests.cs
        ├── RuleTestClass.cs
        ├── RuleValidationTest.cs
        ├── RulesEnabledTests.cs
        ├── RulesEngine.UnitTest.csproj
        ├── ScopedParamsTest.cs
        ├── TestData/
        │   ├── rules1.json
        │   ├── rules10.json
        │   ├── rules11.json
        │   ├── rules2.json
        │   ├── rules3.json
        │   ├── rules4.json
        │   ├── rules5.json
        │   ├── rules6.json
        │   ├── rules7.json
        │   ├── rules8.json
        │   └── rules9.json
        ├── TypedClassTests.cs
        └── UtilsTests.cs

================================================
FILE CONTENTS
================================================

================================================
FILE: .config/dotnet-tools.json
================================================
{
  "version": 1,
  "isRoot": true,
  "tools": {
    "dotnet-reportgenerator-globaltool": {
      "version": "5.1.26",
      "commands": [
        "reportgenerator"
      ]
    }
  }
}

================================================
FILE: .devcontainer/devcontainer.json
================================================
{
	"name": "RulesEngine Codespace",
	"image": "mcr.microsoft.com/vscode/devcontainers/dotnet:0-6.0",
	"settings": {
		"terminal.integrated.defaultProfile.linux": "bash"
	},
	"extensions": [
		"eamodio.gitlens",
		"ms-dotnettools.csharp",
		"VisualStudioExptTeam.vscodeintellicode",
		"ms-vscode.powershell",
		"cschleiden.vscode-github-actions",
		"redhat.vscode-yaml",
		"bierner.markdown-preview-github-styles",
		"coenraads.bracket-pair-colorizer",
		"vscode-icons-team.vscode-icons",
		"editorconfig.editorconfig",
		"aliasadidev.nugetpackagemanagergui",
		"formulahendry.dotnet-test-explorer"
	],
	"postCreateCommand": "dotnet restore RulesEngine.sln && dotnet build RulesEngine.sln --configuration Release --no-restore && dotnet test RulesEngine.sln --configuration Release --no-build --verbosity minimal",
	"features": {
		"powershell": "7.1"
	},
}
// Built with ❤ by [Pipeline Foundation](https://pipeline.foundation)


================================================
FILE: .editorconfig
================================================
# Rules in this file were initially inferred by Visual Studio IntelliCode from the C:\Users\purunjaybhal\source\repos\RulesEngine codebase based on best match to current usage at 22-12-2020
# You can modify the rules from these initially generated values to suit your own policies
# You can learn more about editorconfig here: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
[*.cs]


#Core editorconfig formatting - indentation

#use soft tabs (spaces) for indentation
indent_style = space

#Formatting - indentation options

#indent switch case contents.
csharp_indent_case_contents = true
#indent switch labels
csharp_indent_switch_labels = true

#Formatting - new line options

#place catch statements on a new line
csharp_new_line_before_catch = true
#place else statements on a new line
csharp_new_line_before_else = true
#require members of anonymous types to be on separate lines
csharp_new_line_before_members_in_anonymous_types = true
#require members of object intializers to be on separate lines
csharp_new_line_before_members_in_object_initializers = true
#require braces to be on a new line for methods, control_blocks, and types (also known as "Allman" style)
csharp_new_line_before_open_brace = methods, control_blocks, types

#Formatting - organize using options

#do not place System.* using directives before other using directives
dotnet_sort_system_directives_first = false

#Formatting - spacing options

#require NO space between a cast and the value
csharp_space_after_cast = false
#require a space before the colon for bases or interfaces in a type declaration
csharp_space_after_colon_in_inheritance_clause = true
#require a space after a keyword in a control flow statement such as a for loop
csharp_space_after_keywords_in_control_flow_statements = true
#require a space before the colon for bases or interfaces in a type declaration
csharp_space_before_colon_in_inheritance_clause = true
#remove space within empty argument list parentheses
csharp_space_between_method_call_empty_parameter_list_parentheses = false
#remove space between method call name and opening parenthesis
csharp_space_between_method_call_name_and_opening_parenthesis = false
#do not place space characters after the opening parenthesis and before the closing parenthesis of a method call
csharp_space_between_method_call_parameter_list_parentheses = false
#remove space within empty parameter list parentheses for a method declaration
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
#place a space character after the opening parenthesis and before the closing parenthesis of a method declaration parameter list.
csharp_space_between_method_declaration_parameter_list_parentheses = false

#Formatting - wrapping options

#leave code block on single line
csharp_preserve_single_line_blocks = true
#leave statements and member declarations on the same line
csharp_preserve_single_line_statements = true

#Style - Code block preferences

#prefer curly braces even for one line of code
csharp_prefer_braces = true:suggestion

#Style - expression bodied member options

#prefer block bodies for constructors
csharp_style_expression_bodied_constructors = false:suggestion
#prefer block bodies for methods
csharp_style_expression_bodied_methods = false:suggestion

#Style - expression level options

#prefer out variables to be declared inline in the argument list of a method call when possible
csharp_style_inlined_variable_declaration = true:suggestion
#prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them
dotnet_style_predefined_type_for_member_access = true:suggestion

#Style - Expression-level  preferences

#prefer objects to be initialized using object initializers when possible
dotnet_style_object_initializer = true:suggestion
#prefer inferred anonymous type member names
dotnet_style_prefer_inferred_anonymous_type_member_names = false:suggestion

#Style - implicit and explicit types

#prefer var over explicit type in all cases, unless overridden by another code style rule
csharp_style_var_elsewhere = true:suggestion
#prefer var is used to declare variables with built-in system types such as int
csharp_style_var_for_built_in_types = true:suggestion
#prefer var when the type is already mentioned on the right-hand side of a declaration expression
csharp_style_var_when_type_is_apparent = true:suggestion

#Style - language keyword and framework type options

#prefer the language keyword for local variables, method parameters, and class members, instead of the type name, for types that have a keyword to represent them
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion

#Style - Miscellaneous preferences

#prefer anonymous functions over local functions
csharp_style_pattern_local_over_anonymous_function = false:suggestion

#Style - modifier options

#prefer accessibility modifiers to be declared except for public interface members. This will currently not differ from always and will act as future proofing for if C# adds default interface methods.
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion

#Style - Modifier preferences

#when this rule is set to a list of modifiers, prefer the specified ordering.
csharp_preferred_modifier_order = public,private,internal,readonly,static,async,override,sealed:suggestion

#Style - qualification options

#prefer fields not to be prefaced with this. or Me. in Visual Basic
dotnet_style_qualification_for_field = false:suggestion
#prefer methods not to be prefaced with this. or Me. in Visual Basic
dotnet_style_qualification_for_method = false:suggestion
#prefer properties not to be prefaced with this. or Me. in Visual Basic
dotnet_style_qualification_for_property = false:suggestion


#file header
[*.{cs,vb}]
file_header_template = Copyright (c) Microsoft Corporation.\nLicensed under the MIT License.
file_header_template_style = prepend:error
file_header_template_style = replace:suggestion


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  - package-ecosystem: "github-actions"
    # default location of `.github/workflows`
    directory: "/"
    open-pull-requests-limit: 3
    schedule:
      interval: "weekly"
    # assignees:
    #   - assignee_one
    # reviewers:
    #   - reviewer_one
  - package-ecosystem: "nuget"
    # location of package manifests
    directory: "/"
    open-pull-requests-limit: 3
    schedule:
      interval: "weekly"
    ignore:
      - dependency-name: "*"
        update-types: ["version-update:semver-minor"]
    # assignees:
    #   - assignee_one
    # reviewers:
    #   - reviewer_one
  - package-ecosystem: dotnet-sdk
    directory: /
    schedule:
      interval: weekly
      day: wednesday
    ignore:
      - dependency-name: '*'
        update-types:
          - version-update:semver-major
          - version-update:semver-minor
# Built with ❤ by [Pipeline Foundation](https://pipeline.foundation)


================================================
FILE: .github/workflows/codeql-analysis.yml
================================================
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"

on:
  push:
    branches: [ main, develop ]
  pull_request:
    # The branches below must be a subset of the branches above
    branches: [ main ]
  schedule:
    - cron: '22 15 * * 4'

jobs:
  analyze:
    name: Analyze
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        language: [ 'csharp' ]
        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
        # Learn more:
        # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed

    steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Setup .NET Core
      uses: actions/setup-dotnet@v4
      with:
        dotnet-version: |
          6.0.x
          8.0.x
          9.0.x

    # Initializes the CodeQL tools for scanning.
    - name: Initialize CodeQL
      uses: github/codeql-action/init@v3
      with:
        languages: ${{ matrix.language }}
        # If you wish to specify custom queries, you can do so here or in a config file.
        # By default, queries listed here will override any specified in a config file.
        # Prefix the list here with "+" to use these queries and those in the config file.
        # queries: ./path/to/local/query, your-org/your-repo/queries@main

    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
    # If this step fails, then you should remove it and run the build manually (see below)
    - name: Autobuild
      uses: github/codeql-action/autobuild@v3

    # ℹ️ Command-line programs to run using the OS shell.
    # 📚 https://git.io/JvXDl

    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
    #    and modify them (or add more) to build your code if your project
    #    uses a compiled language

    #- run: |
    #   make bootstrap
    #   make release

    - name: Perform CodeQL Analysis
      uses: github/codeql-action/analyze@v3
    


================================================
FILE: .github/workflows/dotnetcore-build.yml
================================================
name: build

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main, develop ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Setup .NET Core
      uses: actions/setup-dotnet@v4
      with:
        dotnet-version: |
          6.0.x
          8.0.x
          9.0.x
    
    - name: Install dependencies
      run: dotnet restore RulesEngine.sln
    
    - name: Build
      run: dotnet build RulesEngine.sln --configuration Release --no-restore
    
    - name: Test
      run: dotnet test RulesEngine.sln --collect:"XPlat Code Coverage" --no-build --configuration Release --verbosity m 

    - name: Generate Report
      shell: pwsh
      run: ./scripts/generate-coverage-report.ps1

    - name: Check Coverage
      shell: pwsh
      run: ./scripts/check-coverage.ps1 -reportPath coveragereport/Cobertura.xml -threshold 94
    
    - name: Coveralls GitHub Action
      uses: coverallsapp/github-action@v2.3.6
      if: ${{ github.event_name == 'push' }}
      with:
        github-token: ${{ secrets.GITHUB_TOKEN }}
        path-to-lcov: ./coveragereport/lcov.info


================================================
FILE: .gitignore
================================================
## 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/master/VisualStudio.gitignore

# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/

# 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

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

# Benchmark Results
BenchmarkDotNet.Artifacts/

# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json

# StyleCop
StyleCopReport.xml

# Files built by Visual Studio
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.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

# JustCode is a .NET coding add-in
.JustCode

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json

# 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
# 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

# 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

# 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 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/

# JetBrains Rider
.idea/
*.sln.iml

# CodeRush
.cr/

# 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/
/src/RulesEngine/RulesEngine.sln.licenseheader
/assets/RulesEnginePackageFile.xml
coveragereport/

src/**/*.snk

dist

================================================
FILE: .vscode/launch.json
================================================
{
   // 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
   "version": "0.2.0",
   "configurations": [
        {
            "name": ".NET Core Launch (console)",
            "type": "coreclr",
            "request": "launch",
            "preLaunchTask": "build",
            // If you have changed target frameworks, make sure to update the program path.
            "program": "${workspaceFolder}/demo/DemoApp/bin/Debug/netcoreapp3.1/DemoApp.dll",
            "args": [],
            "cwd": "${workspaceFolder}/demo/DemoApp",
            // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
            "console": "internalConsole",
            "stopAtEntry": false
        },
        {
            "name": ".NET Core Attach",
            "type": "coreclr",
            "request": "attach",
            "processId": "${command:pickProcess}"
        }
    ]
}

================================================
FILE: .vscode/settings.json
================================================
{
    "dotnetCoreExplorer.searchpatterns": "test/**/bin/Debug/netcoreapp*/*.{dll,exe,json}",
    "coverage-gutters.coverageBaseDir": "coveragereport",
    "coverage-gutters.coverageReportFileName": "coveragereport/**/index.html"
}

================================================
FILE: .vscode/tasks.json
================================================
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "command": "dotnet",
            "type": "process",
            "args": [
                "build",
                "${workspaceFolder}/demo/DemoApp/DemoApp.csproj",
                "/property:GenerateFullPaths=true",
                "/consoleloggerparameters:NoSummary"
            ],
            "problemMatcher": "$msCompile"
        },
        {
            "label": "publish",
            "command": "dotnet",
            "type": "process",
            "args": [
                "publish",
                "${workspaceFolder}/demo/DemoApp/DemoApp.csproj",
                "/property:GenerateFullPaths=true",
                "/consoleloggerparameters:NoSummary"
            ],
            "problemMatcher": "$msCompile"
        },
        {
            "label": "watch",
            "command": "dotnet",
            "type": "process",
            "args": [
                "watch",
                "run",
                "${workspaceFolder}/demo/DemoApp/DemoApp.csproj",
                "/property:GenerateFullPaths=true",
                "/consoleloggerparameters:NoSummary"
            ],
            "problemMatcher": "$msCompile"
        }
    ]
}

================================================
FILE: CHANGELOG.md
================================================
# CHANGELOG

All notable changes to this project will be documented in this file.

## [5.0.3]
- Updated dependencies to latest
- Fixed RulesEngine throwing exception when type name is same as input name
- Added config to disable FastCompile for expressions
- Added RuleParameter.Create method for better handling on types when value is null

## [5.0.2]
- Fixed Scoped Params returning incorrect results in some corner case scenarios

## [5.0.1]
- Added option to disable automatic type registry for input parameters in reSettings
- Added option to make expression case sensitive in reSettings

## [5.0.0]
- Fixed security bug related to System.Dynamic.Linq.Core

### Breaking Changes
- As a part of security bug fix, method call for only registered types via reSettings will be allowed. This only impacts strongly typed inputs and nested types


## [4.0.0]
- RulesEngine is now available in both dotnet 6 and netstandard 2.0
- Dependency on ILogger, MemoryCache have been removed 
- Obsolete Properties and Methods have been removed
- Fixed name of RuleParameter is ignored if the type is recognized (by @peeveen)
### Breaking Changes
- ILogger has been removed from RulesEngine and all its constructors
```diff
- RulesEngine(string[] jsonConfig, ILogger logger = null, ReSettings reSettings = null)
+ RulesEngine(string[] jsonConfig, ReSettings reSettings = null)

- RulesEngine(Workflow[] Workflows, ILogger logger = null, ReSettings reSettings = null)
+ RulesEngine(Workflow[] Workflows, ReSettings reSettings = null)

- RulesEngine(ILogger logger = null, ReSettings reSettings = null)
+ RulesEngine(ReSettings reSettings = null)
```
- Obsolete methods and properties have been removed, from the follow models:-
	- RuleResultTree
		- `ToResultTreeMessages()` has been removed from `RuleResultTree` model
		- `GetMessages()` has been removed from `RuleResultTree` model
		- `RuleEvaluatedParams` has been removed from `RuleResultTree` model, Please use `Inputs` instead

	- Workflow
		- `WorkflowRulesToInject` has been removed, Please use `WorkflowsToInject` instead
		- `ErrorType` has been removed from `Rule`

	- Resettings
		- `EnableLocalParams` has been removed from `ReSettings`, Please use `EnableScopedParams` instead
	

## [3.5.0]
- `EvaluateRule` action now support custom inputs and filtered inputs
- Added `ContainsWorkflow` method in RulesEngine (by @okolobaxa)
- Fixed minor bugs (#258 & #259)

## [3.4.0]
- Made RulesEngine Strong Name and Authenticode signed
- Renamed few models to streamline names (by @alexrich)
	- `WorkflowRules` is renamed to `Workflow`
	- `WorkflowRulesToInject` is renamed to `WorkflowsToInject`
	- `RuleAction` is renamed to `RuleActions`
	
	**Note**: The old models are still supported but will be removed with version 4.0.0


## [3.3.0]
- Added support for actions in nested rules
- Improved serialization support for System.Text.Json for workflow model
  
Breaking Change:
  - Type of Action has been changed from `Dictionary<ActionTriggerType, ActionInfo>` to `RuleActions`
    - No impact if you are serializing workflow from json
    - For workflow objects created in code, refer - [link](https://github.com/microsoft/RulesEngine/pull/182/files#diff-a5093dda2dcc1e4958ce3533edb607bb61406e1f0a9071eca4e317bdd987c0d3)

## [3.2.0]
- Added AddOrUpdateWorkflow method to update workflows atomically (by @AshishPrasad)
- Updated dependencies to latest

Breaking Change:
  - `AddWorkflow` now throws exception if you try to add a workflow which already exists.
  Use `AddOrUpdateWorkflow` to update existing workflow

## [3.1.0]
- Added globalParams feature which can be applied to all rules
- Enabled localParams support for nested Rules
- Made certain fields in Rule model optional allowing users to define workflow with minimal fields
- Added option to disable Rule in workflow json
- Added `GetAllRegisteredWorkflow` to RulesEngine to return all registered workflows
- Runtime errors for expressions will now be logged as errorMessage instead of throwing Exceptions by default
- Fixed RuleParameter passed as null

## [3.0.2]
- Fixed LocalParams cache not getting cleaned up when RemoveWorkflows and ClearWorkflows are called

## [3.0.1]
- Moved ActionResult and ActionRuleResult under RulesEngine.Models namespace


## [3.0.0]
### Major Enhancements
- Added support for Actions. More details on [actions wiki](https://github.com/microsoft/RulesEngine/wiki/Actions)
- Major performance improvement
	- 25% improvement from previous version
	- Upto 35% improvement by disabling optional features
- RulesEngine now virtually supports unlimited inputs (Previous limitation was 16 inputs)
- RuleExpressionParser is now available to use expression evaluation outside RulesEngine

### Breaking Changes
- `ExecuteRule` method has been renamed to `ExecuteAllRulesAsync`
- `Input` field in RuleResultTree has been changed to `Inputs` which returns all the the inputs as Dictionary of name and value pair

## [2.1.5] - 02-11-2020
- Added `Properties` field to Rule to allow custom fields to Rule

## [2.1.4] - 15-10-2020
- Added exception data properties to identify RuleName.

## [2.1.3] - 12-10-2020
- Optional parameter for rethrow exception on failure of expression compilation.

## [2.1.2] - 02-10-2020
- Fixed binary expression requirement. Now any expression will work as long as it evalutes to boolean.

## [2.1.1] - 01-09-2020
- Fixed exception thrown when errormessage field is null
- Added better messaging when identifier is not found in expression
- Fixed other minor bugs

## [2.1.0] - 18-05-2020
- Adding local param support to make expression authroing more intuitive.

## [2.0.0] - 18-05-2020
### Changed
- Interface simplified by removing redundant parameters in the IRulesEngine.
- Custom Logger replaced with Microsoft Logger.

## [1.0.2] - 16-01-2020
### Added
- Cache system added so that rules compilation is stored and thus made more efficient.

### Fix
- Concurrency issue which arose by dictionary was resolved.

## [1.0.1] - 24-09-2019
### Added
- Exceptions handling scenario in the case a rule execution throws an exception 

## [1.0.0] - 20-08-2019

### Added
- The first version of the NuGet


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Microsoft Open Source Code of Conduct

This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).

Resources:

- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns


================================================
FILE: LICENSE
================================================
    MIT License

    Copyright (c) Microsoft Corporation.

    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


================================================
FILE: README.md
================================================
# Rules Engine
![build](https://github.com/microsoft/RulesEngine/workflows/build/badge.svg?branch=main)
[![Coverage Status](https://coveralls.io/repos/github/microsoft/RulesEngine/badge.svg?branch=main)](https://coveralls.io/github/microsoft/RulesEngine?branch=main)
[![Nuget download][download-image]][download-url]

[download-image]: https://img.shields.io/nuget/dt/RulesEngine
[download-url]: https://www.nuget.org/packages/RulesEngine/

## Overview

Rules Engine is a library/NuGet package for abstracting business logic/rules/policies out of a system. It provides a simple way of giving you the ability to put your rules in a store outside the core logic of the system, thus ensuring that any change in rules don't affect the core system.

## Installation

To install this library, download the latest version of [NuGet Package](https://www.nuget.org/packages/RulesEngine/) from [nuget.org](https://www.nuget.org/) and refer it into your project.  

## How to use it

There are several ways to populate workflows for the Rules Engine as listed below.

You need to store the rules based on the [schema definition](https://github.com/microsoft/RulesEngine/blob/main/schema/workflow-schema.json) given and they can be stored in any store as deemed appropriate like Azure Blob Storage, Cosmos DB, Azure App Configuration, [Entity Framework](https://github.com/microsoft/RulesEngine#entity-framework), SQL Servers, file systems etc. For RuleExpressionType `LambdaExpression`, the rule is written as a [lambda expressions](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions).

An example rule:

```json
[
  {
    "WorkflowName": "Discount",
    "Rules": [
      {
        "RuleName": "GiveDiscount10",
        "SuccessEvent": "10",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.country == \"india\" AND input1.loyaltyFactor <= 2 AND input1.totalPurchasesToDate >= 5000"
      },
      {
        "RuleName": "GiveDiscount20",
        "SuccessEvent": "20",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.country == \"india\" AND input1.loyaltyFactor >= 3 AND input1.totalPurchasesToDate >= 10000"
      }
    ]
  }
]
```

You can inject the rules into the Rules Engine by initiating an instance by using the following code - 

```c#
var rulesEngine = new RulesEngine(workflow);
```
Here, *workflow* is a list of deserialized objects based on the schema explained above
Once initialised, the Rules Engine needs to execute the rules for a given input. This can be done by calling the method `ExecuteAllRulesAsync`: 

```c#
List<RuleResultTree> response = await rulesEngine.ExecuteAllRulesAsync(workflowName, input);
```

Here, *workflowName* is the name of the workflow, which is *Discount* in the above mentioned example. And *input* is the object which needs to be checked against the rules,  which itself may consist of a list of class instances.

The *response* will contain a list of [*RuleResultTree*](https://github.com/microsoft/RulesEngine/wiki/Getting-Started#ruleresulttree) which gives information if a particular rule passed or failed. 

_Note: A detailed example showcasing how to use Rules Engine is explained in [Getting Started page](https://github.com/microsoft/RulesEngine/wiki/Getting-Started) of [Rules Engine Wiki](https://github.com/microsoft/RulesEngine/wiki)._

_A demo app for the is available at [this location](https://github.com/microsoft/RulesEngine/tree/main/demo)._

### Basic

A simple example via code only is as follows:

```c#
List<Rule> rules = new List<Rule>();

Rule rule = new Rule();
rule.RuleName = "Test Rule";
rule.SuccessEvent = "Count is within tolerance.";
rule.ErrorMessage = "Over expected.";
rule.Expression = "count < 3";
rule.RuleExpressionType = RuleExpressionType.LambdaExpression;
rules.Add(rule);

var workflows = new List<Workflow>();

Workflow exampleWorkflow = new Workflow();
exampleWorkflow.WorkflowName = "Example Workflow";
exampleWorkflow.Rules = rules;

workflows.Add(exampleWorkflow);

var bre = new RulesEngine.RulesEngine(workflows.ToArray());
```
### Entity Framework

Consuming Entity Framework and populating the Rules Engine is shown in the [EFDemo class](https://github.com/microsoft/RulesEngine/blob/main/demo/DemoApp/EFDemo.cs) with Workflow rules populating the array and passed to the Rules Engine, The Demo App includes an example [RulesEngineDemoContext](https://github.com/microsoft/RulesEngine/blob/main/demo/DemoApp.EFDataExample/RulesEngineDemoContext.cs) using SQLite and could be swapped out for another provider.

```c#
var wfr = db.Workflows.Include(i => i.Rules).ThenInclude(i => i.Rules).ToArray();
var bre = new RulesEngine.RulesEngine(wfr, null);
```

*Note: For each level of nested rules expected, a ThenInclude query appended will be needed as shown above.*

## How it works

![](https://github.com/microsoft/RulesEngine/blob/main/assets/BlockDiagram.png)

The rules can be stored in any store and be fed to the system in a structure which adheres to the [schema](https://github.com/microsoft/RulesEngine/blob/main/schema/workflow-schema.json) of WorkFlow model.

A wrapper needs to be created over the Rules Engine package, which will get the rules and input message(s) from any store that your system dictates and put it into the Engine. The wrapper then handles the output using appropriate means.

_Note: To know in detail of the workings of Rules Engine, please visit [How it works section](https://github.com/microsoft/RulesEngine/wiki/Introduction#how-it-works) in [Rules Engine Wiki](https://github.com/microsoft/RulesEngine/wiki)._

## 3rd Party Tools

### RulesEngine Editor
There is an editor library with it's own [NuGet Package](https://www.nuget.org/packages/RulesEngineEditor/) written in Blazor, more information is in it's repo https://github.com/alexreich/RulesEngineEditor. 

#### Live Demo
https://alexreich.github.io/RulesEngineEditor  
> This can also be installed as a standalone PWA and used offline.

#### With Sample Data
https://alexreich.github.io/RulesEngineEditor/demo

## Contributing

This project welcomes contributions and suggestions.  Most contributions require you to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.

This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.

---

_For more details please check out [Rules Engine Wiki](https://github.com/microsoft/RulesEngine/wiki)._


================================================
FILE: RulesEngine.sln
================================================

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31717.71
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RulesEngine", "src\RulesEngine\RulesEngine.csproj", "{CD4DFE6A-083B-478E-8377-77F474833E30}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RulesEngine.UnitTest", "test\RulesEngine.UnitTest\RulesEngine.UnitTest.csproj", "{50E0C2A5-E2C8-4B12-8C0E-B69F698A82BF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DemoApp", "demo\DemoApp\DemoApp.csproj", "{57BB8C07-799A-4F87-A7CC-D3D3F694DD02}"
	ProjectSection(ProjectDependencies) = postProject
		{CD4DFE6A-083B-478E-8377-77F474833E30} = {CD4DFE6A-083B-478E-8377-77F474833E30}
	EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{019DF693-8442-45B4-88C3-55CB7AFCB42E}"
	ProjectSection(SolutionItems) = preProject
		.editorconfig = .editorconfig
		CHANGELOG.md = CHANGELOG.md
		global.json = global.json
		README.md = README.md
		schema\workflow-list-schema.json = schema\workflow-list-schema.json
		schema\workflow-schema.json = schema\workflow-schema.json
	EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RulesEngineBenchmark", "benchmark\RulesEngineBenchmark\RulesEngineBenchmark.csproj", "{C058809F-C720-4EFC-925D-A486627B238B}"
	ProjectSection(ProjectDependencies) = postProject
		{CD4DFE6A-083B-478E-8377-77F474833E30} = {CD4DFE6A-083B-478E-8377-77F474833E30}
	EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DemoApp.EFDataExample", "demo\DemoApp.EFDataExample\DemoApp.EFDataExample.csproj", "{E376D3E6-6890-4C09-9EA0-3EFD9C1E036D}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Release|Any CPU = Release|Any CPU
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{CD4DFE6A-083B-478E-8377-77F474833E30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{CD4DFE6A-083B-478E-8377-77F474833E30}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{CD4DFE6A-083B-478E-8377-77F474833E30}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{CD4DFE6A-083B-478E-8377-77F474833E30}.Release|Any CPU.Build.0 = Release|Any CPU
		{50E0C2A5-E2C8-4B12-8C0E-B69F698A82BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{50E0C2A5-E2C8-4B12-8C0E-B69F698A82BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{50E0C2A5-E2C8-4B12-8C0E-B69F698A82BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{50E0C2A5-E2C8-4B12-8C0E-B69F698A82BF}.Release|Any CPU.Build.0 = Release|Any CPU
		{57BB8C07-799A-4F87-A7CC-D3D3F694DD02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{57BB8C07-799A-4F87-A7CC-D3D3F694DD02}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{57BB8C07-799A-4F87-A7CC-D3D3F694DD02}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{57BB8C07-799A-4F87-A7CC-D3D3F694DD02}.Release|Any CPU.Build.0 = Release|Any CPU
		{C058809F-C720-4EFC-925D-A486627B238B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{C058809F-C720-4EFC-925D-A486627B238B}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{C058809F-C720-4EFC-925D-A486627B238B}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{C058809F-C720-4EFC-925D-A486627B238B}.Release|Any CPU.Build.0 = Release|Any CPU
		{E376D3E6-6890-4C09-9EA0-3EFD9C1E036D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{E376D3E6-6890-4C09-9EA0-3EFD9C1E036D}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{E376D3E6-6890-4C09-9EA0-3EFD9C1E036D}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{E376D3E6-6890-4C09-9EA0-3EFD9C1E036D}.Release|Any CPU.Build.0 = Release|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(ExtensibilityGlobals) = postSolution
		SolutionGuid = {E1F2EC8E-4005-4DFE-90ED-296D4592867A}
	EndGlobalSection
EndGlobal


================================================
FILE: SECURITY.md
================================================
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.5 BLOCK -->

## Security

Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).

If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below.

## Reporting Security Issues

**Please do not report security vulnerabilities through public GitHub issues.**

Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).

If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com).  If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).

You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 

Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:

  * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
  * Full paths of source file(s) related to the manifestation of the issue
  * The location of the affected source code (tag/branch/commit or direct URL)
  * Any special configuration required to reproduce the issue
  * Step-by-step instructions to reproduce the issue
  * Proof-of-concept or exploit code (if possible)
  * Impact of the issue, including how an attacker might exploit the issue

This information will help us triage your report more quickly.

If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.

## Preferred Languages

We prefer all communications to be in English.

## Policy

Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).

<!-- END MICROSOFT SECURITY.MD BLOCK -->

================================================
FILE: benchmark/RulesEngineBenchmark/Program.cs
================================================
// Copyright (c) Microsoft Corporation.
//  Licensed under the MIT License.

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using RulesEngine.Models;
using System;
using System.Collections.Generic;
using System.IO;
using BenchmarkDotNet.Jobs;
using System.Text.Json;

namespace RulesEngineBenchmark
{

    [MemoryDiagnoser]
    [SimpleJob(RuntimeMoniker.Net60)]
    [SimpleJob(RuntimeMoniker.Net80)]
    [SimpleJob(RuntimeMoniker.Net90)]
    public class REBenchmark
    {
        private readonly RulesEngine.RulesEngine rulesEngine;
        private readonly object ruleInput;
        private readonly List<Workflow> workflow;

        private class ListItem
        {
            public int Id { get; set; }
            public string Value { get; set; }
        }


        public REBenchmark()
        {
            var files = Directory.GetFiles(Directory.GetCurrentDirectory(), "NestedInputDemo.json", SearchOption.AllDirectories);
            if (files == null || files.Length == 0)
            {
                throw new Exception("Rules not found.");
            }

            var fileData = File.ReadAllText(files[0]);
            workflow = JsonSerializer.Deserialize<List<Workflow>>(fileData);

            rulesEngine = new RulesEngine.RulesEngine(workflow.ToArray(), new ReSettings {
                EnableFormattedErrorMessage = false,
                EnableScopedParams = false
            });

            ruleInput = new {
                SimpleProp = "simpleProp",
                NestedProp = new {
                    SimpleProp = "nestedSimpleProp",
                    ListProp = new List<ListItem>
                    {
                        new ListItem
                        {
                            Id = 1,
                            Value = "first"
                        },
                        new ListItem
                        {
                            Id = 2,
                            Value = "second"
                        }
                    }
                }

            };
        }

        [Params(1000, 10000)]
        public int N;

        [Benchmark]
        public void RuleExecutionDefault()
        {
            foreach (var workflow in workflow)
            {
                _ = rulesEngine.ExecuteAllRulesAsync(workflow.WorkflowName, ruleInput).Result;
            }
        }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            _ = BenchmarkRunner.Run<REBenchmark>();
        }
    }
}


================================================
FILE: benchmark/RulesEngineBenchmark/RulesEngineBenchmark.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFrameworks>net6.0;net8.0;net9.0</TargetFrameworks>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="BenchmarkDotNet" Version="0.14.0" />
    <!--<PackageReference Include="RulesEngine" Version="3.0.2" />-->
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\..\src\RulesEngine\RulesEngine.csproj" />
  </ItemGroup>

  <ItemGroup>
    <None Update="Workflows\Discount.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="Workflows\NestedInputDemo.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>

</Project>


================================================
FILE: benchmark/RulesEngineBenchmark/Workflows/Discount.json
================================================
[
  {
    "WorkflowName": "Discount",
    "Rules": [
      {
        "RuleName": "GiveDiscount10",
        "SuccessEvent": "10",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.country == \"india\" AND input1.loyaltyFactor <= 2 AND input1.totalPurchasesToDate >= 5000 AND input2.totalOrders > 2 AND input3.noOfVisitsPerMonth > 2"
      },
      {
        "RuleName": "GiveDiscount20",
        "SuccessEvent": "20",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.country == \"india\" AND input1.loyaltyFactor == 3 AND input1.totalPurchasesToDate >= 10000 AND input2.totalOrders > 2 AND input3.noOfVisitsPerMonth > 2"
      },
      {
        "RuleName": "GiveDiscount25",
        "SuccessEvent": "25",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.country != \"india\" AND input1.loyaltyFactor >= 2 AND input1.totalPurchasesToDate >= 10000 AND input2.totalOrders > 2 AND input3.noOfVisitsPerMonth > 5"
      },
      {
        "RuleName": "GiveDiscount30",
        "SuccessEvent": "30",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.loyaltyFactor > 3 AND input1.totalPurchasesToDate >= 50000 AND input1.totalPurchasesToDate <= 100000 AND input2.totalOrders > 5 AND input3.noOfVisitsPerMonth > 15"
      },
      {
        "RuleName": "GiveDiscount30NestedOrExample",
        "SuccessEvent": "30",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "Operator": "OrElse",
        "Rules":[
          {
            "RuleName": "IsLoyalAndHasGoodSpend",
            "ErrorMessage": "One or more adjust rules failed.",
            "ErrorType": "Error",
            "RuleExpressionType": "LambdaExpression",
            "Expression": "input1.loyaltyFactor > 3 AND input1.totalPurchasesToDate >= 50000 AND input1.totalPurchasesToDate <= 100000"
          },
          {
            "RuleName": "OrHasHighNumberOfTotalOrders",
            "ErrorMessage": "One or more adjust rules failed.",
            "ErrorType": "Error",
            "RuleExpressionType": "LambdaExpression",
            "Expression": "input2.totalOrders > 15"
          }
        ]
      },
      {
        "RuleName": "GiveDiscount35NestedAndExample",
        "SuccessEvent": "35",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "Operator": "AndAlso",
        "Rules": [
          {
            "RuleName": "IsLoyal",
            "ErrorMessage": "One or more adjust rules failed.",
            "ErrorType": "Error",
            "RuleExpressionType": "LambdaExpression",
            "Expression": "input1.loyaltyFactor > 3"
          },
          {
            "RuleName": "AndHasTotalPurchased100000",
            "ErrorMessage": "One or more adjust rules failed.",
            "ErrorType": "Error",
            "RuleExpressionType": "LambdaExpression",
            "Expression": "input1.totalPurchasesToDate >= 100000"
          },
          {
            "RuleName": "AndOtherConditions",
            "ErrorMessage": "One or more adjust rules failed.",
            "ErrorType": "Error",
            "RuleExpressionType": "LambdaExpression",
            "Expression": "input2.totalOrders > 15 AND input3.noOfVisitsPerMonth > 25"
          }
        ]
      }
    ]
  }
]

================================================
FILE: benchmark/RulesEngineBenchmark/Workflows/NestedInputDemo.json
================================================
[
  {
    "WorkflowName": "NestedInputDemoWorkflow1",
    "Rules": [
      {
        "RuleName": "CheckNestedSimpleProp",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.NestedProp.SimpleProp == \"nestedSimpleProp\""
      }
    ]
  },
  {
    "WorkflowName": "NestedInputDemoWorkflow2",
    "Rules": [
      {
        "RuleName": "CheckNestedListProp",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.NestedProp.ListProp[0].Id == 1 && input1.NestedProp.ListProp[1].Value == \"second\""
      }
    ]
  },

  {
    "WorkflowName": "NestedInputDemoWorkflow3",
    "Rules": [
      {
        "RuleName": "CheckNestedListPropFunctions",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.NestedProp.ListProp[1].Value.ToUpper() = \"SECOND\""
      }
    ]
  }
]

================================================
FILE: demo/DemoApp/BasicDemo.cs
================================================
// Copyright (c) Microsoft Corporation.
//  Licensed under the MIT License.

using RulesEngine.Models;
using System;
using System.Collections.Generic;
using System.Dynamic;
using static RulesEngine.Extensions.ListofRuleResultTreeExtension;

namespace DemoApp
{
    public class BasicDemo
    {
        public void Run()
        {
            Console.WriteLine($"Running {nameof(BasicDemo)}....");
            List<Workflow> workflows = new List<Workflow>();
            Workflow workflow = new Workflow();
            workflow.WorkflowName = "Test Workflow Rule 1";

            List<Rule> rules = new List<Rule>();

            Rule rule = new Rule();
            rule.RuleName = "Test Rule";
            rule.SuccessEvent = "Count is within tolerance.";
            rule.ErrorMessage = "Over expected.";
            rule.Expression = "count < 3";
            rule.RuleExpressionType = RuleExpressionType.LambdaExpression;

            rules.Add(rule);

            workflow.Rules = rules;

            workflows.Add(workflow);

            var bre = new RulesEngine.RulesEngine(workflows.ToArray(), null);

            dynamic datas = new ExpandoObject();
            datas.count = 1;
            var inputs = new dynamic[]
              {
                    datas
              };

            List<RuleResultTree> resultList = bre.ExecuteAllRulesAsync("Test Workflow Rule 1", inputs).Result;

            bool outcome = false;

            //Different ways to show test results:
            outcome = resultList.TrueForAll(r => r.IsSuccess);

            resultList.OnSuccess((eventName) => {
                Console.WriteLine($"Result '{eventName}' is as expected.");
                outcome = true;
            });

            resultList.OnFail(() => {
                outcome = false;
            });

            Console.WriteLine($"Test outcome: {outcome}.");
        }
    }
}


================================================
FILE: demo/DemoApp/DemoApp.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFrameworks>net8.0;net9.0</TargetFrameworks>
    <StartupObject>DemoApp.Program</StartupObject>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="../../src/RulesEngine/RulesEngine.csproj" />
    <ProjectReference Include="..\DemoApp.EFDataExample\DemoApp.EFDataExample.csproj" />
  </ItemGroup>

  <ItemGroup>
    <None Update="Workflows\Discount.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="Workflows\NestedInputDemo.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>

</Project>


================================================
FILE: demo/DemoApp/EFDemo.cs
================================================
// Copyright (c) Microsoft Corporation.
//  Licensed under the MIT License.

using DemoApp.EFDataExample;
using RulesEngine.Models;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.IO;
using System.Linq;
using static RulesEngine.Extensions.ListofRuleResultTreeExtension;
using Microsoft.EntityFrameworkCore;

namespace DemoApp
{
    using System.Text.Json;

    public class EFDemo
    {
        public void Run()
        {
            Console.WriteLine($"Running {nameof(EFDemo)}....");
            var basicInfo = "{\"name\": \"hello\",\"email\": \"abcy@xyz.com\",\"creditHistory\": \"good\",\"country\": \"canada\",\"loyaltyFactor\": 3,\"totalPurchasesToDate\": 10000}";
            var orderInfo = "{\"totalOrders\": 5,\"recurringItems\": 2}";
            var telemetryInfo = "{\"noOfVisitsPerMonth\": 10,\"percentageOfBuyingToVisit\": 15}";

           dynamic input1 = JsonSerializer.Deserialize<ExpandoObject>(basicInfo);
            dynamic input2 = JsonSerializer.Deserialize<ExpandoObject>(orderInfo);
            dynamic input3 = JsonSerializer.Deserialize<ExpandoObject>(telemetryInfo);

            var inputs = new dynamic[]
                {
                    input1,
                    input2,
                    input3
                };

            var files = Directory.GetFiles(Directory.GetCurrentDirectory(), "Discount.json", SearchOption.AllDirectories);
            if (files == null || files.Length == 0)
                throw new Exception("Rules not found.");

            var fileData = File.ReadAllText(files[0]);
            var workflow = JsonSerializer.Deserialize<List<Workflow>>(fileData);

            RulesEngineDemoContext db = new RulesEngineDemoContext();
            if (db.Database.EnsureCreated())
            {
                db.Workflows.AddRange(workflow);
                db.SaveChanges();
            }

            var wfr = db.Workflows.Include(i => i.Rules).ThenInclude(i => i.Rules).ToArray();

            var bre = new RulesEngine.RulesEngine(wfr, null);

            string discountOffered = "No discount offered.";

            List<RuleResultTree> resultList = bre.ExecuteAllRulesAsync("Discount", inputs).Result;

            resultList.OnSuccess((eventName) => {
                discountOffered = $"Discount offered is {eventName} % over MRP.";
            });

            resultList.OnFail(() => {
                discountOffered = "The user is not eligible for any discount.";
            });

            Console.WriteLine(discountOffered);
        }
    }
}


================================================
FILE: demo/DemoApp/JSONDemo.cs
================================================
// Copyright (c) Microsoft Corporation.
//  Licensed under the MIT License.

using RulesEngine.Models;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.IO;
using static RulesEngine.Extensions.ListofRuleResultTreeExtension;

namespace DemoApp
{
    using System.Text.Json;

    public class JSONDemo
    {
        public void Run()
        {
            Console.WriteLine($"Running {nameof(JSONDemo)}....");
            var basicInfo = "{\"name\": \"hello\",\"email\": \"abcy@xyz.com\",\"creditHistory\": \"good\",\"country\": \"canada\",\"loyaltyFactor\": 3,\"totalPurchasesToDate\": 10000}";
            var orderInfo = "{\"totalOrders\": 5,\"recurringItems\": 2}";
            var telemetryInfo = "{\"noOfVisitsPerMonth\": 10,\"percentageOfBuyingToVisit\": 15}";



            dynamic input1 = JsonSerializer.Deserialize<ExpandoObject>(basicInfo);
            dynamic input2 = JsonSerializer.Deserialize<ExpandoObject>(orderInfo);
            dynamic input3 = JsonSerializer.Deserialize<ExpandoObject>(telemetryInfo);

            var inputs = new dynamic[]
                {
                    input1,
                    input2,
                    input3
                };

            var files = Directory.GetFiles(Directory.GetCurrentDirectory(), "Discount.json", SearchOption.AllDirectories);
            if (files == null || files.Length == 0)
                throw new Exception("Rules not found.");

            var fileData = File.ReadAllText(files[0]);
            var workflow = JsonSerializer.Deserialize<List<Workflow>>(fileData);

            var bre = new RulesEngine.RulesEngine(workflow.ToArray(), null);

            string discountOffered = "No discount offered.";

            List<RuleResultTree> resultList = bre.ExecuteAllRulesAsync("Discount", inputs).Result;

            resultList.OnSuccess((eventName) => {
                discountOffered = $"Discount offered is {eventName} % over MRP.";
            });

            resultList.OnFail(() => {
                discountOffered = "The user is not eligible for any discount.";
            });

            Console.WriteLine(discountOffered);
        }
    }
}


================================================
FILE: demo/DemoApp/NestedInputDemo.cs
================================================
// Copyright (c) Microsoft Corporation.
//  Licensed under the MIT License.

using RulesEngine.Extensions;
using RulesEngine.Models;
using System;
using System.Collections.Generic;
using System.IO;

namespace DemoApp
{
    using System.Text.Json;

    internal class ListItem
    {
        public int Id { get; set; }
        public string Value { get; set; }
    }

    public class NestedInputDemo
    {
        public void Run()
        {
            Console.WriteLine($"Running {nameof(NestedInputDemo)}....");
            var nestedInput = new {
                SimpleProp = "simpleProp",
                NestedProp = new {
                    SimpleProp = "nestedSimpleProp",
                    ListProp = new List<ListItem>
                    {
                        new ListItem
                        {
                            Id = 1,
                            Value = "first"
                        },
                        new ListItem
                        {
                            Id = 2,
                            Value = "second"
                        }
                    }
                }

            };

            var files = Directory.GetFiles(Directory.GetCurrentDirectory(), "NestedInputDemo.json", SearchOption.AllDirectories);
            if (files == null || files.Length == 0)
            {
                throw new Exception("Rules not found.");
            }

            var fileData = File.ReadAllText(files[0]);
            var Workflows = JsonSerializer.Deserialize<List<Workflow>>(fileData);

            var bre = new RulesEngine.RulesEngine(Workflows.ToArray(), null);
            foreach (var workflow in Workflows)
            {
                var resultList = bre.ExecuteAllRulesAsync(workflow.WorkflowName, nestedInput).Result;

                resultList.OnSuccess((eventName) => {
                    Console.WriteLine($"{workflow.WorkflowName} evaluation resulted in success - {eventName}");
                }).OnFail(() => {
                    Console.WriteLine($"{workflow.WorkflowName} evaluation resulted in failure");
                });

            }


        }
    }
}

================================================
FILE: demo/DemoApp/Program.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace DemoApp
{
    public static class Program
    {
        public static void Main(string[] args)
        {
            new BasicDemo().Run();
            new JSONDemo().Run();
            new NestedInputDemo().Run();
            new EFDemo().Run();
        }
    }
}

================================================
FILE: demo/DemoApp/Workflows/Discount.json
================================================
[
  {
    "WorkflowName": "Discount",
    "Rules": [
      {
        "RuleName": "GiveDiscount10",
        "SuccessEvent": "10",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.country == \"india\" AND input1.loyaltyFactor <= 2 AND input1.totalPurchasesToDate >= 5000 AND input2.totalOrders > 2 AND input3.noOfVisitsPerMonth > 2"
      },
      {
        "RuleName": "GiveDiscount20",
        "SuccessEvent": "20",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.country == \"india\" AND input1.loyaltyFactor == 3 AND input1.totalPurchasesToDate >= 10000 AND input2.totalOrders > 2 AND input3.noOfVisitsPerMonth > 2"
      },
      {
        "RuleName": "GiveDiscount25",
        "SuccessEvent": "25",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.country != \"india\" AND input1.loyaltyFactor >= 2 AND input1.totalPurchasesToDate >= 10000 AND input2.totalOrders > 2 AND input3.noOfVisitsPerMonth > 5"
      },
      {
        "RuleName": "GiveDiscount30",
        "SuccessEvent": "30",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.loyaltyFactor > 3 AND input1.totalPurchasesToDate >= 50000 AND input1.totalPurchasesToDate <= 100000 AND input2.totalOrders > 5 AND input3.noOfVisitsPerMonth > 15"
      },
      {
        "RuleName": "GiveDiscount30NestedOrExample",
        "SuccessEvent": "30",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "Operator": "OrElse",
        "Rules":[
          {
            "RuleName": "IsLoyalAndHasGoodSpend",
            "ErrorMessage": "One or more adjust rules failed.",
            "ErrorType": "Error",
            "RuleExpressionType": "LambdaExpression",
            "Expression": "input1.loyaltyFactor > 3 AND input1.totalPurchasesToDate >= 50000 AND input1.totalPurchasesToDate <= 100000"
          },
          {
            "RuleName": "OrHasHighNumberOfTotalOrders",
            "ErrorMessage": "One or more adjust rules failed.",
            "ErrorType": "Error",
            "RuleExpressionType": "LambdaExpression",
            "Expression": "input2.totalOrders > 15"
          }
        ]
      },
      {
        "RuleName": "GiveDiscount35NestedAndExample",
        "SuccessEvent": "35",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "Operator": "AndAlso",
        "Rules": [
          {
            "RuleName": "IsLoyal",
            "ErrorMessage": "One or more adjust rules failed.",
            "ErrorType": "Error",
            "RuleExpressionType": "LambdaExpression",
            "Expression": "input1.loyaltyFactor > 3"
          },
          {
            "RuleName": "AndHasTotalPurchased100000",
            "ErrorMessage": "One or more adjust rules failed.",
            "ErrorType": "Error",
            "RuleExpressionType": "LambdaExpression",
            "Expression": "input1.totalPurchasesToDate >= 100000"
          },
          {
            "RuleName": "AndOtherConditions",
            "ErrorMessage": "One or more adjust rules failed.",
            "ErrorType": "Error",
            "RuleExpressionType": "LambdaExpression",
            "Expression": "input2.totalOrders > 15 AND input3.noOfVisitsPerMonth > 25"
          }
        ]
      }
    ]
  }
]

================================================
FILE: demo/DemoApp/Workflows/NestedInputDemo.json
================================================
[
  {
    "WorkflowName": "NestedInputDemoWorkflow1",
    "Rules": [
      {
        "RuleName": "CheckNestedSimpleProp",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.NestedProp.SimpleProp == \"nestedSimpleProp\""
      }
    ]
  },
  {
    "WorkflowName": "NestedInputDemoWorkflow2",
    "Rules": [
      {
        "RuleName": "CheckNestedListProp",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.NestedProp.ListProp[0].Id == 1 && input1.NestedProp.ListProp[1].Value == \"second\""
      }
    ]
  },

  {
    "WorkflowName": "NestedInputDemoWorkflow3",
    "Rules": [
      {
        "RuleName": "CheckNestedListPropFunctions",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.NestedProp.ListProp[1].Value.ToUpper() = \"SECOND\""
      }
    ]
  }
]

================================================
FILE: demo/DemoApp.EFDataExample/DemoApp.EFDataExample.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFrameworks>net8.0;net9.0</TargetFrameworks>
    <RootNamespace>DemoApp.EFDataExample</RootNamespace>
    <AssemblyName>DemoApp.EFDataExample</AssemblyName>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.1" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\..\src\RulesEngine\RulesEngine.csproj" />
  </ItemGroup>

</Project>


================================================
FILE: demo/DemoApp.EFDataExample/RulesEngineContext.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using RulesEngine.Models;

namespace RulesEngine.Data
{
    public class RulesEngineContext : DbContext
    {
        public DbSet<Workflow> Workflows { get; set; }

        public DbSet<Rule> Rules { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<ScopedParam>()
              .HasKey(k => k.Name);

            modelBuilder.Entity<Workflow>(entity => {
                entity.HasKey(k => k.WorkflowName);
                entity.Ignore(b => b.WorkflowsToInject);
            });

            modelBuilder.Entity<Rule>().HasOne<Rule>().WithMany(r => r.Rules).HasForeignKey("RuleNameFK");

            var serializationOptions = new JsonSerializerOptions(JsonSerializerDefaults.General);

            modelBuilder.Entity<Rule>(entity => {
                entity.HasKey(k => k.RuleName);

                var valueComparer = new ValueComparer<Dictionary<string, object>>(
                    (c1, c2) => c1.SequenceEqual(c2),
                    c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())),
                    c => c);

                entity.Property(b => b.Properties)
                .HasConversion(
                    v => JsonSerializer.Serialize(v, serializationOptions),
                    v => JsonSerializer.Deserialize<Dictionary<string, object>>(v, serializationOptions))
                    .Metadata
                    .SetValueComparer(valueComparer);

                entity.Property(p => p.Actions)
                .HasConversion(
                    v => JsonSerializer.Serialize(v, serializationOptions),
                   v => JsonSerializer.Deserialize<RuleActions>(v, serializationOptions));

                entity.Ignore(b => b.WorkflowsToInject);
            });
        }
    }

}


================================================
FILE: demo/DemoApp.EFDataExample/RulesEngineDemoContext.cs
================================================
using System;
using System.Collections.Generic;
using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using RulesEngine.Data;
using RulesEngine.Models;

namespace DemoApp.EFDataExample
{
    public class RulesEngineDemoContext : RulesEngineContext
    {
        public string DbPath { get; private set; }

        public RulesEngineDemoContext()
        {
            var folder = Environment.SpecialFolder.LocalApplicationData;
            var path = Environment.GetFolderPath(folder);
            DbPath = $"{path}{System.IO.Path.DirectorySeparatorChar}RulesEngineDemo.db";
        }
        protected override void OnConfiguring(DbContextOptionsBuilder options)
          => options.UseSqlite($"Data Source={DbPath}");

    }

}

================================================
FILE: deployment/build-signed.ps1
================================================
param(
    [Parameter(Mandatory)]
    [string] $csprojFilePath,
    [Parameter(Mandatory)]
    [string] $signingKey
)

# sign and build the project
$directory = Split-Path $csprojFilePath;
$signKeyFile = Join-Path $directory "signKey.snk";

$bytes = [Convert]::FromBase64String($signingKey)
[IO.File]::WriteAllBytes($signKeyFile, $bytes)

dotnet build $csprojFilePath -c Release -p:ContinuousIntegrationBuild=true -p:DelaySign=false -p:AssemblyOriginatorKeyFile=$signKeyFile 

================================================
FILE: docs/Getting-Started.md
================================================
## Getting Started with Rules Engine
RulesEngine is a library/NuGet package for abstracting rules and running the Rules Engine.

### Publicly accessible interfaces, models, methods and schemas
As with any library/package there are public interfaces with which we interact with that library/packages. There are a few public interfaces in this package as well. The interface which will be used to access this package is [IRulesEngine](#irulesengine), with four overloaded methods for executing rules. To understand the methods, we need to go through some of the models/schemas first. 

#### Rules
The rules used in this system is mostly comprising of [lambda expressions](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions). Anything that can be defined in a lambda expression can be used as a rule in this library.

#### Rules Schema
Rules schema is available in the [schema file](https://github.com/microsoft/RulesEngine/blob/main/schema/workflow-schema.json). The workflow rules are how we store the rules in the system. In our system, the name of the model typed in the library is [Workflow](https://github.com/microsoft/RulesEngine/blob/main/src/RulesEngine/Models/Workflow.cs). An example json would be – 

```json
[
  {
    "WorkflowName": "Discount",
    "Rules": [
      {
        "RuleName": "GiveDiscount10",
        "SuccessEvent": "10",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.country == \"india\" AND input1.loyalityFactor <= 2 AND input1.totalPurchasesToDate >= 5000 AND input2.totalOrders > 2 AND input3.noOfVisitsPerMonth > 2"
      },
      {
        "RuleName": "GiveDiscount20",
        "SuccessEvent": "20",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.country == \"india\" AND input1.loyalityFactor == 3 AND input1.totalPurchasesToDate >= 10000 AND input2.totalOrders > 2 AND input3.noOfVisitsPerMonth > 2"
      },
      {
        "RuleName": "GiveDiscount25",
        "SuccessEvent": "25",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.country != \"india\" AND input1.loyalityFactor >= 2 AND input1.totalPurchasesToDate >= 10000 AND input2.totalOrders > 2 AND input3.noOfVisitsPerMonth > 5"
      },
      {
        "RuleName": "GiveDiscount30",
        "SuccessEvent": "30",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.loyalityFactor > 3 AND input1.totalPurchasesToDate >= 50000 AND input1.totalPurchasesToDate <= 100000 AND input2.totalOrders > 5 AND input3.noOfVisitsPerMonth > 15"
      },
      {
        "RuleName": "GiveDiscount35",
        "SuccessEvent": "35",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.loyalityFactor > 3 AND input1.totalPurchasesToDate >= 100000 AND input2.totalOrders > 15 AND input3.noOfVisitsPerMonth > 25"
      }
    ]
  }
]
```

This workflow rules showcased in the above json is of a sample [Use Case](https://github.com/microsoft/RulesEngine/wiki/Use-Case) which is going to be used to explain the library. 
Demo App for the given use case is available at [this location](https://github.com/microsoft/RulesEngine/tree/main/demo).
#### Logger
Another public interface for custom logging is ILogger. This interface is not implemented and looks for custom implementation of the user who wants to use it. The methods available for this interface are – 
```c# 
void LogTrace(string msg);
void LogError(Exception ex);
```
These methods can be implemented in any logging mechanism that is expected and its instance can be injected into the Rules Engine as shown in [Initiating the Rules Engine](#initiating-the-rules-engine).
#### ReSettings
This model is a list of custom types. 
While, lambda expressions are quite powerful, there is a limit to what they can do because of the fact that the methods that a lambda expression can do are limited to [System namespace](https://docs.microsoft.com/en-us/dotnet/api/system) of [.Net framework](https://docs.microsoft.com/en-us/dotnet/framework/). 

To use more complex and custom classes and have some logics which are way too complex to be written into a lambda expression, these settings come into picture. If the user wants to create a custom method to run for the rule to be used, these settings help them. 

Example – 

You can create a public class called Utils and include a method in it which check contains in a list.
```c#
using System;
using System.Linq;

namespace RE.HelperFunctions
{
    public static class Utils
    {
        public static bool CheckContains(string check, string valList)
        {
            if (String.IsNullOrEmpty(check) || String.IsNullOrEmpty(valList))
                return false;

            var list = valList.Split(',').ToList();
            return list.Contains(check);
        }
    }
}
```
And this can be then used in lambda expression in a very simple manner like this – 
```json
"Expression": "Utils.CheckContains(input1.country, \"india,usa,canada,France\") == true"
```

To use the custom class when evaluating the rules:

1. Register the class
2. Then pass settings through rules engine
```csharp
var reSettingsWithCustomTypes = new ReSettings { CustomTypes = new Type[] { typeof(Utils) } };
new RulesEngine.RulesEngine(workflowRules.ToArray(), null, reSettingsWithCustomTypes);
```

#### RuleParameter
This is a model class for custom inputs which can be seen in the [RuleParameter Class](https://github.com/microsoft/RulesEngine/blob/main/src/RulesEngine/Models/RuleParameter.cs). This type is present to add another layer of customization to the rules. 

For example, the rules present in the example mentioned in the [Rules Schema](#rules-schema) section are using 3 different inputs for each run. The inputs are of different types as mentioned in the [Use Case]((https://github.com/microsoft/RulesEngine/wiki/Use-Case)) and is coming from different sources. Now, in rules we had to use input1, input2 and input3 to target data coming from the basic info, order info and telemetry info, respectively. 


With RuleParameter class, we can give context specific names to the rules in the list of rules instead of input1, input2 and input3. 

#### LocalParams

Rules Engine has a param (like ‘var’ in c#) feature support now, it makes authoring and troubleshooting of issues very easy. Now you can breakdown your bigger statements into smaller logical expressions as parameters within a rule definition.

Below is an example of a complex rule which can be authored easily using logical intermediate parameters and can be used to write the final rule expression to return a binary value. Sample rule requirement here is to provide access to a user only when user has completed some mandatory trainings or the user is accessing the site it from a secure domain. 

```
{
        "name": "allow_access_if_all_mandatory_trainings_are_done_or_access_isSecure",
        "errorMessage": "Please complete all your training(s) to get access to this content or access it from a secure domain/location.",
        "errorType": "Error",
        "localParams": [
          {
            "name": "completedSecurityTrainings",
            "expression": "MasterSecurityComplainceTrainings.Where(Status.Equals(\"Completed\", StringComparison.InvariantCultureIgnoreCase))"
          },
          {
            "name": "completedProjectTrainings",
            "expression": "MasterProjectComplainceTrainings.Where(Status.Equals(\"Completed\", StringComparison.InvariantCultureIgnoreCase))"
          },
          {
            "name": "isRequestAccessSecured",
            "expression": "UserRequestDetails.Location.Country == \"India\" ? ((UserRequestDetails.Location.City == \"Bangalore\" && UserRequestDetails.Domain=\"xxxx\")? true : false):false"
          }
        ],
        "expression": "(completedSecurityTrainings.Any() && completedProjectTrainings.Any()) || isRequestAccessSecured "
      }
 ```


#### RuleResultTree
[This model](https://github.com/microsoft/RulesEngine/blob/main/src/RulesEngine/Models/RuleResultTree.cs) is the output of the Rules Engine. Once the execution of the Rules Engine is completed and the Engine has gone through all the rules, a list of this type is returned. What this model include is – 
##### Rule
This is the rule that is currently being referred. It is of a custom model type and has information of that rule which ran on the input. 
##### IsSuccess
This is a Boolean value showcasing whether the given rule passed or not.
##### ChildResults
In the case, the rule has child rules, this variable gets initialized else it is null. This is a nested list of RuleResultTree type to showcase the response of the children rules.
##### Input
This is the input that was being checked upon while the rules were being verified on this object. In case of multiple inputs, it takes up the first input.


#### IRulesEngine
IRulesEngine is the main interface which is used to handle all the executions. This interface has four overloaded methods to execute rules – 
```c#
List<RuleResultTree> ExecuteRule(string workflowName, IEnumerable<dynamic> input, object[] otherInputs);
List<RuleResultTree> ExecuteRule(string workflowName, object[] inputs);
List<RuleResultTree> ExecuteRule(string workflowName, object input);
List<RuleResultTree> ExecuteRule(string workflowName, RuleParameter[] ruleParams);
```
One Rules Engine can take in multiple workflows and the workflows can be distributed based on the logic dictated by the system you are building.


In the first definition – 
* workflowName is the name of the workflow you want to take up.
* input is a list of dynamic inputs which is being entered. 
* otherInputs is an array of other auxiliary inputs which complement the inputs based on the rules present.


In the second definition – 
* workflowName is the name of the workflow you want to take up.
* input is an array of dynamic inputs which is being entered. 


In the third definition – 
* workflowName is the name of the workflow you want to take up.
* input is a single dynamic input which is being entered.


In the fourth definition – 
* workflowName is the name of the workflow you want to take up.
* ruleParams is an array of RuleParameters as explained in [RuleParameter](#ruleparameter). 

#### Initiating the Rules Engine
To initiate the Rules Engine instance to be used for executing rules, the workflow rules need to be injected into the library. The two different definitions of constructors are – 
```c#
public RulesEngine(string[] jsonConfig, ILogger logger, ReSettings reSettings = null) 
public RulesEngine(WorkflowRules[] workflowRules, ILogger logger, ReSettings reSettings = null)
```
Here, 
* jsonConfig is the list of serialized json strings following the schema mentioned in [Rules Schema](#rules-schema).
* logger is an instance of the logger created by you, following the information given in [Logger](#logger).
* reSettings is list of custom types as mention in [ReSettings](#resettings).
* workflowRules is a list of objects of type WorkflowRules which is mentioned in the [Rules Schema](#rules-schema).

#### Success/Failure
For the rules to make sense, there are always success and failure scenarios. This library gives the user an inbuilt scenario where in success and failure scenario an event can be created.
##### Success
In case of success, there could be one or more than one rules which passed based on the given input(s). The success event will be triggered and will be run based on the first rule which was true and give you the success event which was initialized as SuccessEvent in the RulesSchema section.


Example – 
```c#
List<RuleResultTree> resultList = bre.ExecuteRule("Discount", inputs);

resultList.OnSuccess((eventName) =>
{
discountOffered = $"Discount offered is {eventName} % over MRP.";
});
```
##### Failure
In case, none of the rules succeeded the failure event gets triggered. 

Example – 
```c#
List<RuleResultTree> resultList = bre.ExecuteRule("Discount", inputs);
resultList.OnFail(() =>
{
discountOffered = "The user is not eligible for any discount.";
});
```

### How to use Rules Engine
1.	To install this library, please download the latest version of  [NuGet Package](https://www.nuget.org/packages/RulesEngine/) from [nuget.org](https://www.nuget.org/) and refer it into your project. 
2.	Initiate the instance of Rules Engine as mentioned in [Initiating the Rules Engine](#initiating-the-rules-engine).
3.	Once done, the rules can be executed using any of the overloaded methods as explained in [IRulesEngine](#irulesengine) section. It returns the list of [RuleResultTree](#ruleresulttree) which can be used in any way the user wants to. 
4.	The success or failure events can be defined as explained in the [Success/Failure](#successfailure) section. 
    * Based on the rules and input the success or failure event can be triggered. 


================================================
FILE: docs/Home.md
================================================
## Welcome
Welcome to the RulesEngine Wiki!

The pages here are primarily intended for those who wish to contribute to the Rules Engine Project by suggesting new features or building extensions or submitting pull requests. 

This Wiki also includes a demo along with the explanation of different features of the project so that the using of the application can be easily understood. 

## About
Deep dive into the project code and the Wiki to find different features and workings of the project. 

Search for the solution or file a new issue in [GitHub](https://github.com/microsoft/RulesEngine/issues) if you find something broken in the code.

## Contributing
This project welcomes contributions and suggestions.  Most contributions require you to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.

When you submit a pull request, a CLA bot will automatically determine whether you need to provide
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.


================================================
FILE: docs/Introduction.md
================================================
## What is the Rules Engine
While building any application, the crux or the core part of it is always business logic or business rules. And as with any application, there always comes a time when some or a lot of the rules or policies change in the system. But with that change, comes a lot of rework like changing design or creating a new module altogether to code in the changes in the rules, regression testing, performance testing etc. The rework along with debugging if required amounts to a lot of unnecessary work which can otherwise be utilized for other work, thus reducing the engineering cycle by drastic amounts.  

In this library, we have abstracted the rules so that the core logic is always maintained while the rules change can happen in an easy way without changing the code base. Also, the input to the system is dynamic in nature so the model need not be defined in the system. It can be sent as an expando object or any other typed object and the system will be able to handle it. 

These all features make this library highly configurable and extensible as shown in [Getting Started with Rules Engine](https://github.com/microsoft/RulesEngine/wiki/Getting-Started).


### How it works

![](https://github.com/microsoft/RulesEngine/blob/main/assets/BlockDiagram.png)

Here. there are multiple actors/component involved.
##### Rules Engine
This component is the Rules Engine library/NuGet package being referenced by the developer.
##### Rules Store
As shown in [Rules Schema](https://github.com/microsoft/RulesEngine/wiki/Getting-Started#rules-schema), we need rules in a particular format for the library to work. While the rules structure is rigid, the data itself can be stored in any component and can be accessed in any form the developer chooses. It can be stored in the form of json files in file structure or blob, or as documents in cosmos db, or any database, azure app configuration or any other place the developer thinks is going to be appropriate based on the project requirements. 
##### Input
The input(s) for the system can be taken from any place as well like user input, blobs, databases, service bus or any other system. 
##### Wrapper
This library sits as a black box outside the project as a referenced project or NuGet package. Then the user can create a wrapper around the library, which will get the rules from the rules store and convert it into the WorkFlowRules structure and send it to the RulesEngine along with the input(s). The RulesEngine then computes and give the information to the wrapper and the wrapper can then do whatever the logic demands with the output information.



================================================
FILE: docs/Use-Case.md
================================================
## Use Case
The use case for demo purposes used here is explained as follows. The system we are designing is an e-commerce discount calculation system. 

### Rules
The rules for the discount calculation are –

1.	Give the user a discount of 10% over MRP if the following conditions are followed – 
    * The user’s country is India.
    * The user’s loyalty factor is less than or equal to 2.
    * All the orders purchased by the user so far should amount to more than 5,000.
    * User should have at least made more than two successful orders. 
    * The user should have visited the site more than two times every month.
2.	Give the user a discount of 20% over MRP if the following conditions are followed – 
    * The user’s country is India.
    * The user’s loyalty factor is equal to 3.
    * All the orders purchased by the user so far should amount to more than 10,000.
    * User should have at least made more than two successful orders. 
    * The user should have visited the site more than two times every month.
3.	Give the user a discount of 25% over MRP if the following conditions are followed – 
    * The user’s country is not India.
    * The user’s loyalty factor is greater than or equal to 2.
    * All the orders purchased by the user so far should amount to more than 10,000.
    * User should have at least made more than two successful orders. 
    * The user should have visited the site more than five times every month.
4.	Give the user a discount of 30% over MRP if the following conditions are followed – 
    * The user’s loyalty factor is greater than 3.
    * All the orders purchased by the user so far should amount to more than 50,000 but less than 100,000.
    * User should have at least made more than five successful orders. 
    * The user should have visited the site more than fifteen times every month.
5.	Give the user a discount of 30% over MRP if the following conditions are followed – 
    * The user’s loyalty factor is greater than 3.
    * All the orders purchased by the user so far should amount to more than 100,000.
    * User should have at least made more than fifteen successful orders. 
    * The user should have visited the site more than 25 times every month.
6.	Give 0% discount in any other case.

### Inputs
Here the inputs will be of three different types as they are coming from three different data sources/APIs. 
#### User Basic Info
This input has information like –
* Name
* Country
* Email
* Credit history
* Loyalty factor
* Sum of the purchases made by the user till date.

#### Users Order Information
This input is a summarization of the orders made by the user so far. This input has information like – 
* Total number of orders
* Recurring items in those orders if any

#### Users Telemetry Information
This input is a summarization of the telemetry information collected based on the user’s visit to the site. This input has information like – 
* Number of visits to the site per month
* Percentage of the number of times the user purchased something to the number of times the user visited


================================================
FILE: docs/_Sidebar.md
================================================
[Home](https://github.com/microsoft/RulesEngine/wiki)
* [Welcome](https://github.com/microsoft/RulesEngine/wiki#welcome)
* [About](https://github.com/microsoft/RulesEngine/wiki#about)
* [Contributing](https://github.com/microsoft/RulesEngine/wiki#contributing)

[Introduction](https://github.com/microsoft/RulesEngine/wiki/Introduction)
* [What is the Rules Engine](https://github.com/microsoft/RulesEngine/wiki/Introduction#what-is-the-rules-engine)
  * [How it works](https://github.com/microsoft/RulesEngine/wiki/Introduction#how-it-works) 
    * [Rules Engine](https://github.com/microsoft/RulesEngine/wiki/Introduction#rules-engine)
    * [Rules Store](https://github.com/microsoft/RulesEngine/wiki/Introduction#rules-store)
    * [Input](https://github.com/microsoft/RulesEngine/wiki/Introduction#input)
    * [Wrapper](https://github.com/microsoft/RulesEngine/wiki/Introduction#wrapper)

[Getting Started](https://github.com/microsoft/RulesEngine/wiki/Getting-Started) 
* [Getting Started with Rules Engine](https://github.com/microsoft/RulesEngine/wiki/Getting-Started#getting-started-with-rules-engine)
  * [Publicly accessible interfaces, models, methods and schemas](https://github.com/microsoft/RulesEngine/wiki/Getting-Started#publicly-accessible-interfaces-models-methods-and-schemas) 
    * [Rules](https://github.com/microsoft/RulesEngine/wiki/Getting-Started#rules)
    * [Rules Schema](https://github.com/microsoft/RulesEngine/wiki/Getting-Started#rules-schema)
    * [Logger](https://github.com/microsoft/RulesEngine/wiki/Getting-Started#logger)
    * [ReSettings](https://github.com/microsoft/RulesEngine/wiki/Getting-Started#resettings)
    * [LocalParams](https://github.com/microsoft/RulesEngine/wiki/Getting-Started#localparams)
    * [RuleParameter](https://github.com/microsoft/RulesEngine/wiki/Getting-Started#ruleparameter)
    * [RuleResultTree](https://github.com/microsoft/RulesEngine/wiki/Getting-Started#ruleresulttree)
    * [IRulesEngine](https://github.com/microsoft/RulesEngine/wiki/Getting-Started#irulesengine)
    * [Initiating the Rules Engine](https://github.com/microsoft/RulesEngine/wiki/Getting-Started#initiating-the-rules-engine)
    * [Success/Failure](https://github.com/microsoft/RulesEngine/wiki/Getting-Started#successfailure)
  * [How to use Rules Engine](https://github.com/microsoft/RulesEngine/wiki/Getting-Started#how-to-use-rules-engine) 

[Use Case](https://github.com/microsoft/RulesEngine/wiki/Use-Case)
* [Use Case](https://github.com/microsoft/RulesEngine/wiki/Use-Case#use-case)
  * [Rules](https://github.com/microsoft/RulesEngine/wiki/Use-Case#rules)
  * [Inputs](https://github.com/microsoft/RulesEngine/wiki/Use-Case#inputs)
    * [User Basic Info](https://github.com/microsoft/RulesEngine/wiki/Use-Case#user-basic-info)
    * [Users Order Information](https://github.com/microsoft/RulesEngine/wiki/Use-Case#users-order-information)
    * [Users Telemetry Information](https://github.com/microsoft/RulesEngine/wiki/Use-Case#users-telemetry-information)

================================================
FILE: docs/_config.yml
================================================
theme: jekyll-theme-cayman

================================================
FILE: docs/index.md
================================================
RulesEngine is a highly extensible library to build rule based system using C# expressions


**Features**
- Json based rules definition
- Multiple input support
- Dynamic object input support
- C# Expression support
- Extending expression via custom class/type injection
- Scoped parameters
- Post rule execution actions
- Standalone expression evaluator

**Table Of Content**
- [Installation](#installation)
- [Basic Usage](#basic-usage)
  - [Create a workflow file with rules](#create-a-workflow-file-with-rules)
  - [Initialise RulesEngine with the workflow:](#initialise-rulesengine-with-the-workflow)
  - [Execute the workflow rules with input:](#execute-the-workflow-rules-with-input)
  - [Using custom names for inputs](#using-custom-names-for-inputs)
- [C# Expression support](#c-expression-support)
- [Extending expression via custom class/type injection](#extending-expression-via-custom-classtype-injection)
  - [Example](#example)
- [ScopedParams](#scopedparams)
  - [GlobalParams](#globalparams)
    - [Example](#example-1)
  - [LocalParams](#localparams)
    - [Example](#example-2)
  - [Referencing ScopedParams in other ScopedParams](#referencing-scopedparams-in-other-scopedparams)
- [Post rule execution actions](#post-rule-execution-actions)
  - [Inbuilt Actions](#inbuilt-actions)
    - [OutputExpression](#outputexpression)
      - [Usage](#usage)
    - [EvaluateRule](#evaluaterule)
      - [Usage](#usage-1)
  - [Custom Actions](#custom-actions)
    - [Steps to use a custom Action](#steps-to-use-a-custom-action)
- [Standalone Expression Evaluator](#standalone-expression-evaluator)
  - [Usage](#usage-2)
- [Settings](#settings)
  - [NestedRuleExecutionMode](#nestedruleexecutionmode)



## Installation
Nuget package: [![nuget](https://img.shields.io/nuget/dt/RulesEngine)](https://www.nuget.org/packages/RulesEngine/)

## Basic Usage
### Create a workflow file with rules
```json
[
  {
    "WorkflowName": "Discount",
    "Rules": [
      {
        "RuleName": "GiveDiscount10",
        "Expression": "input1.country == \"india\" AND input1.loyalityFactor <= 2 AND input1.totalPurchasesToDate >= 5000 AND input2.totalOrders > 2 AND input3.noOfVisitsPerMonth > 2"
      },
      {
        "RuleName": "GiveDiscount20",
        "Expression": "input1.country == \"india\" AND input1.loyalityFactor == 3 AND input1.totalPurchasesToDate >= 10000 AND input2.totalOrders > 2 AND input3.noOfVisitsPerMonth > 2"
      }
    ]
  }
] 
```

### Initialise RulesEngine with the workflow:
```c#
var workflowRules = //Get list of workflow rules declared in the json
var re = new RulesEngine.RulesEngine(workflowRules);
```

### Execute the workflow rules with input:
```c#
// Declare input1,input2,input3 
var resultList  = await re.ExecuteAllRulesAsync("Discount", input1,input2,input3);

//Check success for rule
foreach(var result in resultList){
  Console.WriteLine($"Rule - {result.Rule.RuleName}, IsSuccess - {result.IsSuccess}");
}
```
This will execute all the rules under `Discount` workflow and return ruleResultTree for all rules

**Note: input passed to rulesEngine can be of a concrete type, an anonymous type or dynamic(Expandobject). In case of dynamic object, RulesEngine will internally convert to an anonymous type**

### Using custom names for inputs
By Default, RulesEngine will name the inputs as input1, input2, input3... respectively.
It is possible to use a custom name in rules by passing input as `RuleParameter`
```json
[
  {
    "WorkflowName": "DiscountWithCustomInputNames",
    "Rules": [
      {
        "RuleName": "GiveDiscount10",
        "Expression": "basicInfo.country == \"india\" AND basicInfo.loyalityFactor <= 2 AND basicInfo.totalPurchasesToDate >= 5000 AND orderInfo.totalOrders > 2 AND telemetryInfo.noOfVisitsPerMonth > 2"
      },
      {
        "RuleName": "GiveDiscount20",
        "Expression": "basicInfo.country == \"india\" AND basicInfo.loyalityFactor == 3 AND basicInfo.totalPurchasesToDate >= 10000 AND orderInfo.totalOrders > 2 AND telemetryInfo.noOfVisitsPerMonth > 2"
      }
    ]
  }
] 

```
Now we can call rulesEngine with the custom names:
```c#
var workflowRules = //Get list of workflow rules declared in the json
var re = new RulesEngine.RulesEngine(workflowRules);


// Declare input1,input2,input3 

var rp1 = new RuleParameter("basicInfo",input1);
var rp2 = new RuleParameter("orderInfo", input2);
var rp3 = new RuleParameter("telemetryInfo",input3);

var resultList  = await re.ExecuteAllRulesAsync("DiscountWithCustomInputNames",rp1,rp2,rp3);

```

## C# Expression support
The lambda expression allows you to use most of C# constructs and along with some of linq features.

For more details on supported expression language refer - [expression language](https://dynamic-linq.net/expression-language)

For supported linq operations refer - [sequence operators](https://dynamic-linq.net/expression-language#sequence-operators)


## Extending expression via custom class/type injection
Although RulesEngine supports C# expressions, you may need to perform more complex operation.

RulesEngine supports injecting custom classes/types via `ReSettings` which can allow you to call properties and methods of your custom class in expressions

### Example
Create a custom static class
```c#
using System;
using System.Linq;

namespace RE.HelperFunctions
{
    public static class Utils
    {
        public static bool CheckContains(string check, string valList)
        {
            if (String.IsNullOrEmpty(check) || String.IsNullOrEmpty(valList))
                return false;

            var list = valList.Split(',').ToList();
            return list.Contains(check);
        }
    }
}
```

Add it in your ReSettings and pass in RulesEngine constructor

```c#
  var reSettings = new ReSettings{
      CustomTypes = new Type[] { typeof(Utils) }
  };

  var rulesEngine = new RulesEngine.RulesEngine(workflowRules,reSettings);
```

With this you can call Utils class in your Rules

```json
{
    "WorkflowName": "DiscountWithCustomInputNames",
    "Rules": [
      {
        "RuleName": "GiveDiscount10",
        "Expression": "Utils.CheckContains(input1.country, \"india,usa,canada,France\") == true"
      }
    ]
}

```


## ScopedParams
Sometimes Rules can get very long and complex, scopedParams allow users to replace an expression in rule with an alias making it easier to maintain rule.

RulesEngine supports two type of ScopedParams:
- GlobalParams
- LocalParams


### GlobalParams
GlobalParams are defined at workflow level and can be used in any rule.

#### Example

```jsonc
//Rule.json
{
  "WorkflowName": "workflowWithGlobalParam",
  "GlobalParams":[
    {
      "Name":"myglobal1",
      "Expression":"myInput.hello.ToLower()"
    }
  ],
  "Rules":[
    {
      "RuleName": "checkGlobalEqualsHello",
      "Expression":"myglobal1 == \"hello\""
    },
    {
      "RuleName": "checkGlobalEqualsInputHello",
      "Expression":"myInput.hello.ToLower() == myglobal1"
    }
  ]
}
```

These rules when executed with the below input will return success
```c#
  var input = new RuleParameter("myInput",new {
    hello = "HELLO"
  });

  var resultList  = await re.ExecuteAllRulesAsync("workflowWithGlobalParam",rp);


```


### LocalParams
LocalParams are defined at rule level and can be used by the rule and its child rules

#### Example

```jsonc
//Rule.json
{
  "WorkflowName": "workflowWithLocalParam",
  
  "Rules":[
    {
      "RuleName": "checkLocalEqualsHello",
      "LocalParams":[
        {
          "Name":"mylocal1",
          "Expression":"myInput.hello.ToLower()"
        }
      ],
      "Expression":"mylocal1 == \"hello\""
    },
    {
      "RuleName": "checkLocalEqualsInputHelloInNested",
      "LocalParams":[
        {
          "Name":"mylocal1", //redefined here as it is scoped at rule level
          "Expression":"myInput.hello.ToLower()"
        }
      ],
      "Operator": "And",
      "Rules":[
        {
          "RuleName": "nestedRule",
          "Expression":"myInput.hello.ToLower() == mylocal1" //mylocal1 can be used here since it is nested to Rule where mylocal1 is defined
        }
      ]
      
    }
  ]
}
```

These rules when executed with the below input will return success
```c#
  var rp = new RuleParameter("myInput",new {
    hello = "HELLO"
  });

  var resultList  = await re.ExecuteAllRulesAsync("workflowWithLocalParam",rp);
```

### Referencing ScopedParams in other ScopedParams

Similar to how ScopedParams can be used in expressions, they can also be used in other scoped params that come after them.
This allows us to create multi-step rule which is easier to read and maintain


```jsonc
//Rule.json
{
  "WorkflowName": "workflowWithReferencedRule",
  "GlobalParams":[
    {
      "Name":"myglobal1",
      "Expression":"myInput.hello"
    }
  ],
  "Rules":[
    {
      "RuleName": "checkGlobalAndLocalEqualsHello",
      "LocalParams":[
        {
          "Name": "mylocal1",
          "Expression": "myglobal1.ToLower()"
        }
      ],
      "Expression":"mylocal1 == \"hello\""
    },
    {
      "RuleName": "checklocalEqualsInputHello",
       "LocalParams":[
        {
          "Name": "mylocal1",
          "Expression": "myglobal1.ToLower()"
        },
        {
          "Name": "mylocal2",
          "Expression": "myInput.hello.ToLower() == mylocal1"
        }
      ],
      "Expression":"mylocal2 == true"
    }
  ]
}
```

These rules when executed with the below input will return success
```c#
  var input = new RuleParameter("myInput",new {
    hello = "HELLO"
  });

  var resultList  = await re.ExecuteAllRulesAsync("workflowWithReferencedRule",rp);


```

## Post rule execution actions
As a part of v3, Actions have been introduced to allow custom code execution on rule result. This can be achieved by calling `ExecuteAllRulesAsync` method of RulesEngine

### Inbuilt Actions
RulesEngine provides inbuilt action which cover major scenarios related to rule execution

#### OutputExpression
This action evaluates an expression based on the RuleParameters and returns its value as Output
##### Usage
Define OnSuccess or OnFailure Action for your Rule:
```jsonc
{
  "WorkflowName": "inputWorkflow",
  "Rules": [
    {
      "RuleName": "GiveDiscount10Percent",
      "SuccessEvent": "10",
      "ErrorMessage": "One or more adjust rules failed.",
      "ErrorType": "Error",
      "RuleExpressionType": "LambdaExpression",
      "Expression": "input1.couy == \"india\" AND input1.loyalityFactor <= 2 AND input1.totalPurchasesToDate >= 5000 AND input2.totalOrders > 2 AND input2.noOfVisitsPerMonth > 2",
      "Actions": {
         "OnSuccess": {
            "Name": "OutputExpression",  //Name of action you want to call
            "Context": {  //This is passed to the action as action context
               "Expression": "input1.TotalBilled * 0.9"
            }
         }
      }
    }
  ]
}
```
Call `ExecuteAllRulesAsync` with the workflowName, ruleName and ruleParameters
```c#
   var ruleResultList = await rulesEngine.ExecuteAllRulesAsync("inputWorkflow",ruleParameters);
   foreach(var ruleResult in ruleResultList){
      if(ruleResult.ActionResult != null){
          Console.WriteLine(ruleResult.ActionResult.Output); //ActionResult.Output contains the evaluated value of the action
      }
   }
   
```

#### EvaluateRule
This action allows chaining of rules along with their actions. It also supports filtering inputs provided to chained rule as well as providing custom inputs

##### Usage
Define OnSuccess or OnFailure Action for your Rule:
```jsonc
{
  "WorkflowName": "inputWorkflow",
  "Rules": [
    {
        "RuleName": "GiveDiscount20Percent",
        "Expression": "input1.couy == \"india\" AND input1.loyalityFactor <= 5 AND input1.totalPurchasesToDate >= 20000",
        "Actions": {
           "OnSuccess": {
              "Name": "OutputExpression",  //Name of action you want to call
              "Context": {  //This is passed to the action as action context
                 "Expression": "input1.TotalBilled * 0.8"
              }
           },
           "OnFailure": { // This will execute if the Rule evaluates to failure
               "Name": "EvaluateRule",
               "Context": {
                   "workflowName": "inputWorkflow",
                   "ruleName": "GiveDiscount10Percent"
               }
           }
        }
    },
    {
      "RuleName": "GiveDiscount10Percent",
      "SuccessEvent": "10",
      "ErrorMessage": "One or more adjust rules failed.",
      "ErrorType": "Error",
      "RuleExpressionType": "LambdaExpression",
      "Expression": "input1.couy == \"india\" AND input1.loyalityFactor <= 2 AND input1.totalPurchasesToDate >= 5000 AND input2.totalOrders > 2 AND input2.noOfVisitsPerMonth > 2",
      "Actions": {
         "OnSuccess": {
            "Name": "OutputExpression",  //Name of action you want to call
            "Context": {  //This is passed to the action as action context
               "Expression": "input1.TotalBilled * 0.9"
            }
         }
      }
    }
  ]
}
```
Call `ExecuteActionWorkflowAsync` with the workflowName, ruleName and ruleParameters
```c#
   var result = await rulesEngine.ExecuteActionWorkflowAsync("inputWorkflow","GiveDiscount20Percent",ruleParameters);
   Console.WriteLine(result.Output); //result.Output contains the evaluated value of the action
```

In the above scenario if `GiveDiscount20Percent` succeeds, it will return 20 percent discount in output. If it fails, `EvaluateRule` action will call `GiveDiscount10Percent` internally and if it succeeds, it will return 10 percent discount in output.

EvaluateRule also supports passing filtered inputs and computed inputs to chained rule
```jsonc
 "Actions": {
         "OnSuccess": {
            "Name": "EvaluateRule",
               "Context": {
                   "workflowName": "inputWorkflow",
                   "ruleName": "GiveDiscount10Percent",
                   "inputFilter": ["input2"], //will only pass input2 from existing inputs,scopedparams to the chained rule
                   "additionalInputs":[ // will pass a new input named currentDiscount with the result of the expression to the chained rule
                     {
                       "Name": "currentDiscount",
                       "Expression": "input1.TotalBilled * 0.9"
                     }
                   ]
               }
         }
      }

```


### Custom Actions
RulesEngine allows registering custom actions which can be used in the rules workflow.

#### Steps to use a custom Action
1. Create a class which extends `ActionBase` class and implement the run method
```c#
 public class MyCustomAction: ActionBase
    {
     
        public MyCustomAction(SomeInput someInput)
        {
            ....
        }

        public override ValueTask<object> Run(ActionContext context, RuleParameter[] ruleParameters)
        {
            var customInput = context.GetContext<string>("customContextInput");
            //Add your custom logic here and return a ValueTask
        }
```
Actions can have async code as well
```c#
 public class MyCustomAction: ActionBase
    {
     
        public MyCustomAction(SomeInput someInput)
        {
            ....
        }

        public override async ValueTask<object> Run(ActionContext context, RuleParameter[] ruleParameters)
        {
            var customInput = context.GetContext<string>("customContextInput");
            //Add your custom logic here
            return await MyCustomLogicAsync();
        }
```
2. Register them in ReSettings and pass it to RulesEngine
```c#
   var reSettings = new ReSettings{
                        CustomActions = new Dictionary<string, Func<ActionBase>>{
                                             {"MyCustomAction", () => new MyCustomAction(someInput) }
                                         }
                     };

   var re = new RulesEngine(workflowRules,reSettings);
```
3. You can now use the name you registered in the Rules json in success or failure actions
```jsonc
{
  "WorkflowName": "inputWorkflow",
  "Rules": [
    {
      "RuleName": "GiveDiscount10Percent",
      "SuccessEvent": "10",
      "ErrorMessage": "One or more adjust rules failed.",
      "ErrorType": "Error",
      "RuleExpressionType": "LambdaExpression",
      "Expression": "input1.couy == \"india\" AND input1.loyalityFactor <= 2 AND input1.totalPurchasesToDate >= 5000 AND input2.totalOrders > 2 AND input2.noOfVisitsPerMonth > 2",
      "Actions": {
         "OnSuccess": {
            "Name": "MyCustomAction",  //Name context
            "Context": {  //This is passed to the action as action context
               "customContextInput": "input1.TotalBilled * 0.9"
            }
         }
      }
    }
  ]
}
```

## Standalone Expression Evaluator
If you are not looking for a full fledged RulesEngine and need only an expression evaluator. RulesEngine offers `RuleExpressionParser` which handles expression parsing and evaluation.

### Usage
```c#
using System;
using RulesEngine.Models;
using RulesEngine.ExpressionBuilders;
					
public class Program
{
	public static void Main()
	{
		var reParser = new RuleExpressionParser(new ReSettings());
		var result = reParser.Evaluate<string>("a+b", new RuleParameter[]{
			new RuleParameter("a","Hello "),
			new RuleParameter("b","World")
		});
		Console.WriteLine(result);
	}
}
```
This will output "Hello World"

For more advanced usage, refer - https://dotnetfiddle.net/KSX8i0

## Settings
RulesEngine allows you to pass optional `ReSettings` in constructor to specify certain configuration for RulesEngine.

Here are the all the options available:-


| Property | Type | Default Value | Description |
| --- | --- | --- | --- |
| `CustomTypes` | `Type[]` | N/A | Custom types to be used in rule expressions. |
| `CustomActions` | `Dictionary<string, Func<ActionBase>>` | N/A | Custom actions that can be used in the rules. |
| `EnableExceptionAsErrorMessage` | `bool` | `true` | If `true`, returns any exception occurred while rule execution as an error message. Otherwise, throws an exception. This setting is only applicable if `IgnoreException` is set to `false`. |
| `IgnoreException` | `bool` | `false` | If `true`, it will ignore any exception thrown with rule compilation/execution. |
| `EnableFormattedErrorMessage` | `bool` | `true` | Enables error message formatting. |
| `EnableScopedParams` | `bool` | `true` | Enables global parameters and local parameters for rules. |
| `IsExpressionCaseSensitive` | `bool` | `false` | Sets whether expressions are case sensitive. |
| `AutoRegisterInputType` | `bool` | `true` | Auto registers input type in custom type to allow calling method on type. |
| `NestedRuleExecutionMode` | `NestedRuleExecutionMode` | `All` | Sets the mode for nested rule execution. |
| `CacheConfig` | `MemCacheConfig` | N/A | Configures the memory cache. |
| `UseFastExpressionCompiler` | `bool` | `true` | Whether to use FastExpressionCompiler for rule compilation. |


### NestedRuleExecutionMode 

| Value | Description |
| --- | --- |
| `All` | Executes all nested rules. |
| `Performance` | Skips nested rules whose execution does not impact parent rule's result. |


================================================
FILE: global.json
================================================
{
  "sdk": {
    "version": "9.0.301",
    "rollForward": "latestFeature",
    "allowPrerelease": false
  }
}

================================================
FILE: schema/workflow-list-schema.json
================================================
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "array",
  "items": {
    "$ref": "https://raw.githubusercontent.com/microsoft/RulesEngine/main/schema/workflow-schema.json"
  }
}

================================================
FILE: schema/workflow-schema.json
================================================
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "definitions": {
    "ScopedParam": {
      "type": "object",
      "properties": {
        "Name": { "type": "string" },
        "Expression": { "type": "string" }
      },
      "required": [ "Name", "Expression" ]
    },
    "Rule": {
      "title": "Rule",
      "properties": {
        "RuleName": {
          "type": "string"
        },
        "LocalParams": {
          "type": "array",
          "items": { "$ref": "#/definitions/ScopedParam" }
        },
        "Operator": {
          "enum": [
            "And",
            "AndAlso",
            "Or",
            "OrElse"
          ]
        },
        "ErrorMessage": {
          "type": "string"
        },
        "SuccessEvent": {
          "type": "string"
        },
        "Rules": {
          "type": "array",
          "items": {
            "anyOf": [
              {
                "$ref": "#/definitions/LeafRule"
              },
              {
                "$ref": "#/definitions/Rule"
              }
            ]
          }
        },
        "Properties": {
          "type": "object"
        },
        "Actions": {
          "$ref": "#/definitions/RuleActions"
        },
        "Enabled": {
          "type": "boolean",
          "default": true
        }
      },
      "required": [
        "RuleName",
        "Operator",
        "Rules"
      ],
      "type": "object"
    },
    "LeafRule": {
      "title": "Leaf Rule",
      "type": "object",
      "required": [
        "RuleName",
        "Expression"
      ],
      "properties": {
        "RuleName": {
          "type": "string"
        },
        "LocalParams": {
          "type": "array",
          "items": { "$ref": "#/definitions/ScopedParam" }
        },
        "Expression": {
          "type": "string"
        },
        "RuleExpressionType": {
          "enum": [
            "LambdaExpression"
          ]
        },
        "ErrorMessage": {
          "type": "string"
        },
        "SuccessEvent": {
          "type": "string"
        },
        "Properties": {
          "type": "object"
        },
        "Actions": {
          "$ref": "#/definitions/RuleActions"
        },
        "Enabled": {
          "type": "boolean",
          "default": true
        }
      }
    },
    "ActionInfo": {
      "properties": {
        "Name": {
          "type": "string"
        },
        "Context": {
          "type": "object"
        }
      },
      "required": [
        "Name"
      ]
    },
    "RuleActions": {
      "properties": {
        "OnSuccess": {
          "$ref": "#/definitions/ActionInfo"
        },
        "OnFailure": {
          "$ref": "#/definitions/ActionInfo"
        }
      }
    }

  },
  "properties": {
    "WorkflowName": {
      "type": "string"
    },
    "WorkflowsToInject": {
      "type": "array",
      "items": { "type": "string" }
    },
    "GlobalParams": {
      "type": "array",
      "items": { "$ref": "#/definitions/ScopedParam" }
    },
    "Rules": {
      "type": "array",
      "items": {
        "anyOf": [
          {
            "$ref": "#/definitions/LeafRule"
          },
          {
            "$ref": "#/definitions/Rule"
          }
        ]
      }
    }
  },
  "required": [
    "WorkflowName",
    "Rules"
  ],
  "type": "object"
}


================================================
FILE: scripts/check-coverage.ps1
================================================
param(
    [Parameter(Mandatory=$true)][string] $reportPath,
    [Parameter(Mandatory=$true)][decimal] $threshold
)


[XML]$report = Get-Content $reportPath;
[decimal]$coverage = [decimal]$report.coverage.'line-rate' * 100;

if ($coverage -lt $threshold) {
  Write-Error "Coverage($coverage) is less than $threshold percent"
  exit 1
}
else{
    Write-Host "Coverage($coverage) is more than $threshold percent"
}


================================================
FILE: scripts/generate-coverage-report.ps1
================================================
dotnet tool restore
dotnet reportgenerator "-reports:**/coverage.cobertura.xml" "-targetdir:coveragereport" -reporttypes:"Html;lcov;Cobertura"

================================================
FILE: src/RulesEngine/Actions/ActionBase.cs
================================================
// Copyright (c) Microsoft Corporation.
//  Licensed under the MIT License.

using RulesEngine.Models;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace RulesEngine.Actions
{
    public abstract class ActionBase
    {
        internal async virtual ValueTask<ActionRuleResult> ExecuteAndReturnResultAsync(ActionContext context, RuleParameter[] ruleParameters, bool includeRuleResults = false)
        {
            var result = new ActionRuleResult();
            try
            {
                result.Output = await Run(context, ruleParameters);
            }
            catch (Exception ex)
            {
                result.Exception = new Exception($"Exception while executing {GetType().Name}: {ex.Message}", ex);
            }
            finally
            {
                if (includeRuleResults)
                {
                    result.Results = new List<RuleResultTree>()
                    {
                        context.GetParentRuleResult()
                    };
                }
            }
            return result;
        }
        public abstract ValueTask<object> Run(ActionContext context, RuleParameter[] ruleParameters);
    }
}


================================================
FILE: src/RulesEngine/Actions/ActionContext.cs
================================================
// Copyright (c) Microsoft Corporation.
//  Licensed under the MIT License.

using RulesEngine.Models;
using System;
using System.Collections.Generic;

namespace RulesEngine.Actions
{
    using System.Text.Json;

    public class ActionContext
    {
        private readonly IDictionary<string, string> _context;
        private readonly RuleResultTree _parentResult;

        public ActionContext(IDictionary<string, object> context, RuleResultTree parentResult)
        {
            _context = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            foreach (var kv in context)
            {
                string key = kv.Key;
                string value;
                switch (kv.Value.GetType().Name)
                {
                    case "String":
                    case "JsonElement":
                        value =  kv.Value.ToString();
                        break;
                    default:
                        value = JsonSerializer.Serialize(kv.Value);
                        break;

                }
                _context.Add(key, value);
            }
            _parentResult = parentResult;
        }

        public RuleResultTree GetParentRuleResult()
        {
            return _parentResult;
        }

        public bool TryGetContext<T>(string name,out T output)
        {
            try
            {
                //key not found return
                //Returning a KeyNotFoundException has a significant impact on performance.
                if (!_context.ContainsKey(name))
                {
                    output = default(T);
                    return false;
                }
                output =  GetContext<T>(name);
                return true;
            }
            catch(ArgumentException)
            {
                output = default(T);
                return false;
            }
        }

        public T GetContext<T>(string name)
        {
            try
            {
                if (typeof(T) == typeof(string))
                {
                    return (T)Convert.ChangeType(_context[name], typeof(T));
                }
                return JsonSerializer.Deserialize<T>(_context[name]);
            }
            catch (KeyNotFoundException)
            {
                throw new ArgumentException($"Argument `{name}` was not found in the action context");
            }
            catch (JsonException)
            {
                throw new ArgumentException($"Failed to convert argument `{name}` to type `{typeof(T).Name}` in the action context");
            }
        }
    }
}


================================================
FILE: src/RulesEngine/Actions/ActionFactory.cs
================================================
// Copyright (c) Microsoft Corporation.
//  Licensed under the MIT License.

using System;
using System.Collections.Generic;

namespace RulesEngine.Actions
{
    internal class ActionFactory
    {
        private readonly IDictionary<string, Func<ActionBase>> _actionRegistry;

        internal ActionFactory()
        {
            _actionRegistry = new Dictionary<string, Func<ActionBase>>(StringComparer.OrdinalIgnoreCase);
        }
        internal ActionFactory(IDictionary<string, Func<ActionBase>> actionRegistry) : this()
        {
            foreach (var kv in actionRegistry)
            {
                _actionRegistry.Add(kv.Key, kv.Value);
            }
        }

        internal ActionBase Get(string name)
        {
            if (_actionRegistry.ContainsKey(name))
            {
                return _actionRegistry[name]();
            }
            throw new KeyNotFoundException($"Action with name: {name} does not exist");
        }
    }
}


================================================
FILE: src/RulesEngine/Actions/EvaluateRuleAction.cs
================================================
// Copyright (c) Microsoft Corporation.
//  Licensed under the MIT License.

using RulesEngine.ExpressionBuilders;
using RulesEngine.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace RulesEngine.Actions
{
    public class EvaluateRuleAction : ActionBase
    {
        private readonly RulesEngine _ruleEngine;
        private readonly RuleExpressionParser _ruleExpressionParser;

        public EvaluateRuleAction(RulesEngine ruleEngine, RuleExpressionParser ruleExpressionParser)
        {
            _ruleEngine = ruleEngine;
            _ruleExpressionParser = ruleExpressionParser;
        }

        internal async override ValueTask<ActionRuleResult> ExecuteAndReturnResultAsync(ActionContext context, RuleParameter[] ruleParameters, bool includeRuleResults = false)
        {
            var innerResult = await base.ExecuteAndReturnResultAsync(context, ruleParameters, includeRuleResults);
            var output = innerResult.Output as ActionRuleResult;
            List<RuleResultTree> resultList = null;
            if (includeRuleResults)
            {
                resultList = new List<RuleResultTree>(output?.Results ?? new List<RuleResultTree>() { });
                resultList.AddRange(innerResult.Results);
            }
            return new ActionRuleResult {
                Output = output?.Output,
                Exception = innerResult.Exception,
                Results = resultList
            };
        }

        public async override ValueTask<object> Run(ActionContext context, RuleParameter[] ruleParameters)
        {
            var workflowName = context.GetContext<string>("workflowName");
            var ruleName = context.GetContext<string>("ruleName");
            var filteredRuleParameters = new List<RuleParameter>(ruleParameters);
            if(context.TryGetContext<List<string>>("inputFilter",out var inputFilter))
            {
                filteredRuleParameters = ruleParameters.Where(c => inputFilter.Contains(c.Name)).ToList();
            }
            if (context.TryGetContext<List<ScopedParam>>("additionalInputs", out var additionalInputs))
            {
                foreach(var additionalInput in additionalInputs)
                {
                    dynamic value = _ruleExpressionParser.Evaluate<object>(additionalInput.Expression, ruleParameters);
                    filteredRuleParameters.Add(new RuleParameter(additionalInput.Name, value));
                    
                }
            }
   
            var ruleResult = await _ruleEngine.ExecuteActionWorkflowAsync(workflowName, ruleName, filteredRuleParameters.ToArray());
            return ruleResult;
        }
    }
}


================================================
FILE: src/RulesEngine/Actions/ExpressionOutputAction.cs
================================================
// Copyright (c) Microsoft Corporation.
//  Licensed under the MIT License.

using RulesEngine.ExpressionBuilders;
using RulesEngine.Models;
using System.Threading.Tasks;

namespace RulesEngine.Actions
{
    public class OutputExpressionAction : ActionBase
    {
        private readonly RuleExpressionParser _ruleExpressionParser;

        public OutputExpressionAction(RuleExpressionParser ruleExpressionParser)
        {
            _ruleExpressionParser = ruleExpressionParser;
        }

        public override ValueTask<object> Run(ActionContext context, RuleParameter[] ruleParameters)
        {
            var expression = context.GetContext<string>("expression");
            return new ValueTask<object>(_ruleExpressionParser.Evaluate<object>(expression, ruleParameters));
        }
    }
}


================================================
FILE: src/RulesEngine/CustomTypeProvider.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using RulesEngine.HelperFunctions;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Linq.Dynamic.Core.CustomTypeProviders;

namespace RulesEngine
{
    public class CustomTypeProvider : DefaultDynamicLinqCustomTypeProvider
    {
        private readonly HashSet<Type> _types;

        public CustomTypeProvider(Type[] types) : base(ParsingConfig.Default)
        {
            _types = new HashSet<Type>(types ?? Array.Empty<Type>());

            _types.Add(typeof(ExpressionUtils));

            _types.Add(typeof(Enumerable));

            var queue = new Queue<Type>(_types);
            while (queue.Count > 0)
            {
                var t = queue.Dequeue();

                var baseType = t.BaseType;
                if (baseType != null && _types.Add(baseType))
                    queue.Enqueue(baseType);

                foreach (var interfaceType in t.GetInterfaces())
                {
                    if (_types.Add(interfaceType))
                        queue.Enqueue(interfaceType);
                }
            }

            _types.Add(typeof(IEnumerable));
        }

        public override HashSet<Type> GetCustomTypes()
        {
            var all = new HashSet<Type>(base.GetCustomTypes());
            all.UnionWith(_types);
            return all;
        }
    }
}


================================================
FILE: src/RulesEngine/Exceptions/ExpressionParserException.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Text;

namespace RulesEngine.Exceptions
{
    public class ExpressionParserException: Exception
    {
        public ExpressionParserException(string message, string expression) : base(message)
        {
            Data.Add("Expression", expression);
        }
    }
}


================================================
FILE: src/RulesEngine/Exceptions/RuleException.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Text;

namespace RulesEngine.Exceptions
{
    public class RuleException : Exception
    {
        public RuleException(string message) : base(message)
        {
        }

        public RuleException(string message, Exception innerException) : base(message, innerException)
        {
        }
    }
}


================================================
FILE: src/RulesEngine/Exceptions/RuleValidationException.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using FluentValidation;
using FluentValidation.Results;
using System.Collections.Generic;

namespace RulesEngine.Exceptions
{
    public class RuleValidationException : ValidationException
    {
        public RuleValidationException(string message, IEnumerable<ValidationFailure> errors) : base(message, errors)
        {
        }
    }
}


================================================
FILE: src/RulesEngine/Exceptions/ScopedParamException.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Text;

namespace RulesEngine.Exceptions
{
    public class ScopedParamException: Exception
    {
        public ScopedParamException(string message, Exception innerException, string scopedParamName): base(message,innerException)
        {
            Data.Add("ScopedParamName", scopedParamName);
        }
    }
}


================================================
FILE: src/RulesEngine/ExpressionBuilders/LambdaExpressionBuilder.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using RulesEngine.Exceptions;
using RulesEngine.HelperFunctions;
using RulesEngine.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core.Exceptions;
using System.Linq.Expressions;

namespace RulesEngine.ExpressionBuilders
{
    internal sealed class LambdaExpressionBuilder : RuleExpressionBuilderBase
    {
        private readonly ReSettings _reSettings;
        private readonly RuleExpressionParser _ruleExpressionParser;

        internal LambdaExpressionBuilder(ReSettings reSettings, RuleExpressionParser ruleExpressionParser)
        {
            _reSettings = reSettings;
            _ruleExpressionParser = ruleExpressionParser;
        }

        internal override RuleFunc<RuleResultTree> BuildDelegateForRule(Rule rule, RuleParameter[] ruleParams)
        {
            try
            {
                var ruleDelegate = _ruleExpressionParser.Compile<bool>(rule.Expression, ruleParams);
                return Helpers.ToResultTree(_reSettings, rule, null, ruleDelegate);
            }
            catch (Exception ex)
            {
                Helpers.HandleRuleException(ex,rule,_reSettings);

                var exceptionMessage = Helpers.GetExceptionMessage($"Exception while parsing expression `{rule?.Expression}` - {ex.Message}",
                                                                    _reSettings);

                bool func(object[] param) => false;
                
                return Helpers.ToResultTree(_reSettings, rule, null,func, exceptionMessage);
            }
        }

        internal override Expression Parse(string expression, ParameterExpression[] parameters, Type returnType)
        {
            try
            {
                return _ruleExpressionParser.Parse(expression, parameters, returnType);
            }
            catch(ParseException ex)
            {
                throw new ExpressionParserException(ex.Message, expression);
            }
            
        }

        internal override Func<object[],Dictionary<string,object>> CompileScopedParams(RuleParameter[] ruleParameters, RuleExpressionParameter[] scopedParameters)
        {
            return _ruleExpressionParser.CompileRuleExpressionParameters(ruleParameters, scopedParameters);
        }
    }
}


================================================
FILE: src/RulesEngine/ExpressionBuilders/RuleExpressionBuilderBase.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using RulesEngine.Models;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace RulesEngine.ExpressionBuilders
{
    /// <summary>
    /// Base class for expression builders
    /// </summary>
    internal abstract class RuleExpressionBuilderBase
    {
        /// <summary>
        /// Builds the expression for rule.
        /// </summary>
        /// <param name="rule">The rule.</param>
        /// <param name="typeParamExpressions">The type parameter expressions.</param>
        /// <param name="ruleInputExp">The rule input exp.</param>
        /// <returns>Expression type</returns>
        internal abstract RuleFunc<RuleResultTree> BuildDelegateForRule(Rule rule, RuleParameter[] ruleParams);

        internal abstract Expression Parse(string expression, ParameterExpression[] parameters, Type returnType);

        internal abstract Func<object[], Dictionary<string, object>> CompileScopedParams(RuleParameter[] ruleParameters, RuleExpressionParameter[] scopedParameters);
    }
}


================================================
FILE: src/RulesEngine/ExpressionBuilders/RuleExpressionParser.cs
================================================
// Copyright (c) Microsoft Corporation.
//  Licensed under the MIT License.

using FastExpressionCompiler;
using RulesEngine.HelperFunctions;
using RulesEngine.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Linq.Dynamic.Core.Exceptions;
using System.Linq.Dynamic.Core.Parser;
using System.Linq.Expressions;
using System.Reflection;
using System.Text.RegularExpressions;

namespace RulesEngine.ExpressionBuilders
{
    public class RuleExpressionParser
    {
        private readonly ReSettings _reSettings;
        private readonly IDictionary<string, MethodInfo> _methodInfo;

        public RuleExpressionParser(ReSettings reSettings = null)
        {
            _reSettings = reSettings ?? new ReSettings();
            _methodInfo = new Dictionary<string, MethodInfo>();
            PopulateMethodInfo();
        }

        private void PopulateMethodInfo()
        {
            var dict_add = typeof(Dictionary<string, object>).GetMethod("Add", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(string), typeof(object) }, null);
            _methodInfo.Add("dict_add", dict_add);
        }

        public Expression Parse(string expression, ParameterExpression[] parameters, Type returnType)
        {
            var config = new ParsingConfig {
                CustomTypeProvider = new CustomTypeProvider(_reSettings.CustomTypes),
                IsCaseSensitive = _reSettings.IsExpressionCaseSensitive
            };

            // Instead of immediately returning default values, allow for expression parsing to handle dynamic evaluation.
            try
            {
                return new ExpressionParser(parameters, expression, Array.Empty<object>(), config).Parse(returnType);
            }
            catch (ParseException)
            {
                if (_reSettings.EnableExceptionAsErrorMessageForRuleExpressionParsing)
                {
                    throw;
                }
                return Expression.Constant(GetDefaultValueForType(returnType));
            }
            catch (Exception)
            {
                throw;
            }
        }

        private object GetDefaultValueForType(Type type)
        {
            if (type == typeof(bool))
                return false;
            if (type == typeof(int) || type == typeof(float) || type == typeof(double))
                return int.MinValue;
            return null;
        }

        public Func<object[], T> Compile<T>(string expression, RuleParameter[] ruleParams)
        {
            var rtype = typeof(T);
            if (rtype == typeof(object))
            {
                rtype = null;
            }
            var parameterExpressions = GetParameterExpression(ruleParams).ToArray();

            var e = Parse(expression, parameterExpressions, rtype);
            if (rtype == null)
            {
                e = Expression.Convert(e, typeof(T));
            }
            var expressionBody = new List<Expression>() { e };
            var wrappedExpression = WrapExpression<T>(expressionBody, parameterExpressions, new ParameterExpression[] { });
            return CompileExpression(wrappedExpression);

        }

        private Func<object[], T> CompileExpression<T>(Expression<Func<object[], T>> expression)
        {
            if (_reSettings.UseFastExpressionCompiler)
            {
                return expression.CompileFast();
            }
            return expression.Compile();
        }

        private Expression<Func<object[], T>> WrapExpression<T>(List<Expression> expressionList, ParameterExpression[] parameters, ParameterExpression[] variables)
        {
            var argExp = Expression.Parameter(typeof(object[]), "args");
            var paramExps = parameters.Select((c, i) => {
                var arg = Expression.ArrayAccess(argExp, Expression.Constant(i));
                return (Expression)Expression.Assign(c, Expression.Convert(arg, c.Type));
            });
            var blockExpSteps = paramExps.Concat(expressionList);
            var blockExp = Expression.Block(parameters.Concat(variables), blockExpSteps);
            return Expression.Lambda<Func<object[], T>>(blockExp, argExp);
        }

        internal Func<object[], Dictionary<string, object>> CompileRuleExpressionParameters(RuleParameter[] ruleParams, RuleExpressionParameter[] ruleExpParams = null)
        {
            ruleExpParams = ruleExpParams ?? new RuleExpressionParameter[] { };
            var expression = CreateDictionaryExpression(ruleParams, ruleExpParams);
            return CompileExpression(expression);
        }

        public T Evaluate<T>(string expression, RuleParameter[] ruleParams)
        {
            var func = Compile<T>(expression, ruleParams);
            return func(ruleParams.Select(c => c.Value).ToArray());
        }

        private IEnumerable<Expression> CreateAssignedParameterExpression(RuleExpressionParameter[] ruleExpParams)
        {
            return ruleExpParams.Select((c, i) => {
                return Expression.Assign(c.ParameterExpression, c.ValueExpression);
            });
        }

        // <summary>
        /// Gets the parameter expression.
        /// </summary>
        /// <param name="ruleParams">The types.</param>
        /// <returns></returns>
        /// <exception cref="ArgumentException">
        /// types
        /// or
        /// type
        /// </exception>
        private IEnumerable<ParameterExpression> GetParameterExpression(RuleParameter[] ruleParams)
        {
            foreach (var ruleParam in ruleParams)
            {
                if (ruleParam == null)
                {
                    throw new ArgumentException($"{nameof(ruleParam)} can't be null.");
                }

                yield return ruleParam.ParameterExpression;
            }
        }

        private Expression<Func<object[], Dictionary<string, object>>> CreateDictionaryExpression(RuleParameter[] ruleParams, RuleExpressionParameter[] ruleExpParams)
        {
            var body = new List<Expression>();
            var paramExp = new List<ParameterExpression>();
            var variableExp = new List<ParameterExpression>();


            var variableExpressions = CreateAssignedParameterExpression(ruleExpParams);

            body.AddRange(variableExpressions);

            var dict = Expression.Variable(typeof(Dictionary<string, object>));
            var add = _methodInfo["dict_add"];

            body.Add(Expression.Assign(dict, Expression.New(typeof(Dictionary<string, object>))));
            variableExp.Add(dict);

            for (var i = 0; i < ruleParams.Length; i++)
            {
                paramExp.Add(ruleParams[i].ParameterExpression);
            }
            for (var i = 0; i < ruleExpParams.Length; i++)
            {
                var key = Expression.Constant(ruleExpParams[i].ParameterExpression.Name);
                var value = Expression.Convert(ruleExpParams[i].ParameterExpression, typeof(object));
                variableExp.Add(ruleExpParams[i].ParameterExpression);
                body.Add(Expression.Call(dict, add, key, value));

            }
            // Return value
            body.Add(dict);

            return WrapExpression<Dictionary<string, object>>(body, paramExp.ToArray(), variableExp.ToArray());
        }
    }
}

================================================
FILE: src/RulesEngine/Extensions/EnumerableExtensions.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RulesEngine.Extensions
{
    internal static class EnumerableExtensions
    {
        public static IEnumerable<T> Safe<T>(this IEnumerable<T> enumerable)
        {
            return enumerable ?? Enumerable.Empty<T>();
        }
    }
}


================================================
FILE: src/RulesEngine/Extensions/ListofRuleResultTreeExtension.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using RulesEngine.Models;
using System.Collections.Generic;
using System.Linq;


namespace RulesEngine.Extensions
{
    public static class ListofRuleResultTreeExtension
    {
        public delegate void OnSuccessFunc(string eventName);
        public delegate void OnFailureFunc();


        /// <summary>
        /// Calls the Success Func for the first rule which succeeded among the ruleResults
        /// </summary>
        /// <param name="ruleResultTrees"></param>
        /// <param name="onSuccessFunc"></param>
        /// <returns></returns>
        public static List<RuleResultTree> OnSuccess(this List<RuleResultTree> ruleResultTrees, OnSuccessFunc onSuccessFunc)
        {
            var successfulRuleResult = ruleResultTrees.FirstOrDefault(ruleResult => ruleResult.IsSuccess == true);
            if (successfulRuleResult != null)
            {
                var eventName = successfulRuleResult.Rule.SuccessEvent ?? successfulRuleResult.Rule.RuleName;
                onSuccessFunc(eventName);
            }

            return ruleResultTrees;
        }

        /// <summary>
        /// Calls the Failure Func if all rules failed in the ruleReults
        /// </summary>
        /// <param name="ruleResultTrees"></param>
        /// <param name="onFailureFunc"></param>
        /// <returns></returns>
        public static List<RuleResultTree> OnFail(this List<RuleResultTree> ruleResultTrees, OnFailureFunc onFailureFunc)
        {
            bool allFailure = ruleResultTrees.All(ruleResult => ruleResult.IsSuccess == false);
            if (allFailure)
                onFailureFunc();
            return ruleResultTrees;
        }
    }
}


================================================
FILE: src/RulesEngine/HelperFunctions/Constants.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace RulesEngine.HelperFunctions
{
    /// <summary>
    /// Constants
    /// </summary>
    public static class Constants
    {
        public const string WORKFLOW_NAME_NULL_ERRMSG = "Workflow name can not be null or empty";
        public const string INJECT_WORKFLOW_RULES_ERRMSG = "Atleast one of Rules or WorkflowsToInject must be not empty";
        public const string RULE_CATEGORY_CONFIGURED_ERRMSG = "Rule Category should be configured";
        public const string RULE_NULL_ERRMSG = "Rules can not be null or zero";
        public const string NESTED_RULE_NULL_ERRMSG = "Nested rules can not be null";
        public const string NESTED_RULE_CONFIGURED_ERRMSG = "Nested rules can not be configured";
        public const string OPERATOR_NULL_ERRMSG = "Operator can not be null";
        public const string OPERATOR_INCORRECT_ERRMSG = "Operator {PropertyValue} is not allowed";
        public const string RULE_NAME_NULL_ERRMSG = "Rule Name can not be null";
        public const string OPERATOR_RULES_ERRMSG = "Cannot use Rules field when Operator is null";
        public const string LAMBDA_EXPRESSION_EXPRESSION_NULL_ERRMSG = "Expression cannot be null or empty when RuleExpressionType is LambdaExpression";
        public const string LAMBDA_EXPRESSION_OPERATOR_ERRMSG = "Cannot use Operator field when RuleExpressionType is LambdaExpression";
        public const string LAMBDA_EXPRESSION_RULES_ERRMSG = "Cannot use Rules field when RuleExpressionType is LambdaExpression";

    }
}


================================================
FILE: src/RulesEngine/HelperFunctions/ExpressionUtils.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Linq;

namespace RulesEngine.HelperFunctions
{
    public static class ExpressionUtils
    {
        public static bool CheckContains(string check, string valList)
        {
            if (string.IsNullOrEmpty(check) || string.IsNullOrEmpty(valList))
                return false;

            var list = valList.Split(',').ToList();
            return list.Contains(check);
        }
    }
}


================================================
FILE: src/RulesEngine/HelperFunctions/Helpers.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using RulesEngine.Exceptions;
using RulesEngine.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace RulesEngine.HelperFunctions
{
    /// <summary>
    /// Helpers
    /// </summary>
    internal static class Helpers
    {
        internal static RuleFunc<RuleResultTree> ToResultTree(ReSettings reSettings, Rule rule, IEnumerable<RuleResultTree> childRuleResults, Func<object[], bool> isSuccessFunc, string exceptionMessage = "")
        {
            return (inputs) => {
                var isSuccess = false;
                var inputsDict = new Dictionary<string, object>();
                string finalMessage = exceptionMessage;
                try
                {
                    inputsDict = inputs.ToDictionary(c => c.Name, c => c.Value);
                    isSuccess = isSuccessFunc(inputs.Select(c => c.Value).ToArray());
                }
                catch (Exception ex)
                {
                    finalMessage = GetExceptionMessage($"Error while executing rule : {rule?.RuleName} - {ex.Message}", reSettings);
                    HandleRuleException(new RuleException(exceptionMessage,ex), rule, reSettings);
                    isSuccess = false;
                }

                return new RuleResultTree {
                    Rule = rule,
                    Inputs = inputsDict,
                    IsSuccess = isSuccess,
                    ChildResults = childRuleResults,
                    ExceptionMessage = finalMessage
                };

            };
        }

        internal static RuleFunc<RuleResultTree> ToRuleExceptionResult(ReSettings reSettings, Rule rule,Exception ex)
        {
            HandleRuleException(ex, rule, reSettings);
            return ToResultTree(reSettings, rule, null, (args) => false, ex.Message);
        }

        internal static void HandleRuleException(Exception ex, Rule rule, ReSettings reSettings)
        {
            ex.Data.Add(nameof(rule.RuleName), rule.RuleName);
            ex.Data.Add(nameof(rule.Expression), rule.Expression);

            if (!reSettings.EnableExceptionAsErrorMessage)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ex"></param>
        /// <param name="message"></param>
        /// <param name="rule"></param>
        /// <param name="reSettings"></param>
        /// <returns></returns>
        internal static string GetExceptionMessage(string message,ReSettings reSettings)
        {
            return reSettings.IgnoreException ? "" : message;
        }
    }
}


================================================
FILE: src/RulesEngine/HelperFunctions/MemCache.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;

namespace RulesEngine.HelperFunctions
{
    public class MemCacheConfig {
        public int SizeLimit { get; set; } = 1000;
    }


    internal class MemCache
    {
        private readonly MemCacheConfig _config;
        private ConcurrentDictionary<string, (object value, DateTimeOffset expiry)> _cacheDictionary;
        private ConcurrentQueue<(string key, DateTimeOffset expiry)> _cacheEvictionQueue;

        public MemCache(MemCacheConfig config)
        {
            if(config == null)
            {
                config = new MemCacheConfig();
            }
            _config = config;
            _cacheDictionary = new ConcurrentDictionary<string, (object value, DateTimeOffset expiry)>();
            _cacheEvictionQueue = new ConcurrentQueue<(string key, DateTimeOffset expiry)>();
        }

        public bool TryGetValue<T>(string key,out T value)
        {
            value = default;
            if (_cacheDictionary.TryGetValue(key, out var cacheItem))
            {
                if(cacheItem.expiry < DateTimeOffset.UtcNow)
                {
                    _cacheDictionary.TryRemove(key, out _);
                    return false;
                }
                else
                {
                    value = (T)cacheItem.value;
                    return true;
                }   
            }
            return false;
           
        }


        public T Get<T>(string key)
        {
            TryGetValue<T>(key, out var value);
            return value;
        }


        /// <summary>
        /// Returns all known keys. May return keys for expired data as well
        /// </summary>
        /// <returns></returns>
        public IEnumerable<string> GetKeys()
        {
            return _cacheDictionary.Keys;
        }

        public T GetOrCreate<T>(string key, Func<T> createFn, DateTimeOffset? expiry = null)
        {
            if(!TryGetValue<T>(key,out var value))
            {
                value = createFn();
                return Set<T>(key,value,expiry);
            }
            return value;
        }

        public T Set<T>(string key, T value, DateTimeOffset? expiry = null)
        {
            var fixedExpiry = expiry ?? DateTimeOffset.MaxValue;

            while (_cacheDictionary.Count > _config.SizeLimit)
            {
                if (_cacheEvictionQueue.IsEmpty)
                {
                    _cacheDictionary.Clear();
                }
                if(_cacheEvictionQueue.TryDequeue(out var result)
                    && _cacheDictionary.TryGetValue(result.key,out var dictionaryValue)
                    &&  dictionaryValue.expiry == result.expiry)
                {   
                    _cacheDictionary.TryRemove(result.key, out _);
                }
                
            }

            _cacheDictionary.AddOrUpdate(key, (value, fixedExpiry), (k, v) => (value, fixedExpiry));
            _cacheEvictionQueue.Enqueue((key, fixedExpiry));
            return value;
        }

        public void Remove(string key)
        {
            _cacheDictionary.TryRemove(key, out _);
        }

        public void Clear()
        {
            _cacheDictionary.Clear();
            _cacheEvictionQueue =  new ConcurrentQueue<(string key, DateTimeOffset expiry)>();
        }
    }
}


================================================
FILE: src/RulesEngine/HelperFunctions/Utils.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Linq.Dynamic.Core;

namespace RulesEngine.HelperFunctions
{
    public static class Utils
    {
        public static object GetTypedObject(dynamic input)
        {
            if (input is ExpandoObject)
            {
                Type type = CreateAbstractClassType(input);
                return CreateObject(type, input);
            }
            else
            {
                return input;
            }
        }
        public static Type CreateAbstractClassType(dynamic input)
        {
            List<DynamicProperty> props = [];

            if (input is System.Text.Json.JsonElement jsonElement)
            {
                if (jsonElement.ValueKind == System.Text.Json.JsonValueKind.Null)
                {
                    return typeof(object);
                }
            }
            else if (input == null)
            {
                return typeof(object);
            }

            if (input is not ExpandoObject expandoObject)
            {
                return input.GetType();
            }

            foreach (var expando in expandoObject)
            {
                Type value;
                if (expando.Value is IList list)
                {
                    if (list.Count == 0)
                    {
                        value = typeof(List<object>);
                    }
                    else
                    {
                        var internalType = CreateAbstractClassType(list[0]);
                        value = new List<object>().Cast(internalType).ToList(internalType).GetType();
                    }

                }
                else
                {
                    value = CreateAbstractClassType(expando.Value);
                }
                props.Add(new DynamicProperty(expando.Key, value));
            }

            var type = DynamicClassFactory.CreateType(props);
            return type;
        }

        public static object CreateObject(Type type, dynamic input)
        {
            if (input is not ExpandoObject expandoObject)
            {
                return Convert.ChangeType(input, type);
            }
            var obj = Activator.CreateInstance(type);

            var typeProps = type.GetProperties().ToDictionary(c => c.Name);

            foreach (var expando in expandoObject)
            {
                if (typeProps.ContainsKey(expando.Key) &&
                    expando.Value != null && (expando.Value.GetType().Name != "DBNull" || expando.Value != DBNull.Value))
                {
                    object val;
                    var propInfo = typeProps[expando.Key];
                    if (expando.Value is ExpandoObject)
                    {
                        var propType = propInfo.PropertyType;
                        val = CreateObject(propType, expando.Value);
                    }
                    else if (expando.Value is IList temp)
                    {
                        var internalType = propInfo.PropertyType.GenericTypeArguments.FirstOrDefault() ?? typeof(object);
                        var newList = new List<object>().Cast(internalType).ToList(internalType);
                        foreach (var t in temp)
                        {
                            var child = CreateObject(internalType, t);
                            newList.Add(child);
                        };
                        val = newList;
                    }
                    else
                    {
                        val = expando.Value;
                    }
                    propInfo.SetValue(obj, val, null);
                }
            }

            return obj;
        }

        private static IEnumerable Cast(this IEnumerable self, Type innerType)
        {
            var methodInfo = typeof(Enumerable).GetMethod("Cast");
            var genericMethod = methodInfo.MakeGenericMethod(innerType);
            return genericMethod.Invoke(null, new[] { self }) as IEnumerable;
        }

        private static IList ToList(this IEnumerable self, Type innerType)
        {
            var methodInfo = typeof(Enumerable).GetMethod("ToList");
            var genericMethod = methodInfo.MakeGenericMethod(innerType);
            return genericMethod.Invoke(null, new[] { self }) as IList;
        }
    }


}


================================================
FILE: src/RulesEngine/Interfaces/IRulesEngine.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using RulesEngine.Models;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace RulesEngine.Interfaces
{
    public interface IRulesEngine
    {
        /// <summary>
        /// This will execute all the rules of the specified workflow
        /// </summary>
        /// <param name="workflowName">The name of the workflow with rules to execute against the inputs</param>
        /// <param name="inputs">A variable number of inputs</param>
        /// <returns>List of rule results</returns>
        ValueTask<List<RuleResultTree>> ExecuteAllRulesAsync(string workflowName, params object[] inputs);

        /// <summary>
        /// This will execute all the rules of the specified workflow
        /// </summary>
        /// <param name="workflowName">The name of the workflow with rules to execute against the inputs</param>
        /// <param name="ruleParams">A variable number of rule parameters</param>
        /// <returns>List of rule results</returns>
        ValueTask<List<RuleResultTree>> ExecuteAllRulesAsync(string workflowName, params RuleParameter[] ruleParams);
        ValueTask<ActionRuleResult> ExecuteActionWorkflowAsync(string workflowName, string ruleName, RuleParameter[] ruleParameters);

        /// <summary>
        /// Adds new workflows to RulesEngine
        /// </summary>
        /// <param name="workflow"></param>
        void AddWorkflow(params Workflow[] Workflows);

        /// <summary>
        /// Removes all registered workflows from RulesEngine
        /// </summary>
        void ClearWorkflows();

        /// <summary>
        /// Removes the workflow from RulesEngine
        /// </summary>
        /// <param name="workflowNames"></param>
        void RemoveWorkflow(params string[] workflowNames);

        /// <summary>
        /// Checks is workflow exist.
        /// </summary>
        /// <param name="workflowName">The workflow name.</param>
        /// <returns> <c>true</c> if contains the specified workflow name; otherwise, <c>false</c>.</returns>
        bool ContainsWorkflow(string workflowName);

        /// <summary>
        /// Returns the list of all registered workflow names
        /// </summary>
        /// <returns></returns>
        List<string> GetAllRegisteredWorkflowNames();
        void AddOrUpdateWorkflow(params Workflow[] Workflows);
    }
}


================================================
FILE: src/RulesEngine/Models/ActionInfo.cs
================================================
// Copyright (c) Microsoft Corporation.
//  Licensed under the MIT License.

using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace RulesEngine.Models
{
    [ExcludeFromCodeCoverage]
    public class ActionInfo
    {
        public string Name { get; set; }
        public Dictionary<string, object> Context { get; set; }
    }
}


================================================
FILE: src/RulesEngine/Models/ActionResult.cs
================================================
// Copyright (c) Microsoft Corporation.
//  Licensed under the MIT License.

using System;
using System.Diagnostics.CodeAnalysis;

namespace RulesEngine.Models
{
    [ExcludeFromCodeCoverage]
    public class ActionResult
    {
        public object Output { get; set; }
        public Exception Exception { get; set; }
    }
}


================================================
FILE: src/RulesEngine/Models/ActionRuleResult.cs
================================================
// Copyright (c) Microsoft Corporation.
//  Licensed under the MIT License.

using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace RulesEngine.Models
{
    [ExcludeFromCodeCoverage]
    public class ActionRuleResult : ActionResult
    {
        public List<RuleResultTree> Results { get; set; }
    }
}


================================================
FILE: src/RulesEngine/Models/ReSettings.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using RulesEngine.Actions;
using RulesEngine.HelperFunctions;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace RulesEngine.Models
{
    [ExcludeFromCodeCoverage]
    public class ReSettings
    {
        public ReSettings() { }

        // create a copy of settings
        internal ReSettings(ReSettings reSettings)
        {
            CustomTypes = reSettings.CustomTypes;
            CustomActions = reSettings.CustomActions;
            EnableExceptionAsErrorMessage = reSettings.EnableExceptionAsErrorMessage;
            IgnoreException = reSettings.IgnoreException;
            EnableFormattedErrorMessage = reSettings.EnableFormattedErrorMessage;
            EnableScopedParams = reSettings.EnableScopedParams;
            NestedRuleExecutionMode = reSettings.NestedRuleExecutionMode;
            CacheConfig = reSettings.CacheConfig;
            IsExpressionCaseSensitive = reSettings.IsExpressionCaseSensitive;
            AutoRegisterInputType = reSettings.AutoRegisterInputType;
            UseFastExpressionCompiler = reSettings.UseFastExpressionCompiler;
            EnableExceptionAsErrorMessageForRuleExpressionParsing = reSettings.EnableExceptionAsErrorMessageForRuleExpressionParsing;
        }


        /// <summary>
        /// Get/Set the custom types to be used in Rule expressions
        /// </summary>
        public Type[] CustomTypes { get; set; }

        /// <summary>
        /// Get/Set the custom actions that can be used in the Rules
        /// </summary>
        public Dictionary<string, Func<ActionBase>> CustomActions { get; set; }

        /// <summary>
        /// When set to true, returns any exception occurred 
        /// while rule execution as ErrorMessage 
        /// otherwise throws an exception
        /// </summary>
        /// <remarks>This setting is only applicable if IgnoreException is set to false</remarks>
        public bool EnableExceptionAsErrorMessage { get; set; } = true;

        /// <summary>
        /// When set to true, it will ignore any exception thrown with rule compilation/execution
        /// </summary>
        public bool IgnoreException { get; set; } = false;

        /// <summary>
        /// Enables ErrorMessage Formatting 
        /// </summary>
        public bool EnableFormattedErrorMessage { get; set; } = true;

        /// <summary>
        /// Enables Global params and local params for rules
        /// </summary>
        public bool EnableScopedParams { get; set; } = true;

        /// <summary>
        /// Sets whether expression are case sensitive
        /// </summary>
        public bool IsExpressionCaseSensitive { get; set; } = false;

        /// <summary>
        /// Auto Registers input type in Custom Type to allow calling method on type.
        /// Default : true
        /// </summary>
        public bool AutoRegisterInputType { get; set; } = true;

        /// <summary>
        /// Sets the mode for Nested rule execution, Default: All
        /// </summary>
        public NestedRuleExecutionMode NestedRuleExecutionMode { get; set; } = NestedRuleExecutionMode.All;
        public MemCacheConfig CacheConfig { get; set; }
        /// <summary>
        /// Whether to use FastExpressionCompiler for rule compilation
        /// </summary>
        public bool UseFastExpressionCompiler { get; set; } = false;
        /// <summary>
        /// Sets the mode for ParsingException to cascade to child elements and result in a expression parser
        /// Default: true
        /// </summary>
        public bool EnableExceptionAsErrorMessageForRuleExpressionParsing { get; set; } = true;
    }

    public enum NestedRuleExecutionMode
    {
        /// <summary>
        /// Executes all nested rules
        /// </summary>
        All,
        /// <summary>
        /// Skips nested rules whose execution does not impact parent rule's result
        /// </summary>
        Performance
    }
}


================================================
FILE: src/RulesEngine/Models/Rule.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace RulesEngine.Models
{
    using System.Text.Json.Serialization;

    /// <summary>
    /// Rule class
    /// </summary>
    [ExcludeFromCodeCoverage]
    public class Rule
    {
        /// <summary>
        /// Rule name for the Rule
        /// </summary>
        public string RuleName { get; set; }
        /// <summary>	
        /// Gets or sets the custom property or tags of the rule.	
        /// </summary>	
        /// <value>	
        /// The properties of the rule.	
        /// </value>	
        public Dictionary<string, object> Properties { get; set; }
        public string Operator { get; set; }
        public string ErrorMessage { get; set; }

        /// <summary>
        /// Gets or sets whether the rule is enabled.
        /// </summary>
        public bool Enabled { get; set; } = true;

        [JsonConverter (typeof(JsonStringEnumConverter))]
        public RuleExpressionType RuleExpressionType { get; set; } = RuleExpressionType.LambdaExpression;
        public IEnumerable<string> WorkflowsToInject { get; set; }
        public IEnumerable<Rule> Rules { get; set; }
        public IEnumerable<ScopedParam> LocalParams { get; set; }
        public string Expression { get; set; }
        public RuleActions Actions { get; set; }
        public string SuccessEvent { get; set; }

    }
}


================================================
FILE: src/RulesEngine/Models/RuleActions.cs
================================================
// Copyright (c) Microsoft Corporation.
//  Licensed under the MIT License.

using System;
using System.Diagnostics.CodeAnalysis;

namespace RulesEngine.Models
{
    [Obsolete("RuleAction class is deprecated. Use RuleActions class instead.")]
    [ExcludeFromCodeCoverage]
    public class RuleAction : RuleActions
    {
    }
  
    [ExcludeFromCodeCoverage]
    public class RuleActions
    {
        public ActionInfo OnSuccess { get; set; }
        public ActionInfo OnFailure { get; set; }
    }
}


================================================
FILE: src/RulesEngine/Models/RuleDelegate.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace RulesEngine.Models
{
    public delegate T RuleFunc<T>(params RuleParameter[] ruleParameters);
}


================================================
FILE: src/RulesEngine/Models/RuleErrorType.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace RulesEngine.Models
{
    /// <summary>
    /// This is error type of rules which will use in rule config files
    /// </summary>
    public enum ErrorType
    {
        Warning = 0,
        Error = 1,
    }
}


================================================
FILE: src/RulesEngine/Models/RuleExpressionParameter.cs
================================================
// Copyright (c) Microsoft Corporation.
//  Licensed under the MIT License.

using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;

namespace RulesEngine.Models
{
    /// <summary>
    /// CompiledParam class.
    /// </summary>
    [ExcludeFromCodeCoverage]
    public class RuleExpressionParameter
    {
        public ParameterExpression ParameterExpression { get; set; }
        
        public Expression ValueExpression { get; set; }

    }
}


================================================
FILE: src/RulesEngine/Models/RuleExpressionType.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace RulesEngine.Models
{
    /// <summary>
    /// This is rule expression type which will use in rule config files 
    /// </summary>
    public enum RuleExpressionType
    {
        LambdaExpression = 0
    }
}


================================================
FILE: src/RulesEngine/Models/RuleParameter.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using RulesEngine.HelperFunctions;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;

namespace RulesEngine.Models
{
    [ExcludeFromCodeCoverage]
    public class RuleParameter
    {
        public RuleParameter(string name, object value)
        {
            Value = Utils.GetTypedObject(value);
            Init(name, Value?.GetType());
        }

       
        internal RuleParameter(string name, Type type,object value = null)
        {
            Value = Utils.GetTypedObject(value);
            Init(name, type);
        }

        public Type Type { get; private set; }
        public string Name { get; private set; }
        public object Value { get; private set; }
        public ParameterExpression ParameterExpression { get; private set; }

        private void Init(string name, Type type)
        {
            Name = name;
            Type = type ?? typeof(object);
            ParameterExpression = Expression.Parameter(Type, Name);
        }

        public static RuleParameter Create(string name, Type type)
        {
            return new RuleParameter(name, type);
        }
      
        public static RuleParameter Create<T>(string name, T value)
        {
            var typedValue = Utils.GetTypedObject(value);
            var type = typedValue?.GetType() ?? typeof(T);
            return new RuleParameter(name,type,value);
        }


    }
}


================================================
FILE: src/RulesEngine/Models/RuleResultTree.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using RulesEngine.HelperFunctions;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace RulesEngine.Models
{
    /// <summary>
    /// Rule result class with child result heirarchy
    /// </summary>
    [ExcludeFromCodeCoverage]
    public class RuleResultTree
    {
        /// <summary>
        /// Gets or sets the rule.
        /// </summary>
        /// <value>
        /// The rule.
        /// </value>
        public Rule Rule { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether this instance is success.
        /// </summary>
        /// <value>
        ///   <c>true</c> if this instance is success; otherwise, <c>false</c>.
        /// </value>
        public bool IsSuccess { get; set; }

        /// <summary>
        /// Gets or sets the child result.
        /// </summary>
        /// <value>
        /// The child result.
        /// </value>
        public IEnumerable<RuleResultTree> ChildResults { get; set; }

        /// <summary>
        /// Gets or sets the input object
        /// </summary>
        public Dictionary<string, object> Inputs { get; set; }

        public ActionResult ActionResult { get; set; }

        /// <summary>
        /// Gets the exception message in case an error is thrown during rules calculation.
        /// </summary>
        public string ExceptionMessage { get; set; }

    }

    /// <summary>
    /// This class will hold the error messages
    /// </summary>
    [ExcludeFromCodeCoverage]
    public class RuleResultMessage
    {
        /// <summary>
        /// Constructor will initialize the List 
        /// </summary>
        public RuleResultMessage()
        {
            ErrorMessages = new List<string>();
            WarningMessages = new List<string>();
        }

        /// <summary>
        /// This will hold the list of error messages
        /// </summary>
        public List<string> ErrorMessages { get; set; }

        /// <summary>
        /// This will hold the list of warning messages
        /// </summary>
        public List<string> WarningMessages { get; set; }
    }
}


================================================
FILE: src/RulesEngine/Models/ScopedParam.cs
================================================
// Copyright (c) Microsoft Corporation.
//  Licensed under the MIT License.

using System.Diagnostics.CodeAnalysis;

namespace RulesEngine.Models
{
    /// <summary>Class LocalParam.
    /// </summary>
    [ExcludeFromCodeCoverage]
    public class ScopedParam
    {

        /// <summary>
        /// Gets or sets the name of the param.
        /// </summary>
        /// <value>
        /// The name of the rule.
        /// </value>]
        public string Name { get; set; }

        /// <summary>
        /// Gets or Sets the lambda expression which can be reference in Rule. 
        /// </summary>
        public string Expression { get; set; }
    }

    [ExcludeFromCodeCoverage]
    public class LocalParam : ScopedParam { }
}


================================================
FILE: src/RulesEngine/Models/Workflow.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace RulesEngine.Models
{
    [Obsolete("WorkflowRules class is deprecated. Use Workflow class instead.")]
    [ExcludeFromCodeCoverage]
    public class WorkflowRules : Workflow {
    }

    /// <summary>
    /// Workflow rules class for deserialization  the json config file
    /// </summary>
    [ExcludeFromCodeCoverage]
    public class Workflow
    {
        /// <summary>
        /// Gets the workflow name.
        /// </summary>
        public string WorkflowName { get; set; }

        /// <summary>Gets or sets the workflow rules to inject.</summary>
        /// <value>The workflow rules to inject.</value>
        [Obsolete("WorkflowRulesToInject is deprecated. Use WorkflowsToInject instead.")]
        public IEnumerable<string> WorkflowRulesToInject {
          set { WorkflowsToInject = value; }
        }
        public IEnumerable<string> WorkflowsToInject { get; set; }

        public RuleExpressionType RuleExpressionType { get; set; } = RuleExpressionType.LambdaExpression;

        /// <summary>
        /// Gets or Sets the global params which will be applicable to all rules
        /// </summary>
        public IEnumerable<ScopedParam> GlobalParams { get; set; }

        /// <summary>
        /// list of rules.
        /// </summary>
        public IEnumerable<Rule> Rules { get; set; }
    }
}


================================================
FILE: src/RulesEngine/Properties/AssemblyInfo.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// Setting ComVisible to false makes the types in this assembly not visible 
// to COM components.  If you need to access a type in this assembly from 
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
[assembly: InternalsVisibleTo("RulesEngine.UnitTest, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c15956b2ac0945c55b69a185f5c3e02276693b0a5e42c8a1f08cb24e03dd87d91f9fa09f79b6b7b3aac4df46f2ea4ce4bfa31920bb0aad9f02793ab29de9fbf40f5ba9e347aa8569128459f31da1f6357eabe6e1308ac7c16b87a4d61e8d1785746a57ec67956d2e2454b3c98502a5d5c4a4168133bfaa431207c108efae03aa")]


================================================
FILE: src/RulesEngine/RuleCompiler.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using RulesEngine.Exceptions;
using RulesEngine.ExpressionBuilders;
using RulesEngine.HelperFunctions;
using RulesEngine.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace RulesEngine
{
    /// <summary>
    /// Rule compilers
    /// </summary>
    internal class RuleCompiler
    {
        /// <summary>
        /// The nested operators
        /// </summary>
        private readonly ExpressionType[] nestedOperators = new ExpressionType[] { ExpressionType.And, ExpressionType.AndAlso, ExpressionType.Or, ExpressionType.OrElse };

        /// <summary>
        /// The expression builder factory
        /// </summary>
        private readonly RuleExpressionBuilderFactory _expressionBuilderFactory;
        private readonly ReSettings _reSettings;

        /// <summary>
        /// Initializes a new instance of the <see cref="RuleCompiler"/> class.
        /// </summary>
        /// <param name="expressionBuilderFactory">The expression builder factory.</param>
        /// <exception cref="ArgumentNullException">expressionBuilderFactory</exception>
        internal RuleCompiler(RuleExpressionBuilderFactory expressionBuilderFactory, ReSettings reSettings)
        {
            _expressionBuilderFactory = expressionBuilderFactory ?? throw new ArgumentNullException($"{nameof(expressionBuilderFactory)} can't be null.");
            _reSettings = reSettings;
        }

        /// <summary>
        /// Compiles the rule
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="rule"></param>
        /// <param name="input"></param>
        /// <param name="ruleParam"></param>
        /// <returns>Compiled func delegate</returns>
        internal RuleFunc<RuleResultTree> CompileRule(Rule rule, RuleExpressionType ruleExpressionType, RuleParameter[] ruleParams, Lazy<RuleExpressionParameter[]> globalParams)
        {
            if (rule == null)
            {
                var ex =  new ArgumentNullException(nameof(rule));
                throw ex;
            }
            try
            {
                var globalParamExp = globalParams.Value;
                var extendedRuleParams = ruleParams.Concat(globalParamExp.Select(c => new RuleParameter(c.ParameterExpression.Name,c.ParameterExpression.Type)))
                                                   .ToArray();
                var ruleExpression = GetDelegateForRule(rule, extendedRuleParams);
                

                return GetWrappedRuleFunc(rule,ruleExpression,ruleParams,globalParamExp);
            }
            catch (Exception ex)
            {
                var message = $"Error while compiling rule `{rule.RuleName}`: {ex.Message}";
                return Helpers.ToRuleExceptionResult(_reSettings, rule, new RuleException(message, ex));
            }
        }



        /// <summary>
        /// Gets the expression for rule.
        /// </summary>
        /// <param name="rule">The rule.</param>
        /// <param name="typeParameterExpressions">The type parameter expressions.</param>
        /// <param name="ruleInputExp">The rule input exp.</param>
        /// <returns></returns>
        private RuleFunc<RuleResultTree> GetDelegateForRule(Rule rule, RuleParameter[] ruleParams)
        {
            var scopedParamList = GetRuleExpressionParameters(rule.RuleExpressionType, rule?.LocalParams, ruleParams);

            var extendedRuleParams = ruleParams.Concat(scopedParamList.Select(c => new RuleParameter(c.ParameterExpression.Name, c.ParameterExpression.Type)))
                                               .ToArray();

            RuleFunc<RuleResultTree> ruleFn;
            
            if (Enum.TryParse(rule.Operator, out ExpressionType nestedOperator) && nestedOperators.Contains(nestedOperator) &&
                rule.Rules != null && rule.Rules.Any())
            {
                ruleFn = BuildNestedRuleFunc(rule, nestedOperator, extendedRuleParams);
            }
            else
            {
                ruleFn = BuildRuleFunc(rule, extendedRuleParams);
            }

            return GetWrappedRuleFunc(rule, ruleFn, ruleParams, scopedParamList);
        }

        internal RuleExpressionParameter[] GetRuleExpressionParameters(RuleExpressionType ruleExpressionType,IEnumerable<ScopedParam> localParams, RuleParameter[] ruleParams)
        {
            if(!_reSettings.EnableScopedParams)
            {
                return new RuleExpressionParameter[] { };
            }
            var ruleExpParams = new List<RuleExpressionParameter>();

            if (localParams?.Any() == true)
            {

                var parameters = ruleParams.Select(c => c.ParameterExpression)
                                            .ToList();

                var expressionBuilder = GetExpressionBuilder(ruleExpressionType);

                foreach (var lp in localParams)
                {
                    try
                    {
                        var lpExpression = expressionBuilder.Parse(lp.Expression, parameters.ToArray(), null);
                        var ruleExpParam = new RuleExpressionParameter() {
                            ParameterExpression = Expression.Parameter(lpExpression.Type, lp.Name),
                            ValueExpression = lpExpression
                        };
                        parameters.Add(ruleExpParam.ParameterExpression);
                        ruleExpParams.Add(ruleExpParam);
                    }
                    catch(Exception ex)
                    {
                        var message = $"{ex.Message}, in ScopedParam: {lp.Name}";
                        throw new RuleException(message);
                    }
                }
            }
            return ruleExpParams.ToArray();

        }

        /// <summary>
        /// Builds the expression.
        /// </summary>
        /// <param name="rule">The rule.</param>
        /// <param name="typeParameterExpressions">The type parameter expressions.</param>
        /// <param name="ruleInputExp">The rule input exp.</param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        private RuleFunc<RuleResultTree> BuildRuleFunc(Rule rule, RuleParameter[] ruleParams)
        {
            var ruleExpressionBuilder = GetExpressionBuilder(rule.RuleExpressionType);

            var ruleFunc = ruleExpressionBuilder.BuildDelegateForRule(rule, ruleParams);

            return ruleFunc;
        }

        /// <summary>
        /// Builds the nested expression.
        /// </summary>
        /// <param name="parentRule">The parent rule.</param>
        /// <param name="childRules">The child rules.</param>
        /// <param name="operation">The operation.</param>
        /// <param name="typeParameterExpressions">The type parameter expressions.</param>
        /// <param name="ruleInputExp">The rule input exp.</param>
        /// <returns>Expression of func delegate</returns>
        /// <exception cref="InvalidCastException"></exception>
        private RuleFunc<RuleResultTree> BuildNestedRuleFunc(Rule parentRule, ExpressionType operation, RuleParameter[] ruleParams)
        {
            var ruleFuncList = new List<RuleFunc<RuleResultTree>>();
            foreach (var r in parentRule.Rules.Where(c => c.Enabled))
            {
                ruleFuncList.Add(GetDelegateForRule(r, ruleParams));
            }

            return (paramArray) => {
                var (isSuccess, resultList) = ApplyOperation(paramArray, ruleFuncList, operation);
                bool isSuccessFn(object[] p) => isSuccess;
                var result = Helpers.ToResultTree(_reSettings, parentRule, resultList, isSuccessFn);
                return result(paramArray);
            };
        }


        private (bool isSuccess ,IEnumerable<RuleResultTree> result) ApplyOperation(RuleParameter[] paramArray,IEnumerable<RuleFunc<RuleResultTree>> ruleFuncList, ExpressionType operation)
        {
            if (ruleFuncList?.Any() != true)
            {
                return (false,new List<RuleResultTree>());
            }

            var resultList = new List<RuleResultTree>();
            var isSuccess = false;

            if(operation == ExpressionType.And || operation == ExpressionType.AndAlso)
            {
                isSuccess = true;
            }

            foreach(var ruleFunc in ruleFuncList)
            {
                var ruleResult = ruleFunc(paramArray);
                resultList.Add(ruleResult);
                switch (operation)
                {
                    case ExpressionType.And:
                    case ExpressionType.AndAlso:
                        isSuccess = isSuccess && ruleResult.IsSuccess;
                        if(_reSettings.NestedRuleExecutionMode ==  NestedRuleExecutionMode.Performance && isSuccess == false)
                        {
                            return (isSuccess, resultList);
                        }
                        break;

                    case ExpressionType.Or:
                    case ExpressionType.OrElse:
                        isSuccess = isSuccess || ruleResult.IsSuccess;
                        if (_reSettings.NestedRuleExecutionMode == NestedRuleExecutionMode.Performance && isSuccess == true)
                        {
                            return (isSuccess, resultList);
                        }
                        break;
                }
                
            }
            return (isSuccess, resultList);
        }

        internal Func<object[],Dictionary<string,object>> CompileScopedParams(RuleExpressionType ruleExpressionType, RuleParameter[] ruleParameters,RuleExpressionParameter[] ruleExpParams)
        {
            return GetExpressionBuilder(ruleExpressionType).CompileScopedParams(ruleParameters, ruleExpParams);

        }

        private RuleFunc<RuleResultTree> GetWrappedRuleFunc(Rule rule, RuleFunc<RuleResultTree> ruleFunc,RuleParameter[] ruleParameters,RuleExpressionParameter[] ruleExpParams)
        {
            if(ruleExpParams.Length == 0)
            {
                return ruleFunc;
            }
            var paramDelegate = CompileScopedParams(rule.RuleExpressionType,ruleParameters, ruleExpParams);

            return (ruleParams) => {
                var inputs = ruleParams.Select(c => c.Value).ToArray();
                IEnumerable<RuleParameter> scopedParams;
                try
                {
                    var scopedParamsDict = paramDelegate(inputs);
                    scopedParams = scopedParamsDict.Select(c => new RuleParameter(c.Key, c.Value));
                }
                catch(Exception ex)
                {
                    var message = $"Error while executing scoped params for rule `{rule.RuleName}` - {ex}";
                    var resultFn = Helpers.ToRuleExceptionResult(_reSettings, rule, new RuleException(message, ex));
                    return resultFn(ruleParams);
                }
               
                var extendedInputs = ruleParams.Concat(scopedParams);
                var result = ruleFunc(extendedInputs.ToArray());
                return result;
            };
        }

        private RuleExpressionBuilderBase GetExpressionBuilder(RuleExpressionType expressionType)
        {
            return _expressionBuilderFactory.RuleGetExpressionBuilder(expressionType);
        }
    }
}


================================================
FILE: src/RulesEngine/RuleExpressionBuilderFactory.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using RulesEngine.ExpressionBuilders;
using RulesEngine.Models;
using System;

namespace RulesEngine
{
    internal class RuleExpressionBuilderFactory
    {
        private readonly ReSettings _reSettings;
        private readonly LambdaExpressionBuilder _lambdaExpressionBuilder;
        public RuleExpressionBuilderFactory(ReSettings reSettings, RuleExpressionParser expressionParser)
        {
            _reSettings = reSettings;
            _lambdaExpressionBuilder = new LambdaExpressionBuilder(_reSettings, expressionParser);
        }
        public RuleExpressionBuilderBase RuleGetExpressionBuilder(RuleExpressionType ruleExpressionType)
        {
            switch (ruleExpressionType)
            {
                case RuleExpressionType.LambdaExpression:
                    return _lambdaExpressionBuilder;
                default:
                    throw new InvalidOperationException($"{nameof(ruleExpressionType)} has not been supported yet.");
            }
        }
    }
}


================================================
FILE: src/RulesEngine/RulesCache.cs
================================================
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using RulesEngine.HelperFunctions;
using RulesEngine.Models;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;

namespace RulesEngine
{
    /// <summary>Class RulesCache.</summary>
    internal class RulesCache
    {
        /// <summary>The compile rules</summary>
        private readonly MemCache _compileRules;

        /// <summary>The workflow rules</summary>
        private readonly ConcurrentDictionary<string, (Workflow, long)> _workflow = new ConcurrentDictionary<string, (Workflow, long)>();


        public RulesCache(ReSettings reSettings)
        {
            _compileRules = new MemCache(reSettings.CacheConfig);
        }


        /// <summary>Determines whether [contains workflow rules] [the specified workflow name].</summary>
        /// <param name="workflowName">Name of the workflow.</param>
        /// <returns>
        ///   <c>true</c> if [contains workflow rules] [the specified workflow name]; otherwise, <c>false</c>.</returns>
        public bool ContainsWorkflows(string workflowName)
        {
            return _workflow.ContainsKey(workflowName);
        }

        public List<string> GetAllWorkflowNames()
        {
            return _workflow.Keys.ToList();
        }

        /// <summary>Adds the or update workflow rules.</summary>
        /// <param name="workflowName">Name of the workflow.</param>
        /// <param name="rules">The rules.</param>
        public void AddOrUpdateWorkflows(string workflowName, Workflow rules)
        {
            long ticks = DateTime.UtcNow.Ticks;
            _workflow.AddOrUpdate(workflowName, (rules, ticks), (k, v) => (rules, ticks));
        }

        /// <summary>Adds the or update compiled rule.</summary>
        /// <param name="compiledRuleKey">The compiled rule key.</param>
        /// <param name="compiledRule">The compiled rule.</param>
        public void AddOrUpdateCompiledRule(string compiledRuleKey, IDictionary<string, RuleFunc<RuleResultTree>> compiledRule)
        {
            long ticks = DateTime.UtcNow.Ticks;
            _compileRules.Set(compiledRuleKey,(compiledRule, ticks));
        }

        /// <summary>Checks if the compiled rules are up-to-date.</summary>
        /// <param name="compiledRuleKey">The compiled rule key.</param>
        /// <param name="workflowName">The workflow name.</param>
         /// <returns>
        ///   <c>true</c> if [compiled rules] is newer than the [workflow rules]; otherwise, <c>false</c>.</returns>
        public bool AreCompiledRulesUpToDate(string compiledRuleKey, string workflowName)
        {
            if (_compileRules.TryGetValue(compiledRuleKey, out (IDictionary<string, RuleFunc<RuleResultTree>> rules, long tick) compiledRulesObj))
            {
                if (_workflow.TryGetValue(workflowName, out (Workflow rules, long tick) WorkflowsObj))
                {
                    return compiledRulesObj.tick >= WorkflowsObj.tick;
                }
            }

            return false;
        }

        /// <summary>Clears this instance.</summary>
        public void Clear()
        {
            _workflow.Clear();
            _compileRules.Clear();
        }

        /// <summary>Gets the work flow rules.</summary>
        /// <param name="workflowName">Name of the workflow.</param>
        /// <returns>Workflows.</returns>
        /// <exception cref="Exception">Could not find injected Workflow: {wfname}</exception>
        public Workflow GetWorkflow(string workflowName)
        {
            if (_workflow.TryGetValue(workflowName, out (Workflow rules, long tick) WorkflowsObj))
            {
                var workflow = WorkflowsObj.rules;
                if (workflow.WorkflowsToInject?.Any() == true)
                {
                    if (workflow.Rules == null)
                    {
                        workflow.Rules = new List<Rule>();
                    }
                    foreach (string wfname in workflow.WorkflowsToInject)
                    {
                        var injectedWorkflow = GetWorkflow(wfname);
                        if (injectedWorkflow == null)
                        {
                            throw new Exception($"Could not find injected Workflow: {wfname}");
                        }

                        workflow.Rules = workflow.Rules.Concat(injectedWorkflow.Rules).ToList();
                    }
                }

                return workflow;
            }
            else
            {
                return null;
            }
        }


        /// <summary>Gets the compiled rules.</summary>
        /// <param name="compiledRulesKey">The compiled rules key.</param>
        /// <returns>CompiledRule.</returns>
        public IDictionary<string, RuleFunc<RuleResultTree>> GetCompiledRules(string compiledRulesKey)
        {
            return _compileRules.Get<(IDictionary<string, RuleFunc<RuleResultTree>> rules, long tick)>(compiledRulesKey).rules;
        }

        /// <summary>Removes the specified workflow name.</summary>
        /// <param name="workflowName">Name of the workflow.</param>
 
Download .txt
gitextract_4_4zshmg/

├── .config/
│   └── dotnet-tools.json
├── .devcontainer/
│   └── devcontainer.json
├── .editorconfig
├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       ├── codeql-analysis.yml
│       └── dotnetcore-build.yml
├── .gitignore
├── .vscode/
│   ├── launch.json
│   ├── settings.json
│   └── tasks.json
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── RulesEngine.sln
├── SECURITY.md
├── benchmark/
│   └── RulesEngineBenchmark/
│       ├── Program.cs
│       ├── RulesEngineBenchmark.csproj
│       └── Workflows/
│           ├── Discount.json
│           └── NestedInputDemo.json
├── demo/
│   ├── DemoApp/
│   │   ├── BasicDemo.cs
│   │   ├── DemoApp.csproj
│   │   ├── EFDemo.cs
│   │   ├── JSONDemo.cs
│   │   ├── NestedInputDemo.cs
│   │   ├── Program.cs
│   │   └── Workflows/
│   │       ├── Discount.json
│   │       └── NestedInputDemo.json
│   └── DemoApp.EFDataExample/
│       ├── DemoApp.EFDataExample.csproj
│       ├── RulesEngineContext.cs
│       └── RulesEngineDemoContext.cs
├── deployment/
│   └── build-signed.ps1
├── docs/
│   ├── Getting-Started.md
│   ├── Home.md
│   ├── Introduction.md
│   ├── Use-Case.md
│   ├── _Sidebar.md
│   ├── _config.yml
│   └── index.md
├── global.json
├── schema/
│   ├── workflow-list-schema.json
│   └── workflow-schema.json
├── scripts/
│   ├── check-coverage.ps1
│   └── generate-coverage-report.ps1
├── signing/
│   └── RulesEngine-publicKey.snk
├── src/
│   └── RulesEngine/
│       ├── Actions/
│       │   ├── ActionBase.cs
│       │   ├── ActionContext.cs
│       │   ├── ActionFactory.cs
│       │   ├── EvaluateRuleAction.cs
│       │   └── ExpressionOutputAction.cs
│       ├── CustomTypeProvider.cs
│       ├── Exceptions/
│       │   ├── ExpressionParserException.cs
│       │   ├── RuleException.cs
│       │   ├── RuleValidationException.cs
│       │   └── ScopedParamException.cs
│       ├── ExpressionBuilders/
│       │   ├── LambdaExpressionBuilder.cs
│       │   ├── RuleExpressionBuilderBase.cs
│       │   └── RuleExpressionParser.cs
│       ├── Extensions/
│       │   ├── EnumerableExtensions.cs
│       │   └── ListofRuleResultTreeExtension.cs
│       ├── HelperFunctions/
│       │   ├── Constants.cs
│       │   ├── ExpressionUtils.cs
│       │   ├── Helpers.cs
│       │   ├── MemCache.cs
│       │   └── Utils.cs
│       ├── Interfaces/
│       │   └── IRulesEngine.cs
│       ├── Models/
│       │   ├── ActionInfo.cs
│       │   ├── ActionResult.cs
│       │   ├── ActionRuleResult.cs
│       │   ├── ReSettings.cs
│       │   ├── Rule.cs
│       │   ├── RuleActions.cs
│       │   ├── RuleDelegate.cs
│       │   ├── RuleErrorType.cs
│       │   ├── RuleExpressionParameter.cs
│       │   ├── RuleExpressionType.cs
│       │   ├── RuleParameter.cs
│       │   ├── RuleResultTree.cs
│       │   ├── ScopedParam.cs
│       │   └── Workflow.cs
│       ├── Properties/
│       │   └── AssemblyInfo.cs
│       ├── RuleCompiler.cs
│       ├── RuleExpressionBuilderFactory.cs
│       ├── RulesCache.cs
│       ├── RulesEngine.cs
│       ├── RulesEngine.csproj
│       └── Validators/
│           ├── RuleValidator.cs
│           └── WorkflowRulesValidator.cs
└── test/
    └── RulesEngine.UnitTest/
        ├── ActionTests/
        │   ├── ActionContextTests.cs
        │   ├── CustomActionTest.cs
        │   ├── MockClass/
        │   │   └── ReturnContextAction.cs
        │   └── RulesEngineWithActionsTests.cs
        ├── BusinessRuleEngineTest.cs
        ├── CaseSensitiveTests.cs
        ├── CustomTypeProviderTests.cs
        ├── EmptyRulesTest.cs
        ├── ExpressionUtilsTest.cs
        ├── LambdaExpressionBuilderTest.cs
        ├── ListofRuleResultTreeExtensionTest.cs
        ├── NestedRulesTest.cs
        ├── ParameterNameChangeTest.cs
        ├── RuleCompilerTest.cs
        ├── RuleExpressionBuilderFactoryTest.cs
        ├── RuleExpressionParserTests/
        │   └── RuleExpressionParserTests.cs
        ├── RuleParameterTests.cs
        ├── RuleTestClass.cs
        ├── RuleValidationTest.cs
        ├── RulesEnabledTests.cs
        ├── RulesEngine.UnitTest.csproj
        ├── ScopedParamsTest.cs
        ├── TestData/
        │   ├── rules1.json
        │   ├── rules10.json
        │   ├── rules11.json
        │   ├── rules2.json
        │   ├── rules3.json
        │   ├── rules4.json
        │   ├── rules5.json
        │   ├── rules6.json
        │   ├── rules7.json
        │   ├── rules8.json
        │   └── rules9.json
        ├── TypedClassTests.cs
        └── UtilsTests.cs
Download .txt
SYMBOL INDEX (353 symbols across 71 files)

FILE: benchmark/RulesEngineBenchmark/Program.cs
  class REBenchmark (line 16) | [MemoryDiagnoser]
    class ListItem (line 26) | private class ListItem
    method REBenchmark (line 33) | public REBenchmark()
    method RuleExecutionDefault (line 74) | [Benchmark]
  class Program (line 83) | public class Program
    method Main (line 85) | public static void Main(string[] args)

FILE: demo/DemoApp.EFDataExample/RulesEngineContext.cs
  class RulesEngineContext (line 12) | public class RulesEngineContext : DbContext
    method OnModelCreating (line 18) | protected override void OnModelCreating(ModelBuilder modelBuilder)

FILE: demo/DemoApp.EFDataExample/RulesEngineDemoContext.cs
  class RulesEngineDemoContext (line 10) | public class RulesEngineDemoContext : RulesEngineContext
    method RulesEngineDemoContext (line 14) | public RulesEngineDemoContext()
    method OnConfiguring (line 20) | protected override void OnConfiguring(DbContextOptionsBuilder options)

FILE: demo/DemoApp/BasicDemo.cs
  class BasicDemo (line 12) | public class BasicDemo
    method Run (line 14) | public void Run()

FILE: demo/DemoApp/EFDemo.cs
  class EFDemo (line 18) | public class EFDemo
    method Run (line 20) | public void Run()

FILE: demo/DemoApp/JSONDemo.cs
  class JSONDemo (line 15) | public class JSONDemo
    method Run (line 17) | public void Run()

FILE: demo/DemoApp/NestedInputDemo.cs
  class ListItem (line 14) | internal class ListItem
  class NestedInputDemo (line 20) | public class NestedInputDemo
    method Run (line 22) | public void Run()

FILE: demo/DemoApp/Program.cs
  class Program (line 6) | public static class Program
    method Main (line 8) | public static void Main(string[] args)

FILE: src/RulesEngine/Actions/ActionBase.cs
  class ActionBase (line 11) | public abstract class ActionBase
    method ExecuteAndReturnResultAsync (line 13) | internal async virtual ValueTask<ActionRuleResult> ExecuteAndReturnRes...
    method Run (line 36) | public abstract ValueTask<object> Run(ActionContext context, RuleParam...

FILE: src/RulesEngine/Actions/ActionContext.cs
  class ActionContext (line 12) | public class ActionContext
    method ActionContext (line 17) | public ActionContext(IDictionary<string, object> context, RuleResultTr...
    method GetParentRuleResult (line 40) | public RuleResultTree GetParentRuleResult()
    method TryGetContext (line 45) | public bool TryGetContext<T>(string name,out T output)
    method GetContext (line 66) | public T GetContext<T>(string name)

FILE: src/RulesEngine/Actions/ActionFactory.cs
  class ActionFactory (line 9) | internal class ActionFactory
    method ActionFactory (line 13) | internal ActionFactory()
    method ActionFactory (line 17) | internal ActionFactory(IDictionary<string, Func<ActionBase>> actionReg...
    method Get (line 25) | internal ActionBase Get(string name)

FILE: src/RulesEngine/Actions/EvaluateRuleAction.cs
  class EvaluateRuleAction (line 13) | public class EvaluateRuleAction : ActionBase
    method EvaluateRuleAction (line 18) | public EvaluateRuleAction(RulesEngine ruleEngine, RuleExpressionParser...
    method ExecuteAndReturnResultAsync (line 24) | internal async override ValueTask<ActionRuleResult> ExecuteAndReturnRe...
    method Run (line 41) | public async override ValueTask<object> Run(ActionContext context, Rul...

FILE: src/RulesEngine/Actions/ExpressionOutputAction.cs
  class OutputExpressionAction (line 10) | public class OutputExpressionAction : ActionBase
    method OutputExpressionAction (line 14) | public OutputExpressionAction(RuleExpressionParser ruleExpressionParser)
    method Run (line 19) | public override ValueTask<object> Run(ActionContext context, RuleParam...

FILE: src/RulesEngine/CustomTypeProvider.cs
  class CustomTypeProvider (line 14) | public class CustomTypeProvider : DefaultDynamicLinqCustomTypeProvider
    method CustomTypeProvider (line 18) | public CustomTypeProvider(Type[] types) : base(ParsingConfig.Default)
    method GetCustomTypes (line 45) | public override HashSet<Type> GetCustomTypes()

FILE: src/RulesEngine/Exceptions/ExpressionParserException.cs
  class ExpressionParserException (line 10) | public class ExpressionParserException: Exception
    method ExpressionParserException (line 12) | public ExpressionParserException(string message, string expression) : ...

FILE: src/RulesEngine/Exceptions/RuleException.cs
  class RuleException (line 10) | public class RuleException : Exception
    method RuleException (line 12) | public RuleException(string message) : base(message)
    method RuleException (line 16) | public RuleException(string message, Exception innerException) : base(...

FILE: src/RulesEngine/Exceptions/RuleValidationException.cs
  class RuleValidationException (line 10) | public class RuleValidationException : ValidationException
    method RuleValidationException (line 12) | public RuleValidationException(string message, IEnumerable<ValidationF...

FILE: src/RulesEngine/Exceptions/ScopedParamException.cs
  class ScopedParamException (line 10) | public class ScopedParamException: Exception
    method ScopedParamException (line 12) | public ScopedParamException(string message, Exception innerException, ...

FILE: src/RulesEngine/ExpressionBuilders/LambdaExpressionBuilder.cs
  class LambdaExpressionBuilder (line 15) | internal sealed class LambdaExpressionBuilder : RuleExpressionBuilderBase
    method LambdaExpressionBuilder (line 20) | internal LambdaExpressionBuilder(ReSettings reSettings, RuleExpression...
    method BuildDelegateForRule (line 26) | internal override RuleFunc<RuleResultTree> BuildDelegateForRule(Rule r...
    method Parse (line 46) | internal override Expression Parse(string expression, ParameterExpress...
    method CompileScopedParams (line 59) | internal override Func<object[],Dictionary<string,object>> CompileScop...

FILE: src/RulesEngine/ExpressionBuilders/RuleExpressionBuilderBase.cs
  class RuleExpressionBuilderBase (line 14) | internal abstract class RuleExpressionBuilderBase
    method BuildDelegateForRule (line 23) | internal abstract RuleFunc<RuleResultTree> BuildDelegateForRule(Rule r...
    method Parse (line 25) | internal abstract Expression Parse(string expression, ParameterExpress...
    method CompileScopedParams (line 27) | internal abstract Func<object[], Dictionary<string, object>> CompileSc...

FILE: src/RulesEngine/ExpressionBuilders/RuleExpressionParser.cs
  class RuleExpressionParser (line 19) | public class RuleExpressionParser
    method RuleExpressionParser (line 24) | public RuleExpressionParser(ReSettings reSettings = null)
    method PopulateMethodInfo (line 31) | private void PopulateMethodInfo()
    method Parse (line 37) | public Expression Parse(string expression, ParameterExpression[] param...
    method GetDefaultValueForType (line 63) | private object GetDefaultValueForType(Type type)
    method Compile (line 72) | public Func<object[], T> Compile<T>(string expression, RuleParameter[]...
    method CompileExpression (line 92) | private Func<object[], T> CompileExpression<T>(Expression<Func<object[...
    method WrapExpression (line 101) | private Expression<Func<object[], T>> WrapExpression<T>(List<Expressio...
    method CompileRuleExpressionParameters (line 113) | internal Func<object[], Dictionary<string, object>> CompileRuleExpress...
    method Evaluate (line 120) | public T Evaluate<T>(string expression, RuleParameter[] ruleParams)
    method CreateAssignedParameterExpression (line 126) | private IEnumerable<Expression> CreateAssignedParameterExpression(Rule...
    method GetParameterExpression (line 143) | private IEnumerable<ParameterExpression> GetParameterExpression(RulePa...
    method CreateDictionaryExpression (line 156) | private Expression<Func<object[], Dictionary<string, object>>> CreateD...

FILE: src/RulesEngine/Extensions/EnumerableExtensions.cs
  class EnumerableExtensions (line 12) | internal static class EnumerableExtensions
    method Safe (line 14) | public static IEnumerable<T> Safe<T>(this IEnumerable<T> enumerable)

FILE: src/RulesEngine/Extensions/ListofRuleResultTreeExtension.cs
  class ListofRuleResultTreeExtension (line 11) | public static class ListofRuleResultTreeExtension
    method OnSuccess (line 23) | public static List<RuleResultTree> OnSuccess(this List<RuleResultTree>...
    method OnFail (line 41) | public static List<RuleResultTree> OnFail(this List<RuleResultTree> ru...

FILE: src/RulesEngine/HelperFunctions/Constants.cs
  class Constants (line 9) | public static class Constants

FILE: src/RulesEngine/HelperFunctions/ExpressionUtils.cs
  class ExpressionUtils (line 9) | public static class ExpressionUtils
    method CheckContains (line 11) | public static bool CheckContains(string check, string valList)

FILE: src/RulesEngine/HelperFunctions/Helpers.cs
  class Helpers (line 16) | internal static class Helpers
    method ToResultTree (line 18) | internal static RuleFunc<RuleResultTree> ToResultTree(ReSettings reSet...
    method ToRuleExceptionResult (line 47) | internal static RuleFunc<RuleResultTree> ToRuleExceptionResult(ReSetti...
    method HandleRuleException (line 53) | internal static void HandleRuleException(Exception ex, Rule rule, ReSe...
    method GetExceptionMessage (line 72) | internal static string GetExceptionMessage(string message,ReSettings r...

FILE: src/RulesEngine/HelperFunctions/MemCache.cs
  class MemCacheConfig (line 11) | public class MemCacheConfig {
  class MemCache (line 16) | internal class MemCache
    method MemCache (line 22) | public MemCache(MemCacheConfig config)
    method TryGetValue (line 33) | public bool TryGetValue<T>(string key,out T value)
    method Get (line 54) | public T Get<T>(string key)
    method GetKeys (line 65) | public IEnumerable<string> GetKeys()
    method GetOrCreate (line 70) | public T GetOrCreate<T>(string key, Func<T> createFn, DateTimeOffset? ...
    method Set (line 80) | public T Set<T>(string key, T value, DateTimeOffset? expiry = null)
    method Remove (line 104) | public void Remove(string key)
    method Clear (line 109) | public void Clear()

FILE: src/RulesEngine/HelperFunctions/Utils.cs
  class Utils (line 13) | public static class Utils
    method GetTypedObject (line 15) | public static object GetTypedObject(dynamic input)
    method CreateAbstractClassType (line 27) | public static Type CreateAbstractClassType(dynamic input)
    method CreateObject (line 75) | public static object CreateObject(Type type, dynamic input)
    method Cast (line 119) | private static IEnumerable Cast(this IEnumerable self, Type innerType)
    method ToList (line 126) | private static IList ToList(this IEnumerable self, Type innerType)

FILE: src/RulesEngine/Interfaces/IRulesEngine.cs
  type IRulesEngine (line 10) | public interface IRulesEngine
    method ExecuteAllRulesAsync (line 18) | ValueTask<List<RuleResultTree>> ExecuteAllRulesAsync(string workflowNa...
    method ExecuteAllRulesAsync (line 26) | ValueTask<List<RuleResultTree>> ExecuteAllRulesAsync(string workflowNa...
    method ExecuteActionWorkflowAsync (line 27) | ValueTask<ActionRuleResult> ExecuteActionWorkflowAsync(string workflow...
    method AddWorkflow (line 33) | void AddWorkflow(params Workflow[] Workflows);
    method ClearWorkflows (line 38) | void ClearWorkflows();
    method RemoveWorkflow (line 44) | void RemoveWorkflow(params string[] workflowNames);
    method ContainsWorkflow (line 51) | bool ContainsWorkflow(string workflowName);
    method GetAllRegisteredWorkflowNames (line 57) | List<string> GetAllRegisteredWorkflowNames();
    method AddOrUpdateWorkflow (line 58) | void AddOrUpdateWorkflow(params Workflow[] Workflows);

FILE: src/RulesEngine/Models/ActionInfo.cs
  class ActionInfo (line 9) | [ExcludeFromCodeCoverage]

FILE: src/RulesEngine/Models/ActionResult.cs
  class ActionResult (line 9) | [ExcludeFromCodeCoverage]

FILE: src/RulesEngine/Models/ActionRuleResult.cs
  class ActionRuleResult (line 9) | [ExcludeFromCodeCoverage]

FILE: src/RulesEngine/Models/ReSettings.cs
  class ReSettings (line 12) | [ExcludeFromCodeCoverage]
    method ReSettings (line 15) | public ReSettings() { }
    method ReSettings (line 18) | internal ReSettings(ReSettings reSettings)
  type NestedRuleExecutionMode (line 95) | public enum NestedRuleExecutionMode

FILE: src/RulesEngine/Models/Rule.cs
  class Rule (line 14) | [ExcludeFromCodeCoverage]

FILE: src/RulesEngine/Models/RuleActions.cs
  class RuleAction (line 9) | [Obsolete("RuleAction class is deprecated. Use RuleActions class instead...
  class RuleActions (line 15) | [ExcludeFromCodeCoverage]

FILE: src/RulesEngine/Models/RuleErrorType.cs
  type ErrorType (line 9) | public enum ErrorType

FILE: src/RulesEngine/Models/RuleExpressionParameter.cs
  class RuleExpressionParameter (line 13) | [ExcludeFromCodeCoverage]

FILE: src/RulesEngine/Models/RuleExpressionType.cs
  type RuleExpressionType (line 9) | public enum RuleExpressionType

FILE: src/RulesEngine/Models/RuleParameter.cs
  class RuleParameter (line 11) | [ExcludeFromCodeCoverage]
    method RuleParameter (line 14) | public RuleParameter(string name, object value)
    method RuleParameter (line 21) | internal RuleParameter(string name, Type type,object value = null)
    method Init (line 32) | private void Init(string name, Type type)
    method Create (line 39) | public static RuleParameter Create(string name, Type type)
    method Create (line 44) | public static RuleParameter Create<T>(string name, T value)

FILE: src/RulesEngine/Models/RuleResultTree.cs
  class RuleResultTree (line 14) | [ExcludeFromCodeCoverage]
  class RuleResultMessage (line 58) | [ExcludeFromCodeCoverage]
    method RuleResultMessage (line 64) | public RuleResultMessage()

FILE: src/RulesEngine/Models/ScopedParam.cs
  class ScopedParam (line 10) | [ExcludeFromCodeCoverage]
  class LocalParam (line 28) | [ExcludeFromCodeCoverage]

FILE: src/RulesEngine/Models/Workflow.cs
  class WorkflowRules (line 10) | [Obsolete("WorkflowRules class is deprecated. Use Workflow class instead...
  class Workflow (line 18) | [ExcludeFromCodeCoverage]

FILE: src/RulesEngine/RuleCompiler.cs
  class RuleCompiler (line 18) | internal class RuleCompiler
    method RuleCompiler (line 36) | internal RuleCompiler(RuleExpressionBuilderFactory expressionBuilderFa...
    method CompileRule (line 50) | internal RuleFunc<RuleResultTree> CompileRule(Rule rule, RuleExpressio...
    method GetDelegateForRule (line 83) | private RuleFunc<RuleResultTree> GetDelegateForRule(Rule rule, RulePar...
    method GetRuleExpressionParameters (line 105) | internal RuleExpressionParameter[] GetRuleExpressionParameters(RuleExp...
    method BuildRuleFunc (line 152) | private RuleFunc<RuleResultTree> BuildRuleFunc(Rule rule, RuleParamete...
    method BuildNestedRuleFunc (line 171) | private RuleFunc<RuleResultTree> BuildNestedRuleFunc(Rule parentRule, ...
    method ApplyOperation (line 188) | private (bool isSuccess ,IEnumerable<RuleResultTree> result) ApplyOper...
    method CompileScopedParams (line 232) | internal Func<object[],Dictionary<string,object>> CompileScopedParams(...
    method GetWrappedRuleFunc (line 238) | private RuleFunc<RuleResultTree> GetWrappedRuleFunc(Rule rule, RuleFun...
    method GetExpressionBuilder (line 267) | private RuleExpressionBuilderBase GetExpressionBuilder(RuleExpressionT...

FILE: src/RulesEngine/RuleExpressionBuilderFactory.cs
  class RuleExpressionBuilderFactory (line 10) | internal class RuleExpressionBuilderFactory
    method RuleExpressionBuilderFactory (line 14) | public RuleExpressionBuilderFactory(ReSettings reSettings, RuleExpress...
    method RuleGetExpressionBuilder (line 19) | public RuleExpressionBuilderBase RuleGetExpressionBuilder(RuleExpressi...

FILE: src/RulesEngine/RulesCache.cs
  class RulesCache (line 14) | internal class RulesCache
    method RulesCache (line 23) | public RulesCache(ReSettings reSettings)
    method ContainsWorkflows (line 33) | public bool ContainsWorkflows(string workflowName)
    method GetAllWorkflowNames (line 38) | public List<string> GetAllWorkflowNames()
    method AddOrUpdateWorkflows (line 46) | public void AddOrUpdateWorkflows(string workflowName, Workflow rules)
    method AddOrUpdateCompiledRule (line 55) | public void AddOrUpdateCompiledRule(string compiledRuleKey, IDictionar...
    method AreCompiledRulesUpToDate (line 66) | public bool AreCompiledRulesUpToDate(string compiledRuleKey, string wo...
    method Clear (line 80) | public void Clear()
    method GetWorkflow (line 90) | public Workflow GetWorkflow(string workflowName)
    method GetCompiledRules (line 125) | public IDictionary<string, RuleFunc<RuleResultTree>> GetCompiledRules(...
    method Remove (line 132) | public void Remove(string workflowName)

FILE: src/RulesEngine/RulesEngine.cs
  class RulesEngine (line 28) | public class RulesEngine : IRulesEngine
    method RulesEngine (line 40) | public RulesEngine(string[] jsonConfig, ReSettings reSettings = null) ...
    method RulesEngine (line 46) | public RulesEngine(Workflow[] Workflows, ReSettings reSettings = null)...
    method RulesEngine (line 51) | public RulesEngine(ReSettings reSettings = null)
    method GetActionRegistry (line 64) | private IDictionary<string, Func<ActionBase>> GetActionRegistry(ReSett...
    method ExecuteAllRulesAsync (line 85) | public async ValueTask<List<RuleResultTree>> ExecuteAllRulesAsync(stri...
    method ExecuteAllRulesAsync (line 104) | public async ValueTask<List<RuleResultTree>> ExecuteAllRulesAsync(stri...
    method ExecuteActionAsync (line 113) | private async ValueTask ExecuteActionAsync(IEnumerable<RuleResultTree>...
    method ExecuteActionWorkflowAsync (line 129) | public async ValueTask<ActionRuleResult> ExecuteActionWorkflowAsync(st...
    method ExecuteActionForRuleResult (line 136) | private async ValueTask<ActionRuleResult> ExecuteActionForRuleResult(R...
    method AddWorkflow (line 166) | public void AddWorkflow(params Workflow[] workflows)
    method AddOrUpdateWorkflow (line 196) | public void AddOrUpdateWorkflow(params Workflow[] workflows)
    method GetAllRegisteredWorkflowNames (line 213) | public List<string> GetAllRegisteredWorkflowNames()
    method ContainsWorkflow (line 223) | public bool ContainsWorkflow(string workflowName)
    method ClearWorkflows (line 231) | public void ClearWorkflows()
    method RemoveWorkflow (line 240) | public void RemoveWorkflow(params string[] workflowNames)
    method ValidateWorkflowAndExecuteRule (line 255) | private List<RuleResultTree> ValidateWorkflowAndExecuteRule(string wor...
    method RegisterRule (line 279) | private bool RegisterRule(string workflowName, params RuleParameter[] ...
    method CompileRule (line 324) | private RuleFunc<RuleResultTree> CompileRule(string workflowName, stri...
    method CompileRule (line 342) | private RuleFunc<RuleResultTree> CompileRule(Rule rule, RuleExpression...
    method CollectAllElementTypes (line 347) | private static void CollectAllElementTypes(Type t, ISet<Type> collector)
    method ExecuteAllRuleByWorkflow (line 377) | private List<RuleResultTree> ExecuteAllRuleByWorkflow(string workflowN...
    method GetCompiledRulesKey (line 391) | private string GetCompiledRulesKey(string workflowName, RuleParameter[...
    method GetDefaultActionRegistry (line 398) | private IDictionary<string, Func<ActionBase>> GetDefaultActionRegistry()
    method FormatErrorMessages (line 411) | private IEnumerable<RuleResultTree> FormatErrorMessages(IEnumerable<Ru...
    method UpdateErrorMessage (line 458) | private static string UpdateErrorMessage(string errorMessage, IDiction...

FILE: src/RulesEngine/Validators/RuleValidator.cs
  class RuleValidator (line 14) | internal class RuleValidator : AbstractValidator<Rule>
    method RuleValidator (line 17) | public RuleValidator()
    method RegisterExpressionTypeRules (line 38) | private void RegisterExpressionTypeRules()
    method BeValidRulesList (line 46) | private bool BeValidRulesList(IEnumerable<Rule> rules)

FILE: src/RulesEngine/Validators/WorkflowRulesValidator.cs
  class WorkflowsValidator (line 11) | internal class WorkflowsValidator : AbstractValidator<Workflow>
    method WorkflowsValidator (line 13) | public WorkflowsValidator()

FILE: test/RulesEngine.UnitTest/ActionTests/ActionContextTests.cs
  class ActionContextTests (line 14) | [ExcludeFromCodeCoverage]
    method GetParentRuleResult_ReturnsParentRule (line 17) | [Fact]
    method GetContext_ValidName_ReturnsContext (line 38) | [Fact]
    method GetContext_ObjectContext_ReturnsTypedContext (line 59) | [Fact]
    method GetContext_ValidNameWithStringCaseDiffernce_ReturnsContext (line 81) | [Fact]
    method GetContext_InvalidName_ThrowsArgumentException (line 102) | [Fact]
    method GetContext_PrimitiveInputs_ReturnsResult (line 120) | [Fact]
    method GetContext_InvalidNameListContext_ThrowsArgumentException (line 149) | [Fact]
    method GetContext_InvalidTypeConversion_ThrowsArgumentException (line 167) | [Fact]

FILE: test/RulesEngine.UnitTest/ActionTests/CustomActionTest.cs
  class CustomActionTest (line 15) | [ExcludeFromCodeCoverage]
    method CustomActionOnRuleMustHaveContextValues (line 18) | [Fact]
    method CustomAction_WithSystemTextJsobOnRuleMustHaveContextValues (line 33) | [Fact]
    method GetWorkflow (line 54) | private Workflow[] GetWorkflow()

FILE: test/RulesEngine.UnitTest/ActionTests/MockClass/ReturnContextAction.cs
  class ReturnContextAction (line 14) | [ExcludeFromCodeCoverage]
    method Run (line 17) | public override ValueTask<object> Run(ActionContext context, RuleParam...

FILE: test/RulesEngine.UnitTest/ActionTests/RulesEngineWithActionsTests.cs
  class RulesEngineWithActionsTests (line 13) | [ExcludeFromCodeCoverage]
    method WhenExpressionIsSuccess_OutputExpressionAction_ReturnsExpressionEvaluation (line 17) | [Fact]
    method WhenExpressionIsSuccess_ComplexOutputExpressionAction_ReturnsExpressionEvaluation (line 26) | [Fact]
    method WhenExpressionIsSuccess_EvaluateRuleAction_ReturnsExpressionEvaluation (line 36) | [Fact]
    method ExecuteActionWorkflowAsync_CalledWithIncorrectWorkflowOrRuleName_ThrowsArgumentException (line 46) | [Fact]
    method ExecuteActionWorkflowAsync_CalledWithNoActionsInWorkflow_ExecutesSuccessfully (line 55) | [Fact]
    method ExecuteActionWorkflowAsync_SelfReferencingAction_NoFilter_ExecutesSuccessfully (line 66) | [Fact]
    method ExecuteActionWorkflowAsync_SelfReferencingAction_WithFilter_ExecutesSuccessfully (line 76) | [Fact]
    method GetWorkflowsWithoutActions (line 86) | private Workflow[] GetWorkflowsWithoutActions()
    method GetWorkflowWithActions (line 102) | private Workflow[] GetWorkflowWithActions()

FILE: test/RulesEngine.UnitTest/BusinessRuleEngineTest.cs
  class RulesEngineTest (line 24) | [Trait("Category", "Unit")]
    method RulesEngine_New_ReturnsNotNull (line 28) | [Theory]
    method RulesEngine_InjectedRules_ContainsInjectedRules (line 36) | [Theory]
    method ExecuteRule_ReturnsListOfRuleResultTree (line 51) | [Theory]
    method ExecuteRule_AddWorkflowWithSameName_ThrowsValidationException (line 67) | [Theory]
    method ExecuteRule_AddOrUpdateWorkflow_ExecutesUpdatedRules (line 89) | [Theory]
    method GetAllRegisteredWorkflows_ReturnsListOfAllWorkflows (line 121) | [Theory]
    method GetAllRegisteredWorkflows_NoWorkflow_ReturnsEmptyList (line 133) | [Fact]
    method ExecuteRule_ManyInputs_ReturnsListOfRuleResultTree (line 143) | [Theory]
    method ExecuteRule_CalledMultipleTimes_ReturnsSameResult (line 183) | [Theory]
    method ExecuteRule_SingleObject_ReturnsListOfRuleResultTree (line 210) | [Theory]
    method ExecuteRule_ExceptionScenario_RulesInvalid (line 226) | [Theory]
    method RulesEngine_New_IncorrectJSON_ThrowsException (line 242) | [Fact]
    method RulesEngine_AddOrUpdate_IncorrectJSON_ThrowsException (line 257) | [Fact]
    method ExecuteRule_InvalidWorkFlow_ThrowsException (line 274) | [Theory]
    method RemoveWorkflow_RemovesWorkflow (line 284) | [Theory]
    method ClearWorkflow_RemovesAllWorkflow (line 301) | [Theory]
    method ExecuteRule_InputWithVariableProps_ReturnsResult (line 316) | [Theory]
    method RulesEngine_Execute_Rule_For_Nested_Rule_Params_Returns_Success (line 340) | [Theory]
    method ExecuteRule_ReturnsProperErrorOnMissingRuleParameter (line 371) | [Theory]
    method ExecuteRule_WithInjectedUtils_ReturnsListOfRuleResultTree (line 386) | [Theory]
    method ExecuteRule_RuleWithMethodExpression_ReturnsSucess (line 410) | [Theory]
    method ExecuteRule_RuleWithUnaryExpression_ReturnsSucess (line 433) | [Theory]
    method ExecuteRule_RuleWithMemberAccessExpression_ReturnsSucess (line 450) | [Theory]
    method ExecuteRule_MissingMethodInExpression_ReturnsRulesFailed (line 467) | [Theory]
    method ExecuteRule_DynamicParsion_RulesEvaluationFailed (line 484) | [Theory]
    method ExecuteRuleWithIgnoreException_CompilationException_DoesNotReturnsAsErrorMessage (line 501) | [Theory]
    method ExecuteRuleWithJsonElement (line 519) | [Theory]
    method RulesEngineWithGlobalParam_RunsSuccessfully (line 541) | [Theory]
    method ExecuteRule_RuntimeError_ShouldReturnAsErrorMessage (line 816) | [Fact]
    method ExecuteRule_RuntimeErrorInPreviousRun_ShouldReturnEmptyErrorMessage (line 842) | [Fact]
    method ExecuteRule_RuntimeError_ThrowsException (line 874) | [Fact]
    method ExecuteRule_RuntimeError_IgnoreException_DoesNotReturnException (line 899) | [Fact]
    method RemoveWorkFlow_ShouldRemoveAllCompiledCache (line 928) | [Fact]
    method ClearWorkFlow_ShouldRemoveAllCompiledCache (line 962) | [Fact]
    method ExecuteRule_WithNullInput_ShouldNotThrowException (line 996) | [Fact]
    method ExecuteRule_SpecialCharInWorkflowName_RunsSuccessfully (line 1030) | [Fact]
    method ContainsWorkFlowName_ShouldReturn (line 1058) | [Fact]
    method Class_PublicMethods_ArePartOfInterface (line 1086) | [Theory]
    method CreateRulesEngine (line 1103) | private RulesEngine CreateRulesEngine(Workflow workflow)
    method GetRulesEngine (line 1109) | private RulesEngine GetRulesEngine(string filename, ReSettings reSetti...
    method GetFileContent (line 1122) | private string GetFileContent(string filename)
    method ParseAsWorkflow (line 1128) | private Workflow ParseAsWorkflow(string WorkflowsFileName)
    method GetInput1 (line 1134) | private dynamic GetInput1()
    method GetInput2 (line 1141) | private dynamic GetInput2()
    method GetInput3 (line 1148) | private dynamic GetInput3()
    method GetInputs4 (line 1161) | private static dynamic[] GetInputs4()
    class TestInstanceUtils (line 1187) | [ExcludeFromCodeCoverage]
      method CheckExists (line 1190) | public bool CheckExists(string str)

FILE: test/RulesEngine.UnitTest/CaseSensitiveTests.cs
  class CaseSensitiveTests (line 15) | [ExcludeFromCodeCoverage]
    method CaseSensitiveTest (line 18) | [Theory]

FILE: test/RulesEngine.UnitTest/CustomTypeProviderTests.cs
  class CustomTypeProviderTests (line 13) | [Trait("Category", "Unit")]
    method Dispose (line 17) | public void Dispose()
    method CreateProvider (line 21) | private CustomTypeProvider CreateProvider(params Type[] customTypes)
    method GetCustomTypes_DefaultProvider_IncludesEnumerableAndObject (line 26) | [Fact]
    method GetCustomTypes_WithListOfGuid_ContainsIEnumerableOfGuid (line 36) | [Fact]
    method GetCustomTypes_ListOfListString_ContainsIEnumerableOfListString (line 48) | [Fact]
    method GetCustomTypes_ArrayOfStringArrays_ContainsIEnumerableOfStringArray (line 60) | [Fact]
    method GetCustomTypes_NullableIntArray_ContainsIEnumerableOfNullableInt (line 72) | [Fact]
    method GetCustomTypes_MultipleTypes_NoDuplicates (line 85) | [Fact]

FILE: test/RulesEngine.UnitTest/EmptyRulesTest.cs
  class EmptyRulesTest (line 17) | [ExcludeFromCodeCoverage]
    method EmptyRules_ReturnsExepectedResults (line 20) | [Fact]
    method NestedRulesWithEmptyNestedActions_ReturnsExepectedResults (line 36) | [Fact]
    method GetEmptyWorkflow (line 53) | private Workflow[] GetEmptyWorkflow()
    method GetEmptyNestedWorkflows (line 64) | private Workflow[] GetEmptyNestedWorkflows()

FILE: test/RulesEngine.UnitTest/ExpressionUtilsTest.cs
  class ExpressionUtilsTest (line 10) | [Trait("Category", "Unit")]
    method CheckContainsTest (line 14) | [Fact]

FILE: test/RulesEngine.UnitTest/LambdaExpressionBuilderTest.cs
  class LambdaExpressionBuilderTest (line 13) | [Trait("Category", "Unit")]
    method BuildExpressionForRuleTest (line 17) | [Fact]

FILE: test/RulesEngine.UnitTest/ListofRuleResultTreeExtensionTest.cs
  class ListofRuleResultTreeExtensionTest (line 12) | [Trait("Category", "Unit")]
    method OnSuccessWithSuccessTest (line 16) | [Fact]
    method OnSuccessWithSuccessWithEventTest (line 55) | [Fact]
    method OnSuccessWithouSuccessTest (line 95) | [Fact]
    method OnFailWithSuccessTest (line 135) | [Fact]
    method OnFailWithoutSuccessTest (line 174) | [Fact]

FILE: test/RulesEngine.UnitTest/NestedRulesTest.cs
  class NestedRulesTest (line 16) | [ExcludeFromCodeCoverage]
    method NestedRulesShouldFollowExecutionMode (line 20) | [Theory]
    method NestedRulesWithNestedActions_ReturnsCorrectResults (line 68) | [Fact]
    method NestedRulesWithNestedActions_WorkflowParsedWithSystemTextJson_ReturnsCorrectResults (line 84) | [Fact]
    method GetWorkflow (line 111) | private Workflow[] GetWorkflow()

FILE: test/RulesEngine.UnitTest/ParameterNameChangeTest.cs
  class ParameterNameChangeTest (line 14) | [ExcludeFromCodeCoverage]
    method RunTwiceTest_ReturnsExpectedResults (line 17) | [Fact]

FILE: test/RulesEngine.UnitTest/RuleCompilerTest.cs
  class RuleCompilerTest (line 12) | [Trait("Category", "Unit")]
    method RuleCompiler_NullCheck (line 16) | [Fact]
    method RuleCompiler_CompileRule_ThrowsException (line 25) | [Fact]

FILE: test/RulesEngine.UnitTest/RuleExpressionBuilderFactoryTest.cs
  class RuleExpressionBuilderFactoryTest (line 12) | [Trait("Category", "Unit")]
    method RuleGetExpressionBuilderTest (line 16) | [Theory]

FILE: test/RulesEngine.UnitTest/RuleExpressionParserTests/RuleExpressionParserTests.cs
  class RuleExpressionParserTests (line 12) | [ExcludeFromCodeCoverage]
    method RuleExpressionParserTests (line 15) | public RuleExpressionParserTests() {
    method TestExpressionWithJObject (line 21) | [Fact]
    method TestExpressionWithDifferentCompilerSettings (line 63) | [Theory]

FILE: test/RulesEngine.UnitTest/RuleParameterTests.cs
  class RuleParameterTests (line 10) | public class RuleParameterTests
    method Create_SetsPropertiesCorrectly (line 12) | [Fact]

FILE: test/RulesEngine.UnitTest/RuleTestClass.cs
  class RuleTestClass (line 9) | [ExcludeFromCodeCoverage]

FILE: test/RulesEngine.UnitTest/RuleValidationTest.cs
  class RuleValidationTest (line 18) | [ExcludeFromCodeCoverage]
    method NullExpressionithLambdaExpression_ReturnsExepectedResults (line 21) | [Fact]
    method NestedRulesWithMissingOperator_ReturnsExepectedResults (line 39) | [Fact]
    method GetNullExpressionithLambdaExpressionWorkflow (line 57) | private Workflow[] GetNullExpressionithLambdaExpressionWorkflow()
    method GetEmptyOperatorWorkflow (line 72) | private Workflow[] GetEmptyOperatorWorkflow()

FILE: test/RulesEngine.UnitTest/RulesEnabledTests.cs
  class RulesEnabledTests (line 12) | [ExcludeFromCodeCoverage]
    method RulesEnabledTests (line 15) | public RulesEnabledTests()
    method RulesEngine_ShouldOnlyExecuteEnabledRules (line 20) | [Theory]
    method WorkflowUpdatedRuleEnabled_ShouldReflect (line 42) | [Theory]
    method NestedEnabledCheck (line 78) | private bool NestedEnabledCheck(IEnumerable<RuleResultTree> ruleResults)
    method GetWorkflows (line 98) | private Workflow[] GetWorkflows()

FILE: test/RulesEngine.UnitTest/ScopedParamsTest.cs
  class MyObject (line 14) | [ExcludeFromCodeCoverage]
  class ScopedParamsTest (line 22) | [ExcludeFromCodeCoverage]
    method BasicWorkflows_ReturnsTrue (line 25) | [Theory]
    method WorkflowUpdate_GlobalParam_ShouldReflect (line 53) | [Theory]
    method DisabledScopedParam_ShouldReflect (line 81) | [Theory]
    method ErrorInScopedParam_ShouldAppearAsErrorMessage (line 110) | [Theory]
    method RuntimeErrorInScopedParam_ShouldAppearAsErrorMessage (line 131) | [Theory]
    method LocalParam_GivesCorrectAnswer (line 154) | [Theory]
    method CheckResultTreeContainsAllInputs (line 182) | private void CheckResultTreeContainsAllInputs(string workflowName, Lis...
    method CheckInputs (line 196) | private static void CheckInputs(IEnumerable<string> expectedInputs, Ru...
    method GetWorkflowList (line 213) | private Workflow[] GetWorkflowList()

FILE: test/RulesEngine.UnitTest/TypedClassTests.cs
  class TypedClassTests (line 15) | [Trait("Category", "Unit")]
    class Transazione (line 19) | public class Transazione
    class Attore (line 24) | public class Attore
    type RuoloAttore (line 31) | public enum RuoloAttore
    method TypedClassTest (line 38) | [Fact]
    method TypedClassInputSameNameAsTypeTest (line 90) | [Fact]
    method TypedClassBothAccessibleTestWhenCaseInsensitive (line 143) | [Fact]

FILE: test/RulesEngine.UnitTest/UtilsTests.cs
  class TestClass (line 14) | [ExcludeFromCodeCoverage]
  class UtilsTests (line 21) | [Trait("Category", "Unit")]
    method GetTypedObject_dynamicObject (line 26) | [Fact]
    method GetTypedObject_dynamicObject_multipleObjects (line 37) | [Fact]
    method GetTypedObject_nonDynamicObject (line 54) | [Fact]
    method GetJObject_nonDynamicObject (line 66) | [Fact]
    method CreateObject_dynamicObject (line 79) | [Fact]
    method CreateAbstractType_dynamicObject (line 92) | [Fact]
Condensed preview — 123 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (394K chars).
[
  {
    "path": ".config/dotnet-tools.json",
    "chars": 184,
    "preview": "{\n  \"version\": 1,\n  \"isRoot\": true,\n  \"tools\": {\n    \"dotnet-reportgenerator-globaltool\": {\n      \"version\": \"5.1.26\",\n "
  },
  {
    "path": ".devcontainer/devcontainer.json",
    "chars": 952,
    "preview": "{\r\n\t\"name\": \"RulesEngine Codespace\",\r\n\t\"image\": \"mcr.microsoft.com/vscode/devcontainers/dotnet:0-6.0\",\r\n\t\"settings\": {\r\n"
  },
  {
    "path": ".editorconfig",
    "chars": 6081,
    "preview": "# Rules in this file were initially inferred by Visual Studio IntelliCode from the C:\\Users\\purunjaybhal\\source\\repos\\Ru"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 929,
    "preview": "version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    # default location of `.github/workflows`\n    directory:"
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "chars": 2511,
    "preview": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# Y"
  },
  {
    "path": ".github/workflows/dotnetcore-build.yml",
    "chars": 1136,
    "preview": "name: build\n\non:\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: [ main, develop ]\n\njobs:\n  build:\n    runs"
  },
  {
    "path": ".gitignore",
    "chars": 5699,
    "preview": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## G"
  },
  {
    "path": ".vscode/launch.json",
    "chars": 1107,
    "preview": "{\n   // Use IntelliSense to find out which attributes exist for C# debugging\n   // Use hover for the description of the "
  },
  {
    "path": ".vscode/settings.json",
    "chars": 230,
    "preview": "{\n    \"dotnetCoreExplorer.searchpatterns\": \"test/**/bin/Debug/netcoreapp*/*.{dll,exe,json}\",\n    \"coverage-gutters.cover"
  },
  {
    "path": ".vscode/tasks.json",
    "chars": 1247,
    "preview": "{\n    \"version\": \"2.0.0\",\n    \"tasks\": [\n        {\n            \"label\": \"build\",\n            \"command\": \"dotnet\",\n      "
  },
  {
    "path": "CHANGELOG.md",
    "chars": 6160,
    "preview": "# CHANGELOG\n\nAll notable changes to this project will be documented in this file.\n\n## [5.0.3]\n- Updated dependencies to "
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 444,
    "preview": "# Microsoft Open Source Code of Conduct\n\nThis project has adopted the [Microsoft Open Source Code of Conduct](https://op"
  },
  {
    "path": "LICENSE",
    "chars": 1141,
    "preview": "    MIT License\n\n    Copyright (c) Microsoft Corporation.\n\n    Permission is hereby granted, free of charge, to any pers"
  },
  {
    "path": "README.md",
    "chars": 7056,
    "preview": "# Rules Engine\n![build](https://github.com/microsoft/RulesEngine/workflows/build/badge.svg?branch=main)\n[![Coverage Stat"
  },
  {
    "path": "RulesEngine.sln",
    "chars": 3887,
    "preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.3171"
  },
  {
    "path": "SECURITY.md",
    "chars": 2780,
    "preview": "<!-- BEGIN MICROSOFT SECURITY.MD V0.0.5 BLOCK -->\n\n## Security\n\nMicrosoft takes the security of our software products an"
  },
  {
    "path": "benchmark/RulesEngineBenchmark/Program.cs",
    "chars": 2541,
    "preview": "// Copyright (c) Microsoft Corporation.\n//  Licensed under the MIT License.\n\nusing BenchmarkDotNet.Attributes;\nusing Be"
  },
  {
    "path": "benchmark/RulesEngineBenchmark/RulesEngineBenchmark.csproj",
    "chars": 738,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFrameworks>net6.0;net8."
  },
  {
    "path": "benchmark/RulesEngineBenchmark/Workflows/Discount.json",
    "chars": 3725,
    "preview": "[\n  {\n    \"WorkflowName\": \"Discount\",\n    \"Rules\": [\n      {\n        \"RuleName\": \"GiveDiscount10\",\n        \"SuccessEvent"
  },
  {
    "path": "benchmark/RulesEngineBenchmark/Workflows/NestedInputDemo.json",
    "chars": 1121,
    "preview": "[\n  {\n    \"WorkflowName\": \"NestedInputDemoWorkflow1\",\n    \"Rules\": [\n      {\n        \"RuleName\": \"CheckNestedSimpleProp"
  },
  {
    "path": "demo/DemoApp/BasicDemo.cs",
    "chars": 1890,
    "preview": "// Copyright (c) Microsoft Corporation.\n//  Licensed under the MIT License.\n\nusing RulesEngine.Models;\nusing System;\nus"
  },
  {
    "path": "demo/DemoApp/DemoApp.csproj",
    "chars": 704,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFrameworks>net8.0;net9"
  },
  {
    "path": "demo/DemoApp/EFDemo.cs",
    "chars": 2562,
    "preview": "// Copyright (c) Microsoft Corporation.\n//  Licensed under the MIT License.\n\nusing DemoApp.EFDataExample;\nusing RulesEn"
  },
  {
    "path": "demo/DemoApp/JSONDemo.cs",
    "chars": 2177,
    "preview": "// Copyright (c) Microsoft Corporation.\n//  Licensed under the MIT License.\n\nusing RulesEngine.Models;\nusing System;\nus"
  },
  {
    "path": "demo/DemoApp/NestedInputDemo.cs",
    "chars": 2153,
    "preview": "// Copyright (c) Microsoft Corporation.\n//  Licensed under the MIT License.\n\nusing RulesEngine.Extensions;\nusing RulesE"
  },
  {
    "path": "demo/DemoApp/Program.cs",
    "chars": 366,
    "preview": "// Copyright (c) Microsoft Corporation.\r\n// Licensed under the MIT License.\r\n\r\nnamespace DemoApp\r\n{\r\n    public static "
  },
  {
    "path": "demo/DemoApp/Workflows/Discount.json",
    "chars": 3725,
    "preview": "[\n  {\n    \"WorkflowName\": \"Discount\",\n    \"Rules\": [\n      {\n        \"RuleName\": \"GiveDiscount10\",\n        \"SuccessEvent"
  },
  {
    "path": "demo/DemoApp/Workflows/NestedInputDemo.json",
    "chars": 1121,
    "preview": "[\n  {\n    \"WorkflowName\": \"NestedInputDemoWorkflow1\",\n    \"Rules\": [\n      {\n        \"RuleName\": \"CheckNestedSimpleProp"
  },
  {
    "path": "demo/DemoApp.EFDataExample/DemoApp.EFDataExample.csproj",
    "chars": 556,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>net8.0;net9.0</TargetFrameworks>\n    <RootNam"
  },
  {
    "path": "demo/DemoApp.EFDataExample/RulesEngineContext.cs",
    "chars": 2100,
    "preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text.Json;\nusing Microsoft.EntityFramew"
  },
  {
    "path": "demo/DemoApp.EFDataExample/RulesEngineDemoContext.cs",
    "chars": 739,
    "preview": "using System;\nusing System.Collections.Generic;\nusing System.Text.Json;\nusing Microsoft.EntityFrameworkCore;\nusing Rule"
  },
  {
    "path": "deployment/build-signed.ps1",
    "chars": 475,
    "preview": "param(\n    [Parameter(Mandatory)]\n    [string] $csprojFilePath,\n    [Parameter(Mandatory)]\n    [string] $signingKey\n)\n\n#"
  },
  {
    "path": "docs/Getting-Started.md",
    "chars": 13376,
    "preview": "## Getting Started with Rules Engine\nRulesEngine is a library/NuGet package for abstracting rules and running the Rules "
  },
  {
    "path": "docs/Home.md",
    "chars": 1578,
    "preview": "## Welcome\nWelcome to the RulesEngine Wiki!\n\nThe pages here are primarily intended for those who wish to contribute to t"
  },
  {
    "path": "docs/Introduction.md",
    "chars": 2632,
    "preview": "## What is the Rules Engine\nWhile building any application, the crux or the core part of it is always business logic or "
  },
  {
    "path": "docs/Use-Case.md",
    "chars": 3075,
    "preview": "## Use Case\nThe use case for demo purposes used here is explained as follows. The system we are designing is an e-commer"
  },
  {
    "path": "docs/_Sidebar.md",
    "chars": 3020,
    "preview": "[Home](https://github.com/microsoft/RulesEngine/wiki)\n* [Welcome](https://github.com/microsoft/RulesEngine/wiki#welcome)"
  },
  {
    "path": "docs/_config.yml",
    "chars": 26,
    "preview": "theme: jekyll-theme-cayman"
  },
  {
    "path": "docs/index.md",
    "chars": 19204,
    "preview": "RulesEngine is a highly extensible library to build rule based system using C# expressions\n\n\n**Features**\n- Json based r"
  },
  {
    "path": "global.json",
    "chars": 109,
    "preview": "{\n  \"sdk\": {\n    \"version\": \"9.0.301\",\n    \"rollForward\": \"latestFeature\",\n    \"allowPrerelease\": false\n  }\n}"
  },
  {
    "path": "schema/workflow-list-schema.json",
    "chars": 198,
    "preview": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"type\": \"array\",\n  \"items\": {\n    \"$ref\": \"https://raw.githu"
  },
  {
    "path": "schema/workflow-schema.json",
    "chars": 3333,
    "preview": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"definitions\": {\n    \"ScopedParam\": {\n      \"type\": \"object\""
  },
  {
    "path": "scripts/check-coverage.ps1",
    "chars": 413,
    "preview": "param(\n    [Parameter(Mandatory=$true)][string] $reportPath,\n    [Parameter(Mandatory=$true)][decimal] $threshold\n)\n\n\n[X"
  },
  {
    "path": "scripts/generate-coverage-report.ps1",
    "chars": 142,
    "preview": "dotnet tool restore\ndotnet reportgenerator \"-reports:**/coverage.cobertura.xml\" \"-targetdir:coveragereport\" -reporttypes"
  },
  {
    "path": "src/RulesEngine/Actions/ActionBase.cs",
    "chars": 1214,
    "preview": "// Copyright (c) Microsoft Corporation.\n//  Licensed under the MIT License.\n\nusing RulesEngine.Models;\nusing System;\nus"
  },
  {
    "path": "src/RulesEngine/Actions/ActionContext.cs",
    "chars": 2618,
    "preview": "// Copyright (c) Microsoft Corporation.\n//  Licensed under the MIT License.\n\nusing RulesEngine.Models;\nusing System;\nus"
  },
  {
    "path": "src/RulesEngine/Actions/ActionFactory.cs",
    "chars": 971,
    "preview": "// Copyright (c) Microsoft Corporation.\n//  Licensed under the MIT License.\n\nusing System;\nusing System.Collections.Gen"
  },
  {
    "path": "src/RulesEngine/Actions/EvaluateRuleAction.cs",
    "chars": 2726,
    "preview": "// Copyright (c) Microsoft Corporation.\n//  Licensed under the MIT License.\n\nusing RulesEngine.ExpressionBuilders;\nusing"
  },
  {
    "path": "src/RulesEngine/Actions/ExpressionOutputAction.cs",
    "chars": 804,
    "preview": "// Copyright (c) Microsoft Corporation.\n//  Licensed under the MIT License.\n\nusing RulesEngine.ExpressionBuilders;\nusin"
  },
  {
    "path": "src/RulesEngine/CustomTypeProvider.cs",
    "chars": 1472,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.HelperFunctions;\nusing Sy"
  },
  {
    "path": "src/RulesEngine/Exceptions/ExpressionParserException.cs",
    "chars": 408,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing System;\nusing System.Collections.Gene"
  },
  {
    "path": "src/RulesEngine/Exceptions/RuleException.cs",
    "chars": 442,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing System;\nusing System.Collections.Gene"
  },
  {
    "path": "src/RulesEngine/Exceptions/RuleValidationException.cs",
    "chars": 418,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing FluentValidation;\nusing FluentValidat"
  },
  {
    "path": "src/RulesEngine/Exceptions/ScopedParamException.cs",
    "chars": 453,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing System;\nusing System.Collections.Gene"
  },
  {
    "path": "src/RulesEngine/ExpressionBuilders/LambdaExpressionBuilder.cs",
    "chars": 2376,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.Exceptions;\nusing RulesEn"
  },
  {
    "path": "src/RulesEngine/ExpressionBuilders/RuleExpressionBuilderBase.cs",
    "chars": 1107,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.Models;\nusing System;\nusi"
  },
  {
    "path": "src/RulesEngine/ExpressionBuilders/RuleExpressionParser.cs",
    "chars": 7598,
    "preview": "// Copyright (c) Microsoft Corporation.\r\n//  Licensed under the MIT License.\r\n\r\nusing FastExpressionCompiler;\r\nusing Ru"
  },
  {
    "path": "src/RulesEngine/Extensions/EnumerableExtensions.cs",
    "chars": 443,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing System;\nusing System.Collections.Gene"
  },
  {
    "path": "src/RulesEngine/Extensions/ListofRuleResultTreeExtension.cs",
    "chars": 1749,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.Models;\nusing System.Coll"
  },
  {
    "path": "src/RulesEngine/HelperFunctions/Constants.cs",
    "chars": 1585,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nnamespace RulesEngine.HelperFunctions\n{\n   "
  },
  {
    "path": "src/RulesEngine/HelperFunctions/ExpressionUtils.cs",
    "chars": 498,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing System;\nusing System.Linq;\n\nnamespace"
  },
  {
    "path": "src/RulesEngine/HelperFunctions/Helpers.cs",
    "chars": 2730,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.Exceptions;\nusing RulesEn"
  },
  {
    "path": "src/RulesEngine/HelperFunctions/MemCache.cs",
    "chars": 3495,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing System;\nusing System.Collections;\nusi"
  },
  {
    "path": "src/RulesEngine/HelperFunctions/Utils.cs",
    "chars": 4507,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing System;\nusing System.Collections;\nusi"
  },
  {
    "path": "src/RulesEngine/Interfaces/IRulesEngine.cs",
    "chars": 2428,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.Models;\nusing System.Coll"
  },
  {
    "path": "src/RulesEngine/Models/ActionInfo.cs",
    "chars": 360,
    "preview": "// Copyright (c) Microsoft Corporation.\n//  Licensed under the MIT License.\n\nusing System.Collections.Generic;\nusing Sy"
  },
  {
    "path": "src/RulesEngine/Models/ActionResult.cs",
    "chars": 328,
    "preview": "// Copyright (c) Microsoft Corporation.\n//  Licensed under the MIT License.\n\nusing System;\nusing System.Diagnostics.Code"
  },
  {
    "path": "src/RulesEngine/Models/ActionRuleResult.cs",
    "chars": 333,
    "preview": "// Copyright (c) Microsoft Corporation.\n//  Licensed under the MIT License.\n\nusing System.Collections.Generic;\nusing Sys"
  },
  {
    "path": "src/RulesEngine/Models/ReSettings.cs",
    "chars": 4038,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.Actions;\nusing RulesEngin"
  },
  {
    "path": "src/RulesEngine/Models/Rule.cs",
    "chars": 1478,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing System.Collections.Generic;\nusing Sys"
  },
  {
    "path": "src/RulesEngine/Models/RuleActions.cs",
    "chars": 503,
    "preview": "// Copyright (c) Microsoft Corporation.\n//  Licensed under the MIT License.\n\nusing System;\nusing System.Diagnostics.Code"
  },
  {
    "path": "src/RulesEngine/Models/RuleDelegate.cs",
    "chars": 184,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nnamespace RulesEngine.Models\n{\n    public d"
  },
  {
    "path": "src/RulesEngine/Models/RuleErrorType.cs",
    "chars": 297,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nnamespace RulesEngine.Models\n{\n    /// <sum"
  },
  {
    "path": "src/RulesEngine/Models/RuleExpressionParameter.cs",
    "chars": 480,
    "preview": "// Copyright (c) Microsoft Corporation.\n//  Licensed under the MIT License.\n\nusing System;\nusing System.Diagnostics.Cod"
  },
  {
    "path": "src/RulesEngine/Models/RuleExpressionType.cs",
    "chars": 297,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nnamespace RulesEngine.Models\n{\n    /// <sum"
  },
  {
    "path": "src/RulesEngine/Models/RuleParameter.cs",
    "chars": 1491,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.HelperFunctions;\nusing Sy"
  },
  {
    "path": "src/RulesEngine/Models/RuleResultTree.cs",
    "chars": 2225,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.HelperFunctions;\nusing Sy"
  },
  {
    "path": "src/RulesEngine/Models/ScopedParam.cs",
    "chars": 737,
    "preview": "// Copyright (c) Microsoft Corporation.\n//  Licensed under the MIT License.\n\nusing System.Diagnostics.CodeAnalysis;\n\nna"
  },
  {
    "path": "src/RulesEngine/Models/Workflow.cs",
    "chars": 1496,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing System;\nusing System.Collections.Gene"
  },
  {
    "path": "src/RulesEngine/Properties/AssemblyInfo.cs",
    "chars": 783,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing System.Runtime.CompilerServices;\nusin"
  },
  {
    "path": "src/RulesEngine/RuleCompiler.cs",
    "chars": 11545,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.Exceptions;\nusing RulesEn"
  },
  {
    "path": "src/RulesEngine/RuleExpressionBuilderFactory.cs",
    "chars": 1076,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.ExpressionBuilders;\nusing"
  },
  {
    "path": "src/RulesEngine/RulesCache.cs",
    "chars": 5642,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.HelperFunctions;\nusing Ru"
  },
  {
    "path": "src/RulesEngine/RulesEngine.cs",
    "chars": 20063,
    "preview": "// Copyright (c) Microsoft Corporation.\r\n// Licensed under the MIT License.\r\n\r\nusing FluentValidation;\r\nusing RulesEngi"
  },
  {
    "path": "src/RulesEngine/RulesEngine.csproj",
    "chars": 2640,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>net6.0;net8.0;net9.0;netstandard2.0</TargetFr"
  },
  {
    "path": "src/RulesEngine/Validators/RuleValidator.cs",
    "chars": 2286,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing FluentValidation;\nusing RulesEngine.H"
  },
  {
    "path": "src/RulesEngine/Validators/WorkflowRulesValidator.cs",
    "chars": 802,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing FluentValidation;\nusing RulesEngine.H"
  },
  {
    "path": "test/RulesEngine.UnitTest/ActionTests/ActionContextTests.cs",
    "chars": 6253,
    "preview": "// Copyright (c) Microsoft Corporation.\n//  Licensed under the MIT License.\n\nusing AutoFixture;\nusing RulesEngine.Action"
  },
  {
    "path": "test/RulesEngine.UnitTest/ActionTests/CustomActionTest.cs",
    "chars": 2905,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing Newtonsoft.Json;\nusing RulesEngine.Mo"
  },
  {
    "path": "test/RulesEngine.UnitTest/ActionTests/MockClass/ReturnContextAction.cs",
    "chars": 912,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.Actions;\nusing RulesEngin"
  },
  {
    "path": "test/RulesEngine.UnitTest/ActionTests/RulesEngineWithActionsTests.cs",
    "chars": 9108,
    "preview": "// Copyright (c) Microsoft Corporation.\n//  Licensed under the MIT License.\nusing RulesEngine.Models;\nusing System;\nusin"
  },
  {
    "path": "test/RulesEngine.UnitTest/BusinessRuleEngineTest.cs",
    "chars": 45192,
    "preview": "// Copyright (c) Microsoft Corporation.\r\n// Licensed under the MIT License.\r\n\r\nusing Moq;\r\nusing Newtonsoft.Json;\r\nusin"
  },
  {
    "path": "test/RulesEngine.UnitTest/CaseSensitiveTests.cs",
    "chars": 1489,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.Models;\nusing System;\nusi"
  },
  {
    "path": "test/RulesEngine.UnitTest/CustomTypeProviderTests.cs",
    "chars": 3656,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing Moq;\nusing System;\nusing System.Collec"
  },
  {
    "path": "test/RulesEngine.UnitTest/EmptyRulesTest.cs",
    "chars": 5900,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing Newtonsoft.Json;\nusing RulesEngine.Mo"
  },
  {
    "path": "test/RulesEngine.UnitTest/ExpressionUtilsTest.cs",
    "chars": 790,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.HelperFunctions;\nusing Sy"
  },
  {
    "path": "test/RulesEngine.UnitTest/LambdaExpressionBuilderTest.cs",
    "chars": 1661,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.ExpressionBuilders;\nusing"
  },
  {
    "path": "test/RulesEngine.UnitTest/ListofRuleResultTreeExtensionTest.cs",
    "chars": 6372,
    "preview": "// Copyright (c) Microsoft Corporation.\n//  Licensed under the MIT License.\n\nusing RulesEngine.Extensions;\nusing RulesE"
  },
  {
    "path": "test/RulesEngine.UnitTest/NestedRulesTest.cs",
    "chars": 9768,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing Newtonsoft.Json;\nusing RulesEngine.Mo"
  },
  {
    "path": "test/RulesEngine.UnitTest/ParameterNameChangeTest.cs",
    "chars": 1702,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.Models;\nusing System;\nusin"
  },
  {
    "path": "test/RulesEngine.UnitTest/RuleCompilerTest.cs",
    "chars": 1313,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.ExpressionBuilders;\nusing"
  },
  {
    "path": "test/RulesEngine.UnitTest/RuleExpressionBuilderFactoryTest.cs",
    "chars": 1043,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.ExpressionBuilders;\nusing"
  },
  {
    "path": "test/RulesEngine.UnitTest/RuleExpressionParserTests/RuleExpressionParserTests.cs",
    "chars": 2374,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing Newtonsoft.Json.Linq;\nusing RulesEngi"
  },
  {
    "path": "test/RulesEngine.UnitTest/RuleParameterTests.cs",
    "chars": 554,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing AutoFixture;\nusing RulesEngine.Models"
  },
  {
    "path": "test/RulesEngine.UnitTest/RuleTestClass.cs",
    "chars": 469,
    "preview": "// Copyright (c) Microsoft Corporation.\n//  Licensed under the MIT License.\n\nusing Newtonsoft.Json;\nusing System.Diagno"
  },
  {
    "path": "test/RulesEngine.UnitTest/RuleValidationTest.cs",
    "chars": 3235,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing Newtonsoft.Json;\nusing RulesEngine.He"
  },
  {
    "path": "test/RulesEngine.UnitTest/RulesEnabledTests.cs",
    "chars": 7338,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\nusing RulesEngine.Models;\nusing System.Colle"
  },
  {
    "path": "test/RulesEngine.UnitTest/RulesEngine.UnitTest.csproj",
    "chars": 2610,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFrameworks>net6.0;net8.0;net9.0</TargetFrameworks>\n    <S"
  },
  {
    "path": "test/RulesEngine.UnitTest/ScopedParamsTest.cs",
    "chars": 18069,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.Models;\nusing System;\nusi"
  },
  {
    "path": "test/RulesEngine.UnitTest/TestData/rules1.json",
    "chars": 346,
    "preview": "{\n  \"WorkflowName\": \"inputWorkflow\",\n  \"Rules\": [\n    {\n      \"RuleName\": \"GiveDiscount10\",\n      \"SuccessEvent\": \"10\",\n"
  },
  {
    "path": "test/RulesEngine.UnitTest/TestData/rules10.json",
    "chars": 283,
    "preview": "{\n    \"WorkflowName\": \"inputWorkflow\",\n    \"Rules\": [\n      {\n        \"RuleName\": \"GiveDiscount10\",\n        \"SuccessEven"
  },
  {
    "path": "test/RulesEngine.UnitTest/TestData/rules11.json",
    "chars": 1377,
    "preview": "{\n  \"WorkflowName\": \"MyWorkflow\",\n  \"WorkflowsToInject\": null,\n  \"RuleExpressionType\": 0,\n  \"GlobalParams\": [\n    {\n    "
  },
  {
    "path": "test/RulesEngine.UnitTest/TestData/rules2.json",
    "chars": 1503,
    "preview": "{\n  \"WorkflowName\": \"inputWorkflow\",\n  \"Rules\": [\n    {\n      \"RuleName\": \"Rule1\",\n      \"Operator\": \"Or\",\n      \"ErrorM"
  },
  {
    "path": "test/RulesEngine.UnitTest/TestData/rules3.json",
    "chars": 443,
    "preview": "{\n  \"WorkflowName\": \"inputWorkflow\",\n  \"Rules\": [\n    {\n      \"RuleName\": \"GiveDiscount10\",\n      \"SuccessEvent\": \"10\",\n"
  },
  {
    "path": "test/RulesEngine.UnitTest/TestData/rules4.json",
    "chars": 3336,
    "preview": "[\n  {\n    \"WorkflowName\": \"inputWorkflow\",\n    \"Rules\": [\n      {\n        \"RuleName\": \"GiveDiscount10\",\n        \"Success"
  },
  {
    "path": "test/RulesEngine.UnitTest/TestData/rules5.json",
    "chars": 627,
    "preview": "{\n  \"WorkflowName\": \"inputWorkflow\",\n  \"Rules\": [\n    {\n      \"RuleName\": \"upperCaseAccess\",\n      \"SuccessEvent\": \"10\","
  },
  {
    "path": "test/RulesEngine.UnitTest/TestData/rules6.json",
    "chars": 1005,
    "preview": "{\n    \"WorkflowName\": \"inputWorkflow\",\n    \"Rules\": [\n        {\n            \"RuleName\": \"GiveDiscount10\",\n            \"S"
  },
  {
    "path": "test/RulesEngine.UnitTest/TestData/rules7.json",
    "chars": 654,
    "preview": "{\n    \"WorkflowName\": \"inputWorkflow\",\n    \"Rules\": [\n        {\n            \"RuleName\": \"GiveDiscount10\",\n            \"S"
  },
  {
    "path": "test/RulesEngine.UnitTest/TestData/rules8.json",
    "chars": 672,
    "preview": "{\n    \"WorkflowName\": \"inputWorkflow\",\n    \"Rules\": [\n        {\n            \"RuleName\": \"GiveDiscount10\",\n            \"S"
  },
  {
    "path": "test/RulesEngine.UnitTest/TestData/rules9.json",
    "chars": 626,
    "preview": "{\n    \"WorkflowName\": \"inputWorkflow\",\n    \"Rules\": [\n      {\n        \"RuleName\": \"GiveDiscount10\",\n        \"SuccessEven"
  },
  {
    "path": "test/RulesEngine.UnitTest/TypedClassTests.cs",
    "chars": 6758,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing RulesEngine.Models;\nusing System;\nusi"
  },
  {
    "path": "test/RulesEngine.UnitTest/UtilsTests.cs",
    "chars": 3228,
    "preview": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nusing Newtonsoft.Json.Linq;\nusing RulesEngi"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the microsoft/RulesEngine GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 123 files (359.4 KB), approximately 79.3k tokens, and a symbol index with 353 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!