Skip to content

Commit ccd9663

Browse files
Enhance semantic string type conversions and path handling
This commit introduces several improvements to the semantic string conversion API and path handling methods: - Added a new extension method `As<TSource, TTarget>()` for converting between different semantic string types, providing a fluent syntax for type conversions. - Consolidated the `AsAbsolute()` method across various path interfaces to return the appropriate concrete types, removing redundant methods like `AsAbsoluteFilePath()` and `AsAbsoluteDirectoryPath()`. - Updated documentation for clarity on the new conversion methods and their usage. - Enhanced unit tests to validate the new functionality and ensure correct behavior across different path types.
1 parent 2ef86b3 commit ccd9663

20 files changed

Lines changed: 3279 additions & 34 deletions

.cursor/rules/derived-cursor-rules.mdc

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,91 @@ When adding XML documentation comments:
234234
* **IDE0060 Warning**: Replace unused parameters with `_`.
235235
* **Semantic Path Length**: Most systems have a path limit around 260 chars (Windows) or 4096 (Unix). Use a limit that works on all systems for testing. Use a limit that works on all systems for testing.
236236
* **Formatting Errors**: Apply `dotnet format` to fix formatting errors (IDE0055).
237+
* **Semantic String Conversion**: For converting **one semantic string type to another**, you can use the pattern of converting to string first and then to the target type:
238+
```csharp
239+
// Example: Converting from one semantic string type to another
240+
var sourceSemanticString = "example".As<SourceType>();
241+
var targetSemanticString = sourceSemanticString.ToString().As<TargetType>();
242+
243+
// Or using implicit conversion to string:
244+
var targetSemanticString = ((string)sourceSemanticString).As<TargetType>();
245+
```
246+
* **SemanticStringExtensions Class**: The `SemanticStringExtensions` class provides three main extension methods:
247+
1. **`As<TDerived>(this string? value)`** - Converts a string to any semantic string type
248+
2. **`As<TDerived>(this char[]? value)`** - Converts a character array to any semantic string type
249+
3. **`As<TDerived>(this ReadOnlySpan<char> value)`** - Converts a read-only character span to any semantic string type
250+
* **SemanticStringExtensions.As\<TSource, TTarget\> Method**:
251+
* Converts one semantic string type to another semantic string type.
252+
* Provides a fluent syntax for converting between semantic string types.
253+
```csharp
254+
// Example:
255+
var emailAddress = "user@example.com".As<EmailAddress>();
256+
var userName = emailAddress.As<EmailAddress, UserName>(); // Explicit type parameters
257+
// or with type inference in many cases:
258+
var userName = emailAddress.As<UserName>(); // Will infer the source type
259+
```
260+
* Leverages the existing `SemanticString<T>.Create<T>()` factory method.
261+
* **Path Interfaces - AsAbsolute Method**:
262+
* The `IFilePath` and `IDirectoryPath` interfaces include the `AsAbsolute()` method.
263+
* `AsAbsolute()` converts the path to an absolute path representation.
264+
* For relative paths, `AsAbsolute()` resolves against the current working directory.
265+
* For absolute paths, `AsAbsolute()` returns the path itself.
266+
* **Path Conversion API**:
267+
* **API Design Principles**
268+
1. Consistent Naming: All conversion methods use the `As*()` prefix
269+
2. Clear Purpose: Different method signatures for different conversion scenarios
270+
3. Type Safety: Return concrete types for predictable behavior
271+
4. Polymorphism: Works seamlessly through interfaces
272+
273+
* **Complete API Reference**
274+
275+
#### **Interface-to-Concrete Conversions** (Type Casting)
276+
277+
* `AsAbsoluteFilePath()` - Cast interface to concrete absolute file path (REDUNDANT - REMOVE)
278+
* `AsRelativeFilePath()` - Cast interface to concrete relative file path (REDUNDANT - REMOVE)
279+
* `AsAbsoluteDirectoryPath()` - Cast interface to concrete absolute directory path (REDUNDANT - REMOVE)
280+
* `AsRelativeDirectoryPath()` - Cast interface to concrete relative directory path (REDUNDANT - REMOVE)
281+
282+
#### **Path Category Conversions** (Path Transformations)
283+
284+
* `AsAbsolute()` - Convert to absolute using current working directory
285+
* `AsAbsolute(baseDirectory)` - Convert to absolute using specific base directory
286+
* `AsRelative(baseDirectory)` - Convert to relative using specific base directory
287+
288+
* **Conversion Matrix**
289+
290+
| **From Type** | **AsAbsolute()** | **AsAbsolute(base)** | **AsRelative(base)** |
291+
| :---------------------- | :------------------------- | :----------------------------- | :----------------------------- |
292+
| `AbsoluteFilePath` | Returns self | Returns self | Creates `RelativeFilePath` |
293+
| `RelativeFilePath` | Uses CWD | Uses base directory | Returns self |
294+
| `FilePath` | Uses CWD | Uses CWD + base logic | Uses CWD + base logic |
295+
| `AbsoluteDirectoryPath` | Returns self | Returns self | Creates `RelativeDirectoryPath` |
296+
| `RelativeDirectoryPath` | Uses CWD | Uses base directory | Returns self |
297+
| `DirectoryPath` | Uses CWD | Uses CWD + base logic | Uses CWD + base logic |
298+
299+
* **Usage Examples**
300+
301+
```csharp
302+
// Interface-based polymorphic usage
303+
IFilePath somePath = GetSomeFilePath();
304+
AbsoluteFilePath absolutePath = somePath.AsAbsolute();
305+
306+
// Converting between absolute and relative
307+
AbsoluteDirectoryPath baseDir = AbsoluteDirectoryPath.Create<AbsoluteDirectoryPath>("C:\\base");
308+
RelativeFilePath relativeFile = RelativeFilePath.Create<RelativeFilePath>("sub\\file.txt");
309+
310+
// Convert relative to absolute with specific base
311+
AbsoluteFilePath absoluteFile = relativeFile.AsAbsolute(baseDir);
312+
313+
// Convert absolute to relative using base
314+
RelativeFilePath backToRelative = absoluteFile.AsRelative(baseDir);
315+
316+
// Interface conversions
317+
IAbsoluteFilePath iAbsFile = absoluteFile;
318+
AbsoluteFilePath concrete = iAbsFile.AsAbsoluteFilePath();
319+
```
320+
321+
* **Redundant Interface Conversions**: The interface conversion methods like `AsAbsoluteDirectoryPath()` are redundant given the consolidated `As*()` API and direct casting, and should be removed.
237322

238323
## DEBUGGING
239324

0 commit comments

Comments
 (0)