Skip to content

Commit 41cdb70

Browse files
arika0093Copilotgithub-actions[bot]
authored
Ver 0.4.1 (#176)
* chore: use .NET10 only (#165) * chore: update projects to use only .NET 10.0 * chore: update devcontainer to use only .NET 10.0 (cherry picked from commit 19c02fd) * Update GitHub repository link in README (cherry picked from commit 27bc288) * Fix badge links in README.md (cherry picked from commit b0b98e4) * Add Linqraft Playground web application (#166) * Initial plan * feat: add Linqraft Playground web application - Create Blazor WebAssembly project for interactive Linqraft demo - Add Monaco Editor for C# syntax highlighting - Implement template selection sidebar with sample code - Add file navigation pane - Create query expression preview pane (readonly) - Create DTO class preview pane (readonly) - Add resizable pane layout - Include 4 sample templates from examples - Add GitHub Pages deployment workflow Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * refactor: address review feedback - Remove GitHub Actions workflow (to be prepared separately) - Replace Bootstrap with Tailwind CSS custom utilities - Break Home.razor into Sidebar, EditorPane, PreviewPane components - Add JetBrains Mono font for Monaco editor - Add .monaco-editor-container height fix - Update code generation to be per template unit - Update TemplateService with clearer documentation Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * feat: integrate Roslyn and add collapse buttons - Integrate Linqraft.Core with Roslyn for actual code generation - Add collapse buttons to preview panes (▲/▼) - Use Visual Studio theme for preview panes - Remove HttpClient from services - Use custom Tailwind CSS utilities (build-time generated CSS) - Handle WebAssembly environment for metadata references Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * fix: code generation now works with proper Roslyn compilation - Add using directives and SelectExpr stub to templates for Roslyn analysis - Default to file containing SelectExpr when template is selected - Use dark theme for all editor panes - Make collapse buttons less conspicuous - Add IsHidden property to ProjectFile for internal stub files - Use Basic.Reference.Assemblies.Net90 for Roslyn compilation Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * feat: add debounce, settings dialog, and fix collapse behavior - Add 300ms debounce for code generation after input stops - Add settings dialog for LinqraftConfiguration with all options - Set CommentOutput to None by default - Fix collapse button behavior to preserve generated content - Remove hardcoded file names from query conditions - Add Settings button to sidebar Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * fix: address code review feedback - Fix CommentOutput default value fallback to None (0) - Extract debounce delay to named constant DebounceDelayMs Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * fix: properly parse multiple source files for code generation - Parse each file into its own syntax tree for correct Roslyn compilation - This fixes type resolution issues where all types became 'object' - Add bracket pair colorization to Monaco editors - DTO classes now show correct types (int, DateTime, string, List<T>, etc.) Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * fix: cache semantic models to avoid redundant GetSemanticModel calls Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * some fixes * space fix * feat: add home page and improve UX - Rename Home.razor to Playground.razor at /playground route - Create new Home.razor at / with intro to Linqraft and Playground link - Move settings into sidebar as collapsible section like Templates/Files - Make preview pane headers fully clickable to toggle collapse - Remove resize cursor from dividers (visual only) - Delete SettingsDialog.razor (no longer needed) - Update navigation in MainLayout Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * template update * small fix * use Tailwind.Hosting * feat: add semantic syntax highlighting with Roslyn - Create SemanticHighlightingService using Roslyn to extract tokens - Add JavaScript for applying Monaco decorations via JSInterop - Apply CSS styling matching Visual Studio dark theme colors - Highlight class names (cyan), methods (yellow), properties (light blue) - Apply highlighting to both editor and preview panes - Debounce highlighting updates to 200ms Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * fix: address code review feedback - Fix array bounds check in getClassName JS function - Replace System.Timers.Timer with CancellationTokenSource for debouncing - Extract magic number 100ms to InitialHighlightDelayMs constant Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * feat: improve semantic highlighting for generics and keywords - Add highlighting for generic type arguments (e.g., Order in List<Order>) - Add highlighting for contextual keywords (required, init) - Add record declaration highlighting - Handle nullable types and array types in generics - Add CSS style for keyword highlighting - Fixed ProcessNode to process TypeArgumentListSyntax Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * feat: share CSharpCompilation between code generation and semantic highlighting - Create SharedCompilationService for consistent compilation across services - Include SelectExpr extension methods source (from ConstSourceCodes) for Roslyn recognition - Add generated code to compilation for accurate highlighting - Update CodeGenerationService to use shared compilation - Update SemanticHighlightingService to use shared compilation - Add IsExpressionPane parameter to PreviewPane for correct highlighting context Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * superfix * format * feat: add TargetFramework to Linqraft.MinimumSample project * test sdk deps update * path changed --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> Co-authored-by: Arika Ishinami <delete0093@gmail.com> (cherry picked from commit 663c4ce) * chore: apply formatting (cherry picked from commit 8e104be) * wip (cherry picked from commit 1a4a276) * wip (cherry picked from commit 32c9e82) * Add LinqraftNestedDtoNamespace option for namespace-based child DTO naming (#168) * Initial plan * Add LinqraftNestedDtoNamespace configuration option Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * option name renamed * testcase merged * option name changed and use new generate logic in playground * Remove hash suffix from generated nested DTO class names and add configuration option --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> Co-authored-by: Arika Ishinami <delete0093@gmail.com> (cherry picked from commit a6395aa) * chore: apply formatting (cherry picked from commit d11684c) * style: enhance typography and spacing across components (cherry picked from commit 7db5008) * Refactor Playground Home page with component separation, Prism.js syntax highlighting, and vertical layout (#169) * Initial plan * Improve Playground Home page with rotating features, sticky tabs, code comparison, syntax highlighting, and NuGet icon Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * Fix code review issues: accessibility, HttpClient usage, and error handling Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * Fix extra closing brackets and use HttpRequestMessage for thread-safe API calls Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * Improve timer handling with CancellationToken and proper disposal Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * fix * fix * Refactor Home page into separate components with Prism.js syntax highlighting and lazy loading Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * Fix Playground page by restoring service registration Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * Fix code review issues: clarify auto-generated DTOs and fix Prism.js bugs Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * Improve Prism.js regex handling for global flag Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * wip * small fix * style updated * wip * Update Key Features section: replace "Production-Ready Performance" with "Escape Anytime" and revise description for clarity * smallfix * Add GitHub Actions workflow for deploying to GitHub Pages and update project dependencies --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> Co-authored-by: Arika Ishinami <delete0093@gmail.com> (cherry picked from commit f904a31) * chore: apply formatting (cherry picked from commit bf330e2) * some fixed (cherry picked from commit a7a8ce6) * update (cherry picked from commit eb09770) * fix: downgrade .NET version to 9.0 in playground because PublishSPAforGitHubPages.Build is not support .NET 10 yet (maybe...) (cherry picked from commit 498dfe9) * Revert "fix: downgrade .NET version to 9.0 in playground" This reverts commit 498dfe9. (cherry picked from commit 42609f6) * fix: update links to use relative paths in FaqSection, HeroSection, and MainLayout (cherry picked from commit 7724e05) * add bg to hero section (cherry picked from commit 9caadf1) * website visual update (cherry picked from commit baa4b38) * style updated (cherry picked from commit 24b1c0d) * refactor: improve layout and styling in HeroSection, EditorPane, Sidebar, and Playground components; update package references (cherry picked from commit 9e459a5) * fix (cherry picked from commit 211f7b5) * feat: implement C# syntax highlighting and update layout styles across components (cherry picked from commit 68784a0) * fix: update property names in order DTO generation for clarity (cherry picked from commit 86f4fcc) * fix: update Tailwind CDN usage to conditional rendering based on build configuration (cherry picked from commit 60c337f) * feat: enhance C# syntax highlighting to include property and field declarations (cherry picked from commit 6155e8f) * feat: update KeyFeaturesSection layout and styles for improved readability and consistency (cherry picked from commit 1b5c17d) * feat: enhance C# syntax highlighting to differentiate between type and property declarations (cherry picked from commit b10a002) * feat: implement collapsible editor pane and sidebar for improved UI/UX (cherry picked from commit 61b249e) * feat: add links to web page and online playground in README; improve layout in EditorPane and PreviewPane (cherry picked from commit 115ec4a) * feat: simplify Playground layout by removing unused CSS classes and improving responsiveness (cherry picked from commit ebe2a02) * feat: Add Min Repro template and URL sharing for issue reporting (#174) * Initial plan * Initial plan for issue reporting template Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * feat: Add Min Repro template and URL sharing for issue reporting Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * feat: Enhance Min Repro template with additional sample classes for better issue reproduction * feat: Refactor UrlStateService to streamline navigation manager usage and improve code readability * feat: Update Sidebar buttons and styles for improved UI consistency --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> Co-authored-by: Arika Ishinami <delete0093@gmail.com> (cherry picked from commit a57f41a) * Fix documentation comment extraction for nested properties and Select expressions (#175) close #172 * Initial plan * Fix documentation extraction for nested properties and Select expressions Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * Improve documentation comments in DtoProperty.cs Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> (cherry picked from commit cd4a277) * chore: apply formatting (cherry picked from commit a942995) * feat: update Sidebar UI and enhance Tailwind CSS styles for improved aesthetics (cherry picked from commit fe339ca) * Integrate LQRS004 ternary null check transformation into LQRS002/LQRS003 (#171) * Initial plan * Initial plan for integrating LQRS004 into LQRS002/LQRS003 Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * Integrate LQRS004 transformation into LQRS002/LQRS003 code fixes Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * Add support for inverted null check conditions in ternary simplification Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * Update LQRS003 options: remove RootOnly, add Struct option Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * Fix terminology: update 'struct' to 'strict' in LQRS003 documentation and related code fix provider * Re-enable LQRS004 and remove ternary simplification from Predefined option Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> * Update LQRS004 documentation to reflect relationship with LQRS002/LQRS003 Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> Co-authored-by: Arika Ishinami <delete0093@gmail.com> (cherry picked from commit f551f00) * chore: apply formatting (cherry picked from commit da9aa16) * fix: update PackageProjectUrl to point to the correct GitHub Pages URL (cherry picked from commit 360e750) * refactor: rename DTO classes for clarity and improve null handling in queries (cherry picked from commit 5336f54) --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: arika0093 <4524647+arika0093@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 5e6b741 commit 41cdb70

File tree

85 files changed

+7178
-321
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+7178
-321
lines changed

.devcontainer/devcontainer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// https://github.com/devcontainers/features/tree/main/src/dotnet
1010
"ghcr.io/devcontainers/features/dotnet:2": {
1111
"version": "latest",
12-
"additionalVersions": "10.0, 8.0, 6.0"
12+
"additionalVersions": "10.0"
1313
}
1414
},
1515
"containerEnv": {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Deploy to GitHub Pages
2+
3+
permissions:
4+
contents: write
5+
6+
on:
7+
push:
8+
branches:
9+
- main
10+
11+
env:
12+
DOTNET_VERSION: '10.0.x'
13+
14+
jobs:
15+
build-and-deploy:
16+
runs-on: ubuntu-latest
17+
18+
steps:
19+
- name: Checkout repository
20+
uses: actions/checkout@v4
21+
with:
22+
fetch-depth: 0
23+
24+
- name: Setup .NET
25+
uses: actions/setup-dotnet@v4
26+
with:
27+
dotnet-version: ${{ env.DOTNET_VERSION }}
28+
29+
- name: Restore dependencies
30+
run: dotnet restore
31+
32+
- name: Build BlazorLocalTimeSample
33+
run: dotnet publish -c:Release -o:public -p:GHPages=true playground/Linqraft.Playground.csproj
34+
35+
- name: Deploy to GitHub Pages
36+
uses: peaceiris/actions-gh-pages@v4
37+
with:
38+
github_token: ${{ secrets.GITHUB_TOKEN }}
39+
publish_dir: public/wwwroot
40+
force_orphan: true

.github/workflows/test.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ on:
1111
- '**./Directories.Build.props'
1212
- '.github/workflows/test.yaml'
1313

14+
env:
15+
DOTNET_VERSION: '10.0.x'
16+
1417
jobs:
1518
build:
1619
strategy:
@@ -28,10 +31,7 @@ jobs:
2831
- name: Setup .NET
2932
uses: actions/setup-dotnet@v4
3033
with:
31-
dotnet-version: |
32-
6.0.x
33-
8.0.x
34-
10.0.x
34+
dotnet-version: ${{ env.DOTNET_VERSION }}
3535
cache: true
3636
cache-dependency-path: '**/packages.lock.json'
3737

Linqraft.slnx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
<Project Path="examples/Linqraft.MinimumSample/Linqraft.MinimumSample.csproj" />
1313
<Project Path="examples/Linqraft.Sample/Linqraft.Sample.csproj" />
1414
</Folder>
15+
<Folder Name="/playground/">
16+
<Project Path="playground/Linqraft.Playground.csproj" />
17+
</Folder>
1518
<Folder Name="/src/">
1619
<File Path="src/Directory.Build.props" />
1720
<Project Path="src/Linqraft.Analyzer/Linqraft.Analyzer.csproj" />

README.md

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11

22
# <img width="24" src="./assets/linqraft.png" /> Linqraft
33

4-
[![NuGet Version](https://img.shields.io/nuget/v/Linqraft?style=flat-square&logo=NuGet&color=0080CC)](https://www.nuget.org/packages/Linqraft/) ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/arika0093/Linqraft/test.yaml?branch=main&label=Test&style=flat-square) [![DeepWiki](https://img.shields.io/badge/DeepWiki-arika0093%2FLinqraft-blue.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAyCAYAAAAnWDnqAAAAAXNSR0IArs4c6QAAA05JREFUaEPtmUtyEzEQhtWTQyQLHNak2AB7ZnyXZMEjXMGeK/AIi+QuHrMnbChYY7MIh8g01fJoopFb0uhhEqqcbWTp06/uv1saEDv4O3n3dV60RfP947Mm9/SQc0ICFQgzfc4CYZoTPAswgSJCCUJUnAAoRHOAUOcATwbmVLWdGoH//PB8mnKqScAhsD0kYP3j/Yt5LPQe2KvcXmGvRHcDnpxfL2zOYJ1mFwrryWTz0advv1Ut4CJgf5uhDuDj5eUcAUoahrdY/56ebRWeraTjMt/00Sh3UDtjgHtQNHwcRGOC98BJEAEymycmYcWwOprTgcB6VZ5JK5TAJ+fXGLBm3FDAmn6oPPjR4rKCAoJCal2eAiQp2x0vxTPB3ALO2CRkwmDy5WohzBDwSEFKRwPbknEggCPB/imwrycgxX2NzoMCHhPkDwqYMr9tRcP5qNrMZHkVnOjRMWwLCcr8ohBVb1OMjxLwGCvjTikrsBOiA6fNyCrm8V1rP93iVPpwaE+gO0SsWmPiXB+jikdf6SizrT5qKasx5j8ABbHpFTx+vFXp9EnYQmLx02h1QTTrl6eDqxLnGjporxl3NL3agEvXdT0WmEost648sQOYAeJS9Q7bfUVoMGnjo4AZdUMQku50McDcMWcBPvr0SzbTAFDfvJqwLzgxwATnCgnp4wDl6Aa+Ax283gghmj+vj7feE2KBBRMW3FzOpLOADl0Isb5587h/U4gGvkt5v60Z1VLG8BhYjbzRwyQZemwAd6cCR5/XFWLYZRIMpX39AR0tjaGGiGzLVyhse5C9RKC6ai42ppWPKiBagOvaYk8lO7DajerabOZP46Lby5wKjw1HCRx7p9sVMOWGzb/vA1hwiWc6jm3MvQDTogQkiqIhJV0nBQBTU+3okKCFDy9WwferkHjtxib7t3xIUQtHxnIwtx4mpg26/HfwVNVDb4oI9RHmx5WGelRVlrtiw43zboCLaxv46AZeB3IlTkwouebTr1y2NjSpHz68WNFjHvupy3q8TFn3Hos2IAk4Ju5dCo8B3wP7VPr/FGaKiG+T+v+TQqIrOqMTL1VdWV1DdmcbO8KXBz6esmYWYKPwDL5b5FA1a0hwapHiom0r/cKaoqr+27/XcrS5UwSMbQAAAABJRU5ErkJggg==)](https://deepwiki.com/arika0093/Linqraft)
4+
[![NuGet Version](https://img.shields.io/nuget/v/Linqraft?style=flat-square&logo=NuGet&color=0080CC)](https://www.nuget.org/packages/Linqraft/) ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/arika0093/Linqraft/test.yaml?branch=main&label=Test&style=flat-square) [![DeepWiki](https://img.shields.io/badge/DeepWiki-Linqraft-blue.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAyCAYAAAAnWDnqAAAAAXNSR0IArs4c6QAAA05JREFUaEPtmUtyEzEQhtWTQyQLHNak2AB7ZnyXZMEjXMGeK/AIi+QuHrMnbChYY7MIh8g01fJoopFb0uhhEqqcbWTp06/uv1saEDv4O3n3dV60RfP947Mm9/SQc0ICFQgzfc4CYZoTPAswgSJCCUJUnAAoRHOAUOcATwbmVLWdGoH//PB8mnKqScAhsD0kYP3j/Yt5LPQe2KvcXmGvRHcDnpxfL2zOYJ1mFwrryWTz0advv1Ut4CJgf5uhDuDj5eUcAUoahrdY/56ebRWeraTjMt/00Sh3UDtjgHtQNHwcRGOC98BJEAEymycmYcWwOprTgcB6VZ5JK5TAJ+fXGLBm3FDAmn6oPPjR4rKCAoJCal2eAiQp2x0vxTPB3ALO2CRkwmDy5WohzBDwSEFKRwPbknEggCPB/imwrycgxX2NzoMCHhPkDwqYMr9tRcP5qNrMZHkVnOjRMWwLCcr8ohBVb1OMjxLwGCvjTikrsBOiA6fNyCrm8V1rP93iVPpwaE+gO0SsWmPiXB+jikdf6SizrT5qKasx5j8ABbHpFTx+vFXp9EnYQmLx02h1QTTrl6eDqxLnGjporxl3NL3agEvXdT0WmEost648sQOYAeJS9Q7bfUVoMGnjo4AZdUMQku50McDcMWcBPvr0SzbTAFDfvJqwLzgxwATnCgnp4wDl6Aa+Ax283gghmj+vj7feE2KBBRMW3FzOpLOADl0Isb5587h/U4gGvkt5v60Z1VLG8BhYjbzRwyQZemwAd6cCR5/XFWLYZRIMpX39AR0tjaGGiGzLVyhse5C9RKC6ai42ppWPKiBagOvaYk8lO7DajerabOZP46Lby5wKjw1HCRx7p9sVMOWGzb/vA1hwiWc6jm3MvQDTogQkiqIhJV0nBQBTU+3okKCFDy9WwferkHjtxib7t3xIUQtHxnIwtx4mpg26/HfwVNVDb4oI9RHmx5WGelRVlrtiw43zboCLaxv46AZeB3IlTkwouebTr1y2NjSpHz68WNFjHvupy3q8TFn3Hos2IAk4Ju5dCo8B3wP7VPr/FGaKiG+T+v+TQqIrOqMTL1VdWV1DdmcbO8KXBz6esmYWYKPwDL5b5FA1a0hwapHiom0r/cKaoqr+27/XcrS5UwSMbQAAAABJRU5ErkJggg==)](https://deepwiki.com/arika0093/Linqraft)
55

66
Write Select queries easily with on-demand DTO generation and null-coalescing operators. No depedendencies.
77

8+
[Web Page](https://arika0093.github.io/Linqraft/) | [Online Playground](https://arika0093.github.io/Linqraft/playground/)
9+
810
## Features
911
### Overview
1012
Linqraft is a Roslyn Source Generator for easily writing `IQueryable` projections with null-propagation and automatic DTO generation.
@@ -82,7 +84,7 @@ namespace Linqraft
8284
CustomerName = o.Customer != null ? (string?)o.Customer.Name : null,
8385
CustomerCountry = o.Customer != null && o.Customer.Address != null && o.Customer.Address.Country != null ? (string?)o.Customer.Address.Country.Name : null,
8486
CustomerCity = o.Customer != null && o.Customer.Address != null && o.Customer.Address.City != null ? (string?)o.Customer.Address.City.Name : null,
85-
CustomerInfo = new global::Tutorial.Dto_F1A64BF4
87+
CustomerInfo = new global::Tutorial.CustomerInfoDto_F1A64BF4
8688
{
8789
Email = o.Customer != null ? (string?)o.Customer.EmailAddress : null,
8890
Phone = o.Customer != null ? (string?)o.Customer.PhoneNumber : null
@@ -100,7 +102,7 @@ namespace Linqraft
100102

101103
namespace Tutorial
102104
{
103-
public partial class Dto_F1A64BF4
105+
public partial class CustomerInfoDto_F1A64BF4
104106
{
105107
public required string? Email { get; set; }
106108
public required string? Phone { get; set; }
@@ -118,7 +120,7 @@ namespace Tutorial
118120
public required string? CustomerName { get; set; }
119121
public required string? CustomerCountry { get; set; }
120122
public required string? CustomerCity { get; set; }
121-
public required global::Tutorial.Dto_F1A64BF4? CustomerInfo { get; set; }
123+
public required global::Tutorial.CustomerInfoDto_F1A64BF4? CustomerInfo { get; set; }
122124
public required global::System.Collections.Generic.List<Tutorial.OrderItemDto_DE33EA40> Items { get; set; }
123125
}
124126
}
@@ -496,6 +498,53 @@ public partial class ParentDto
496498
}
497499
```
498500

501+
### Remove Hash from Generated Class Names
502+
By default, nested DTO classes are generated with hash-suffixed class names (e.g., `ItemsDto_HASH1234`).
503+
This behavior is necessary to avoid class name collisions, but in some cases, the hash name can be inconvenient (for example, in OpenAPI/Swagger where class names are displayed).
504+
In such cases, you can change the behavior to generate nested DTO classes in hash-named namespaces (e.g., `Generated_HASH1234.ItemsDto`) instead.
505+
This option can be controlled using the `LinqraftNestedDtoUseHashNamespace` property.
506+
507+
<details>
508+
<summary>Generated code example</summary>
509+
510+
**LinqraftNestedDtoUseHashNamespace = false (default)**
511+
512+
```csharp
513+
namespace Tutorial
514+
{
515+
public partial class OrderDto
516+
{
517+
public required System.Collections.Generic.List<global::Tutorial.OrderItemDto_DE33EA40> Items { get; set; }
518+
}
519+
520+
public partial class OrderItemDto_DE33EA40
521+
{
522+
public required string? ProductName { get; set; }
523+
}
524+
}
525+
```
526+
527+
**LinqraftNestedDtoUseHashNamespace = true**
528+
529+
```csharp
530+
namespace Tutorial
531+
{
532+
public partial class OrderDto
533+
{
534+
public required System.Collections.Generic.List<global::Tutorial.Generated_DE33EA40.ItemsDto> Items { get; set; }
535+
}
536+
}
537+
namespace Tutorial.Generated_DE33EA40
538+
{
539+
public partial class ItemsDto
540+
{
541+
public required string? ProductName { get; set; }
542+
}
543+
}
544+
```
545+
546+
</details>
547+
499548
### Auto generated comments
500549
Linqraft attempts to retrieve comments attached to the original properties as much as possible and attach them as XML documentation comments to the properties of the DTO class.
501550
In addition, reference information indicating what kind of query the DTO class was generated from is also attached.
@@ -607,6 +656,9 @@ Linqraft supports several MSBuild properties to customize the generated code:
607656
<LinqraftCommentOutput>All</LinqraftCommentOutput>
608657
<!-- remove nullability from array-type properties -->
609658
<LinqraftArrayNullabilityRemoval>true</LinqraftArrayNullabilityRemoval>
659+
<!-- generate nested DTOs in hash-named namespace (e.g., Generated_HASH.ItemsDto) -->
660+
<!-- instead of hash-suffixed class names (e.g., ItemsDto_HASH) -->
661+
<LinqraftNestedDtoUseHashNamespace>false</LinqraftNestedDtoUseHashNamespace>
610662
</PropertyGroup>
611663
</Project>
612664
```

docs/README.nuget.md

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[![NuGet Version](https://img.shields.io/nuget/v/Linqraft?style=flat-square&logo=NuGet&color=0080CC)](https://www.nuget.org/packages/Linqraft/) ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/arika0093/Linqraft/test.yaml?branch=main&label=Test&style=flat-square) [![DeepWiki](https://img.shields.io/badge/DeepWiki-arika0093%2FLinqraft-blue.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAyCAYAAAAnWDnqAAAAAXNSR0IArs4c6QAAA05JREFUaEPtmUtyEzEQhtWTQyQLHNak2AB7ZnyXZMEjXMGeK/AIi+QuHrMnbChYY7MIh8g01fJoopFb0uhhEqqcbWTp06/uv1saEDv4O3n3dV60RfP947Mm9/SQc0ICFQgzfc4CYZoTPAswgSJCCUJUnAAoRHOAUOcATwbmVLWdGoH//PB8mnKqScAhsD0kYP3j/Yt5LPQe2KvcXmGvRHcDnpxfL2zOYJ1mFwrryWTz0advv1Ut4CJgf5uhDuDj5eUcAUoahrdY/56ebRWeraTjMt/00Sh3UDtjgHtQNHwcRGOC98BJEAEymycmYcWwOprTgcB6VZ5JK5TAJ+fXGLBm3FDAmn6oPPjR4rKCAoJCal2eAiQp2x0vxTPB3ALO2CRkwmDy5WohzBDwSEFKRwPbknEggCPB/imwrycgxX2NzoMCHhPkDwqYMr9tRcP5qNrMZHkVnOjRMWwLCcr8ohBVb1OMjxLwGCvjTikrsBOiA6fNyCrm8V1rP93iVPpwaE+gO0SsWmPiXB+jikdf6SizrT5qKasx5j8ABbHpFTx+vFXp9EnYQmLx02h1QTTrl6eDqxLnGjporxl3NL3agEvXdT0WmEost648sQOYAeJS9Q7bfUVoMGnjo4AZdUMQku50McDcMWcBPvr0SzbTAFDfvJqwLzgxwATnCgnp4wDl6Aa+Ax283gghmj+vj7feE2KBBRMW3FzOpLOADl0Isb5587h/U4gGvkt5v60Z1VLG8BhYjbzRwyQZemwAd6cCR5/XFWLYZRIMpX39AR0tjaGGiGzLVyhse5C9RKC6ai42ppWPKiBagOvaYk8lO7DajerabOZP46Lby5wKjw1HCRx7p9sVMOWGzb/vA1hwiWc6jm3MvQDTogQkiqIhJV0nBQBTU+3okKCFDy9WwferkHjtxib7t3xIUQtHxnIwtx4mpg26/HfwVNVDb4oI9RHmx5WGelRVlrtiw43zboCLaxv46AZeB3IlTkwouebTr1y2NjSpHz68WNFjHvupy3q8TFn3Hos2IAk4Ju5dCo8B3wP7VPr/FGaKiG+T+v+TQqIrOqMTL1VdWV1DdmcbO8KXBz6esmYWYKPwDL5b5FA1a0hwapHiom0r/cKaoqr+27/XcrS5UwSMbQAAAABJRU5ErkJggg==)](https://deepwiki.com/arika0093/Linqraft)
44

5-
Simplifies Select query expressions for EntityFrameworkCore (EF Core) by providing automatic DTO generation and support for null-propagating expressions.
5+
Write Select queries easily with on-demand DTO generation and null-coalescing operators. No depedendencies.
66

77
For Example:
88

@@ -12,18 +12,26 @@ var orders = await dbContext.Orders
1212
// OrderDto: output DTO type (auto-generated)
1313
.SelectExpr<Order, OrderDto>(o => new
1414
{
15-
Id = o.Id,
16-
// you can use null-propagating operator (?.)
15+
// can use inferred member names
16+
o.Id,
17+
// null-propagation supported
1718
CustomerName = o.Customer?.Name,
19+
// also works for nested objects
1820
CustomerCountry = o.Customer?.Address?.Country?.Name,
1921
CustomerCity = o.Customer?.Address?.City?.Name,
20-
// Items type will be also auto-generated
22+
// you can use anonymous types inside
23+
CustomerInfo = new
24+
{
25+
Email = o.Customer?.EmailAddress,
26+
Phone = o.Customer?.PhoneNumber,
27+
},
28+
// collections available
2129
Items = o.OrderItems.Select(oi => new
2230
{
23-
// you can nested Select with null-propagating operator
31+
// of course, features work here too
2432
ProductName = oi.Product?.Name,
25-
Quantity = oi.Quantity
26-
}).ToList(),
33+
oi.Quantity
34+
}),
2735
})
2836
.ToListAsync();
2937
```
@@ -43,40 +51,50 @@ will be generated as:
4351
using System;
4452
using System.Linq;
4553
using System.Collections.Generic;
46-
using Tutorial;
4754

4855
namespace Linqraft
4956
{
5057
file static partial class GeneratedExpression
5158
{
5259
/// <summary>
5360
/// generated select expression method OrderDto (explicit) <br/>
54-
/// at TutorialCaseTest.cs(40,14)
61+
/// at TutorialCaseTest.cs(17,14)
5562
/// </summary>
56-
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "9IBuY2cLVnfIVhZ8DH1V8UkEAABUdXRvcmlhbENhc2VUZXN0LmNz")]
57-
public static IQueryable<TResult> SelectExpr_E6B721AD_FA0FABCE<TIn, TResult>(
63+
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "1rTP47TjaPKlTizGJTAHaXsBAABUdXRvcmlhbENhc2VUZXN0LmNz")]
64+
public static IQueryable<TResult> SelectExpr_54EA5DDB_8D42F5FB<TIn, TResult>(
5865
this IQueryable<TIn> query, Func<TIn, object> selector)
5966
{
6067
var matchedQuery = query as object as IQueryable<global::Tutorial.Order>;
61-
var converted = matchedQuery.Select(s => new global::Tutorial.OrderDto
68+
var converted = matchedQuery.Select(o => new global::Tutorial.OrderDto
6269
{
63-
Id = s.Id,
64-
CustomerName = s.Customer != null ? (string?)s.Customer.Name : null,
65-
CustomerCountry = s.Customer != null && s.Customer.Address != null && s.Customer.Address.Country != null ? (string?)s.Customer.Address.Country.Name : null,
66-
CustomerCity = s.Customer != null && s.Customer.Address != null && s.Customer.Address.City != null ? (string?)s.Customer.Address.City.Name : null,
67-
Items = s.OrderItems.Select(oi => new global::Tutorial.OrderItemDto_DE33EA40 {
70+
Id = o.Id,
71+
CustomerName = o.Customer != null ? (string?)o.Customer.Name : null,
72+
CustomerCountry = o.Customer != null && o.Customer.Address != null && o.Customer.Address.Country != null ? (string?)o.Customer.Address.Country.Name : null,
73+
CustomerCity = o.Customer != null && o.Customer.Address != null && o.Customer.Address.City != null ? (string?)o.Customer.Address.City.Name : null,
74+
CustomerInfo = new global::Tutorial.CustomerInfoDto_F1A64BF4
75+
{
76+
Email = o.Customer != null ? (string?)o.Customer.EmailAddress : null,
77+
Phone = o.Customer != null ? (string?)o.Customer.PhoneNumber : null
78+
},
79+
Items = o.OrderItems.Select(oi => new global::Tutorial.OrderItemDto_DE33EA40
80+
{
6881
ProductName = oi.Product != null ? (string?)oi.Product.Name : null,
69-
Quantity = oi.Quantity,
70-
}).ToList()
82+
Quantity = oi.Quantity
83+
})
7184
});
7285
return converted as object as IQueryable<TResult>;
7386
}
74-
7587
}
7688
}
7789

7890
namespace Tutorial
7991
{
92+
public partial class CustomerInfoDto_F1A64BF4
93+
{
94+
public required string? Email { get; set; }
95+
public required string? Phone { get; set; }
96+
}
97+
8098
public partial class OrderItemDto_DE33EA40
8199
{
82100
public required string? ProductName { get; set; }
@@ -89,10 +107,10 @@ namespace Tutorial
89107
public required string? CustomerName { get; set; }
90108
public required string? CustomerCountry { get; set; }
91109
public required string? CustomerCity { get; set; }
110+
public required global::Tutorial.CustomerInfoDto_F1A64BF4? CustomerInfo { get; set; }
92111
public required global::System.Collections.Generic.List<Tutorial.OrderItemDto_DE33EA40> Items { get; set; }
93112
}
94-
95113
}
96114
```
97115

98-
See the [GitHub Repository](https://arika0093.github.io/Linqraft/) for more details.
116+
See the [GitHub Repository](https://github.com/arika0093/Linqraft) for more details.

docs/analyzers/LQRS002.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,21 @@ Detects `System.Linq` `Select` calls performed on `IQueryable<T>` whose selector
2222
- Convert `Select(...)``SelectExpr(...)` preserving the anonymous projection.
2323
- Convert `Select(...)``SelectExpr<TSource, TDto>(...)` with a generated DTO type when that is preferable.
2424

25+
### Automatic Ternary Null Check Simplification
26+
As of version 0.5.0, the code fix also **automatically simplifies ternary null check patterns** (previously handled by LQRS004). When converting `Select` to `SelectExpr`, patterns like:
27+
28+
```csharp
29+
prop = x.A != null ? new { x.A.B } : null
30+
```
31+
32+
are automatically converted to:
33+
34+
```csharp
35+
prop = new { B = x.A?.B }
36+
```
37+
38+
This provides more concise code using null-conditional operators. See [LQRS004](LQRS004.md) for details on this transformation.
39+
2540
## Example
2641
Before:
2742
```csharp
@@ -52,3 +67,20 @@ var result = query.SelectExpr<Product, ResultDto_XXXXXXXX>(x => new
5267
x.Price
5368
});
5469
```
70+
71+
### With Ternary Null Check Simplification
72+
Before:
73+
```csharp
74+
var result = query.Select(x => new
75+
{
76+
ChildData = x.Child != null ? new { x.Child.Name } : null
77+
});
78+
```
79+
80+
After (with automatic simplification):
81+
```csharp
82+
var result = query.SelectExpr(x => new
83+
{
84+
ChildData = new { Name = x.Child?.Name }
85+
});
86+
```

0 commit comments

Comments
 (0)