{"id":23962786,"url":"https://github.com/jonathanalgar/customcode-analyzer","last_synced_at":"2025-04-23T08:08:49.043Z","repository":{"id":270656616,"uuid":"881398965","full_name":"jonathanalgar/CustomCode-Analyzer","owner":"jonathanalgar","description":"Get feedback on your OutSytems Developer Cloud (ODC) custom C# code as you code.","archived":false,"fork":false,"pushed_at":"2025-03-02T09:11:13.000Z","size":473,"stargazers_count":3,"open_issues_count":3,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-23T08:08:41.810Z","etag":null,"topics":["csharp","odc","outsystems","roslyn","static-analysis"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jonathanalgar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-31T13:52:29.000Z","updated_at":"2025-02-28T03:50:14.000Z","dependencies_parsed_at":"2025-03-01T06:15:13.578Z","dependency_job_id":null,"html_url":"https://github.com/jonathanalgar/CustomCode-Analyzer","commit_stats":null,"previous_names":["jonathanalgar/customcode-analyzer"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanalgar%2FCustomCode-Analyzer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanalgar%2FCustomCode-Analyzer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanalgar%2FCustomCode-Analyzer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanalgar%2FCustomCode-Analyzer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jonathanalgar","download_url":"https://codeload.github.com/jonathanalgar/CustomCode-Analyzer/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250395288,"owners_count":21423400,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","odc","outsystems","roslyn","static-analysis"],"created_at":"2025-01-06T20:55:54.438Z","updated_at":"2025-04-23T08:08:49.038Z","avatar_url":"https://github.com/jonathanalgar.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OutSystems Developer Cloud (ODC) Custom Code Analyzer\n\n[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=jonathanalgar_CustomCode-Analyzer\u0026metric=coverage\u0026token=cdc14f785767dbdef568a43b914c07c5be4f2e69)](https://sonarcloud.io/summary/new_code?id=jonathanalgar_CustomCode-Analyzer)\n[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=jonathanalgar_CustomCode-Analyzer\u0026metric=ncloc\u0026token=cdc14f785767dbdef568a43b914c07c5be4f2e69)](https://sonarcloud.io/summary/new_code?id=jonathanalgar_CustomCode-Analyzer) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://makeapullrequest.com)\n\n[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=jonathanalgar_CustomCode-Analyzer\u0026metric=reliability_rating\u0026token=cdc14f785767dbdef568a43b914c07c5be4f2e69)](https://sonarcloud.io/summary/new_code?id=jonathanalgar_CustomCode-Analyzer) [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=jonathanalgar_CustomCode-Analyzer\u0026metric=sqale_rating\u0026token=cdc14f785767dbdef568a43b914c07c5be4f2e69)](https://sonarcloud.io/summary/new_code?id=jonathanalgar_CustomCode-Analyzer)\n [![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=jonathanalgar_CustomCode-Analyzer\u0026metric=vulnerabilities\u0026token=cdc14f785767dbdef568a43b914c07c5be4f2e69)](https://sonarcloud.io/summary/new_code?id=jonathanalgar_CustomCode-Analyzer)\n\n\u003e :information_source: This component is unofficial and unsupported by OutSystems.\n\n![](https://github.com/jonathanalgar/CustomCode-Analyzer/blob/main/screenshot.png?raw=true)\n\n⚡ _Screenshot showing the development of an ODC External Library in Visual Studio. The **ODC Custom Code Analyzer** flags several rule violations in the Problems panel. A related Quick Fix menu is open for one rule violation, offering to \"Fix this type mapping\" so the field correctly matches its `OSDataType.PhoneNumber`. You can get identical functionality in Visual Studio Code and Rider._  ⚡ \n\n## Overview\n\nWhen you want to extend your ODC apps with custom C# code, you do so with the [External Libraries SDK](https://success.outsystems.com/documentation/outsystems_developer_cloud/building_apps/extend_your_apps_with_custom_code/external_libraries_sdk_readme/). This SDK allows you to write C# code that you can call from your ODC apps.\n\nAlthough IntelliSense in your IDE guides the available SDK decorators and their syntax, it does not guide the rules you must follow (for example, on [naming](https://www.outsystems.com/tk/redirect?g=OS-ELG-MODL-05019) and [design decisions](https://www.outsystems.com/tk/redirect?g=OS-ELG-MODL-05018)). This guidance is provided when uploading your project's built assembly to the ODC Portal, where you get feedback on rule violations. **Using this component brings that feedback forward and gives you real-time feedback on compliance with the rules as you write the code. You also get real-time guidance on best practices and automatic fixes.**\n\n### Technical Primer\n\nWhen you upload your project's built assembly to the ODC Portal, it does not have access to the underlying code—the ODC Portal checks compliance with the rules by reflecting on the assembly's metadata.\n\nThis component, built from scratch, implements the rules using the rich code analysis APIs of [Roslyn](https://github.com/dotnet/roslyn), the .NET compiler.\n\n```mermaid\ngraph TB\n    subgraph User[\"👩‍💻 User\"]\n        code[\"Writes code\"]:::userArea\n    end\n\n    subgraph Roslyn[\"🛠 Roslyn\"]\n        ast[\"Generates AST\u003cbr/\u003eand semantic model\"]:::roslyn\n    end\n\n    subgraph CustomCode_Analyzer[\"🔍 CustomCode-Analyzer\"]\n        analysis[\"Code analysis\u003cbr/\u003eand fix provider\"]:::analyzerArea\n    end\n\n    subgraph IDE[\"🖥 IDE\"]\n        display[\"Displays diagnosis and fixes\"]:::ideArea\n    end\n\n    code --\u003e ast\n    ast --\u003e analysis\n    analysis --\u003e display\n    display --\u003e code\n\n    Roslyn -.\"using Roslyn APIs\".-\u003e CustomCode_Analyzer\n```\n\n#### Code analysis phases\n\nThe analyzer operates in two distinct phases, registered through the Roslyn [`AnalysisContext`](https://github.com/jonathanalgar/CustomCode-Analyzer/blob/33c0d5ce0a762236a495ebc940b688e9e14cd901/src/CustomCode-Analyzer/Analyzer.cs#L355-L364):\n\n1. **Symbol analysis phase**  \n   Triggered by [`RegisterSymbolAction`](https://github.com/jonathanalgar/CustomCode-Analyzer/blob/33c0d5ce0a762236a495ebc940b688e9e14cd901/src/CustomCode-Analyzer/Analyzer.cs#L383-L410), this phase performs immediate syntax and semantic analysis on individual declarations as you type. For example, when you declare a method, the analyzer instantly checks if its name starts with an underscore and reports a violation if it does (`NameBeginsWithUnderscoreRule`). These diagnostics appear immediately in your IDE's Problems window.\n\n2. **Compilation end phase**  \n   Registered via [`RegisterCompilationEndAction`](https://github.com/jonathanalgar/CustomCode-Analyzer/blob/33c0d5ce0a762236a495ebc940b688e9e14cd901/src/CustomCode-Analyzer/Analyzer.cs#L414-L417), this phase runs after all symbols have been processed and the semantic model is complete. For example, it ensures exactly one `[OSInterface]` exists across your project by maintaining a `ConcurrentDictionary` of interface declarations and validating their uniqueness (`NoSingleInterfaceRule` or `ManyInterfacesRule`). These diagnostics may appear with a slight delay as they require complete semantic analysis.\n\n#### Code fixes for certain rules\n\nWherever we can infer a single, unambiguous fix, we provide an **automated code fix** through the Roslyn `CodeFixProvider`. Currently, code fixes are available for these rules:\n\n| Rule description                 | OS-ELG-MODL code | Action performed                               |\n|----------------------------------|------------------|------------------------------------------------|\n| **Non-public OSInterface**       | 05004            | Make interface `public`                        |\n| **Non-public OSStructure**       | 05010            | Make struct `public`                           |\n| **Non-public OSStructureField**  | 05011            | Make property/field `public`                   |\n| **Non-public OSIgnore**          | 05012            | Make `[OSIgnore]` property/field `public`      |\n| **Missing structure decoration** | 05024            | Add `[OSStructure]` attribute to struct        |\n| **Name begins with underscores** | 05022            | Remove leading `_` in method names             |\n| **Unsupported type mapping**     | 05017            | Change field/property type to match `DataType` |\n\nThe code fix suggestions appear as \"lightbulb\" actions (or \"quick actions\") in your IDE. If you accept the fix, the analyzer modifies your source code to make it compliant with the respective rule.\n\n## How to use\n\n### Visual Studio 2022 (Enterprise, Pro and, Community editions)\n\nYou can use the auto-updating extension from the Visual Studio Marketplace. Simply [install the extension from the Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=JonathanAlgar.CustomCodeAnalyzer).\n\n\u003e :bulb: Want your extension to stay up to date? Enable auto-updates in Visual Studio: Go to **Tools** \u003e **Options** \u003e **Environment** \u003e **Extensions** and check **Automatically update extensions**.\n\nIf your project references the External Libraries SDK (`OutSystems.ExternalLibraries.SDK`), the extension should automatically start providing feedback on your code. \n\nTo ensure real-time feedback for [compilation end phase](#code-analysis-phases) rules (and not just at the point of build), you need to configure your Visual Studio's background analysis:\n\n1. Select **Tools** \u003e **Options**. \n1. From the left menu select **C#** \u003e **Advanced**. \n1. Set both **Run background code analysis** for and **Show compiler errors and warnings** to **Entire solution**.\n1. Make sure the **Run code analysis in separate process box** is unchecked. \n\n\n### Others\n\nAdd the [NuGet package](https://www.nuget.org/packages/CustomCode.Analyzer/) as a dev dependency to your ODC external libraries project:\n\n    dotnet add package CustomCode.Analyzer\n\nIf your project references the External Libraries SDK (`OutSystems.ExternalLibraries.SDK`), the package should automatically start providing feedback on your code.\n\nThe NuGet package cannot be automatically updated—be sure to update regularly to get the latest features.\n\n#### Visual Studio Code\n\nTo ensure real-time feedback for [compilation end phase](#code-analysis-phases) rules (and not just at the point of build), you need to configure your Visual Studio's background analysis:\n\n1. Open the command palette (_Ctrl+Shift+P_).\n1. Search for \"roslyn\". Set the **Dotnet › Background Analysis: Analyzer Diagnostics Scope** to **fullSolution**.\n\n#### Custom projects\n\n`CustomCode-Analyzer` was released to give you real-time feedback on your C# code as you build an external library in your IDE of choice. But more generally, `CustomCode-Analyzer` can be thought of as a way of locally validating an external library project at the point of build. This makes it a powerful component for projects that require automated validation—see, for example, [`CustomCode-Analyzer-Generator`](https://github.com/jonathanalgar/CustomCode-Analyzer-Generator).\n\n## TODO\n\nSee [here](https://github.com/jonathanalgar/CustomCode-Analyzer/issues?q=is%3Aopen+is%3Aissue).\n\n## Feedback and contributions\n\nPlease report bugs and feature requests [here](https://github.com/jonathanalgar/CustomCode-Analyzer/issues/new/choose). Feel free to leave general feedback on the [OutSystems Community Forum post](https://www.outsystems.com/forums/discussion/100963/odc-external-libraries-custom-code-analyzer/).\n\nPRs are welcome. Code quality improvements, new features (especially those unassigned and listed [here](https://github.com/jonathanalgar/CustomCode-Analyzer/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement)), and documentation improvements are all welcome 🤗 All changes to Analyzer code should pass all existing tests (`dotnet test`), and all new features should  be covered by new tests. Please format any new code with [csharpier](https://csharpier.com/).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonathanalgar%2Fcustomcode-analyzer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjonathanalgar%2Fcustomcode-analyzer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonathanalgar%2Fcustomcode-analyzer/lists"}