You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# Copilot Instructions for PSFluentObjectValidation
2
+
3
+
## Project Overview
4
+
PSFluentObjectValidation is a PowerShell module that provides fluent syntax for validating complex object structures using dot notation with validation operators. The core functionality is implemented as a C# class embedded in PowerShell, supporting deep object traversal, array indexing, and wildcard validation.
5
+
6
+
## Architecture
7
+
8
+
### Core Components
9
+
-**C# Implementation**: `PSFluentObjectValidation/Private/PSFluentObjectValidation.ps1` contains the main logic as embedded C# code using `Add-Type`
10
+
-**Public Functions**: Thin PowerShell wrappers around the C# class
11
+
-`Test-Exist`: Safe validation that returns boolean
12
+
-`Assert-Exist`: Throws exceptions with detailed error messages
13
+
-**Module Structure**: Standard PowerShell module with Public/Private folder separation
14
+
15
+
### Key Design Patterns
16
+
17
+
#### Validation Syntax
18
+
The module uses a fluent dot notation with special operators:
-`property?` - Existence validation (allows null values)
22
+
-`array[0]` - Array indexing
23
+
-`array[*]` - Wildcard validation (all elements must pass)
24
+
25
+
#### Error Handling Strategy
26
+
-`Test-Exist` wraps `Assert-Exist` in try/catch, never throws
27
+
-`Assert-Exist` provides detailed error messages with context
28
+
- C# implementation uses regex patterns for parsing validation operators
29
+
30
+
## Development Workflows
31
+
32
+
### Build System (psake + PowerShellBuild)
33
+
```powershell
34
+
# Bootstrap dependencies first (one-time setup)
35
+
./build.ps1 -Bootstrap
36
+
37
+
# Standard development workflow
38
+
./build.ps1 -Task Build # Compiles and validates module
39
+
./build.ps1 -Task Test # Runs Pester tests + analysis
40
+
./build.ps1 -Task Clean # Cleans output directory
41
+
```
42
+
43
+
The build uses PowerShellBuild tasks defined in `psakeFile.ps1`. The `requirements.psd1` manages all build dependencies including Pester 5.4.0, PSScriptAnalyzer, and psake.
44
+
45
+
### Testing Strategy
46
+
Tests live in `tests/` directory following these patterns:
-`Meta.tests.ps1` - Code quality and PSScriptAnalyzer rules
49
+
-`Help.tests.ps1` - Documentation validation
50
+
- Use `ScriptAnalyzerSettings.psd1` for custom analysis rules
51
+
52
+
### Module Compilation
53
+
The module uses **non-monolithic** compilation (`$PSBPreference.Build.CompileModule = $false`), preserving individual Public/Private .ps1 files in the output rather than combining into a single .psm1.
54
+
55
+
## Critical Implementation Details
56
+
57
+
### C# Embedded Code Patterns
58
+
When modifying the C# implementation:
59
+
- Use `Add-Type` with `ReferencedAssemblies` for System.Management.Automation
60
+
- Regex patterns are compiled for performance: `PropertyWithValidation`, `ArrayIndexPattern`
- Include property path context: `"Property 'user.name' does not exist"`
98
+
- For arrays: `"Array index [10] is out of bounds for 'users' (length: 5)"`
99
+
- For wildcards: `"Property 'email' in element [2] is empty"`
100
+
101
+
## Cross-Platform Considerations
102
+
The module targets PowerShell 5.1+ and supports Windows/Linux/macOS. The CI pipeline tests on all three platforms using GitHub Actions with the psmodulecache action for dependency management.
return new WildcardArrayWrapper(firstPropertyValue);
269
+
}
270
+
else
271
+
{
272
+
int index = int.Parse(indexStr);
273
+
int count = GetCount(firstPropertyValue);
274
+
if (index < 0 || index >= count)
275
+
throw new InvalidOperationException(String.Format("Array index [{0}] is out of bounds for property '{1}' (length: {2})", index, basePropertyName, count));
276
+
277
+
if (firstPropertyValue is Array)
278
+
{
279
+
Array firstArray = (Array)firstPropertyValue;
280
+
return firstArray.GetValue(index);
281
+
}
282
+
if (firstPropertyValue is IList)
283
+
{
284
+
IList firstList = (IList)firstPropertyValue;
285
+
return firstList[index];
286
+
}
287
+
}
288
+
}
289
+
290
+
if (arrayObject is IList)
291
+
{
292
+
IList list = (IList)arrayObject;
293
+
for (int i = 0; i < list.Count; i++)
294
+
{
295
+
object element = list[i];
296
+
if (element == null)
297
+
throw new InvalidOperationException(String.Format("Array element [{0}] is null", i));
298
+
if (!HasProperty(element, basePropertyName))
299
+
throw new InvalidOperationException(String.Format("Array element [{0}] does not have property '{1}'", i, basePropertyName));
return new WildcardArrayWrapper(firstPropertyValue);
315
+
}
316
+
else
317
+
{
318
+
int index = int.Parse(indexStr);
319
+
int count = GetCount(firstPropertyValue);
320
+
if (index < 0 || index >= count)
321
+
throw new InvalidOperationException(String.Format("Array index [{0}] is out of bounds for property '{1}' (length: {2})", index, basePropertyName, count));
322
+
323
+
if (firstPropertyValue is Array)
324
+
{
325
+
Array firstArray = (Array)firstPropertyValue;
326
+
return firstArray.GetValue(index);
327
+
}
328
+
if (firstPropertyValue is IList)
329
+
{
330
+
IList firstList = (IList)firstPropertyValue;
331
+
return firstList[index];
332
+
}
333
+
}
334
+
}
335
+
336
+
throw new InvalidOperationException(String.Format("Cannot process wildcard array indexing on type {0}", arrayObject.GetType().Name));
337
+
}
338
+
339
+
340
+
228
341
// Parse validation suffix if present
229
342
Match validationMatch = PropertyWithValidation.Match(propertyName);
Copy file name to clipboardExpand all lines: PSFluentObjectValidation/Public/Assert-Exist.ps1
+36Lines changed: 36 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -1,3 +1,39 @@
1
+
<#
2
+
.SYNOPSIS
3
+
Asserts the existence and validity of a property within an object.
4
+
5
+
.DESCRIPTION
6
+
The `Assert-Exist` function validates the existence of a property within an object and ensures it meets the specified validation criteria. If the validation fails, it throws a detailed exception, making it suitable for scenarios where strict validation is required.
7
+
8
+
.PARAMETERInputObject
9
+
The object to validate. This can be a hashtable, PSObject, .NET object, or any other object type.
10
+
11
+
.PARAMETERKey
12
+
The property path to validate. Supports fluent syntax with validation operators:
Copy file name to clipboardExpand all lines: PSFluentObjectValidation/Public/Test-Exist.ps1
+36Lines changed: 36 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -1,3 +1,39 @@
1
+
<#
2
+
.SYNOPSIS
3
+
Tests the existence and validity of a property within an object.
4
+
5
+
.DESCRIPTION
6
+
The `Test-Exist` function validates the existence of a property within an object and ensures it meets the specified validation criteria. Unlike `Assert-Exist`, this function does not throw exceptions; instead, it returns a boolean value indicating whether the validation passed.
7
+
8
+
.PARAMETERInputObject
9
+
The object to validate. This can be a hashtable, PSObject, .NET object, or any other object type.
10
+
11
+
.PARAMETERKey
12
+
The property path to validate. Supports fluent syntax with validation operators:
0 commit comments