diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
new file mode 100644
index 0000000..5cd79ab
--- /dev/null
+++ b/.config/dotnet-tools.json
@@ -0,0 +1,18 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "husky": {
+ "version": "0.7.2",
+ "commands": [
+ "husky"
+ ]
+ },
+ "csharpier": {
+ "version": "1.0.3",
+ "commands": [
+ "csharpier"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..8babb0b
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1 @@
+* @bmazzarol
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..654ba62
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,38 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '…'
+2. Click on '…'
+3. Scroll down to '…'
+4. See error.
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Desktop (please complete the following information):**
+ - OS: [e.g. iOS]
+ - Browser [e.g. chrome, safari]
+ - Version [e.g. 22]
+
+**Smartphone (please complete the following information):**
+ - Device: [e.g. iPhone6]
+ - OS: [e.g. iOS8.1]
+ - Browser [e.g. stock browser, safari]
+ - Version [e.g. 22]
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..5f43738
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when (...)
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/workflows/build-deploy-docs.yml b/.github/workflows/build-deploy-docs.yml
new file mode 100644
index 0000000..85c55d5
--- /dev/null
+++ b/.github/workflows/build-deploy-docs.yml
@@ -0,0 +1,17 @@
+name: Build and Deploy Docs
+
+on:
+ push:
+ branches: [main]
+
+jobs:
+ build-and-deploy-docs:
+ runs-on: ubuntu-latest
+ permissions:
+ pages: write
+ id-token: write
+ steps:
+ - uses: bmazzarol/bmazzarol/.github/actions/build-deploy-docs@main
+ with:
+ docsProjectPath: Cutout.Docs
+ csProjFileName: Cutout.Docs.csproj
diff --git a/.github/workflows/cd-build.yml b/.github/workflows/cd-build.yml
new file mode 100644
index 0000000..7ae2866
--- /dev/null
+++ b/.github/workflows/cd-build.yml
@@ -0,0 +1,23 @@
+name: CD Build
+
+on:
+ workflow_dispatch:
+ inputs:
+ version:
+ description: Release Version
+ required: true
+ release:
+ types: [published]
+
+env:
+ PACKAGE_VERSION: ${{ github.event.inputs.version || github.event.release.tag_name }}
+
+jobs:
+ publish:
+ name: Publish to Nuget
+ runs-on: ubuntu-latest
+ steps:
+ - uses: bmazzarol/bmazzarol/.github/actions/cd-build@main
+ with:
+ version: ${{ env.PACKAGE_VERSION }}
+ nugetKey: ${{ secrets.NUGET_API_KEY }}
diff --git a/.github/workflows/check-code-format.yml b/.github/workflows/check-code-format.yml
new file mode 100644
index 0000000..89f0122
--- /dev/null
+++ b/.github/workflows/check-code-format.yml
@@ -0,0 +1,12 @@
+name: Check C# Formatting
+
+on:
+ pull_request:
+ branches: [main]
+
+jobs:
+ check_formatting:
+ runs-on: ubuntu-latest
+ name: Check C# Formatting
+ steps:
+ - uses: bmazzarol/bmazzarol/.github/actions/check-code-format@main
diff --git a/.github/workflows/check-commit-message.yml b/.github/workflows/check-commit-message.yml
new file mode 100644
index 0000000..6250ed2
--- /dev/null
+++ b/.github/workflows/check-commit-message.yml
@@ -0,0 +1,12 @@
+name: Check Commit Message
+
+on:
+ pull_request:
+ branches: [main]
+
+jobs:
+ commitlint:
+ if: ${{ github.actor != 'dependabot[bot]' }}
+ runs-on: ubuntu-latest
+ steps:
+ - uses: bmazzarol/bmazzarol/.github/actions/check-commit-message@main
diff --git a/.github/workflows/check-docs.yml b/.github/workflows/check-docs.yml
new file mode 100644
index 0000000..47a10d8
--- /dev/null
+++ b/.github/workflows/check-docs.yml
@@ -0,0 +1,14 @@
+name: Check the Docfx site
+
+on:
+ pull_request:
+ branches: [main]
+
+jobs:
+ check-docs:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: bmazzarol/bmazzarol/.github/actions/check-docs@main
+ with:
+ docsProjectPath: Cutout.Docs
+ csProjFileName: Cutout.Docs.csproj
diff --git a/.github/workflows/check-markdown.yml b/.github/workflows/check-markdown.yml
new file mode 100644
index 0000000..4379dd8
--- /dev/null
+++ b/.github/workflows/check-markdown.yml
@@ -0,0 +1,21 @@
+name: Check Markdown
+
+on:
+ push:
+ branches: [main]
+ paths:
+ - "**/*.md"
+ - .github/workflows/check-markdown.yml
+ pull_request:
+ branches: [main]
+
+jobs:
+ lint:
+ runs-on: ubuntu-latest
+ permissions:
+ statuses: write
+ steps:
+ - uses: bmazzarol/bmazzarol/.github/actions/check-markdown@main
+ with:
+ targetMdFiles: |
+ "Cutout*/**/*.md" "Cutout.Docs/**/*.md" "*.md" "!LICENSE.md"
\ No newline at end of file
diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml
new file mode 100644
index 0000000..a436f4c
--- /dev/null
+++ b/.github/workflows/ci-build.yml
@@ -0,0 +1,22 @@
+name: CI Build
+
+on:
+ push:
+ branches: [main]
+ pull_request:
+ branches: [main]
+
+jobs:
+ build:
+ if: ${{ github.actor != 'dependabot[bot]' }}
+ name: Build and analyze
+ runs-on: ubuntu-latest
+ permissions:
+ checks: write
+ pull-requests: write
+ steps:
+ - uses: bmazzarol/bmazzarol/.github/actions/ci-build@main
+ with:
+ githubToken: ${{ secrets.GITHUB_TOKEN }}
+ sonarToken: ${{ secrets.SONAR_TOKEN }}
+ sonarProjectKey: bmazzarol_Cutout
\ No newline at end of file
diff --git a/.github/workflows/test-reporter.yml b/.github/workflows/test-reporter.yml
new file mode 100644
index 0000000..0aed7fb
--- /dev/null
+++ b/.github/workflows/test-reporter.yml
@@ -0,0 +1,18 @@
+name: Test Reporter
+
+on:
+ workflow_run:
+ workflows: [CI Build]
+ types: [completed]
+
+jobs:
+ report:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: dorny/test-reporter@v1
+ with:
+ artifact: test-results
+ name: Test Results
+ path: |
+ **/*.trx
+ reporter: dotnet-trx
diff --git a/.husky/commit-msg b/.husky/commit-msg
new file mode 100644
index 0000000..fd2e998
--- /dev/null
+++ b/.husky/commit-msg
@@ -0,0 +1,22 @@
+#!/bin/sh
+. "$(dirname "$0")/_/husky.sh"
+
+## husky task runner examples -------------------
+## Note : for local installation use 'dotnet' prefix. e.g. 'dotnet husky'
+
+## run all tasks
+#husky run
+
+### run all tasks with group: 'group-name'
+#husky run --group group-name
+
+## run task with name: 'task-name'
+#husky run --name task-name
+
+## pass hook arguments to task
+#husky run --args "$1" "$2"
+
+## or put your custom commands -------------------
+#echo 'Husky.Net is awesome!'
+
+npx --no -- commitlint --edit ${1}
diff --git a/.husky/pre-commit b/.husky/pre-commit
new file mode 100644
index 0000000..fd85d23
--- /dev/null
+++ b/.husky/pre-commit
@@ -0,0 +1,22 @@
+#!/bin/sh
+. "$(dirname "$0")/_/husky.sh"
+
+## husky task runner examples -------------------
+## Note : for local installation use 'dotnet' prefix. e.g. 'dotnet husky'
+
+## run all tasks
+#husky run
+
+### run all tasks with group: 'group-name'
+#husky run --group group-name
+
+## run task with name: 'task-name'
+#husky run --name task-name
+
+## pass hook arguments to task
+#husky run --args "$1" "$2"
+
+## or put your custom commands -------------------
+#echo 'Husky.Net is awesome!'
+
+dotnet husky run
diff --git a/.husky/task-runner.json b/.husky/task-runner.json
new file mode 100644
index 0000000..ed079de
--- /dev/null
+++ b/.husky/task-runner.json
@@ -0,0 +1,39 @@
+{
+ "tasks": [
+ {
+ "name": "Format C# Code",
+ "command": "dotnet",
+ "args": [
+ "csharpier",
+ "format",
+ "."
+ ]
+ },
+ {
+ "name": "Lint Markdown",
+ "command": "npx",
+ "args": [
+ "markdownlint-cli2",
+ "Cutout*/**/*.md",
+ "Cutout.Docs/**/*.md",
+ "*.md",
+ "!LICENSE.md"
+ ]
+ },
+ {
+ "name": "Test C# Code",
+ "command": "dotnet",
+ "args": [
+ "test"
+ ]
+ },
+ {
+ "name": "Lint Docs",
+ "command": "dotnet",
+ "args": [
+ "build",
+ "Cutout.Docs/Cutout.Docs.csproj"
+ ]
+ }
+ ]
+}
diff --git a/Cutout.Docs/.config/dotnet-tools.json b/Cutout.Docs/.config/dotnet-tools.json
new file mode 100644
index 0000000..6e7d362
--- /dev/null
+++ b/Cutout.Docs/.config/dotnet-tools.json
@@ -0,0 +1,12 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "docfx": {
+ "version": "2.78.2",
+ "commands": [
+ "docfx"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/Cutout.Docs/.gitignore b/Cutout.Docs/.gitignore
new file mode 100644
index 0000000..9ebe008
--- /dev/null
+++ b/Cutout.Docs/.gitignore
@@ -0,0 +1,3 @@
+_site
+api
+doctests
\ No newline at end of file
diff --git a/Cutout.Docs/Cutout.Docs.csproj b/Cutout.Docs/Cutout.Docs.csproj
new file mode 100644
index 0000000..445083c
--- /dev/null
+++ b/Cutout.Docs/Cutout.Docs.csproj
@@ -0,0 +1,3 @@
+
+
+
diff --git a/Cutout.Docs/articles/getting-started.md b/Cutout.Docs/articles/getting-started.md
new file mode 100644
index 0000000..d1ea31e
--- /dev/null
+++ b/Cutout.Docs/articles/getting-started.md
@@ -0,0 +1,25 @@
+# Getting Started
+
+To use this library, simply include `Cutout.dll` in your project or grab
+it from [NuGet](https://www.nuget.org/packages/Cutout/), and add a reference to it.
+
+```xml
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+```
+
+Then use the `Cutout.Template` attribute to define a template method.
+
+[!code-csharp[](../../Cutout.Sample/Examples.cs#ParameterExample)]
+
+The first parameter is the `StringBuilder`-like type to write to. Everything
+else passed can be used in the template.
+
+The template must be a compile-time constant string, so it can be defined
+as a `const` field or inline in the attribute.
+
+[!code-csharp[](../../Cutout.Sample/Examples.cs#ExampleWithConditionAndConstTemplate)]
diff --git a/Cutout.Docs/articles/rules/CUTOUT001.md b/Cutout.Docs/articles/rules/CUTOUT001.md
new file mode 100644
index 0000000..3751111
--- /dev/null
+++ b/Cutout.Docs/articles/rules/CUTOUT001.md
@@ -0,0 +1,9 @@
+# CUTOUT001 - Invalid Template
+
+The template used is not valid in some way. This could be due to a syntax
+error, or it could be that the template is not compatible with the Cutout
+version of the liquid language.
+
+The error will indicate the line number and position where the parser
+encountered the issue. The user should review the template string and
+resolve the problem.
diff --git a/Cutout.Docs/articles/rules/toc.yml b/Cutout.Docs/articles/rules/toc.yml
new file mode 100644
index 0000000..a6bb6c5
--- /dev/null
+++ b/Cutout.Docs/articles/rules/toc.yml
@@ -0,0 +1,3 @@
+items:
+ - name: (CUTOUT001) Invalid Template
+ href: CUTOUT001.md
diff --git a/Cutout.Docs/articles/template/break.md b/Cutout.Docs/articles/template/break.md
new file mode 100644
index 0000000..8eaa20e
--- /dev/null
+++ b/Cutout.Docs/articles/template/break.md
@@ -0,0 +1,21 @@
+# Break Statement
+
+The `break` statement can be used inside loops to exit the loop early,
+just like in C#.
+
+## Syntax
+
+```c#
+{% break %}
+```
+
+## Example
+
+```c#
+{% for i = 0; i < 10; i++ %}
+ {% if i == 5 %}
+ {% break %}
+ {% end %}
+ Value: {{ i }}
+{% end %}
+```
diff --git a/Cutout.Docs/articles/template/call.md b/Cutout.Docs/articles/template/call.md
new file mode 100644
index 0000000..3c37b96
--- /dev/null
+++ b/Cutout.Docs/articles/template/call.md
@@ -0,0 +1,16 @@
+# Call Statement
+
+The `call` statement allows you to invoke other template methods decorated
+with `[Cutout.Template]`.
+
+## Syntax
+
+```c#
+{% call MethodName(arg1, arg2) %}
+```
+
+## Example
+
+```c#
+{% call RenderHeader("Title") %}
+```
diff --git a/Cutout.Docs/articles/template/continue.md b/Cutout.Docs/articles/template/continue.md
new file mode 100644
index 0000000..6e8819f
--- /dev/null
+++ b/Cutout.Docs/articles/template/continue.md
@@ -0,0 +1,21 @@
+# Continue Statement
+
+The `continue` statement can be used inside loops to skip to the next iteration
+, just like in C#.
+
+## Syntax
+
+```c#
+{% continue %}
+```
+
+## Example
+
+```c#
+{% for i = 0; i < 10; i++ %}
+ {% if i % 2 == 0 %}
+ {% continue %}
+ {% end %}
+ Odd: {{ i }}
+{% end %}
+```
diff --git a/Cutout.Docs/articles/template/for.md b/Cutout.Docs/articles/template/for.md
new file mode 100644
index 0000000..c126822
--- /dev/null
+++ b/Cutout.Docs/articles/template/for.md
@@ -0,0 +1,19 @@
+# For Statement
+
+The `for` statement allows you to write C#-style for loops in your template.
+
+## Syntax
+
+```c#
+{% for i = 0; i < items.Count; i++ %}
+ ...
+{% end %}
+```
+
+## Example
+
+```c#
+{% for i = 0; i < items.Count; i++ %}
+Item: {{ items[i] }}
+{% end %}
+```
diff --git a/Cutout.Docs/articles/template/foreach.md b/Cutout.Docs/articles/template/foreach.md
new file mode 100644
index 0000000..46fbb26
--- /dev/null
+++ b/Cutout.Docs/articles/template/foreach.md
@@ -0,0 +1,20 @@
+# Foreach Statement
+
+The `foreach` statement allows you to iterate over collections in your template
+using C# syntax.
+
+## Syntax
+
+```c#
+{% foreach item in items %}
+ ...
+{% end %}
+```
+
+## Example
+
+```c#
+{% foreach item in items %}
+Item: {{ item }}
+{% end %}
+```
diff --git a/Cutout.Docs/articles/template/if.md b/Cutout.Docs/articles/template/if.md
new file mode 100644
index 0000000..1469369
--- /dev/null
+++ b/Cutout.Docs/articles/template/if.md
@@ -0,0 +1,26 @@
+# If/Else Statement
+
+The `if` statement allows conditional rendering in templates.
+The condition must be a valid C# boolean expression.
+
+## Syntax
+
+```c#
+{% if condition %}
+ ...
+{% elseif otherCondition %}
+ ...
+{% else %}
+ ...
+{% end %}
+```
+
+## Example
+
+```c#
+{% if name == "Bob" %}
+Hello Bob
+{% else %}
+Hello {{ name }}
+{% end %}
+```
diff --git a/Cutout.Docs/articles/template/return.md b/Cutout.Docs/articles/template/return.md
new file mode 100644
index 0000000..a052110
--- /dev/null
+++ b/Cutout.Docs/articles/template/return.md
@@ -0,0 +1,19 @@
+# Return Statement
+
+The `return` statement can be used to exit from a template method early,
+similar to C#.
+
+## Syntax
+
+```c#
+{% return %}
+```
+
+## Example
+
+```c#
+{% if shouldExit %}
+ {% return %}
+{% end %}
+Continue rendering...
+```
diff --git a/Cutout.Docs/articles/template/syntax.md b/Cutout.Docs/articles/template/syntax.md
new file mode 100644
index 0000000..ff9b3ee
--- /dev/null
+++ b/Cutout.Docs/articles/template/syntax.md
@@ -0,0 +1,61 @@
+# Template Definition
+
+Cutout templates use a syntax inspired
+by [Liquid](https://shopify.github.io/liquid/), but support C# expressions
+instead of the custom language that Liquid uses. This allows you to write
+templates that are both powerful and easy to read, while leveraging the full
+capabilities of C#.
+
+## Syntax Overview
+
+* **Literals:** Any text outside of `{{ ... }}` or `{% ... %}` is treated as a
+ string literal and written directly to the output.
+* **Expressions:** Use `{{ ... }}` to insert the value of any valid C#
+ expression.
+* **Blocks:** Use `{% ... %}` for control flow (e.g., if, for, foreach, while)
+ and function calls.
+* **Whitespace Control:** Whitespace can be managed using the `-` character,
+ similar to Liquid. For example, `{%- ... -%}` trims whitespace around the
+ block.
+
+### Example
+
+```csharp
+private const string Template = """
+ {% if name == "Bob" %}
+ Hello Bob
+ {% else %}
+ Hello {{ name }}
+ {% end %}
+ """;
+
+[Cutout.Template(Template)]
+public static partial void MyTemplateMethod(StringBuilder sb, string name);
+```
+
+## Whitespace Handling
+
+Cutout supports whitespace control similar to
+[Liquid's whitespace basics](https://shopify.github.io/liquid/basics/whitespace/)
+:
+
+* `{% ... %}`: Preserves whitespace around the block.
+* `{%- ... %}`: Trims whitespace before the block.
+* `{% ... -%}`: Trims whitespace after the block.
+* `{%- ... -%}`: Trims whitespace both before and after the block.
+* The same applies to output tags: `{{ ... }}`, `{{- ... }}`, `{{ ... -}}`,
+ `{{- ... -}}`.
+
+This allows for fine-grained control over the formatting of generated code,
+making it easier to maintain correct indentation and spacing.
+
+## Deviations from Liquid Standard
+
+| Feature | Cutout Implementation | Liquid Standard |
+|--------------------|-------------------------------------------------|---------------------------------------------------|
+| End Block | Single `{% end %}` for all blocks | Specific `{% endif %}`, `{% endfor %}` etc. |
+| Expressions | Must be valid C# expressions | Liquid expressions |
+| Function Calls | `{% call Function(args) %}` | Not supported in Liquid |
+| Loop Syntax | C# style (`for`, `foreach`, `while`) | Liquid style (`for ... in ...`) |
+| Whitespace Control | Same as Liquid (`-` modifier) | Liquid whitespace control |
+| Conditionals | Only one conditional statement (`if`) supported | Multiple conditional types (`if`, `unless`, etc.) |
diff --git a/Cutout.Docs/articles/template/toc.yml b/Cutout.Docs/articles/template/toc.yml
new file mode 100644
index 0000000..052e332
--- /dev/null
+++ b/Cutout.Docs/articles/template/toc.yml
@@ -0,0 +1,21 @@
+items:
+ - name: Syntax
+ href: syntax.md
+ - name: If/Else
+ href: if.md
+ - name: For
+ href: for.md
+ - name: Foreach
+ href: foreach.md
+ - name: While
+ href: while.md
+ - name: Call
+ href: call.md
+ - name: Var
+ href: var.md
+ - name: Continue
+ href: continue.md
+ - name: Break
+ href: break.md
+ - name: Return
+ href: return.md
diff --git a/Cutout.Docs/articles/template/var.md b/Cutout.Docs/articles/template/var.md
new file mode 100644
index 0000000..59c45f1
--- /dev/null
+++ b/Cutout.Docs/articles/template/var.md
@@ -0,0 +1,17 @@
+# Var Statement
+
+The `var` statement allows you to declare variables within your template
+using C# syntax.
+
+## Syntax
+
+```c#
+{% var x = 10 %}
+```
+
+## Example
+
+```c#
+{% var greeting = "Hello" %}
+{{ greeting }}
+```
diff --git a/Cutout.Docs/articles/template/while.md b/Cutout.Docs/articles/template/while.md
new file mode 100644
index 0000000..bbb868f
--- /dev/null
+++ b/Cutout.Docs/articles/template/while.md
@@ -0,0 +1,19 @@
+# While Statement
+
+The `while` statement allows you to write C#-style while loops in your template.
+
+## Syntax
+
+```c#
+{% while condition %}
+ ...
+{% end %}
+```
+
+## Example
+
+```c#
+{% while i < 10 %}
+Value: {{ i }}
+{% end %}
+```
diff --git a/Cutout.Docs/docfx.json b/Cutout.Docs/docfx.json
new file mode 100644
index 0000000..e89aae7
--- /dev/null
+++ b/Cutout.Docs/docfx.json
@@ -0,0 +1,37 @@
+{
+ "metadata": [],
+ "build": {
+ "content": [
+ {
+ "files": [
+ "articles/**.md",
+ "articles/**.yml",
+ "toc.yml",
+ "*.md"
+ ]
+ }
+ ],
+ "resource": [
+ {
+ "files": [
+ "images/**"
+ ]
+ }
+ ],
+ "postProcessors": [
+ "ExtractSearchIndex"
+ ],
+ "template": [
+ "default",
+ "modern",
+ "template"
+ ],
+ "output": "_site",
+ "globalMetadata": {
+ "_appName": "Cutout",
+ "_appLogoPath": "images/scissors-icon.png",
+ "_appFaviconPath": "images/favicon.ico",
+ "_appFooter": "Created By Ben Mazzarol"
+ }
+ }
+}
\ No newline at end of file
diff --git a/Cutout.Docs/images/favicon.ico b/Cutout.Docs/images/favicon.ico
new file mode 100644
index 0000000..c4097a9
Binary files /dev/null and b/Cutout.Docs/images/favicon.ico differ
diff --git a/Cutout.Docs/images/scissors-icon.png b/Cutout.Docs/images/scissors-icon.png
new file mode 100644
index 0000000..5c546e5
Binary files /dev/null and b/Cutout.Docs/images/scissors-icon.png differ
diff --git a/Cutout.Docs/index.md b/Cutout.Docs/index.md
new file mode 100644
index 0000000..44406ac
--- /dev/null
+++ b/Cutout.Docs/index.md
@@ -0,0 +1,40 @@
+
+
+
+

+
+# Cutout
+
+---
+
+[](https://www.nuget.org/packages/Cutout/)
+[](https://sonarcloud.io/summary/new_code?id=bmazzarol_Cutout)
+[](https://sonarcloud.io/summary/new_code?id=bmazzarol_Cutout)
+[](https://github.com/bmazzarol/Cutout/actions/workflows/cd-build.yml)
+[](https://github.com/bmazzarol/Cutout/actions/workflows/check-markdown.yml)
+
+Zero cost :muscle: source generated templating for .NET
+
+---
+
+
+
+## Why?
+
+When building source generators there is a requirement to generate source code
+as a string that has indentation managed correctly. The code also needs to be
+as fast as possible to not impact users in large repositories.
+
+The recommended approach is to use
+the [IndentedTextWriter](https://learn.microsoft.com/en-us/dotnet/api/system.codedom.compiler.indentedtextwriter?view=net-9.0)
+. This class is simple to use, but is low level.
+
+A standard template engine is a better approach from a code maintenance
+perspective, but the performance is not as good.
+
+This aims to provide the best of both worlds.
+
+It's a source generator, so can be used in other source generators without
+incurring a dependency on a template engine, and it lets you use a simplified
+version of [liquid](https://shopify.github.io/liquid/) and any type that
+implements the basic StringBuilder API.
diff --git a/Cutout.Docs/template/public/main.css b/Cutout.Docs/template/public/main.css
new file mode 100644
index 0000000..4228cef
--- /dev/null
+++ b/Cutout.Docs/template/public/main.css
@@ -0,0 +1,18 @@
+#logo {
+ margin-right: 1em;
+ height: 2.5em;
+}
+
+.navbar {
+ background-color: var(--bs-border-color);
+}
+
+body > footer {
+ background-color: var(--bs-tertiary-bg);
+ height: auto;
+ padding: 0.5em;
+}
+
+body > footer.border-top {
+ border-top-color: var(--bs-tertiary-bg);
+}
diff --git a/Cutout.Docs/template/public/main.js b/Cutout.Docs/template/public/main.js
new file mode 100644
index 0000000..0c99bf7
--- /dev/null
+++ b/Cutout.Docs/template/public/main.js
@@ -0,0 +1,9 @@
+export default {
+ iconLinks: [
+ {
+ icon: 'github',
+ href: 'https://github.com/bmazzarol/Cutout',
+ title: 'GitHub'
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Cutout.Docs/toc.yml b/Cutout.Docs/toc.yml
new file mode 100644
index 0000000..045380b
--- /dev/null
+++ b/Cutout.Docs/toc.yml
@@ -0,0 +1,9 @@
+items:
+ - name: About
+ href: index.md
+ - name: Getting Started
+ href: articles/getting-started.md
+ - name: Template
+ href: articles/template/
+ - name: Analyser Rules
+ href: articles/rules/
diff --git a/Cutout.Sample/Examples.cs b/Cutout.Sample/Examples.cs
index deff70e..d62b7eb 100644
--- a/Cutout.Sample/Examples.cs
+++ b/Cutout.Sample/Examples.cs
@@ -6,4 +6,30 @@ public static partial class Examples
{
[Template("This is a very simple example")]
public static partial void Test(this StringBuilder builder);
+
+ #region ParameterExample
+
+ [Template("This is a very simple example with a {{parameter}} parameter")]
+ public static partial void Test2(this StringBuilder builder, string parameter);
+
+ #endregion
+
+ #region ExampleWithConditionAndConstTemplate
+
+ private const string TemplateExample = """
+ A multi-line template example
+ with a {{parameter}} parameter.
+
+ It also has a conditional section,
+ {%- if parameter == "INVALID" -%}
+ show this text
+ {%- else -%}
+ show this text instead
+ {%- end -%}
+ """;
+
+ [Template(TemplateExample)]
+ public static partial void Test3(this StringBuilder builder, string parameter);
+
+ #endregion
}
diff --git a/Cutout.sln b/Cutout.sln
index 1db3910..4f05841 100644
--- a/Cutout.sln
+++ b/Cutout.sln
@@ -6,6 +6,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cutout.Sample", "Cutout.Sam
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cutout.Tests", "Cutout.Tests\Cutout.Tests.csproj", "{EA3D7126-C006-47DE-AF88-AEC0F5FD485E}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cutout.Docs", "Cutout.Docs\Cutout.Docs.csproj", "{8D842E29-21B3-4D8A-9EA5-581795C0132A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -24,5 +26,9 @@ Global
{EA3D7126-C006-47DE-AF88-AEC0F5FD485E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EA3D7126-C006-47DE-AF88-AEC0F5FD485E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EA3D7126-C006-47DE-AF88-AEC0F5FD485E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8D842E29-21B3-4D8A-9EA5-581795C0132A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8D842E29-21B3-4D8A-9EA5-581795C0132A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8D842E29-21B3-4D8A-9EA5-581795C0132A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8D842E29-21B3-4D8A-9EA5-581795C0132A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/Cutout/README.md b/Cutout/README.md
index 3b7209f..90bacbc 100644
--- a/Cutout/README.md
+++ b/Cutout/README.md
@@ -51,7 +51,7 @@ public static partial class MyTemplate
## Template Language
-Everything that is not between `{{` or `{@` and `}}` or `%}` is treated as a
+Everything that is not between `{{` or `{@` and `}}` or `%}` is treated as a
string literal.
Any valid C# expression can be used in the template as it is compiled to C#
diff --git a/README.md b/README.md
index dd09a14..433e719 100644
--- a/README.md
+++ b/README.md
@@ -67,7 +67,7 @@ public static partial class MyTemplate
## Template Language
-Everything that is not between `{{` or `{@` and `}}` or `%}` is treated as a
+Everything that is not between `{{` or `{@` and `}}` or `%}` is treated as a
string literal.
Any valid C# expression can be used in the template as it is compiled to C#
diff --git a/commitlint.config.js b/commitlint.config.js
new file mode 100644
index 0000000..de8425d
--- /dev/null
+++ b/commitlint.config.js
@@ -0,0 +1,15 @@
+module.exports = {
+ extends: ['@commitlint/config-conventional'],
+ rules: {
+ "subject-case": [0, 'never'],
+ "subject-max-length": [2, "always", 100],
+ "scope-enum": _ => [
+ 2,
+ "always",
+ [
+ "deps",
+ "docs"
+ ]
+ ]
+ }
+}