Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4,694 changes: 4,694 additions & 0 deletions .ai/outputs/codebase.txt

Large diffs are not rendered by default.

71 changes: 71 additions & 0 deletions .github/codebase.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# codebase.ps1 - Generate codebase documentation for AI analysis
# This script creates a comprehensive text file containing the directory structure
# and all source code files from your project's source directory for AI processing.
#
# Customize the $sourceDirectory path to match your project's structure.

$repoRoot = git rev-parse --show-toplevel

Write-Host "Repository root: $repoRoot"

$sourceDirectory = Join-Path $repoRoot 'src' # Change this to your source directory
Write-Host "Source directory: $sourceDirectory"

$outputDir = "$repoRoot/.ai/outputs" # Change this to your preferred output location
if (-not (Test-Path $outputDir)) {
New-Item -ItemType Directory -Path $outputDir -Force
}

$outputPath = Join-Path $outputDir 'codebase.txt'
Write-Host "Output path: $outputPath"

# Build directory tree
$directoryTree = Get-ChildItem -Directory -Path $sourceDirectory -Recurse -Exclude obj, bin | Where-Object {
(-not $_.FullName.Contains('Tests'))
} | ForEach-Object {
$indent = ' ' * ($_.FullName.Split('\').Length - $sourceDirectory.Split('\').Length)
"$indent- $($_.Name)"
} | Out-String

$contextBlock = "$directoryTree`n# --- Start of Code Files ---`n`n"
Set-Content -Path $outputPath -Value $contextBlock

# Extension -> language mapping
$languageMap = @{
'.cs' = 'csharp'
'.ps1' = 'powershell'
'.json' = 'json'
'.xml' = 'xml'
'.yml' = 'yaml'
'.yaml' = 'yaml'
'.md' = 'markdown'
'.sh' = 'bash'
'.ts' = 'typescript'
'.js' = 'javascript'
}

# Grab all files except bin/obj
$allFiles = Get-ChildItem -Path $sourceDirectory -Recurse -File -Include *.cs, *.ps1, *.json, *.xml, *.yml, *.yaml, *.md, *.sh, *.ts, *.js | Where-Object {
-not $_.DirectoryName.ToLower().Contains('tests')
}

foreach ($file in $allFiles) {
$relativePath = $file.FullName.Substring($PWD.Path.Length + 1)

# Determine language based on extension (default: text)
$ext = $file.Extension.ToLower()
$lang = if ($languageMap.ContainsKey($ext)) { $languageMap[$ext] } else { 'text' }

$filePathHeader = @"
// File: $relativePath
"@

$codeBlockStart = @"
```$lang
"@
$codeBlockEnd = "`n``````"

$fileContent = Get-Content -Path $file.FullName | Out-String
$formattedContent = $filePathHeader + $codeBlockStart + $fileContent + $codeBlockEnd
Add-Content -Path $outputPath -Value $formattedContent
}
28 changes: 28 additions & 0 deletions .github/workflows/prerelease-nuget.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Publish Preview Nuget

on:
push:
tags:
- "[0-9]*.[0-9]*.[0-9]*-*" # Matches semver tags with a suffix, e.g., 1.2.3-preview, 1.2.3-beta1
workflow_dispatch:

permissions:
contents: write

jobs:
release-nuget-preview:
name: Publish Preview NuGet Package
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Run Tests
run: dotnet run .build/targets.cs test
- name: Pack NuGet Package
run: dotnet run .build/targets.cs pack
- name: Push NuGet Package
run: dotnet nuget push "dist/nuget/*.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source "https://api.nuget.org/v3/index.json" --skip-duplicate
2 changes: 2 additions & 0 deletions .github/workflows/release-nuget.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ on:
push:
tags:
- "[0-9]+.[0-9]+.[0-9]+"
branches:
- main

permissions:
contents: write
Expand Down
145 changes: 145 additions & 0 deletions docs/low-level-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# Lower-Level API: Reader, Writer, and AST

For scenarios where the high-level `KdlSerializer` is too restrictive, Kuddle.Net provides direct access to the KDL AST (Abstract Syntax Tree) via `KdlReader` and `KdlWriter`.

## Reading KDL (KdlReader)

`KdlReader.Read` parses a KDL string and returns a `KdlDocument`.

```csharp
using Kuddle.AST;
using Kuddle.Serialization;

string kdl = "node 1 2 key=\"val\"";
KdlDocument doc = KdlReader.Read(kdl);

foreach (KdlNode node in doc.Nodes)
{
Console.WriteLine($"Node name: {node.Name.Value}");
}
```

### Options

`KdlReaderOptions` allows you to customize the reading process:

```csharp
var options = new KdlReaderOptions
{
ValidateReservedTypes = true // Validates (uuid), (date-time), etc. format
};

KdlDocument doc = KdlReader.Read(kdl, options);
```

---

## Writing KDL (KdlWriter)

`KdlWriter.Write` takes a `KdlDocument` (or any `KdlObject`) and returns its KDL string representation.

```csharp
var doc = new KdlDocument();
// ... build doc ...

string kdl = KdlWriter.Write(doc);
// Or use doc.ToString() which uses default options
```

### Options

`KdlWriterOptions` controls the output formatting:

```csharp
var options = new KdlWriterOptions
{
IndentChar = "\t",
NewLine = "\r\n",
SpaceAfterProp = " ",
EscapeUnicode = true
};

string kdl = KdlWriter.Write(doc, options);
```

---

## The KDL AST

The AST is composed of records representing KDL constructs.

### `KdlDocument`

The root of a KDL file.

- `Nodes`: `List<KdlNode>`

### `KdlNode`

A single KDL node.

- `Name`: `KdlString`
- `Entries`: `List<KdlEntry>` (Arguments or Properties)
- `Children`: `KdlBlock?` (Nested nodes)
- `TypeAnnotation`: `string?`

### `KdlEntry`

Base class for entries within a node.

- `KdlArgument`: Positional value (`KdlValue`)
- `KdlProperty`: Key-value pair (`KdlString Key`, `KdlValue Value`)

### `KdlValue`

Base class for all constants.

- `KdlString`: Represents strings. Support for varieties via `StringKind`:
- `StringKind.Bare`: `bare-string`
- `StringKind.Quoted`: `"quoted string"`
- `StringKind.Raw`: `r#"raw string"#`
- `StringKind.MultiLine`: `"""multi-line string"""`
- `KdlNumber`: Represents numeric values. Stores the `RawValue` string to preserve precision and formatting (e.g., `0xFF` vs `255`).
- `KdlBool`: `#true` or `#false`.
- `KdlNull`: `#null`.

---

## Serialization Options

When using `KdlSerializer`, you can pass `KdlSerializerOptions` to control the behavior:

```csharp
var options = new KdlSerializerOptions
{
IgnoreNullValues = true, // Don't write properties with null values
CaseInsensitiveNames = true, // Match KDL names to C# properties case-insensitively
WriteTypeAnnotations = true // Include (uuid), (date-time) etc. in output
};

string kdl = KdlSerializer.Serialize(myObj, options);
```

---

## Extension Methods

Kuddle.Net provides helpful extension methods in `Kuddle.Extensions` for working with the AST:

```csharp
using Kuddle.Extensions;

KdlNode node = ...;

// Get property value
KdlValue? val = node.Prop("my-key");

// Get argument by index
KdlValue? arg = node.Arg(0);

// Try to get typed values
if (node.TryGetProp<int>("port", out int port))
{
// ...
}
```
Loading