Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bdff84b9aa |
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"csharpier": {
|
||||
"version": "0.28.2",
|
||||
"commands": [
|
||||
"dotnet-csharpier"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-564
@@ -1,568 +1,6 @@
|
||||
# Version: 2.0.1 (Using https://semver.org/)
|
||||
# Updated: 2020-12-11
|
||||
# See https://github.com/RehanSaeed/EditorConfig/releases for release notes.
|
||||
# See https://github.com/RehanSaeed/EditorConfig for updates to this file.
|
||||
# See http://EditorConfig.org for more information about .editorconfig files.
|
||||
|
||||
##########################################
|
||||
# Common Settings
|
||||
##########################################
|
||||
|
||||
# This file is the top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# All Files
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
##########################################
|
||||
# File Extension Settings
|
||||
##########################################
|
||||
|
||||
# Visual Studio Solution Files
|
||||
[*.sln]
|
||||
indent_style = tab
|
||||
|
||||
# Visual Studio XML Project Files
|
||||
[*.{csproj,vbproj,vcxproj.filters,proj,projitems,shproj}]
|
||||
indent_size = 2
|
||||
|
||||
# XML Configuration Files
|
||||
[*.{xml,config,props,targets,nuspec,resx,ruleset,vsixmanifest,vsct}]
|
||||
indent_size = 2
|
||||
|
||||
# JSON Files
|
||||
[*.{json,json5,webmanifest}]
|
||||
indent_size = 2
|
||||
|
||||
# YAML Files
|
||||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
||||
|
||||
# Markdown Files
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
# Web Files
|
||||
[*.{htm,html,js,jsm,ts,tsx,css,sass,scss,less,svg,vue}]
|
||||
indent_size = 2
|
||||
|
||||
# Batch Files
|
||||
[*.{cmd,bat}]
|
||||
end_of_line = crlf
|
||||
|
||||
# Bash Files
|
||||
[*.sh]
|
||||
end_of_line = lf
|
||||
|
||||
# Makefiles
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
||||
##########################################
|
||||
# Default .NET Code Style Severities
|
||||
# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/configuration-options#scope
|
||||
##########################################
|
||||
|
||||
[*.{cs,csx,cake,vb,vbx}]
|
||||
# Default Severity for all .NET Code Style rules below
|
||||
dotnet_analyzer_diagnostic.severity = silent
|
||||
|
||||
##########################################
|
||||
# File Header (Uncomment to support file headers)
|
||||
# https://docs.microsoft.com/visualstudio/ide/reference/add-file-header
|
||||
##########################################
|
||||
|
||||
# [*.{cs,csx,cake,vb,vbx}]
|
||||
# file_header_template = <copyright file="{fileName}" company="PROJECT-AUTHOR">\n© PROJECT-AUTHOR\n</copyright>
|
||||
|
||||
# SA1636: File header copyright text should match
|
||||
# Justification: .editorconfig supports file headers. If this is changed to a value other than "none", a stylecop.json file will need to added to the project.
|
||||
# dotnet_diagnostic.SA1636.severity = none
|
||||
|
||||
##########################################
|
||||
# .NET Language Conventions
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions
|
||||
##########################################
|
||||
|
||||
# .NET Code Style Settings
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#net-code-style-settings
|
||||
[*.{cs,csx,cake,vb,vbx}]
|
||||
# "this." and "Me." qualifiers
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#this-and-me
|
||||
#dotnet_style_qualification_for_field = true:warning
|
||||
#dotnet_style_qualification_for_property = true:warning
|
||||
#dotnet_style_qualification_for_method = true:warning
|
||||
#dotnet_style_qualification_for_event = true:warning
|
||||
# Language keywords instead of framework type names for type references
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#language-keywords
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:warning
|
||||
dotnet_style_predefined_type_for_member_access = true:warning
|
||||
# Modifier preferences
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#normalize-modifiers
|
||||
dotnet_style_require_accessibility_modifiers = always:warning
|
||||
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:warning
|
||||
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:warning
|
||||
dotnet_style_readonly_field = true:warning
|
||||
# Parentheses preferences
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#parentheses-preferences
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning
|
||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning
|
||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning
|
||||
dotnet_style_parentheses_in_other_operators = always_for_clarity:suggestion
|
||||
# Expression-level preferences
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-level-preferences
|
||||
dotnet_style_object_initializer = true:warning
|
||||
dotnet_style_collection_initializer = true:warning
|
||||
dotnet_style_explicit_tuple_names = true:warning
|
||||
dotnet_style_prefer_inferred_tuple_names = true:warning
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning
|
||||
dotnet_style_prefer_auto_properties = true:warning
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = false:suggestion
|
||||
dotnet_diagnostic.IDE0045.severity = suggestion
|
||||
dotnet_style_prefer_conditional_expression_over_return = false:suggestion
|
||||
dotnet_diagnostic.IDE0046.severity = suggestion
|
||||
dotnet_style_prefer_compound_assignment = true:warning
|
||||
# Null-checking preferences
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#null-checking-preferences
|
||||
dotnet_style_coalesce_expression = true:warning
|
||||
dotnet_style_null_propagation = true:warning
|
||||
# Parameter preferences
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#parameter-preferences
|
||||
dotnet_code_quality_unused_parameters = all:warning
|
||||
# More style options (Undocumented)
|
||||
# https://github.com/MicrosoftDocs/visualstudio-docs/issues/3641
|
||||
dotnet_style_operator_placement_when_wrapping = end_of_line
|
||||
# https://github.com/dotnet/roslyn/pull/40070
|
||||
dotnet_style_prefer_simplified_interpolation = true:warning
|
||||
|
||||
# C# Code Style Settings
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#c-code-style-settings
|
||||
[*.{cs,csx,cake}]
|
||||
# Implicit and explicit types
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#implicit-and-explicit-types
|
||||
csharp_style_var_for_built_in_types = true:warning
|
||||
csharp_style_var_when_type_is_apparent = true:warning
|
||||
csharp_style_var_elsewhere = true:warning
|
||||
# Expression-bodied members
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-bodied-members
|
||||
csharp_style_expression_bodied_methods = true:warning
|
||||
csharp_style_expression_bodied_constructors = true:warning
|
||||
csharp_style_expression_bodied_operators = true:warning
|
||||
csharp_style_expression_bodied_properties = true:warning
|
||||
csharp_style_expression_bodied_indexers = true:warning
|
||||
csharp_style_expression_bodied_accessors = true:warning
|
||||
csharp_style_expression_bodied_lambdas = true:warning
|
||||
csharp_style_expression_bodied_local_functions = true:warning
|
||||
# Pattern matching
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#pattern-matching
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:warning
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:warning
|
||||
# Inlined variable declarations
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#inlined-variable-declarations
|
||||
csharp_style_inlined_variable_declaration = true:warning
|
||||
# Expression-level preferences
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-level-preferences
|
||||
csharp_prefer_simple_default_expression = true:warning
|
||||
# "Null" checking preferences
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#c-null-checking-preferences
|
||||
csharp_style_throw_expression = true:warning
|
||||
csharp_style_conditional_delegate_call = true:warning
|
||||
# Code block preferences
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#code-block-preferences
|
||||
csharp_prefer_braces = true:warning
|
||||
# Unused value preferences
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#unused-value-preferences
|
||||
csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion
|
||||
dotnet_diagnostic.IDE0058.severity = suggestion
|
||||
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
|
||||
dotnet_diagnostic.IDE0059.severity = suggestion
|
||||
# Index and range preferences
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#index-and-range-preferences
|
||||
csharp_style_prefer_index_operator = true:warning
|
||||
csharp_style_prefer_range_operator = true:warning
|
||||
# Miscellaneous preferences
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#miscellaneous-preferences
|
||||
csharp_style_deconstructed_variable_declaration = true:warning
|
||||
csharp_style_pattern_local_over_anonymous_function = true:warning
|
||||
csharp_using_directive_placement = outside_namespace:warning
|
||||
csharp_prefer_static_local_function = true:warning
|
||||
csharp_prefer_simple_using_statement = true:suggestion
|
||||
dotnet_diagnostic.IDE0063.severity = suggestion
|
||||
|
||||
##########################################
|
||||
# .NET Formatting Conventions
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-code-style-settings-reference#formatting-conventions
|
||||
##########################################
|
||||
|
||||
# Organize usings
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#organize-using-directives
|
||||
dotnet_sort_system_directives_first = true
|
||||
# Newline options
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#new-line-options
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_finally = true
|
||||
csharp_new_line_before_members_in_object_initializers = true
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
csharp_new_line_between_query_expression_clauses = true
|
||||
# Indentation options
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#indentation-options
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_switch_labels = true
|
||||
csharp_indent_labels = no_change
|
||||
csharp_indent_block_contents = true
|
||||
csharp_indent_braces = false
|
||||
csharp_indent_case_contents_when_block = false
|
||||
# Spacing options
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#spacing-options
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
csharp_space_between_parentheses = false
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
csharp_space_after_comma = true
|
||||
csharp_space_before_comma = false
|
||||
csharp_space_after_dot = false
|
||||
csharp_space_before_dot = false
|
||||
csharp_space_after_semicolon_in_for_statement = true
|
||||
csharp_space_before_semicolon_in_for_statement = false
|
||||
csharp_space_around_declaration_statements = false
|
||||
csharp_space_before_open_square_brackets = false
|
||||
csharp_space_between_empty_square_brackets = false
|
||||
csharp_space_between_square_brackets = false
|
||||
# Wrapping options
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#wrap-options
|
||||
csharp_preserve_single_line_statements = false
|
||||
csharp_preserve_single_line_blocks = true
|
||||
|
||||
csharp_style_namespace_declarations = file_scoped
|
||||
|
||||
##########################################
|
||||
# .NET Naming Conventions
|
||||
# https://docs.microsoft.com/visualstudio/ide/editorconfig-naming-conventions
|
||||
##########################################
|
||||
|
||||
[*.{cs,csx,cake,vb,vbx}]
|
||||
dotnet_diagnostic.CA1000.severity = suggestion
|
||||
dotnet_diagnostic.CA1001.severity = error
|
||||
dotnet_diagnostic.CA1018.severity = error
|
||||
dotnet_diagnostic.CA1036.severity = silent
|
||||
dotnet_diagnostic.CA1051.severity = suggestion
|
||||
dotnet_diagnostic.CA1068.severity = error
|
||||
dotnet_diagnostic.CA1069.severity = error
|
||||
dotnet_diagnostic.CA1304.severity = error
|
||||
dotnet_diagnostic.CA1305.severity = suggestion
|
||||
dotnet_diagnostic.CA1307.severity = suggestion
|
||||
dotnet_diagnostic.CA1309.severity = suggestion
|
||||
dotnet_diagnostic.CA1310.severity = error
|
||||
dotnet_diagnostic.CA1507.severity = suggestion
|
||||
dotnet_diagnostic.CA1513.severity = suggestion
|
||||
dotnet_diagnostic.CA1707.severity = suggestion
|
||||
dotnet_diagnostic.CA1708.severity = suggestion
|
||||
dotnet_diagnostic.CA1711.severity = suggestion
|
||||
dotnet_diagnostic.CA1716.severity = suggestion
|
||||
dotnet_diagnostic.CA1720.severity = suggestion
|
||||
dotnet_diagnostic.CA1725.severity = suggestion
|
||||
dotnet_diagnostic.CA1805.severity = suggestion
|
||||
dotnet_diagnostic.CA1816.severity = suggestion
|
||||
dotnet_diagnostic.CA1822.severity = suggestion
|
||||
dotnet_diagnostic.CA1825.severity = error
|
||||
dotnet_diagnostic.CA1826.severity = silent
|
||||
dotnet_diagnostic.CA1827.severity = error
|
||||
dotnet_diagnostic.CA1829.severity = suggestion
|
||||
dotnet_diagnostic.CA1834.severity = error
|
||||
dotnet_diagnostic.CA1845.severity = suggestion
|
||||
dotnet_diagnostic.CA1848.severity = suggestion
|
||||
dotnet_diagnostic.CA1852.severity = suggestion
|
||||
dotnet_diagnostic.CA1860.severity = silent
|
||||
dotnet_diagnostic.CA2016.severity = suggestion
|
||||
dotnet_diagnostic.CA2201.severity = error
|
||||
dotnet_diagnostic.CA2206.severity = error
|
||||
dotnet_diagnostic.CA2208.severity = error
|
||||
dotnet_diagnostic.CA2211.severity = error
|
||||
dotnet_diagnostic.CA2249.severity = error
|
||||
dotnet_diagnostic.CA2251.severity = error
|
||||
dotnet_diagnostic.CA2252.severity = none
|
||||
dotnet_diagnostic.CA2254.severity = suggestion
|
||||
|
||||
dotnet_diagnostic.CS0169.severity = error
|
||||
dotnet_diagnostic.CS0219.severity = error
|
||||
dotnet_diagnostic.CS0649.severity = suggestion
|
||||
dotnet_diagnostic.CS1998.severity = error
|
||||
dotnet_diagnostic.CS8602.severity = error
|
||||
dotnet_diagnostic.CS8604.severity = error
|
||||
dotnet_diagnostic.CS8618.severity = error
|
||||
dotnet_diagnostic.CS0618.severity = suggestion
|
||||
dotnet_diagnostic.CS1998.severity = error
|
||||
dotnet_diagnostic.CS4014.severity = error
|
||||
dotnet_diagnostic.CS8600.severity = error
|
||||
dotnet_diagnostic.CS8603.severity = error
|
||||
dotnet_diagnostic.CS8625.severity = error
|
||||
|
||||
dotnet_diagnostic.BL0005.severity = suggestion
|
||||
|
||||
dotnet_diagnostic.MVC1000.severity = suggestion
|
||||
|
||||
dotnet_diagnostic.RZ10012.severity = error
|
||||
|
||||
dotnet_diagnostic.IDE0004.severity = error # redundant cast
|
||||
dotnet_diagnostic.IDE0005.severity = error
|
||||
dotnet_diagnostic.IDE0007.severity = error # Use var
|
||||
dotnet_diagnostic.IDE0011.severity = error # Use braces on if statements
|
||||
dotnet_diagnostic.IDE0010.severity = silent # populate switch
|
||||
dotnet_diagnostic.IDE0017.severity = suggestion # initialization can be simplified
|
||||
dotnet_diagnostic.IDE0021.severity = silent # expression body for constructors
|
||||
dotnet_diagnostic.IDE0022.severity = silent # expression body for methods
|
||||
dotnet_diagnostic.IDE0023.severity = suggestion # use expression body for operators
|
||||
dotnet_diagnostic.IDE0024.severity = silent # expression body for operators
|
||||
dotnet_diagnostic.IDE0025.severity = suggestion # use expression body for properties
|
||||
dotnet_diagnostic.IDE0027.severity = suggestion # Use expression body for accessors
|
||||
dotnet_diagnostic.IDE0028.severity = silent # expression body for accessors
|
||||
dotnet_diagnostic.IDE0032.severity = suggestion # Use auto property
|
||||
dotnet_diagnostic.IDE0033.severity = error # prefer tuple name
|
||||
dotnet_diagnostic.IDE0037.severity = suggestion # simplify anonymous type
|
||||
dotnet_diagnostic.IDE0040.severity = error # modifiers required
|
||||
dotnet_diagnostic.IDE0041.severity = error # simplify null
|
||||
dotnet_diagnostic.IDE0042.severity = error # deconstruct variable
|
||||
dotnet_diagnostic.IDE0044.severity = suggestion # make field only when possible
|
||||
dotnet_diagnostic.IDE0047.severity = suggestion # parameter name
|
||||
dotnet_diagnostic.IDE0051.severity = error # unused field
|
||||
dotnet_diagnostic.IDE0052.severity = error # unused member
|
||||
dotnet_diagnostic.IDE0053.severity = suggestion # lambda not needed
|
||||
dotnet_diagnostic.IDE0055.severity = suggestion # Fix formatting
|
||||
dotnet_diagnostic.IDE0057.severity = suggestion # substring can be simplified
|
||||
dotnet_diagnostic.IDE0060.severity = suggestion # unused parameters
|
||||
dotnet_diagnostic.IDE0061.severity = suggestion # local expression body
|
||||
dotnet_diagnostic.IDE0062.severity = suggestion # local to static
|
||||
dotnet_diagnostic.IDE0063.severity = error # simplify using
|
||||
dotnet_diagnostic.IDE0066.severity = suggestion # switch expression
|
||||
dotnet_diagnostic.IDE0072.severity = suggestion # Populate switch - forces population of all cases even when default specified
|
||||
dotnet_diagnostic.IDE0078.severity = suggestion # use pattern matching
|
||||
dotnet_diagnostic.IDE0090.severity = suggestion # new can be simplified
|
||||
dotnet_diagnostic.IDE0130.severity = suggestion # namespace folder structure
|
||||
dotnet_diagnostic.IDE0160.severity = silent # Use block namespaces ARE NOT required
|
||||
dotnet_diagnostic.IDE0161.severity = error # Please use file namespaces
|
||||
dotnet_diagnostic.IDE0200.severity = suggestion # lambda not needed
|
||||
dotnet_diagnostic.IDE1006.severity = suggestion # Naming rule violation: These words cannot contain lower case characters
|
||||
dotnet_diagnostic.IDE0260.severity = suggestion # Use pattern matching
|
||||
dotnet_diagnostic.IDE0270.severity = suggestion # Null check simplifcation
|
||||
dotnet_diagnostic.IDE0290.severity = error # Primary Constructor
|
||||
dotnet_diagnostic.IDE0300.severity = suggestion # Collection
|
||||
dotnet_diagnostic.IDE0305.severity = suggestion # Collection ToList
|
||||
|
||||
dotnet_diagnostic.NX0001.severity = error
|
||||
dotnet_diagnostic.NX0002.severity = silent
|
||||
dotnet_diagnostic.NX0003.severity = silent
|
||||
|
||||
##########################################
|
||||
# Styles
|
||||
##########################################
|
||||
|
||||
# camel_case_style - Define the camelCase style
|
||||
dotnet_naming_style.camel_case_style.capitalization = camel_case
|
||||
# pascal_case_style - Define the PascalCase style
|
||||
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
|
||||
# constant_case - Define the CONSTANT_CASE style
|
||||
dotnet_naming_style.constant_case.capitalization = all_upper
|
||||
dotnet_naming_style.constant_case.word_separator = _
|
||||
# first_upper_style - The first character must start with an upper-case character
|
||||
dotnet_naming_style.first_upper_style.capitalization = first_word_upper
|
||||
# prefix_interface_with_i_style - Interfaces must be PascalCase and the first character of an interface must be an 'I'
|
||||
dotnet_naming_style.prefix_interface_with_i_style.capitalization = pascal_case
|
||||
dotnet_naming_style.prefix_interface_with_i_style.required_prefix = I
|
||||
# prefix_type_parameters_with_t_style - Generic Type Parameters must be PascalCase and the first character must be a 'T'
|
||||
dotnet_naming_style.prefix_type_parameters_with_t_style.capitalization = pascal_case
|
||||
dotnet_naming_style.prefix_type_parameters_with_t_style.required_prefix = T
|
||||
# disallowed_style - Anything that has this style applied is marked as disallowed
|
||||
dotnet_naming_style.disallowed_style.capitalization = pascal_case
|
||||
dotnet_naming_style.disallowed_style.required_prefix = ____RULE_VIOLATION____
|
||||
dotnet_naming_style.disallowed_style.required_suffix = ____RULE_VIOLATION____
|
||||
# internal_error_style - This style should never occur... if it does, it indicates a bug in file or in the parser using the file
|
||||
dotnet_naming_style.internal_error_style.capitalization = pascal_case
|
||||
dotnet_naming_style.internal_error_style.required_prefix = ____INTERNAL_ERROR____
|
||||
dotnet_naming_style.internal_error_style.required_suffix = ____INTERNAL_ERROR____
|
||||
|
||||
# prefix_interface_with_i_style - Interfaces must be PascalCase and the first character of an interface must be an 'I'
|
||||
dotnet_naming_style.underscore_camel_case_style.capitalization = camel_case
|
||||
dotnet_naming_style.underscore_camel_case_style.required_prefix = _
|
||||
|
||||
##########################################
|
||||
# .NET Design Guideline Field Naming Rules
|
||||
# Naming rules for fields follow the .NET Framework design guidelines
|
||||
# https://docs.microsoft.com/dotnet/standard/design-guidelines/index
|
||||
##########################################
|
||||
|
||||
# All public/protected/protected_internal constant fields must be constant_case
|
||||
# https://docs.microsoft.com/dotnet/standard/design-guidelines/field
|
||||
dotnet_naming_symbols.public_protected_constant_fields_group.applicable_accessibilities = public, protected, protected_internal
|
||||
dotnet_naming_symbols.public_protected_constant_fields_group.required_modifiers = const
|
||||
dotnet_naming_symbols.public_protected_constant_fields_group.applicable_kinds = field
|
||||
dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.symbols = public_protected_constant_fields_group
|
||||
dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.style = constant_case
|
||||
dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.severity = warning
|
||||
|
||||
# All public/protected/protected_internal static readonly fields must be constant_case
|
||||
# https://docs.microsoft.com/dotnet/standard/design-guidelines/field
|
||||
dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_accessibilities = public, protected, protected_internal
|
||||
dotnet_naming_symbols.public_protected_static_readonly_fields_group.required_modifiers = static, readonly
|
||||
dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_kinds = field
|
||||
dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.symbols = public_protected_static_readonly_fields_group
|
||||
dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.style = constant_case
|
||||
dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.severity = warning
|
||||
|
||||
# No other public/protected/protected_internal fields are allowed
|
||||
# https://docs.microsoft.com/dotnet/standard/design-guidelines/field
|
||||
dotnet_naming_symbols.other_public_protected_fields_group.applicable_accessibilities = public, protected, protected_internal
|
||||
dotnet_naming_symbols.other_public_protected_fields_group.applicable_kinds = field
|
||||
dotnet_naming_rule.other_public_protected_fields_disallowed_rule.symbols = other_public_protected_fields_group
|
||||
dotnet_naming_rule.other_public_protected_fields_disallowed_rule.style = disallowed_style
|
||||
dotnet_naming_rule.other_public_protected_fields_disallowed_rule.severity = error
|
||||
|
||||
##########################################
|
||||
# StyleCop Field Naming Rules
|
||||
# Naming rules for fields follow the StyleCop analyzers
|
||||
# This does not override any rules using disallowed_style above
|
||||
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers
|
||||
##########################################
|
||||
|
||||
# All constant fields must be constant_case
|
||||
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1303.md
|
||||
dotnet_naming_symbols.stylecop_constant_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected, private
|
||||
dotnet_naming_symbols.stylecop_constant_fields_group.required_modifiers = const
|
||||
dotnet_naming_symbols.stylecop_constant_fields_group.applicable_kinds = field
|
||||
dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.symbols = stylecop_constant_fields_group
|
||||
dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.style = constant_case
|
||||
dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.severity = warning
|
||||
|
||||
# All static readonly fields must be constant_case
|
||||
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1311.md
|
||||
dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected, private
|
||||
dotnet_naming_symbols.stylecop_static_readonly_fields_group.required_modifiers = static, readonly
|
||||
dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_kinds = field
|
||||
dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.symbols = stylecop_static_readonly_fields_group
|
||||
dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.style = constant_case
|
||||
dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.severity = warning
|
||||
|
||||
# No non-private instance fields are allowed
|
||||
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1401.md
|
||||
dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected
|
||||
dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_kinds = field
|
||||
dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.symbols = stylecop_fields_must_be_private_group
|
||||
dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.style = disallowed_style
|
||||
dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.severity = error
|
||||
|
||||
# Private fields must be camelCase
|
||||
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1306.md
|
||||
dotnet_naming_symbols.stylecop_private_fields_group.applicable_accessibilities = private
|
||||
dotnet_naming_symbols.stylecop_private_fields_group.applicable_kinds = field
|
||||
dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.symbols = stylecop_private_fields_group
|
||||
dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.style = underscore_camel_case_style
|
||||
dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.severity = warning
|
||||
|
||||
# Local variables must be camelCase
|
||||
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1312.md
|
||||
dotnet_naming_symbols.stylecop_local_fields_group.applicable_accessibilities = local
|
||||
dotnet_naming_symbols.stylecop_local_fields_group.applicable_kinds = local
|
||||
dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.symbols = stylecop_local_fields_group
|
||||
dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.style = camel_case_style
|
||||
dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.severity = warning
|
||||
|
||||
# This rule should never fire. However, it's included for at least two purposes:
|
||||
# First, it helps to understand, reason about, and root-case certain types of issues, such as bugs in .editorconfig parsers.
|
||||
# Second, it helps to raise immediate awareness if a new field type is added (as occurred recently in C#).
|
||||
dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_accessibilities = *
|
||||
dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_kinds = field
|
||||
dotnet_naming_rule.sanity_check_uncovered_field_case_rule.symbols = sanity_check_uncovered_field_case_group
|
||||
dotnet_naming_rule.sanity_check_uncovered_field_case_rule.style = internal_error_style
|
||||
dotnet_naming_rule.sanity_check_uncovered_field_case_rule.severity = error
|
||||
|
||||
|
||||
##########################################
|
||||
# Other Naming Rules
|
||||
##########################################
|
||||
|
||||
# All of the following must be PascalCase:
|
||||
# - Namespaces
|
||||
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-namespaces
|
||||
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md
|
||||
# - Classes and Enumerations
|
||||
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
|
||||
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md
|
||||
# - Delegates
|
||||
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces#names-of-common-types
|
||||
# - Constructors, Properties, Events, Methods
|
||||
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-type-members
|
||||
dotnet_naming_symbols.element_group.applicable_kinds = namespace, class, enum, struct, delegate, event, method, property
|
||||
dotnet_naming_rule.element_rule.symbols = element_group
|
||||
dotnet_naming_rule.element_rule.style = pascal_case_style
|
||||
dotnet_naming_rule.element_rule.severity = warning
|
||||
|
||||
# Interfaces use PascalCase and are prefixed with uppercase 'I'
|
||||
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
|
||||
dotnet_naming_symbols.interface_group.applicable_kinds = interface
|
||||
dotnet_naming_rule.interface_rule.symbols = interface_group
|
||||
dotnet_naming_rule.interface_rule.style = prefix_interface_with_i_style
|
||||
dotnet_naming_rule.interface_rule.severity = warning
|
||||
|
||||
# Generics Type Parameters use PascalCase and are prefixed with uppercase 'T'
|
||||
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
|
||||
dotnet_naming_symbols.type_parameter_group.applicable_kinds = type_parameter
|
||||
dotnet_naming_rule.type_parameter_rule.symbols = type_parameter_group
|
||||
dotnet_naming_rule.type_parameter_rule.style = prefix_type_parameters_with_t_style
|
||||
dotnet_naming_rule.type_parameter_rule.severity = warning
|
||||
|
||||
# Function parameters use camelCase
|
||||
# https://docs.microsoft.com/dotnet/standard/design-guidelines/naming-parameters
|
||||
dotnet_naming_symbols.parameters_group.applicable_kinds = parameter
|
||||
dotnet_naming_rule.parameters_rule.symbols = parameters_group
|
||||
dotnet_naming_rule.parameters_rule.style = camel_case_style
|
||||
dotnet_naming_rule.parameters_rule.severity = warning
|
||||
|
||||
##########################################
|
||||
# License
|
||||
##########################################
|
||||
# The following applies as to the .editorconfig file ONLY, and is
|
||||
# included below for reference, per the requirements of the license
|
||||
# corresponding to this .editorconfig file.
|
||||
# See: https://github.com/RehanSaeed/EditorConfig
|
||||
#
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2017-2019 Muhammad Rehan Saeed
|
||||
# Copyright (c) 2019 Henry Gabryjelski
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any
|
||||
# person obtaining a copy of this software and associated
|
||||
# documentation files (the "Software"), to deal in the
|
||||
# Software without restriction, including without limitation
|
||||
# the rights to use, copy, modify, merge, publish, distribute,
|
||||
# sublicense, and/or sell copies of the Software, and to permit
|
||||
# persons to whom the Software is furnished to do so, subject
|
||||
# to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
# OTHER DEALINGS IN THE SOFTWARE.
|
||||
##########################################
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
@@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [StefH]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # wiremocknet
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: https://www.paypal.me/stefheyenrath
|
||||
@@ -1,6 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions" # search for actions - there are other options available
|
||||
directory: "/" # search in .github/workflows under root `/`
|
||||
schedule:
|
||||
interval: "weekly" # check for action update every week
|
||||
@@ -0,0 +1,15 @@
|
||||
name: CreateRelease
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*.*.*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
@@ -1,23 +0,0 @@
|
||||
name: "Check Build"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
check-build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Project
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
|
||||
- name: Build
|
||||
run: dotnet build --configuration Debug --no-restore
|
||||
@@ -1,29 +0,0 @@
|
||||
name: "Deploy to Nuget.org"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Project
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
|
||||
- name: Build
|
||||
run: dotnet build --configuration Release --no-restore src/Speckle.ProxyGenerator/Speckle.ProxyGenerator.csproj
|
||||
|
||||
- name: Pack
|
||||
run: dotnet pack --no-build --configuration Release src/Speckle.ProxyGenerator/Speckle.ProxyGenerator.csproj --output .
|
||||
|
||||
- name: Push to nuget.org
|
||||
run: dotnet nuget push *.nupkg --source "https://api.nuget.org/v3/index.json" --api-key ${{secrets.CONNECTORS_NUGET_TOKEN }} --skip-duplicate
|
||||
@@ -351,5 +351,3 @@ MigrationBackup/
|
||||
/tests/ProxyInterfaceSourceGeneratorTests/Destination/Disposable/*.g.cs
|
||||
|
||||
.idea/
|
||||
|
||||
Speckle.ProxyGenerator.sln.DotSettings
|
||||
|
||||
@@ -1,84 +1,93 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31521.260
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ED3DA9DD-1E07-444B-A2D7-2DBA280F96D4}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2CE637DC-E8F5-4603-8B57-E51A32F631F1}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
Generate-ReleaseNotes.bat = Generate-ReleaseNotes.bat
|
||||
PackageReadme.md = PackageReadme.md
|
||||
PackageReleaseNotes.template = PackageReleaseNotes.template
|
||||
PackageReleaseNotes.txt = PackageReleaseNotes.txt
|
||||
README.md = README.md
|
||||
ReleaseNotes.md = ReleaseNotes.md
|
||||
ToDo.md = ToDo.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{19009F5B-3267-45E2-A8B6-89F2AB47D72C}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src-examples", "src-examples", "{38BA087F-EDA1-4F8A-A140-85B84791B815}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.ProxyGenerator", "src\Speckle.ProxyGenerator\Speckle.ProxyGenerator.csproj", "{12344228-91F4-4502-9595-39584E5ABB34}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceConsumer", "src-examples\ProxyInterfaceConsumer\ProxyInterfaceConsumer.csproj", "{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceSourceGeneratorTests", "tests\ProxyInterfaceSourceGeneratorTests\ProxyInterfaceSourceGeneratorTests.csproj", "{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceConsumerForPnP", "src-examples\ProxyInterfaceConsumerForPnP\ProxyInterfaceConsumerForPnP.csproj", "{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceConsumerViaNuGet", "src-examples\ProxyInterfaceConsumerViaNuGet\ProxyInterfaceConsumerViaNuGet.csproj", "{1EA000E4-6103-4577-8D98-BDDA3BE458A2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
DebugAttach|Any CPU = DebugAttach|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{12344228-91F4-4502-9595-39584E5ABB34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{12344228-91F4-4502-9595-39584E5ABB34}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{12344228-91F4-4502-9595-39584E5ABB34}.DebugAttach|Any CPU.ActiveCfg = DebugAttach|Any CPU
|
||||
{12344228-91F4-4502-9595-39584E5ABB34}.DebugAttach|Any CPU.Build.0 = DebugAttach|Any CPU
|
||||
{12344228-91F4-4502-9595-39584E5ABB34}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{12344228-91F4-4502-9595-39584E5ABB34}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}.DebugAttach|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.DebugAttach|Any CPU.ActiveCfg = DebugAttach|Any CPU
|
||||
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.DebugAttach|Any CPU.Build.0 = DebugAttach|Any CPU
|
||||
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.DebugAttach|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.DebugAttach|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.DebugAttach|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.DebugAttach|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{12344228-91F4-4502-9595-39584E5ABB34} = {ED3DA9DD-1E07-444B-A2D7-2DBA280F96D4}
|
||||
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9} = {38BA087F-EDA1-4F8A-A140-85B84791B815}
|
||||
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A} = {19009F5B-3267-45E2-A8B6-89F2AB47D72C}
|
||||
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C} = {38BA087F-EDA1-4F8A-A140-85B84791B815}
|
||||
{1EA000E4-6103-4577-8D98-BDDA3BE458A2} = {38BA087F-EDA1-4F8A-A140-85B84791B815}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {585F071D-051D-441C-9C6B-226D9E15A1F5}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31521.260
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ED3DA9DD-1E07-444B-A2D7-2DBA280F96D4}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2CE637DC-E8F5-4603-8B57-E51A32F631F1}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
Generate-ReleaseNotes.bat = Generate-ReleaseNotes.bat
|
||||
PackageReadme.md = PackageReadme.md
|
||||
PackageReleaseNotes.template = PackageReleaseNotes.template
|
||||
PackageReleaseNotes.txt = PackageReleaseNotes.txt
|
||||
README.md = README.md
|
||||
ReleaseNotes.md = ReleaseNotes.md
|
||||
ToDo.md = ToDo.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{19009F5B-3267-45E2-A8B6-89F2AB47D72C}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src-examples", "src-examples", "{38BA087F-EDA1-4F8A-A140-85B84791B815}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceSourceGenerator", "src\ProxyInterfaceSourceGenerator\ProxyInterfaceSourceGenerator.csproj", "{12344228-91F4-4502-9595-39584E5ABB34}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceConsumer", "src-examples\ProxyInterfaceConsumer\ProxyInterfaceConsumer.csproj", "{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceSourceGeneratorTests", "tests\ProxyInterfaceSourceGeneratorTests\ProxyInterfaceSourceGeneratorTests.csproj", "{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceConsumerForPnP", "src-examples\ProxyInterfaceConsumerForPnP\ProxyInterfaceConsumerForPnP.csproj", "{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceConsumerForAkka", "src-examples\ProxyInterfaceConsumerForAkka\ProxyInterfaceConsumerForAkka.csproj", "{590908DF-A813-467A-94E4-3500020D0D54}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProxyInterfaceConsumerViaNuGet", "src-examples\ProxyInterfaceConsumerViaNuGet\ProxyInterfaceConsumerViaNuGet.csproj", "{1EA000E4-6103-4577-8D98-BDDA3BE458A2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
DebugAttach|Any CPU = DebugAttach|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{12344228-91F4-4502-9595-39584E5ABB34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{12344228-91F4-4502-9595-39584E5ABB34}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{12344228-91F4-4502-9595-39584E5ABB34}.DebugAttach|Any CPU.ActiveCfg = DebugAttach|Any CPU
|
||||
{12344228-91F4-4502-9595-39584E5ABB34}.DebugAttach|Any CPU.Build.0 = DebugAttach|Any CPU
|
||||
{12344228-91F4-4502-9595-39584E5ABB34}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{12344228-91F4-4502-9595-39584E5ABB34}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}.DebugAttach|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.DebugAttach|Any CPU.ActiveCfg = DebugAttach|Any CPU
|
||||
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.DebugAttach|Any CPU.Build.0 = DebugAttach|Any CPU
|
||||
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.DebugAttach|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.DebugAttach|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{590908DF-A813-467A-94E4-3500020D0D54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{590908DF-A813-467A-94E4-3500020D0D54}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{590908DF-A813-467A-94E4-3500020D0D54}.DebugAttach|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{590908DF-A813-467A-94E4-3500020D0D54}.DebugAttach|Any CPU.Build.0 = Debug|Any CPU
|
||||
{590908DF-A813-467A-94E4-3500020D0D54}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{590908DF-A813-467A-94E4-3500020D0D54}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.DebugAttach|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.DebugAttach|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1EA000E4-6103-4577-8D98-BDDA3BE458A2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{12344228-91F4-4502-9595-39584E5ABB34} = {ED3DA9DD-1E07-444B-A2D7-2DBA280F96D4}
|
||||
{7E0A10EE-CCC3-4281-9541-B0AF037D3DF9} = {38BA087F-EDA1-4F8A-A140-85B84791B815}
|
||||
{1BDB9046-D6D1-4FB4-AAB5-F24E33EEAE0A} = {19009F5B-3267-45E2-A8B6-89F2AB47D72C}
|
||||
{5F7DA2C5-B908-4B57-9F5F-BADF1216D89C} = {38BA087F-EDA1-4F8A-A140-85B84791B815}
|
||||
{590908DF-A813-467A-94E4-3500020D0D54} = {38BA087F-EDA1-4F8A-A140-85B84791B815}
|
||||
{1EA000E4-6103-4577-8D98-BDDA3BE458A2} = {38BA087F-EDA1-4F8A-A140-85B84791B815}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {585F071D-051D-441C-9C6B-226D9E15A1F5}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,3 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Mapster/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Usings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
@@ -1,51 +1,26 @@
|
||||
# Speckle.ProxyGenerator
|
||||
|
||||
This is a fork of a library that almost gets us there but needed some new functionality to achieve a goal: successfully wrap a library we cannot modify and have interfaces in a separate assembly.
|
||||
|
||||
Modifications have been mainly due that the primary interfaces need to be in a different assembly.
|
||||
|
||||
## Usage so far
|
||||
|
||||
Interface Assembly:
|
||||
|
||||
- Base interfaces usable by anyone and Unit tests
|
||||
|
||||
Api Assembly:
|
||||
|
||||
- Proxy Interfaces that inherit from the base interfaces
|
||||
- Proxy attribute references wrapped Api
|
||||
- If `ImplementationOptions` is omitted then defaults are used: `ImplementationOptions.UseExtendedInterfaces | ImplementationOptions.ProxyForBaseInterface`
|
||||
|
||||
New needs: base interface is used by wrappers. Need to ignore members from wrapped api on demand.
|
||||
|
||||
## Old Docs
|
||||
|
||||
# ProxyInterfaceGenerator
|
||||
This project uses Source Generation to generate an interface and a Proxy class for classes.
|
||||
This makes it possible to wrap external classes which do not have an interface, in a Proxy class which makes it easier to Mock and use DI.
|
||||
|
||||
It supports:
|
||||
|
||||
- properties
|
||||
- methods
|
||||
- events
|
||||
- implicit and explicit operators
|
||||
|
||||
## Install
|
||||
|
||||
[](https://www.nuget.org/packages/Speckle.ProxyGenerator)
|
||||
[](https://www.nuget.org/packages/ProxyInterfaceGenerator)
|
||||
|
||||
You can install from NuGet using the following command in the package manager window:
|
||||
|
||||
`Install-Package Speckle.ProxyGenerator`
|
||||
`Install-Package ProxyInterfaceGenerator`
|
||||
|
||||
Or via the Visual Studio NuGet package manager or if you use the `dotnet` command:
|
||||
|
||||
`dotnet add package Speckle.ProxyGenerator`
|
||||
`dotnet add package ProxyInterfaceGenerator`
|
||||
|
||||
## Usage
|
||||
|
||||
### Given: an external existing class which does not implement an interface
|
||||
|
||||
``` c#
|
||||
public sealed class Person
|
||||
{
|
||||
@@ -59,7 +34,6 @@ public sealed class Person
|
||||
```
|
||||
|
||||
### Create a partial interface
|
||||
|
||||
And annotate this with `ProxyInterfaceGenerator.Proxy[...]` and with the Type which needs to be wrapped:
|
||||
|
||||
``` c#
|
||||
@@ -70,7 +44,6 @@ public partial interface IPerson
|
||||
```
|
||||
|
||||
#### ProxyBaseClasses
|
||||
|
||||
In case also want to proxy the properties/methods/events from the base class(es), use this:
|
||||
|
||||
``` c#
|
||||
@@ -81,7 +54,6 @@ public partial interface IPerson
|
||||
```
|
||||
|
||||
#### ProxyClassAccessibility
|
||||
|
||||
By default, the generated Proxy class is `public`. If you want to create the Proxy class as `internal`, use the following:
|
||||
|
||||
``` c#
|
||||
@@ -94,9 +66,7 @@ public partial interface IPerson
|
||||
### When the code is compiled, this source generator creates the following
|
||||
|
||||
#### :one: An additional partial interface
|
||||
|
||||
Which defines the same properties and methods as in the external class.
|
||||
|
||||
``` c#
|
||||
public partial interface IPerson
|
||||
{
|
||||
@@ -107,7 +77,6 @@ public partial interface IPerson
|
||||
```
|
||||
|
||||
#### :two: A Proxy class
|
||||
|
||||
Which takes the external class in the constructor and wraps all public properties, events and methods.
|
||||
|
||||
``` c#
|
||||
@@ -135,7 +104,6 @@ public class PersonProxy : IPerson
|
||||
:star: By default the accessibility from the generated Proxy class is `public`.
|
||||
|
||||
### :three: Use it
|
||||
|
||||
``` c#
|
||||
IPerson p = new PersonProxy(new Person());
|
||||
p.Name = "test";
|
||||
@@ -143,5 +111,4 @@ p.HelloWorld("stef");
|
||||
```
|
||||
|
||||
# References
|
||||
|
||||
- <https://route2roslyn.netlify.app/symbols-for-dummies/>
|
||||
- https://route2roslyn.netlify.app/symbols-for-dummies/
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "8.0.0",
|
||||
"rollForward": "latestMinor",
|
||||
"allowPrerelease": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"RoslynExtensionsOptions": {
|
||||
"enableAnalyzersSupport": true
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace ProxyInterfaceConsumer
|
||||
{
|
||||
@@ -7,8 +6,8 @@ namespace ProxyInterfaceConsumer
|
||||
{
|
||||
public int HouseNumber { get; set; }
|
||||
|
||||
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
|
||||
public event EventHandler<EventArgs> MyEvent = null!;
|
||||
public event EventHandler<EventArgs> MyEvent;
|
||||
|
||||
public int Weird { get; set; }
|
||||
|
||||
public int Weird2()
|
||||
@@ -16,4 +15,4 @@ namespace ProxyInterfaceConsumer
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
using System.Net.Http;
|
||||
using Speckle.ProxyGenerator;
|
||||
|
||||
namespace ProxyInterfaceConsumer.Http;
|
||||
|
||||
[Speckle.ProxyGenerator.Proxy(typeof(HttpClient), ImplementationOptions.ProxyBaseClasses)]
|
||||
public partial interface IHttpClient : IHttpMessageInvoker { }
|
||||
[ProxyInterfaceGenerator.Proxy(typeof(HttpClient), true)]
|
||||
public partial interface IHttpClient : IHttpMessageInvoker
|
||||
{
|
||||
}
|
||||
|
||||
[Speckle.ProxyGenerator.Proxy(typeof(HttpMessageInvoker), ImplementationOptions.None)]
|
||||
public partial interface IHttpMessageInvoker { }
|
||||
[ProxyInterfaceGenerator.Proxy(typeof(HttpMessageInvoker))]
|
||||
public partial interface IHttpMessageInvoker
|
||||
{
|
||||
}
|
||||
@@ -13,212 +13,96 @@ namespace ProxyInterfaceConsumer.Http;
|
||||
public static class IHttpClientExtensions
|
||||
{
|
||||
#region PostAsJsonAsync
|
||||
public static Task<HttpResponseMessage> PostAsJsonAsync<TValue>(
|
||||
this IHttpClient client,
|
||||
[StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri,
|
||||
TValue value,
|
||||
JsonSerializerOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static Task<HttpResponseMessage> PostAsJsonAsync<TValue>(this IHttpClient client, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, TValue value, JsonSerializerOptions? options = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return client._Instance.PostAsJsonAsync(requestUri, value, options, cancellationToken);
|
||||
}
|
||||
|
||||
public static Task<HttpResponseMessage> PostAsJsonAsync<TValue>(
|
||||
this IHttpClient client,
|
||||
Uri? requestUri,
|
||||
TValue value,
|
||||
JsonSerializerOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static Task<HttpResponseMessage> PostAsJsonAsync<TValue>(this IHttpClient client, Uri? requestUri, TValue value, JsonSerializerOptions? options = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return client._Instance.PostAsJsonAsync(requestUri, value, options, cancellationToken);
|
||||
}
|
||||
|
||||
public static Task<HttpResponseMessage> PostAsJsonAsync<TValue>(
|
||||
this IHttpClient client,
|
||||
[StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri,
|
||||
TValue value,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
public static Task<HttpResponseMessage> PostAsJsonAsync<TValue>(this IHttpClient client, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, TValue value, CancellationToken cancellationToken)
|
||||
{
|
||||
return client._Instance.PostAsJsonAsync(
|
||||
requestUri,
|
||||
value,
|
||||
options: null,
|
||||
cancellationToken
|
||||
);
|
||||
return client._Instance.PostAsJsonAsync(requestUri, value, options: null, cancellationToken);
|
||||
}
|
||||
|
||||
public static Task<HttpResponseMessage> PostAsJsonAsync<TValue>(
|
||||
this IHttpClient client,
|
||||
Uri? requestUri,
|
||||
TValue value,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
public static Task<HttpResponseMessage> PostAsJsonAsync<TValue>(this IHttpClient client, Uri? requestUri, TValue value, CancellationToken cancellationToken)
|
||||
{
|
||||
return client._Instance.PostAsJsonAsync(
|
||||
requestUri,
|
||||
value,
|
||||
options: null,
|
||||
cancellationToken
|
||||
);
|
||||
return client._Instance.PostAsJsonAsync(requestUri, value, options: null, cancellationToken);
|
||||
}
|
||||
|
||||
public static Task<HttpResponseMessage> PostAsJsonAsync<TValue>(
|
||||
this IHttpClient client,
|
||||
[StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri,
|
||||
TValue value,
|
||||
JsonTypeInfo<TValue> jsonTypeInfo,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static Task<HttpResponseMessage> PostAsJsonAsync<TValue>(this IHttpClient client, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, TValue value, JsonTypeInfo<TValue> jsonTypeInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return client._Instance.PostAsJsonAsync(requestUri, value, jsonTypeInfo, cancellationToken);
|
||||
}
|
||||
|
||||
public static Task<HttpResponseMessage> PostAsJsonAsync<TValue>(
|
||||
this IHttpClient client,
|
||||
Uri? requestUri,
|
||||
TValue value,
|
||||
JsonTypeInfo<TValue> jsonTypeInfo,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static Task<HttpResponseMessage> PostAsJsonAsync<TValue>(this IHttpClient client, Uri? requestUri, TValue value, JsonTypeInfo<TValue> jsonTypeInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return client._Instance.PostAsJsonAsync(requestUri, value, jsonTypeInfo, cancellationToken);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GetFromJsonAsync
|
||||
public static Task<object?> GetFromJsonAsync(
|
||||
this IHttpClient client,
|
||||
[StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri,
|
||||
Type type,
|
||||
JsonSerializerOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static Task<object?> GetFromJsonAsync(this IHttpClient client, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, Type type, JsonSerializerOptions? options, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return client._Instance.GetFromJsonAsync(requestUri, type, options, cancellationToken);
|
||||
}
|
||||
|
||||
public static Task<object?> GetFromJsonAsync(
|
||||
this IHttpClient client,
|
||||
Uri? requestUri,
|
||||
Type type,
|
||||
JsonSerializerOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static Task<object?> GetFromJsonAsync(this IHttpClient client, Uri? requestUri, Type type, JsonSerializerOptions? options, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return client._Instance.GetFromJsonAsync(requestUri, type, options, cancellationToken);
|
||||
}
|
||||
|
||||
public static Task<TValue?> GetFromJsonAsync<TValue>(
|
||||
this IHttpClient client,
|
||||
[StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri,
|
||||
JsonSerializerOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static Task<TValue?> GetFromJsonAsync<TValue>(this IHttpClient client, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, JsonSerializerOptions? options, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return client._Instance.GetFromJsonAsync<TValue>(requestUri, options, cancellationToken);
|
||||
}
|
||||
|
||||
public static Task<TValue?> GetFromJsonAsync<TValue>(
|
||||
this IHttpClient client,
|
||||
Uri? requestUri,
|
||||
JsonSerializerOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static Task<TValue?> GetFromJsonAsync<TValue>(this IHttpClient client, Uri? requestUri, JsonSerializerOptions? options, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return client._Instance.GetFromJsonAsync<TValue>(requestUri, options, cancellationToken);
|
||||
}
|
||||
|
||||
public static Task<object?> GetFromJsonAsync(
|
||||
this IHttpClient client,
|
||||
[StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri,
|
||||
Type type,
|
||||
JsonSerializerContext context,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static Task<object?> GetFromJsonAsync(this IHttpClient client, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, Type type, JsonSerializerContext context, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return client._Instance.GetFromJsonAsync(requestUri, type, context, cancellationToken);
|
||||
}
|
||||
|
||||
public static Task<object?> GetFromJsonAsync(
|
||||
this IHttpClient client,
|
||||
Uri? requestUri,
|
||||
Type type,
|
||||
JsonSerializerContext context,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static Task<object?> GetFromJsonAsync(this IHttpClient client, Uri? requestUri, Type type, JsonSerializerContext context, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return client._Instance.GetFromJsonAsync(requestUri, type, context, cancellationToken);
|
||||
}
|
||||
|
||||
public static Task<TValue?> GetFromJsonAsync<TValue>(
|
||||
this IHttpClient client,
|
||||
[StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri,
|
||||
JsonTypeInfo<TValue> jsonTypeInfo,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static Task<TValue?> GetFromJsonAsync<TValue>(this IHttpClient client, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, JsonTypeInfo<TValue> jsonTypeInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return client._Instance.GetFromJsonAsync(requestUri, jsonTypeInfo, cancellationToken);
|
||||
}
|
||||
|
||||
public static Task<TValue?> GetFromJsonAsync<TValue>(
|
||||
this IHttpClient client,
|
||||
Uri? requestUri,
|
||||
JsonTypeInfo<TValue> jsonTypeInfo,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static Task<TValue?> GetFromJsonAsync<TValue>(this IHttpClient client, Uri? requestUri, JsonTypeInfo<TValue> jsonTypeInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return client._Instance.GetFromJsonAsync(requestUri, jsonTypeInfo, cancellationToken);
|
||||
}
|
||||
|
||||
public static Task<object?> GetFromJsonAsync(
|
||||
this IHttpClient client,
|
||||
[StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri,
|
||||
Type type,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static Task<object?> GetFromJsonAsync(this IHttpClient client, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, Type type, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return client._Instance.GetFromJsonAsync(
|
||||
requestUri,
|
||||
type,
|
||||
options: null,
|
||||
cancellationToken
|
||||
);
|
||||
return client._Instance.GetFromJsonAsync(requestUri, type, options: null, cancellationToken);
|
||||
}
|
||||
|
||||
public static Task<object?> GetFromJsonAsync(
|
||||
this IHttpClient client,
|
||||
Uri? requestUri,
|
||||
Type type,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static Task<object?> GetFromJsonAsync(this IHttpClient client, Uri? requestUri, Type type, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return client._Instance.GetFromJsonAsync(
|
||||
requestUri,
|
||||
type,
|
||||
options: null,
|
||||
cancellationToken
|
||||
);
|
||||
return client._Instance.GetFromJsonAsync(requestUri, type, options: null, cancellationToken);
|
||||
}
|
||||
|
||||
public static Task<TValue?> GetFromJsonAsync<TValue>(
|
||||
this IHttpClient client,
|
||||
[StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static Task<TValue?> GetFromJsonAsync<TValue>(this IHttpClient client, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return client._Instance.GetFromJsonAsync<TValue>(requestUri, cancellationToken);
|
||||
}
|
||||
|
||||
public static Task<TValue?> GetFromJsonAsync<TValue>(
|
||||
this IHttpClient client,
|
||||
Uri? requestUri,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
public static Task<TValue?> GetFromJsonAsync<TValue>(this IHttpClient client, Uri? requestUri, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return client._Instance.GetFromJsonAsync<TValue>(requestUri, cancellationToken);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,8 @@
|
||||
using Speckle.ProxyGenerator;
|
||||
using ProxyInterfaceGenerator;
|
||||
|
||||
namespace ProxyInterfaceConsumer
|
||||
{
|
||||
[Proxy(
|
||||
typeof(Address),
|
||||
ImplementationOptions.ProxyBaseClasses,
|
||||
ProxyClassAccessibility.Public,
|
||||
new[] { "Weird" }
|
||||
)]
|
||||
[Proxy(typeof(Address), false, ProxyClassAccessibility.Public, new []{"Weird"})]
|
||||
public partial interface IAddress
|
||||
{
|
||||
public void Weird()
|
||||
@@ -15,4 +10,4 @@ namespace ProxyInterfaceConsumer
|
||||
_Instance.Weird2();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
namespace ProxyInterfaceConsumer
|
||||
{
|
||||
// [Speckle.ProxyGenerator.Proxy(typeof(Microsoft.CodeAnalysis.GeneratorExecutionContext))]
|
||||
public partial interface IGeneratorExecutionContext { }
|
||||
}
|
||||
// [ProxyInterfaceGenerator.Proxy(typeof(Microsoft.CodeAnalysis.GeneratorExecutionContext))]
|
||||
public partial interface IGeneratorExecutionContext
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace ProxyInterfaceConsumer
|
||||
{
|
||||
public interface IMyInterface { }
|
||||
}
|
||||
public interface IMyInterface
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
using Speckle.ProxyGenerator;
|
||||
using ProxyInterfaceGenerator;
|
||||
|
||||
namespace ProxyInterfaceConsumer
|
||||
{
|
||||
[Proxy(typeof(ProxyInterfaceConsumer.Person), ProxyClassAccessibility.Internal)]
|
||||
public partial interface IPerson { }
|
||||
}
|
||||
public partial interface IPerson
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
using Speckle.ProxyGenerator;
|
||||
|
||||
namespace ProxyInterfaceConsumer
|
||||
{
|
||||
[Speckle.ProxyGenerator.Proxy(typeof(ProxyInterfaceConsumer.PersonT<>), ImplementationOptions.None)]
|
||||
[ProxyInterfaceGenerator.Proxy(typeof(ProxyInterfaceConsumer.PersonT<>))]
|
||||
public partial interface IPersonT //<T> where T : struct
|
||||
{ }
|
||||
}
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
namespace ProxyInterfaceConsumer
|
||||
{
|
||||
[ProxyInterfaceGenerator.Proxy(typeof(ProxyInterfaceConsumer.PersonTT<,>))]
|
||||
public partial interface IPersonTT<T1, T2>
|
||||
public partial interface IPersonTT<T1, T2>
|
||||
where T1 : struct
|
||||
where T2 : class, new() { }
|
||||
}
|
||||
where T2 : class, new()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ProxyInterfaceConsumer
|
||||
@@ -9,31 +8,24 @@ namespace ProxyInterfaceConsumer
|
||||
private int PrivateId { get; }
|
||||
public int Id { get; }
|
||||
|
||||
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
|
||||
public object @object { get; set; } = null!;
|
||||
public object @object { get; set; }
|
||||
|
||||
public long? NullableLong { get; }
|
||||
|
||||
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
|
||||
public string Name { get; set; } = null!;
|
||||
public string Name { get; set; }
|
||||
|
||||
public string? StringNullable { get; set; }
|
||||
|
||||
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
|
||||
public Address Address { get; set; } = null!;
|
||||
public Address Address { get; set; }
|
||||
|
||||
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
|
||||
public List<Address> AddressesList { get; set; } = null!;
|
||||
public List<Address> AddressesList { get; set; }
|
||||
|
||||
public Dictionary<string, Address> AddressesDict { get; set; } =
|
||||
new Dictionary<string, Address>();
|
||||
public Dictionary<Address, Address> AddressesDict2 { get; set; } =
|
||||
new Dictionary<Address, Address>();
|
||||
public Dictionary<string, Address> AddressesDict { get; set; } = new Dictionary<string, Address>();
|
||||
public Dictionary<Address, Address> AddressesDict2 { get; set; } = new Dictionary<Address, Address>();
|
||||
|
||||
public E E { get; set; }
|
||||
|
||||
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
|
||||
public IMyInterface MyInterface { get; set; } = null!;
|
||||
public IMyInterface MyInterface { get; set; }
|
||||
|
||||
public bool TMethod<T1, T2>(int x, T1 t1, T2 t2)
|
||||
where T1 : struct
|
||||
@@ -57,7 +49,9 @@ namespace ProxyInterfaceConsumer
|
||||
return $"Hello {name} !";
|
||||
}
|
||||
|
||||
public void AddWithParams(params string[] values) { }
|
||||
public void AddWithParams(params string[] values)
|
||||
{
|
||||
}
|
||||
|
||||
public Address AddAddress(Address a)
|
||||
{
|
||||
@@ -66,7 +60,9 @@ namespace ProxyInterfaceConsumer
|
||||
return a;
|
||||
}
|
||||
|
||||
public void AddAddresses(params Address[] addresses) { }
|
||||
public void AddAddresses(params Address[] addresses)
|
||||
{
|
||||
}
|
||||
|
||||
public void In_Out_Ref1(in int a, out int b, ref int c)
|
||||
{
|
||||
@@ -81,7 +77,9 @@ namespace ProxyInterfaceConsumer
|
||||
// return 404;
|
||||
//}
|
||||
|
||||
public void Void() { }
|
||||
public void Void()
|
||||
{
|
||||
}
|
||||
|
||||
public Task Method1Async()
|
||||
{
|
||||
@@ -104,4 +102,4 @@ namespace ProxyInterfaceConsumer
|
||||
V1,
|
||||
V2
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
namespace ProxyInterfaceConsumer
|
||||
{
|
||||
public class PersonT<T>
|
||||
where T : struct
|
||||
public class PersonT<T> where T : struct
|
||||
{
|
||||
public T TVal { get; set; }
|
||||
|
||||
@@ -15,4 +14,4 @@ namespace ProxyInterfaceConsumer
|
||||
return new PersonT<T>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ namespace ProxyInterfaceConsumer
|
||||
|
||||
public T2 TVal2 { get; set; }
|
||||
|
||||
public void Call(int x, T1 t1, T2 t2) { }
|
||||
public void Call(int x, T1 t1, T2 t2)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
@@ -11,7 +10,10 @@ namespace ProxyInterfaceConsumer;
|
||||
|
||||
public class Program
|
||||
{
|
||||
private static JsonSerializerOptions JsonSerializerOptions = new() { WriteIndented = true };
|
||||
private static JsonSerializerOptions JsonSerializerOptions = new ()
|
||||
{
|
||||
WriteIndented = true
|
||||
};
|
||||
|
||||
public static async Task Main()
|
||||
{
|
||||
@@ -21,10 +23,7 @@ public class Program
|
||||
var result = await ph.GetAsync("https://www.google.nl");
|
||||
var todo = await ph.GetFromJsonAsync<Todo>("https://jsonplaceholder.typicode.com/todos/1");
|
||||
|
||||
var postResult = await h.PostAsJsonAsync<Todo>(
|
||||
"https://jsonplaceholder.typicode.com/todos",
|
||||
new Todo { Id = 123 }
|
||||
);
|
||||
var postResult = await h.PostAsJsonAsync<Todo>("https://jsonplaceholder.typicode.com/todos", new Todo { Id = 123 });
|
||||
|
||||
var t = new TestProxy(new Test());
|
||||
|
||||
@@ -41,7 +40,9 @@ public class Program
|
||||
|
||||
var ap = new AddressProxy(new Address { HouseNumber = 42 });
|
||||
ap.HouseNumber = -1;
|
||||
ap.MyEvent += delegate(object x, EventArgs a) { };
|
||||
ap.MyEvent += delegate (object x, EventArgs a)
|
||||
{
|
||||
};
|
||||
|
||||
IPerson p = new PersonProxy(new Person());
|
||||
p.Name = "test";
|
||||
@@ -64,10 +65,9 @@ public class Test
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
|
||||
public Clazz C { get; } = null!;
|
||||
public Clazz C { get; }
|
||||
|
||||
public IList<Clazz> Cs { get; set; } = new List<Clazz>();
|
||||
public IList<Clazz> Cs { get; set; }
|
||||
|
||||
public int AddString(string s)
|
||||
{
|
||||
@@ -87,11 +87,15 @@ public class Test
|
||||
|
||||
public sealed class Clazz
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
[Speckle.ProxyGenerator.Proxy(typeof(Test))]
|
||||
public partial interface ITest { }
|
||||
[ProxyInterfaceGenerator.Proxy(typeof(Test))]
|
||||
public partial interface ITest
|
||||
{
|
||||
}
|
||||
|
||||
[Speckle.ProxyGenerator.Proxy(typeof(Clazz))]
|
||||
public partial interface IClazz { }
|
||||
[ProxyInterfaceGenerator.Proxy(typeof(Clazz))]
|
||||
public partial interface IClazz
|
||||
{
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<Nullable>enable</Nullable>
|
||||
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -13,6 +12,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="10.1.1" />
|
||||
<PackageReference Include="Mapster" Version="7.3.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
@@ -24,7 +24,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Speckle.ProxyGenerator\Speckle.ProxyGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||
<ProjectReference Include="..\..\src\ProxyInterfaceSourceGenerator\ProxyInterfaceSourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -0,0 +1,9 @@
|
||||
using Akka.Remote;
|
||||
|
||||
// namespace ProxyInterfaceConsumerForAkka.Interfaces; <-- no namespace
|
||||
|
||||
[ProxyInterfaceGenerator.Proxy(typeof(AddressUid))]
|
||||
// ReSharper disable once CheckNamespace
|
||||
public partial interface IAddressUid
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Akka.Actor;
|
||||
|
||||
namespace ProxyInterfaceConsumerForAkka.Interfaces
|
||||
{
|
||||
[ProxyInterfaceGenerator.Proxy(typeof(LocalActorRefProvider))]
|
||||
public partial interface ILocalActorRefProvider
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Akka.Actor;
|
||||
using ProxyInterfaceConsumerForAkka.Interfaces;
|
||||
|
||||
namespace ProxyInterfaceConsumerForAkka;
|
||||
|
||||
public class Program
|
||||
{
|
||||
public static void Main()
|
||||
{
|
||||
Akka.Remote.AddressUid auid = null;
|
||||
IAddressUid addressUidProxy = new AddressUidProxy(auid);
|
||||
|
||||
LocalActorRefProvider p = null;
|
||||
ILocalActorRefProvider proxy = new LocalActorRefProviderProxy(p);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Akka.Remote" Version="1.4.47" />
|
||||
<PackageReference Include="Mapster" Version="7.3.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="3.10.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.10.0" />
|
||||
<PackageReference Include="TinyMapper" Version="3.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!--<PackageReference Include="ProxyInterfaceGenerator" Version="0.0.24">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>-->
|
||||
|
||||
<ProjectReference Include="..\..\src\ProxyInterfaceSourceGenerator\ProxyInterfaceSourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -11,15 +11,9 @@ namespace ProxyInterfaceConsumerForPnP.Interfaces;
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public partial class ClientContextProxy
|
||||
{
|
||||
public Task ExecuteQueryRetryAsync(
|
||||
Interfaces.IClientRuntimeContext clientContext,
|
||||
int retryCount = 10,
|
||||
string? userAgent = null
|
||||
)
|
||||
public Task ExecuteQueryRetryAsync(Interfaces.IClientRuntimeContext clientContext, int retryCount = 10, string? userAgent = null)
|
||||
{
|
||||
ClientRuntimeContext clientObject_ = Mapster.TypeAdapter.Adapt<ClientRuntimeContext>(
|
||||
clientContext
|
||||
);
|
||||
ClientRuntimeContext clientObject_ = Mapster.TypeAdapter.Adapt<ClientRuntimeContext>(clientContext);
|
||||
return clientObject_.ExecuteQueryRetryAsync(retryCount, userAgent);
|
||||
}
|
||||
|
||||
@@ -31,24 +25,17 @@ public partial class ClientContextProxy
|
||||
_Instance.Load<T>(clientObject_, retrievals_);
|
||||
}
|
||||
|
||||
public void Load<TSource, TTarget>(
|
||||
Interfaces.IClientObject clientObject,
|
||||
params Expression<Func<TSource, object>>[] retrievals
|
||||
)
|
||||
public void Load<TSource, TTarget>(Interfaces.IClientObject clientObject, params Expression<Func<TSource, object>>[] retrievals)
|
||||
where TSource : Interfaces.IClientObject
|
||||
where TTarget : ClientObject
|
||||
{
|
||||
TTarget clientObject_ = Mapster.TypeAdapter.Adapt<TTarget>(clientObject);
|
||||
Expression<Func<TTarget, object>>[] retrievals_ = retrievals
|
||||
.Select(MapExpression<TSource, TTarget>)
|
||||
.ToArray();
|
||||
Expression<Func<TTarget, object>>[] retrievals_ = retrievals.Select(MapExpression<TSource, TTarget>).ToArray();
|
||||
|
||||
_Instance.Load(clientObject_, retrievals_);
|
||||
}
|
||||
|
||||
private static Expression<Func<TTarget, object>> MapExpression<TSource, TTarget>(
|
||||
Expression<Func<TSource, object>> expression
|
||||
)
|
||||
private static Expression<Func<TTarget, object>> MapExpression<TSource, TTarget>(Expression<Func<TSource, object>> expression)
|
||||
where TSource : Interfaces.IClientObject
|
||||
where TTarget : ClientObject
|
||||
{
|
||||
@@ -58,28 +45,20 @@ public partial class ClientContextProxy
|
||||
switch (expression.Body)
|
||||
{
|
||||
case MemberExpression memberExpression:
|
||||
memberAccessExpression = Expression.PropertyOrField(
|
||||
parameterExpression,
|
||||
memberExpression.Member.Name
|
||||
);
|
||||
memberAccessExpression = Expression.PropertyOrField(parameterExpression, memberExpression.Member.Name);
|
||||
break;
|
||||
|
||||
case UnaryExpression unaryExpression:
|
||||
var expressionOperand = (MemberExpression)unaryExpression.Operand;
|
||||
memberAccessExpression = Expression.PropertyOrField(
|
||||
parameterExpression,
|
||||
expressionOperand.Member.Name
|
||||
);
|
||||
memberAccessExpression = Expression.PropertyOrField(parameterExpression, expressionOperand.Member.Name);
|
||||
memberAccessExpression = Expression.Convert(memberAccessExpression, typeof(object));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotSupportedException();
|
||||
|
||||
}
|
||||
|
||||
return Expression.Lambda<Func<TTarget, object>>(
|
||||
memberAccessExpression,
|
||||
parameterExpression
|
||||
);
|
||||
return Expression.Lambda<Func<TTarget, object>>(memberAccessExpression, parameterExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-9
@@ -6,15 +6,9 @@ namespace ProxyInterfaceConsumerForPnP.Implementations;
|
||||
|
||||
public static class ClientRuntimeContextExtensions
|
||||
{
|
||||
public static Task ExecuteQueryRetryAsync(
|
||||
this IClientRuntimeContext clientContext,
|
||||
int retryCount = 10,
|
||||
string? userAgent = null
|
||||
)
|
||||
public static Task ExecuteQueryRetryAsync(this IClientRuntimeContext clientContext, int retryCount = 10, string? userAgent = null)
|
||||
{
|
||||
ClientRuntimeContext clientObject_ = Mapster.TypeAdapter.Adapt<ClientRuntimeContext>(
|
||||
clientContext
|
||||
);
|
||||
ClientRuntimeContext clientObject_ = Mapster.TypeAdapter.Adapt<ClientRuntimeContext>(clientContext);
|
||||
return clientObject_.ExecuteQueryRetryAsync(retryCount, userAgent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,14 @@
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using Microsoft.SharePoint.Client;
|
||||
using Speckle.ProxyGenerator;
|
||||
|
||||
namespace ProxyInterfaceConsumerForPnP.Interfaces
|
||||
{
|
||||
[Speckle.ProxyGenerator.Proxy(typeof(ClientContext), ImplementationOptions.None)]
|
||||
[ProxyInterfaceGenerator.Proxy(typeof(ClientContext))]
|
||||
public partial interface IClientContext : IClientRuntimeContext
|
||||
{
|
||||
void Load<TSource, TTarget>(
|
||||
IClientObject clientObject,
|
||||
params Expression<Func<TSource, object>>[] retrievals
|
||||
)
|
||||
void Load<TSource, TTarget>(IClientObject clientObject, params Expression<Func<TSource, object>>[] retrievals)
|
||||
where TSource : IClientObject
|
||||
where TTarget : ClientObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using Speckle.ProxyGenerator;
|
||||
|
||||
namespace ProxyInterfaceConsumerForPnP.Interfaces
|
||||
{
|
||||
[Speckle.ProxyGenerator.Proxy(typeof(Microsoft.SharePoint.Client.ClientObject), ImplementationOptions.None)]
|
||||
public partial interface IClientObject { }
|
||||
}
|
||||
[ProxyInterfaceGenerator.Proxy(typeof(Microsoft.SharePoint.Client.ClientObject))]
|
||||
public partial interface IClientObject
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
using Speckle.ProxyGenerator;
|
||||
|
||||
namespace ProxyInterfaceConsumerForPnP.Interfaces
|
||||
{
|
||||
[Speckle.ProxyGenerator.Proxy(typeof(Microsoft.SharePoint.Client.ClientRuntimeContext), ImplementationOptions.None)]
|
||||
public partial interface IClientRuntimeContext { }
|
||||
}
|
||||
[ProxyInterfaceGenerator.Proxy(typeof(Microsoft.SharePoint.Client.ClientRuntimeContext))]
|
||||
public partial interface IClientRuntimeContext
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
//using System.Collections;
|
||||
//using System.Linq;
|
||||
|
||||
//namespace ProxyInterfaceConsumerForPnP.Interfaces
|
||||
//{
|
||||
// [ProxyInterfaceGenerator.Proxy(typeof(Microsoft.SharePoint.Client.ListCollection))]
|
||||
// public partial interface IProxyListCollection: IClientObject, IEnumerable, IQueryable
|
||||
// {
|
||||
// }
|
||||
//}
|
||||
@@ -1,10 +1,8 @@
|
||||
using Speckle.ProxyGenerator;
|
||||
|
||||
namespace ProxyInterfaceConsumerForPnP.Interfaces
|
||||
{
|
||||
[Speckle.ProxyGenerator.Proxy(typeof(Microsoft.SharePoint.Client.SecurableObject), ImplementationOptions.None)]
|
||||
[ProxyInterfaceGenerator.Proxy(typeof(Microsoft.SharePoint.Client.SecurableObject))]
|
||||
public partial interface ISecurableObject : IClientObject
|
||||
{
|
||||
// public virtual void X();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using Speckle.ProxyGenerator;
|
||||
|
||||
namespace ProxyInterfaceConsumerForPnP.Interfaces
|
||||
{
|
||||
[Speckle.ProxyGenerator.Proxy(typeof(Microsoft.SharePoint.Client.User), ImplementationOptions.None)]
|
||||
public partial interface IUser { }
|
||||
}
|
||||
[ProxyInterfaceGenerator.Proxy(typeof(Microsoft.SharePoint.Client.User))]
|
||||
public partial interface IUser
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using Speckle.ProxyGenerator;
|
||||
|
||||
namespace ProxyInterfaceConsumerForPnP.Interfaces
|
||||
{
|
||||
[Speckle.ProxyGenerator.Proxy(typeof(Microsoft.SharePoint.Client.Web), ImplementationOptions.None)]
|
||||
public partial interface IWeb : ISecurableObject { }
|
||||
}
|
||||
[ProxyInterfaceGenerator.Proxy(typeof(Microsoft.SharePoint.Client.Web))]
|
||||
public partial interface IWeb: ISecurableObject
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -18,12 +18,9 @@ public class Program
|
||||
"15b347bf-90a2-4c16-aa76-5a3263476b59",
|
||||
"Test.pfx",
|
||||
Environment.GetEnvironmentVariable("Test.pfx_PWD"),
|
||||
"s7gb6.onmicrosoft.com"
|
||||
);
|
||||
"s7gb6.onmicrosoft.com");
|
||||
|
||||
using var clientContext = await authManager.GetContextAsync(
|
||||
"https://s7gb6.sharepoint.com/sites/Test"
|
||||
);
|
||||
using var clientContext = await authManager.GetContextAsync("https://s7gb6.sharepoint.com/sites/Test");
|
||||
clientContext.Load(clientContext.Web, p => p.Title);
|
||||
await clientContext.ExecuteQueryRetryAsync();
|
||||
|
||||
@@ -31,12 +28,7 @@ public class Program
|
||||
|
||||
IClientContext cp = new ClientContextProxy(clientContext);
|
||||
|
||||
cp.Load<ProxyInterfaceConsumerForPnP.Interfaces.IWeb, Web>(
|
||||
cp.Web,
|
||||
w => w.Lists,
|
||||
w => w.Language,
|
||||
w => w.Author
|
||||
);
|
||||
cp.Load<ProxyInterfaceConsumerForPnP.Interfaces.IWeb, Web>(cp.Web, w => w.Lists, w => w.Language, w => w.Author);
|
||||
|
||||
await cp.ExecuteQueryRetryAsync();
|
||||
|
||||
@@ -63,4 +55,4 @@ public class Program
|
||||
Console.WriteLine("Error Message: " + ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!--<PackageReference Include="AutoMapper" Version="10.1.1" />-->
|
||||
<PackageReference Include="Mapster" Version="7.3.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
@@ -19,7 +20,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Speckle.ProxyGenerator\Speckle.ProxyGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||
<ProjectReference Include="..\..\src\ProxyInterfaceSourceGenerator\ProxyInterfaceSourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -29,6 +30,9 @@
|
||||
<Compile Update="Interfaces\IClientObject.cs">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Compile>
|
||||
<Compile Update="Interfaces\IListCollection.cs">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Compile>
|
||||
<Compile Update="Interfaces\IUser.cs">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Compile>
|
||||
@@ -49,4 +53,4 @@
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -4,4 +4,4 @@
|
||||
{
|
||||
public int HouseNumber { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
namespace ProxyInterfaceConsumer
|
||||
{
|
||||
[ProxyInterfaceGenerator.Proxy(typeof(ProxyInterfaceConsumer.Address))]
|
||||
public partial interface IAddress { }
|
||||
}
|
||||
public partial interface IAddress
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace ProxyInterfaceConsumer
|
||||
{
|
||||
public interface IMyInterface { }
|
||||
}
|
||||
public interface IMyInterface
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -3,5 +3,7 @@ using ProxyInterfaceGenerator;
|
||||
namespace ProxyInterfaceConsumer
|
||||
{
|
||||
[Proxy(typeof(Person), ProxyClassAccessibility.Internal)]
|
||||
public partial interface IPerson { }
|
||||
}
|
||||
public partial interface IPerson
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ProxyInterfaceConsumer
|
||||
@@ -9,38 +8,33 @@ namespace ProxyInterfaceConsumer
|
||||
private int PrivateId { get; }
|
||||
public int Id { get; }
|
||||
|
||||
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
|
||||
public object @object { get; set; } = null!;
|
||||
public object @object { get; set; }
|
||||
|
||||
public long? NullableLong { get; }
|
||||
|
||||
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
|
||||
public string Name { get; set; } = null!;
|
||||
public string Name { get; set; }
|
||||
|
||||
public string? StringNullable { get; set; }
|
||||
|
||||
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
|
||||
public Address Address { get; set; } = null!;
|
||||
public Address Address { get; set; }
|
||||
|
||||
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
|
||||
public List<Address> AddressesLIst { get; set; } = null!;
|
||||
public List<Address> AddressesLIst { get; set; }
|
||||
|
||||
public Dictionary<string, Address> AddressesDict { get; set; } =
|
||||
new Dictionary<string, Address>();
|
||||
public Dictionary<Address, Address> AddressesDict2 { get; set; } =
|
||||
new Dictionary<Address, Address>();
|
||||
public Dictionary<string, Address> AddressesDict { get; set; } = new Dictionary<string, Address>();
|
||||
public Dictionary<Address, Address> AddressesDict2 { get; set; } = new Dictionary<Address, Address>();
|
||||
|
||||
public E E { get; set; }
|
||||
|
||||
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
|
||||
public IMyInterface MyInterface { get; set; } = null!;
|
||||
public IMyInterface MyInterface { get; set; }
|
||||
|
||||
public string Add(string s, string @string)
|
||||
{
|
||||
return s + @string;
|
||||
}
|
||||
|
||||
public void AddWithParams(params string[] values) { }
|
||||
public void AddWithParams(params string[] values)
|
||||
{
|
||||
}
|
||||
|
||||
public Address AddAddress(Address a)
|
||||
{
|
||||
@@ -49,7 +43,9 @@ namespace ProxyInterfaceConsumer
|
||||
return a;
|
||||
}
|
||||
|
||||
public void AddAddresses(params Address[] addresses) { }
|
||||
public void AddAddresses(params Address[] addresses)
|
||||
{
|
||||
}
|
||||
|
||||
public void In_Out_Ref1(in int a, out int b, ref int c)
|
||||
{
|
||||
@@ -62,7 +58,9 @@ namespace ProxyInterfaceConsumer
|
||||
return 404;
|
||||
}
|
||||
|
||||
public void Void() { }
|
||||
public void Void()
|
||||
{
|
||||
}
|
||||
|
||||
public Task Method1Async()
|
||||
{
|
||||
@@ -85,4 +83,4 @@ namespace ProxyInterfaceConsumer
|
||||
V1,
|
||||
V2
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,10 @@ namespace ProxyInterfaceConsumer
|
||||
{
|
||||
class Program
|
||||
{
|
||||
private static JsonSerializerOptions JsonSerializerOptions = new() { WriteIndented = true };
|
||||
private static JsonSerializerOptions JsonSerializerOptions = new ()
|
||||
{
|
||||
WriteIndented = true
|
||||
};
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
@@ -21,4 +24,4 @@ namespace ProxyInterfaceConsumer
|
||||
Console.WriteLine(JsonSerializer.Serialize(p, JsonSerializerOptions));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<AssemblyName>ProxyInterfaceConsumer</AssemblyName>
|
||||
<RootNamespace>ProxyInterfaceConsumer</RootNamespace>
|
||||
<Nullable>enable</Nullable>
|
||||
@@ -10,11 +10,12 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="12.0.1" />
|
||||
<PackageReference Include="Mapster" Version="7.3.0" />
|
||||
<PackageReference Include="ProxyInterfaceGenerator" Version="0.1.0">
|
||||
<PackageReference Include="ProxyInterfaceGenerator" Version="0.0.38">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
</Project>
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Speckle.ProxyGenerator.Extensions;
|
||||
using ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
namespace Speckle.ProxyGenerator.Builders;
|
||||
namespace ProxyInterfaceSourceGenerator.Builders;
|
||||
|
||||
internal static class MethodParameterBuilder
|
||||
{
|
||||
@@ -16,10 +16,10 @@ internal static class MethodParameterBuilder
|
||||
stringBuilder.Append(parameterSymbol.GetRefKindPrefix()); // "" or "out "
|
||||
stringBuilder.AppendFormat("{0} ", type); // string or another type
|
||||
}
|
||||
|
||||
|
||||
stringBuilder.Append(parameterSymbol.GetSanitizedName()); // "s" or "i" or ...
|
||||
stringBuilder.Append(parameterSymbol.GetDefaultValue()); // "" or the value
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
namespace Speckle.ProxyGenerator.Enums;
|
||||
namespace ProxyInterfaceSourceGenerator.Enums;
|
||||
|
||||
internal enum TypeEnum
|
||||
{
|
||||
@@ -7,4 +7,4 @@ internal enum TypeEnum
|
||||
Interface,
|
||||
|
||||
Complex
|
||||
}
|
||||
}
|
||||
+12
-14
@@ -1,14 +1,12 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Speckle.ProxyGenerator.Extensions;
|
||||
|
||||
internal static class MethodSymbolExtensions
|
||||
{
|
||||
public static string GetMethodNameWithOptionalTypeParameters(this IMethodSymbol method) =>
|
||||
!method.IsGenericMethod
|
||||
? method.Name
|
||||
: $"{method.Name}<{string.Join(", ", method.TypeParameters.Select(tp => tp.Name))}>";
|
||||
|
||||
//public static string GetWhereStatement(this IMethodSymbol method) =>
|
||||
// !method.IsGenericMethod ? string.Empty : string.Join("", method.TypeParameters.Select(tp => tp.GetWhereConstraints()));
|
||||
}
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
internal static class MethodSymbolExtensions
|
||||
{
|
||||
public static string GetMethodNameWithOptionalTypeParameters(this IMethodSymbol method) =>
|
||||
!method.IsGenericMethod ? method.Name : $"{method.Name}<{string.Join(", ", method.TypeParameters.Select(tp => tp.Name))}>";
|
||||
|
||||
//public static string GetWhereStatement(this IMethodSymbol method) =>
|
||||
// !method.IsGenericMethod ? string.Empty : string.Join("", method.TypeParameters.Select(tp => tp.GetWhereConstraints()));
|
||||
}
|
||||
+88
-121
@@ -1,121 +1,88 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Speckle.ProxyGenerator.Extensions;
|
||||
|
||||
internal static class NamedTypeSymbolExtensions
|
||||
{
|
||||
public static List<INamedTypeSymbol> GetBaseTypes(this INamedTypeSymbol? type)
|
||||
{
|
||||
var types = new List<INamedTypeSymbol>();
|
||||
|
||||
bool me = true;
|
||||
while (type != null && type.SpecialType != SpecialType.System_Object)
|
||||
{
|
||||
if (!me)
|
||||
{
|
||||
types.Add(type);
|
||||
}
|
||||
|
||||
type = type.BaseType;
|
||||
me = false;
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
public static string GetFullType(this INamedTypeSymbol namedTypeSymbol)
|
||||
{
|
||||
// https://www.codeproject.com/Articles/861548/Roslyn-Code-Analysis-in-Easy-Samples-Part
|
||||
//var str = new StringBuilder(namedTypeSymbol.Name);
|
||||
|
||||
//if (namedTypeSymbol.TypeArguments.Count() > 0)
|
||||
//{
|
||||
// str.AppendFormat("<{0}>", string.Join(", ", namedTypeSymbol.TypeArguments.OfType<INamedTypeSymbol>().Select(typeArg => typeArg.GetFullType())));
|
||||
//}
|
||||
|
||||
return namedTypeSymbol.OriginalDefinition.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See https://stackoverflow.com/questions/24157101/roslyns-gettypebymetadataname-and-generic-types
|
||||
/// </summary>
|
||||
public static string ResolveProxyClassName(this INamedTypeSymbol namedTypeSymbol)
|
||||
{
|
||||
return !namedTypeSymbol.IsGenericType
|
||||
? $"{namedTypeSymbol.Name}Proxy"
|
||||
: $"{namedTypeSymbol.Name}Proxy<{string.Join(", ", namedTypeSymbol.TypeArguments.Select(ta => ta.Name))}>";
|
||||
}
|
||||
|
||||
public static List<INamedTypeSymbol> ResolveImplementedInterfaces(
|
||||
this INamedTypeSymbol symbol,
|
||||
bool proxyBaseClasses,
|
||||
bool proxyInterfaces
|
||||
)
|
||||
{
|
||||
// Members implemented by us or base classes should go here.
|
||||
var publicMembers = symbol
|
||||
.GetMembers()
|
||||
.Where(m => m.DeclaredAccessibility == Accessibility.Public)
|
||||
.ToList();
|
||||
|
||||
// Direct interfaces, recursive interfaces or base class interfaces should go here.
|
||||
var interfaces = new List<INamedTypeSymbol>();
|
||||
if (proxyInterfaces)
|
||||
{
|
||||
interfaces.AddRange(symbol.Interfaces);
|
||||
}
|
||||
var baseType = symbol.BaseType;
|
||||
while (
|
||||
proxyBaseClasses
|
||||
&& baseType != null
|
||||
&& baseType.SpecialType != SpecialType.System_Object
|
||||
)
|
||||
{
|
||||
publicMembers.AddRange(
|
||||
baseType.GetMembers().Where(m => m.DeclaredAccessibility == Accessibility.Public)
|
||||
);
|
||||
if (proxyInterfaces)
|
||||
{
|
||||
interfaces.AddRange(baseType.Interfaces);
|
||||
}
|
||||
baseType = baseType.BaseType;
|
||||
}
|
||||
|
||||
// Filter explicitly implemented interfaces.
|
||||
var realizedInterfaces = new List<INamedTypeSymbol>();
|
||||
foreach (var @interface in interfaces)
|
||||
{
|
||||
var isRealized = true;
|
||||
var allMembers = @interface.AllInterfaces.Aggregate(
|
||||
@interface.GetMembers(),
|
||||
(xs, x) => xs.AddRange(x.GetMembers())
|
||||
);
|
||||
foreach (var member in allMembers)
|
||||
{
|
||||
var implementation = symbol.FindImplementationForInterfaceMember(member);
|
||||
if (!publicMembers.Contains(implementation!))
|
||||
{
|
||||
isRealized = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isRealized)
|
||||
{
|
||||
realizedInterfaces.Add(@interface);
|
||||
}
|
||||
}
|
||||
|
||||
return realizedInterfaces;
|
||||
}
|
||||
|
||||
public static IEnumerable<INamedTypeSymbol> ResolveBaseInterfaces(
|
||||
this INamedTypeSymbol symbol,
|
||||
List<INamedTypeSymbol> previousInterfaces
|
||||
)
|
||||
{
|
||||
// Direct interfaces, recursive interfaces or base class interfaces should go here.
|
||||
var interfaces = new List<INamedTypeSymbol>(symbol.Interfaces);
|
||||
return interfaces.Except(previousInterfaces);
|
||||
}
|
||||
}
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
internal static class NamedTypeSymbolExtensions
|
||||
{
|
||||
public static List<INamedTypeSymbol> GetBaseTypes(this INamedTypeSymbol? type)
|
||||
{
|
||||
var types = new List<INamedTypeSymbol>();
|
||||
|
||||
bool me = true;
|
||||
while (type != null && type.SpecialType != SpecialType.System_Object)
|
||||
{
|
||||
if (!me)
|
||||
{
|
||||
types.Add(type);
|
||||
}
|
||||
|
||||
type = type.BaseType;
|
||||
me = false;
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
public static string GetFullType(this INamedTypeSymbol namedTypeSymbol)
|
||||
{
|
||||
// https://www.codeproject.com/Articles/861548/Roslyn-Code-Analysis-in-Easy-Samples-Part
|
||||
//var str = new StringBuilder(namedTypeSymbol.Name);
|
||||
|
||||
//if (namedTypeSymbol.TypeArguments.Count() > 0)
|
||||
//{
|
||||
// str.AppendFormat("<{0}>", string.Join(", ", namedTypeSymbol.TypeArguments.OfType<INamedTypeSymbol>().Select(typeArg => typeArg.GetFullType())));
|
||||
//}
|
||||
|
||||
return namedTypeSymbol.OriginalDefinition.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See https://stackoverflow.com/questions/24157101/roslyns-gettypebymetadataname-and-generic-types
|
||||
/// </summary>
|
||||
public static string ResolveProxyClassName(this INamedTypeSymbol namedTypeSymbol)
|
||||
{
|
||||
return !namedTypeSymbol.IsGenericType ?
|
||||
$"{namedTypeSymbol.Name}Proxy" :
|
||||
$"{namedTypeSymbol.Name}Proxy<{string.Join(", ", namedTypeSymbol.TypeArguments.Select(ta => ta.Name))}>";
|
||||
}
|
||||
|
||||
public static List<INamedTypeSymbol> ResolveImplementedInterfaces(this INamedTypeSymbol symbol, bool proxyBaseClasses)
|
||||
{
|
||||
// Members implemented by us or base classes should go here.
|
||||
var publicMembers = symbol.GetMembers().Where(m => m.DeclaredAccessibility == Accessibility.Public).ToList();
|
||||
|
||||
// Direct interfaces, recursive interfaces or base class interfaces should go here.
|
||||
var interfaces = new List<INamedTypeSymbol>(symbol.Interfaces);
|
||||
var baseType = symbol.BaseType;
|
||||
while (proxyBaseClasses && baseType != null && baseType.SpecialType != SpecialType.System_Object)
|
||||
{
|
||||
publicMembers.AddRange(baseType.GetMembers().Where(m => m.DeclaredAccessibility == Accessibility.Public));
|
||||
interfaces.AddRange(baseType.Interfaces);
|
||||
baseType = baseType.BaseType;
|
||||
}
|
||||
|
||||
// Filter explicitly implemented interfaces.
|
||||
var realizedInterfaces = new List<INamedTypeSymbol>();
|
||||
foreach (var @interface in interfaces)
|
||||
{
|
||||
var isRealized = true;
|
||||
var allMembers = @interface.AllInterfaces.Aggregate(@interface.GetMembers(), (xs, x) => xs.AddRange(x.GetMembers()));
|
||||
foreach (var member in allMembers)
|
||||
{
|
||||
var implementation = symbol.FindImplementationForInterfaceMember(member);
|
||||
if (!publicMembers.Contains(implementation!))
|
||||
{
|
||||
isRealized = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isRealized)
|
||||
{
|
||||
realizedInterfaces.Add(@interface);
|
||||
}
|
||||
}
|
||||
|
||||
return realizedInterfaces;
|
||||
}
|
||||
}
|
||||
+60
-62
@@ -1,62 +1,60 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Speckle.ProxyGenerator.Enums;
|
||||
|
||||
namespace Speckle.ProxyGenerator.Extensions;
|
||||
|
||||
internal static class ParameterSymbolExtensions
|
||||
{
|
||||
private const string ParameterValueNull = "null";
|
||||
|
||||
public static bool IsRef(this IParameterSymbol ps)
|
||||
{
|
||||
return ps.RefKind is RefKind.Ref or RefKind.RefReadOnly;
|
||||
}
|
||||
|
||||
public static string GetRefKindPrefix(this IParameterSymbol ps)
|
||||
{
|
||||
return ps.RefKind switch
|
||||
{
|
||||
RefKind.In => "in ",
|
||||
RefKind.Out => "out ",
|
||||
RefKind.Ref => "ref ",
|
||||
_ => string.Empty
|
||||
};
|
||||
}
|
||||
|
||||
public static string GetParamsPrefix(this IParameterSymbol ps) =>
|
||||
ps.IsParams ? "params " : string.Empty;
|
||||
|
||||
public static string GetDefaultValue(this IParameterSymbol ps)
|
||||
{
|
||||
if (!ps.HasExplicitDefaultValue)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
string defaultValue;
|
||||
if (ps.ExplicitDefaultValue == null)
|
||||
{
|
||||
if (ps.NullableAnnotation == NullableAnnotation.Annotated)
|
||||
{
|
||||
// The parameter is defined as Nullable, so always use "null".
|
||||
defaultValue = ParameterValueNull;
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultValue = ps.Type.IsReferenceType
|
||||
? ParameterValueNull
|
||||
: // The parameter is a ReferenceType, so use "null".
|
||||
$"default({ps.Type})"; // The parameter is not a ReferenceType, so use "default(T)".
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultValue = SymbolDisplay.FormatPrimitive(ps.ExplicitDefaultValue, true, false);
|
||||
}
|
||||
|
||||
return $" = {defaultValue}";
|
||||
}
|
||||
|
||||
public static TypeEnum GetTypeEnum(this IParameterSymbol p) => p.Type.GetTypeEnum();
|
||||
}
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using ProxyInterfaceSourceGenerator.Enums;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
internal static class ParameterSymbolExtensions
|
||||
{
|
||||
private const string ParameterValueNull = "null";
|
||||
|
||||
public static bool IsRef(this IParameterSymbol ps)
|
||||
{
|
||||
return ps.RefKind is RefKind.Ref or RefKind.RefReadOnly;
|
||||
}
|
||||
|
||||
public static string GetRefKindPrefix(this IParameterSymbol ps)
|
||||
{
|
||||
return ps.RefKind switch
|
||||
{
|
||||
RefKind.In => "in ",
|
||||
RefKind.Out => "out ",
|
||||
RefKind.Ref => "ref ",
|
||||
_ => string.Empty
|
||||
};
|
||||
}
|
||||
|
||||
public static string GetParamsPrefix(this IParameterSymbol ps) => ps.IsParams ? "params " : string.Empty;
|
||||
|
||||
public static string GetDefaultValue(this IParameterSymbol ps)
|
||||
{
|
||||
if (!ps.HasExplicitDefaultValue)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
string defaultValue;
|
||||
if (ps.ExplicitDefaultValue == null)
|
||||
{
|
||||
if (ps.NullableAnnotation == NullableAnnotation.Annotated)
|
||||
{
|
||||
// The parameter is defined as Nullable, so always use "null".
|
||||
defaultValue = ParameterValueNull;
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultValue = ps.Type.IsReferenceType
|
||||
? ParameterValueNull : // The parameter is a ReferenceType, so use "null".
|
||||
$"default({ps.Type})"; // The parameter is not a ReferenceType, so use "default(T)".
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultValue = SymbolDisplay.FormatPrimitive(ps.ExplicitDefaultValue, true, false);
|
||||
}
|
||||
|
||||
return $" = {defaultValue}";
|
||||
}
|
||||
|
||||
public static TypeEnum GetTypeEnum(this IParameterSymbol p) => p.Type.GetTypeEnum();
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using ProxyInterfaceSourceGenerator.Enums;
|
||||
using ProxyInterfaceSourceGenerator.FileGenerators;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
internal static class PropertySymbolExtensions
|
||||
{
|
||||
public static TypeEnum GetTypeEnum(this IPropertySymbol p) => p.Type.GetTypeEnum();
|
||||
|
||||
public static (string PropertyType, string? PropertyName, string GetSet)? ToPropertyDetails(this IPropertySymbol property, string? overrideType = null)
|
||||
{
|
||||
var getIsPublic = property.GetMethod.IsPublic();
|
||||
var setIsPublic = property.SetMethod.IsPublic();
|
||||
|
||||
if (!getIsPublic && !setIsPublic)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var get = getIsPublic ? "get; " : string.Empty;
|
||||
var set = setIsPublic ? "set; " : string.Empty;
|
||||
|
||||
var type = !string.IsNullOrEmpty(overrideType) ? overrideType
|
||||
: BaseGenerator.FixType(property.Type.ToFullyQualifiedDisplayString(), property.NullableAnnotation);
|
||||
|
||||
return (type!, property.GetSanitizedName(), $"{{ {get}{set}}}");
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
using System.Globalization;
|
||||
|
||||
namespace Speckle.ProxyGenerator.Extensions;
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
internal static class StringExtensions
|
||||
{
|
||||
@@ -38,4 +38,4 @@ internal static class StringExtensions
|
||||
{
|
||||
return fullTypeName.Split('.').LastOrDefault() ?? fullTypeName;
|
||||
}
|
||||
}
|
||||
}
|
||||
+74
-84
@@ -1,84 +1,74 @@
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
|
||||
namespace Speckle.ProxyGenerator.Extensions;
|
||||
|
||||
internal static class SymbolExtensions
|
||||
{
|
||||
private static readonly string[] ExcludedAttributes =
|
||||
[
|
||||
"System.Runtime.CompilerServices.NullableAttribute",
|
||||
"System.Runtime.CompilerServices.NullableContextAttribute",
|
||||
"System.Runtime.CompilerServices.AsyncStateMachineAttribute"
|
||||
];
|
||||
|
||||
public static IReadOnlyList<string> GetAttributesAsList(this ISymbol symbol)
|
||||
{
|
||||
return symbol
|
||||
.GetAttributes()
|
||||
.Where(a =>
|
||||
a.AttributeClass.IsPublic()
|
||||
&& !ExcludedAttributes.Contains(
|
||||
a.AttributeClass?.ToString(),
|
||||
StringComparer.OrdinalIgnoreCase
|
||||
)
|
||||
)
|
||||
.Select(a => $"[{a}]")
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public static string GetAttributesPrefix(this ISymbol symbol)
|
||||
{
|
||||
var attributes = symbol.GetAttributesAsList();
|
||||
|
||||
return attributes.Any() ? $"{string.Join(" ", attributes)} " : string.Empty;
|
||||
}
|
||||
|
||||
//https://stackoverflow.com/questions/27105909/get-fully-qualified-metadata-name-in-roslyn
|
||||
public static string GetFullMetadataName(this ISymbol? s)
|
||||
{
|
||||
if (s == null || IsRootNamespace(s))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var sb = new StringBuilder(s.MetadataName);
|
||||
var last = s;
|
||||
|
||||
s = s.ContainingSymbol;
|
||||
|
||||
while (!IsRootNamespace(s))
|
||||
{
|
||||
if (s is ITypeSymbol && last is ITypeSymbol)
|
||||
{
|
||||
sb.Insert(0, '+');
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Insert(0, '.');
|
||||
}
|
||||
|
||||
sb.Insert(
|
||||
0,
|
||||
s.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)
|
||||
);
|
||||
s = s.ContainingSymbol;
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string GetSanitizedName(this ISymbol symbol) =>
|
||||
symbol.IsKeywordOrReserved() ? $"@{symbol.Name}" : symbol.Name;
|
||||
|
||||
public static bool IsKeywordOrReserved(this ISymbol symbol) =>
|
||||
SyntaxFacts.GetKeywordKind(symbol.Name) != SyntaxKind.None
|
||||
|| SyntaxFacts.GetContextualKeywordKind(symbol.Name) != SyntaxKind.None;
|
||||
|
||||
public static bool IsPublic(this ISymbol? symbol) =>
|
||||
symbol is { DeclaredAccessibility: Accessibility.Public };
|
||||
|
||||
private static bool IsRootNamespace(ISymbol symbol) =>
|
||||
symbol is INamespaceSymbol { IsGlobalNamespace: true };
|
||||
}
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using System.Text;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
internal static class SymbolExtensions
|
||||
{
|
||||
private static readonly string[] ExcludedAttributes =
|
||||
{
|
||||
"System.Runtime.CompilerServices.NullableAttribute",
|
||||
"System.Runtime.CompilerServices.NullableContextAttribute",
|
||||
"System.Runtime.CompilerServices.AsyncStateMachineAttribute"
|
||||
};
|
||||
|
||||
public static IReadOnlyList<string> GetAttributesAsList(this ISymbol symbol)
|
||||
{
|
||||
return symbol
|
||||
.GetAttributes()
|
||||
.Where(a => a.AttributeClass.IsPublic() && !ExcludedAttributes.Contains(a.AttributeClass?.ToString(), StringComparer.OrdinalIgnoreCase))
|
||||
.Select(a => $"[{a}]")
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public static string GetAttributesPrefix(this ISymbol symbol)
|
||||
{
|
||||
var attributes = symbol.GetAttributesAsList();
|
||||
|
||||
return attributes.Any() ? $"{string.Join(" ", attributes)} " : string.Empty;
|
||||
}
|
||||
|
||||
//https://stackoverflow.com/questions/27105909/get-fully-qualified-metadata-name-in-roslyn
|
||||
public static string GetFullMetadataName(this ISymbol? s)
|
||||
{
|
||||
if (s == null || IsRootNamespace(s))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var sb = new StringBuilder(s.MetadataName);
|
||||
var last = s;
|
||||
|
||||
s = s.ContainingSymbol;
|
||||
|
||||
while (!IsRootNamespace(s))
|
||||
{
|
||||
if (s is ITypeSymbol && last is ITypeSymbol)
|
||||
{
|
||||
sb.Insert(0, '+');
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Insert(0, '.');
|
||||
}
|
||||
|
||||
sb.Insert(0, s.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat));
|
||||
s = s.ContainingSymbol;
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string GetSanitizedName(this ISymbol symbol) =>
|
||||
symbol.IsKeywordOrReserved() ? $"@{symbol.Name}" : symbol.Name;
|
||||
|
||||
public static bool IsKeywordOrReserved(this ISymbol symbol) =>
|
||||
SyntaxFacts.GetKeywordKind(symbol.Name) != SyntaxKind.None || SyntaxFacts.GetContextualKeywordKind(symbol.Name) != SyntaxKind.None;
|
||||
|
||||
public static bool IsPublic(this ISymbol? symbol) =>
|
||||
symbol is { DeclaredAccessibility: Accessibility.Public };
|
||||
|
||||
private static bool IsRootNamespace(ISymbol symbol) =>
|
||||
symbol is INamespaceSymbol { IsGlobalNamespace: true };
|
||||
}
|
||||
+7
-13
@@ -1,17 +1,13 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Speckle.ProxyGenerator.Extensions;
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
internal static class SyntaxNodeExtensions
|
||||
{
|
||||
// https://stackoverflow.com/questions/20458457/getting-class-fullname-including-namespace-from-roslyn-classdeclarationsyntax
|
||||
public static bool TryGetParentSyntax<T>(
|
||||
this SyntaxNode? syntaxNode,
|
||||
[NotNullWhen(true)] out T? result
|
||||
)
|
||||
where T : SyntaxNode
|
||||
public static bool TryGetParentSyntax<T>(this SyntaxNode? syntaxNode, [NotNullWhen(true)] out T? result) where T : SyntaxNode
|
||||
{
|
||||
result = null;
|
||||
|
||||
@@ -61,11 +57,9 @@ internal static class SyntaxNodeExtensions
|
||||
|
||||
// Keep moving "out" of nested classes etc until we get to a namespace
|
||||
// or until we run out of parents
|
||||
while (
|
||||
potentialNamespaceParent != null
|
||||
&& potentialNamespaceParent is not NamespaceDeclarationSyntax
|
||||
&& potentialNamespaceParent is not FileScopedNamespaceDeclarationSyntax
|
||||
)
|
||||
while (potentialNamespaceParent != null &&
|
||||
potentialNamespaceParent is not NamespaceDeclarationSyntax
|
||||
&& potentialNamespaceParent is not FileScopedNamespaceDeclarationSyntax)
|
||||
{
|
||||
potentialNamespaceParent = potentialNamespaceParent.Parent;
|
||||
}
|
||||
@@ -94,4 +88,4 @@ internal static class SyntaxNodeExtensions
|
||||
// return the final namespace
|
||||
return nameSpace;
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
-29
@@ -1,29 +1,28 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Speckle.ProxyGenerator.Enums;
|
||||
|
||||
namespace Speckle.ProxyGenerator.Extensions;
|
||||
|
||||
internal static class TypeSymbolExtensions
|
||||
{
|
||||
public static TypeEnum GetTypeEnum(this ITypeSymbol ts)
|
||||
{
|
||||
if (ts.IsValueType || ts.IsString())
|
||||
{
|
||||
return TypeEnum.ValueTypeOrString;
|
||||
}
|
||||
|
||||
if (ts.TypeKind == TypeKind.Interface)
|
||||
{
|
||||
return TypeEnum.Interface;
|
||||
}
|
||||
|
||||
return TypeEnum.Complex;
|
||||
}
|
||||
|
||||
public static bool IsString(this ITypeSymbol ts) =>
|
||||
ts.ToString().ToLowerInvariant() == "string"
|
||||
|| ts.ToString().ToLowerInvariant() == "string?";
|
||||
|
||||
public static string ToFullyQualifiedDisplayString(this ITypeSymbol property) =>
|
||||
property.ToDisplayString(NullableFlowState.None, SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
}
|
||||
using Microsoft.CodeAnalysis;
|
||||
using ProxyInterfaceSourceGenerator.Enums;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
internal static class TypeSymbolExtensions
|
||||
{
|
||||
public static TypeEnum GetTypeEnum(this ITypeSymbol ts)
|
||||
{
|
||||
if (ts.IsValueType || ts.IsString())
|
||||
{
|
||||
return TypeEnum.ValueTypeOrString;
|
||||
}
|
||||
|
||||
if (ts.TypeKind == TypeKind.Interface)
|
||||
{
|
||||
return TypeEnum.Interface;
|
||||
}
|
||||
|
||||
return TypeEnum.Complex;
|
||||
}
|
||||
|
||||
public static bool IsString(this ITypeSymbol ts) =>
|
||||
ts.ToString().ToLowerInvariant() == "string" || ts.ToString().ToLowerInvariant() == "string?";
|
||||
|
||||
public static string ToFullyQualifiedDisplayString(this ITypeSymbol property) =>
|
||||
property.ToDisplayString(NullableFlowState.None, SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
}
|
||||
+262
-348
@@ -1,348 +1,262 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Speckle.ProxyGenerator.Builders;
|
||||
using Speckle.ProxyGenerator.Enums;
|
||||
using Speckle.ProxyGenerator.Extensions;
|
||||
using Speckle.ProxyGenerator.Models;
|
||||
|
||||
namespace Speckle.ProxyGenerator.FileGenerators;
|
||||
|
||||
internal abstract class BaseGenerator
|
||||
{
|
||||
protected const string globalPrefix = "global::";
|
||||
protected readonly Context Context;
|
||||
protected readonly bool SupportsNullable;
|
||||
|
||||
protected BaseGenerator(Context context, bool supportsNullable)
|
||||
{
|
||||
Context = context;
|
||||
SupportsNullable = supportsNullable;
|
||||
}
|
||||
|
||||
protected FixedType GetPropertyType(IPropertySymbol property, out bool isReplaced)
|
||||
{
|
||||
return GetReplacedTypeAsString(property.Type, null, out isReplaced);
|
||||
}
|
||||
|
||||
protected FixedType GetParameterType(IParameterSymbol property, out bool isReplaced)
|
||||
{
|
||||
return GetReplacedTypeAsString(property.Type, property.GetDefaultValue(), out isReplaced);
|
||||
}
|
||||
|
||||
protected bool TryFindProxyDataByTypeName(
|
||||
string type,
|
||||
[NotNullWhen(true)] out ProxyData? proxyData
|
||||
)
|
||||
{
|
||||
proxyData = Context.Candidates.Values.FirstOrDefault(x =>
|
||||
x.FullQualifiedMappedTypeName == type
|
||||
);
|
||||
if (proxyData is not null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
proxyData = Context.Candidates.Values.FirstOrDefault(x => x.FullQualifiedTypeName == type);
|
||||
return proxyData != null;
|
||||
}
|
||||
|
||||
protected string GetWhereStatementFromMethod(IMethodSymbol method)
|
||||
{
|
||||
if (!method.IsGenericMethod)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var list = new List<string>();
|
||||
foreach (var typeParameterSymbol in method.TypeParameters)
|
||||
{
|
||||
if (TryGetWhereConstraints(typeParameterSymbol, false, out var constraint))
|
||||
{
|
||||
list.Add(constraint.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
return string.Concat(list);
|
||||
}
|
||||
|
||||
protected string ResolveInterfaceNameWithOptionalTypeConstraints(
|
||||
INamedTypeSymbol namedTypeSymbol,
|
||||
string interfaceName
|
||||
)
|
||||
{
|
||||
if (!namedTypeSymbol.IsGenericType)
|
||||
{
|
||||
return interfaceName;
|
||||
}
|
||||
|
||||
var str = new StringBuilder(
|
||||
$"{interfaceName}<{string.Join(", ", namedTypeSymbol.TypeArguments.Select(ta => ta.Name))}>"
|
||||
);
|
||||
|
||||
foreach (
|
||||
var typeParameterSymbol in namedTypeSymbol.TypeArguments.OfType<ITypeParameterSymbol>()
|
||||
)
|
||||
{
|
||||
if (TryGetWhereConstraints(typeParameterSymbol, false, out var constraint))
|
||||
{
|
||||
str.Append(constraint);
|
||||
}
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://www.codeproject.com/Articles/871704/Roslyn-Code-Analysis-in-Easy-Samples-Part-2
|
||||
/// </summary>
|
||||
public bool TryGetWhereConstraints(
|
||||
ITypeParameterSymbol typeParameterSymbol,
|
||||
bool replaceIt,
|
||||
[NotNullWhen(true)] out ConstraintInfo? constraint
|
||||
)
|
||||
{
|
||||
var constraints = new List<string>();
|
||||
if (typeParameterSymbol.HasReferenceTypeConstraint)
|
||||
{
|
||||
constraints.Add("class");
|
||||
}
|
||||
|
||||
if (typeParameterSymbol.HasValueTypeConstraint)
|
||||
{
|
||||
constraints.Add("struct");
|
||||
}
|
||||
|
||||
foreach (
|
||||
var namedTypeSymbol in typeParameterSymbol.ConstraintTypes.OfType<INamedTypeSymbol>()
|
||||
)
|
||||
{
|
||||
if (replaceIt)
|
||||
{
|
||||
var (_, type) = GetReplacedTypeAsString(namedTypeSymbol, null, out _);
|
||||
constraints.Add(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
constraints.Add(namedTypeSymbol.GetFullType());
|
||||
}
|
||||
}
|
||||
|
||||
// The new() constraint must be the last constraint specified.
|
||||
if (typeParameterSymbol.HasConstructorConstraint)
|
||||
{
|
||||
constraints.Add("new()");
|
||||
}
|
||||
|
||||
if (constraints.Count > 0)
|
||||
{
|
||||
constraint = new(typeParameterSymbol.Name, constraints);
|
||||
return true;
|
||||
}
|
||||
|
||||
constraint = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
internal readonly SymbolDisplayFormat NullableDisplayFormat = new SymbolDisplayFormat(
|
||||
globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included,
|
||||
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
|
||||
genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
|
||||
miscellaneousOptions: SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers
|
||||
| SymbolDisplayMiscellaneousOptions.UseSpecialTypes
|
||||
| SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier
|
||||
);
|
||||
|
||||
protected FixedType GetReplacedTypeAsString(
|
||||
ITypeSymbol typeSymbol,
|
||||
string? defaultValue,
|
||||
out bool isReplaced
|
||||
)
|
||||
{
|
||||
isReplaced = false;
|
||||
|
||||
var typeSymbolAsString = typeSymbol.ToFullyQualifiedDisplayString();
|
||||
var nullableTypeSymbolAsString = typeSymbol.ToDisplayString(
|
||||
NullableFlowState.None,
|
||||
NullableDisplayFormat
|
||||
);
|
||||
|
||||
if (TryFindProxyDataByTypeName(typeSymbolAsString, out var existing))
|
||||
{
|
||||
if (!Context.ReplacedTypes.ContainsKey(typeSymbolAsString))
|
||||
{
|
||||
Context.ReplacedTypes.Add(typeSymbolAsString, existing.FullInterfaceName);
|
||||
}
|
||||
|
||||
isReplaced = true;
|
||||
return FixType(existing.FullInterfaceName, typeSymbol.NullableAnnotation, defaultValue);
|
||||
}
|
||||
|
||||
ITypeSymbol[] typeArguments;
|
||||
if (typeSymbol is INamedTypeSymbol namedTypedSymbol1)
|
||||
{
|
||||
typeArguments = namedTypedSymbol1.TypeArguments.ToArray();
|
||||
}
|
||||
else if (typeSymbol is IArrayTypeSymbol arrayTypeSymbol)
|
||||
{
|
||||
typeArguments = [arrayTypeSymbol.ElementType];
|
||||
}
|
||||
else
|
||||
{
|
||||
return FixType(typeSymbolAsString, typeSymbol.NullableAnnotation, defaultValue);
|
||||
}
|
||||
|
||||
var propertyTypeAsStringToBeModified = nullableTypeSymbolAsString;
|
||||
foreach (var typeArgument in typeArguments)
|
||||
{
|
||||
var typeArgumentAsString = typeArgument.ToFullyQualifiedDisplayString();
|
||||
|
||||
if (TryFindProxyDataByTypeName(typeArgumentAsString, out var existingTypeArgument))
|
||||
{
|
||||
isReplaced = true;
|
||||
|
||||
if (!Context.ReplacedTypes.ContainsKey(typeArgumentAsString))
|
||||
{
|
||||
Context.ReplacedTypes.Add(
|
||||
typeArgumentAsString,
|
||||
existingTypeArgument.FullInterfaceName
|
||||
);
|
||||
}
|
||||
|
||||
propertyTypeAsStringToBeModified = propertyTypeAsStringToBeModified.Replace(
|
||||
typeArgumentAsString,
|
||||
existingTypeArgument.FullInterfaceName
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return FixType(
|
||||
propertyTypeAsStringToBeModified,
|
||||
typeSymbol.NullableAnnotation,
|
||||
defaultValue
|
||||
);
|
||||
}
|
||||
|
||||
protected bool TryGetNamedTypeSymbolByFullName(
|
||||
TypeKind[] kind,
|
||||
string name,
|
||||
IEnumerable<string> usings,
|
||||
[NotNullWhen(true)] out ClassSymbol? classSymbol
|
||||
)
|
||||
{
|
||||
classSymbol = default;
|
||||
if (name.StartsWith(globalPrefix, StringComparison.Ordinal))
|
||||
{
|
||||
name = name.Substring(globalPrefix.Length);
|
||||
}
|
||||
|
||||
// The GetTypeByMetadataName method returns null if no type matches the full name or if 2 or more types (in different assemblies) match the full name.
|
||||
var symbol = Context.GeneratorExecutionContext.Compilation.GetTypeByMetadataName(name);
|
||||
|
||||
if (symbol is not null && kind.Contains(symbol.TypeKind))
|
||||
{
|
||||
classSymbol = new ClassSymbol(
|
||||
symbol,
|
||||
symbol.GetBaseTypes(),
|
||||
symbol.AllInterfaces.ToList()
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (var @using in usings)
|
||||
{
|
||||
symbol = Context.GeneratorExecutionContext.Compilation.GetTypeByMetadataName(
|
||||
$"{@using}.{name}"
|
||||
);
|
||||
if (symbol is not null && kind.Contains(symbol.TypeKind))
|
||||
{
|
||||
classSymbol = new ClassSymbol(
|
||||
symbol,
|
||||
symbol.GetBaseTypes(),
|
||||
symbol.AllInterfaces.ToList()
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected IReadOnlyList<string> GetMethodParameters(
|
||||
ImmutableArray<IParameterSymbol> parameterSymbols,
|
||||
bool includeType
|
||||
)
|
||||
{
|
||||
var methodParameters = new List<string>();
|
||||
foreach (var parameterSymbol in parameterSymbols)
|
||||
{
|
||||
string? type = null;
|
||||
if (includeType)
|
||||
{
|
||||
if (parameterSymbol.GetTypeEnum() == TypeEnum.Complex)
|
||||
{
|
||||
(_, type) = GetParameterType(parameterSymbol, out _);
|
||||
}
|
||||
else
|
||||
{
|
||||
(_, type) = FixType(
|
||||
parameterSymbol.Type.ToFullyQualifiedDisplayString(),
|
||||
parameterSymbol.NullableAnnotation,
|
||||
parameterSymbol.GetDefaultValue()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
methodParameters.Add(MethodParameterBuilder.Build(parameterSymbol, type));
|
||||
}
|
||||
|
||||
return methodParameters;
|
||||
}
|
||||
|
||||
protected IReadOnlyList<ProxyData> GetExtendsProxyData(
|
||||
ClassSymbol targetClassSymbol,
|
||||
bool useFullQualifiedMappedTypeName
|
||||
)
|
||||
{
|
||||
var extendsProxyClasses = new List<ProxyData>();
|
||||
foreach (var baseType in targetClassSymbol.BaseTypes)
|
||||
{
|
||||
var candidate = Context.Candidates.Values.FirstOrDefault(ci =>
|
||||
ci.FullQualifiedTypeName == baseType.ToFullyQualifiedDisplayString()
|
||||
);
|
||||
if (useFullQualifiedMappedTypeName)
|
||||
{
|
||||
//is a candidate and overrides
|
||||
}
|
||||
else
|
||||
{
|
||||
if (candidate != null)
|
||||
{
|
||||
extendsProxyClasses.Add(candidate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return extendsProxyClasses;
|
||||
}
|
||||
|
||||
internal FixedType FixType(
|
||||
string type,
|
||||
NullableAnnotation nullableAnnotation,
|
||||
string? defaultValue
|
||||
)
|
||||
{
|
||||
var na = nullableAnnotation;
|
||||
if (SupportsNullable && defaultValue == " = null")
|
||||
{
|
||||
na = NullableAnnotation.Annotated;
|
||||
}
|
||||
if (na == NullableAnnotation.Annotated && !type.EndsWith("?", StringComparison.Ordinal))
|
||||
{
|
||||
return new(true, $"{type}?");
|
||||
}
|
||||
return new(false, type);
|
||||
}
|
||||
}
|
||||
|
||||
internal record FixedType(bool Fixed, string Type);
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using ProxyInterfaceSourceGenerator.Builders;
|
||||
using ProxyInterfaceSourceGenerator.Enums;
|
||||
using ProxyInterfaceSourceGenerator.Extensions;
|
||||
using ProxyInterfaceSourceGenerator.Models;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators;
|
||||
|
||||
internal abstract class BaseGenerator
|
||||
{
|
||||
protected readonly Context Context;
|
||||
protected readonly bool SupportsNullable;
|
||||
|
||||
protected BaseGenerator(Context context, bool supportsNullable)
|
||||
{
|
||||
Context = context;
|
||||
SupportsNullable = supportsNullable;
|
||||
}
|
||||
|
||||
protected string GetPropertyType(IPropertySymbol property, out bool isReplaced)
|
||||
{
|
||||
return GetReplacedTypeAsString(property.Type, out isReplaced);
|
||||
}
|
||||
|
||||
protected string GetParameterType(IParameterSymbol property, out bool isReplaced)
|
||||
{
|
||||
return GetReplacedTypeAsString(property.Type, out isReplaced);
|
||||
}
|
||||
|
||||
protected bool TryFindProxyDataByTypeName(string type, [NotNullWhen(true)] out ProxyData? proxyData)
|
||||
{
|
||||
proxyData = Context.Candidates.Values.FirstOrDefault(x => x.FullQualifiedTypeName == type);
|
||||
return proxyData != null;
|
||||
}
|
||||
|
||||
protected string GetWhereStatementFromMethod(IMethodSymbol method)
|
||||
{
|
||||
if (!method.IsGenericMethod)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var list = new List<string>();
|
||||
foreach (var typeParameterSymbol in method.TypeParameters)
|
||||
{
|
||||
if (TryGetWhereConstraints(typeParameterSymbol, false, out var constraint))
|
||||
{
|
||||
list.Add(constraint.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
return string.Concat(list);
|
||||
}
|
||||
|
||||
protected string ResolveInterfaceNameWithOptionalTypeConstraints(INamedTypeSymbol namedTypeSymbol, string interfaceName)
|
||||
{
|
||||
if (!namedTypeSymbol.IsGenericType)
|
||||
{
|
||||
return interfaceName;
|
||||
}
|
||||
|
||||
var str = new StringBuilder($"{interfaceName}<{string.Join(", ", namedTypeSymbol.TypeArguments.Select(ta => ta.Name))}>");
|
||||
|
||||
foreach (var typeParameterSymbol in namedTypeSymbol.TypeArguments.OfType<ITypeParameterSymbol>())
|
||||
{
|
||||
if (TryGetWhereConstraints(typeParameterSymbol, false, out var constraint))
|
||||
{
|
||||
str.Append(constraint);
|
||||
}
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://www.codeproject.com/Articles/871704/Roslyn-Code-Analysis-in-Easy-Samples-Part-2
|
||||
/// </summary>
|
||||
public bool TryGetWhereConstraints(ITypeParameterSymbol typeParameterSymbol, bool replaceIt, [NotNullWhen(true)] out ConstraintInfo? constraint)
|
||||
{
|
||||
var constraints = new List<string>();
|
||||
if (typeParameterSymbol.HasReferenceTypeConstraint)
|
||||
{
|
||||
constraints.Add("class");
|
||||
}
|
||||
|
||||
if (typeParameterSymbol.HasValueTypeConstraint)
|
||||
{
|
||||
constraints.Add("struct");
|
||||
}
|
||||
|
||||
foreach (var namedTypeSymbol in typeParameterSymbol.ConstraintTypes.OfType<INamedTypeSymbol>())
|
||||
{
|
||||
if (replaceIt)
|
||||
{
|
||||
constraints.Add(GetReplacedTypeAsString(namedTypeSymbol, out _));
|
||||
}
|
||||
else
|
||||
{
|
||||
constraints.Add(namedTypeSymbol.GetFullType());
|
||||
}
|
||||
}
|
||||
|
||||
// The new() constraint must be the last constraint specified.
|
||||
if (typeParameterSymbol.HasConstructorConstraint)
|
||||
{
|
||||
constraints.Add("new()");
|
||||
}
|
||||
|
||||
if (constraints.Count > 0)
|
||||
{
|
||||
constraint = new(typeParameterSymbol.Name, constraints);
|
||||
return true;
|
||||
}
|
||||
|
||||
constraint = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
internal readonly SymbolDisplayFormat NullableDisplayFormat = new SymbolDisplayFormat(
|
||||
globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included,
|
||||
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
|
||||
genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
|
||||
miscellaneousOptions:
|
||||
SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers |
|
||||
SymbolDisplayMiscellaneousOptions.UseSpecialTypes |
|
||||
SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier);
|
||||
|
||||
protected string GetReplacedTypeAsString(ITypeSymbol typeSymbol, out bool isReplaced)
|
||||
{
|
||||
isReplaced = false;
|
||||
|
||||
var typeSymbolAsString = typeSymbol.ToFullyQualifiedDisplayString();
|
||||
var nullableTypeSymbolAsString = typeSymbol.ToDisplayString(NullableFlowState.None, NullableDisplayFormat);
|
||||
|
||||
if (TryFindProxyDataByTypeName(typeSymbolAsString, out var existing))
|
||||
{
|
||||
if (!Context.ReplacedTypes.ContainsKey(typeSymbolAsString))
|
||||
{
|
||||
Context.ReplacedTypes.Add(typeSymbolAsString, existing.FullInterfaceName);
|
||||
}
|
||||
|
||||
isReplaced = true;
|
||||
return FixType(existing.FullInterfaceName, typeSymbol.NullableAnnotation);
|
||||
}
|
||||
|
||||
ITypeSymbol[] typeArguments;
|
||||
if (typeSymbol is INamedTypeSymbol namedTypedSymbol1)
|
||||
{
|
||||
typeArguments = namedTypedSymbol1.TypeArguments.ToArray();
|
||||
}
|
||||
else if (typeSymbol is IArrayTypeSymbol arrayTypeSymbol)
|
||||
{
|
||||
typeArguments = new[] { arrayTypeSymbol.ElementType };
|
||||
}
|
||||
else
|
||||
{
|
||||
return FixType(typeSymbolAsString, typeSymbol.NullableAnnotation);
|
||||
}
|
||||
|
||||
var propertyTypeAsStringToBeModified = nullableTypeSymbolAsString;
|
||||
foreach (var typeArgument in typeArguments)
|
||||
{
|
||||
var typeArgumentAsString = typeArgument.ToFullyQualifiedDisplayString();
|
||||
|
||||
if (TryFindProxyDataByTypeName(typeArgumentAsString, out var existingTypeArgument))
|
||||
{
|
||||
isReplaced = true;
|
||||
|
||||
if (!Context.ReplacedTypes.ContainsKey(typeArgumentAsString))
|
||||
{
|
||||
Context.ReplacedTypes.Add(typeArgumentAsString, existingTypeArgument.FullInterfaceName);
|
||||
}
|
||||
|
||||
propertyTypeAsStringToBeModified = propertyTypeAsStringToBeModified.Replace(typeArgumentAsString, existingTypeArgument.FullInterfaceName);
|
||||
}
|
||||
}
|
||||
|
||||
return FixType(propertyTypeAsStringToBeModified, typeSymbol.NullableAnnotation);
|
||||
}
|
||||
|
||||
protected bool TryGetNamedTypeSymbolByFullName(TypeKind kind, string name, IEnumerable<string> usings, [NotNullWhen(true)] out ClassSymbol? classSymbol)
|
||||
{
|
||||
classSymbol = default;
|
||||
const string globalPrefix = "global::";
|
||||
if (name.StartsWith(globalPrefix, StringComparison.Ordinal))
|
||||
{
|
||||
name = name.Substring(globalPrefix.Length);
|
||||
}
|
||||
|
||||
// The GetTypeByMetadataName method returns null if no type matches the full name or if 2 or more types (in different assemblies) match the full name.
|
||||
var symbol = Context.GeneratorExecutionContext.Compilation.GetTypeByMetadataName(name);
|
||||
|
||||
if (symbol is not null && symbol.TypeKind == kind)
|
||||
{
|
||||
classSymbol = new ClassSymbol(symbol, symbol.GetBaseTypes(), symbol.AllInterfaces.ToList());
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (var @using in usings)
|
||||
{
|
||||
symbol = Context.GeneratorExecutionContext.Compilation.GetTypeByMetadataName($"{@using}.{name}");
|
||||
if (symbol is not null && symbol.TypeKind == kind)
|
||||
{
|
||||
classSymbol = new ClassSymbol(symbol, symbol.GetBaseTypes(), symbol.AllInterfaces.ToList());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected IReadOnlyList<string> GetMethodParameters(ImmutableArray<IParameterSymbol> parameterSymbols, bool includeType)
|
||||
{
|
||||
var methodParameters = new List<string>();
|
||||
foreach (var parameterSymbol in parameterSymbols)
|
||||
{
|
||||
string? type = null;
|
||||
if (includeType)
|
||||
{
|
||||
if (parameterSymbol.GetTypeEnum() == TypeEnum.Complex)
|
||||
{
|
||||
type = GetParameterType(parameterSymbol, out _);
|
||||
}
|
||||
else
|
||||
{
|
||||
type = FixType(parameterSymbol.Type.ToFullyQualifiedDisplayString(), parameterSymbol.NullableAnnotation);
|
||||
}
|
||||
}
|
||||
|
||||
methodParameters.Add(MethodParameterBuilder.Build(parameterSymbol, type));
|
||||
}
|
||||
|
||||
return methodParameters;
|
||||
}
|
||||
|
||||
protected IReadOnlyList<ProxyData> GetExtendsProxyData(ProxyData proxyData, ClassSymbol targetClassSymbol)
|
||||
{
|
||||
var extendsProxyClasses = new List<ProxyData>();
|
||||
foreach (var baseType in targetClassSymbol.BaseTypes)
|
||||
{
|
||||
var candidate = Context.Candidates.Values.FirstOrDefault(ci => ci.FullQualifiedTypeName == baseType.ToFullyQualifiedDisplayString());
|
||||
if (candidate is not null)
|
||||
{
|
||||
extendsProxyClasses.Add(candidate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return extendsProxyClasses;
|
||||
}
|
||||
|
||||
internal static string FixType(string type, NullableAnnotation nullableAnnotation)
|
||||
{
|
||||
if (nullableAnnotation == NullableAnnotation.Annotated && !type.EndsWith("?", StringComparison.Ordinal))
|
||||
{
|
||||
return $"{type}?";
|
||||
}
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using ProxyInterfaceSourceGenerator.Models;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators;
|
||||
|
||||
internal class ExtraFilesGenerator : IFileGenerator
|
||||
{
|
||||
private const string Name = "ProxyInterfaceGenerator.Extra.g.cs";
|
||||
|
||||
public FileData GenerateFile()
|
||||
{
|
||||
return new FileData($"{Name}", $@"//----------------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
|
||||
namespace ProxyInterfaceGenerator
|
||||
{{
|
||||
[AttributeUsage(AttributeTargets.Interface)]
|
||||
internal sealed class ProxyAttribute : Attribute
|
||||
{{
|
||||
public Type Type {{ get; }}
|
||||
public bool ProxyBaseClasses {{ get; }}
|
||||
public ProxyClassAccessibility Accessibility {{ get; }}
|
||||
public string[]? MembersToIgnore {{ get; }}
|
||||
|
||||
public ProxyAttribute(Type type) : this(type, false, ProxyClassAccessibility.Public)
|
||||
{{
|
||||
}}
|
||||
|
||||
public ProxyAttribute(Type type, bool proxyBaseClasses) : this(type, proxyBaseClasses, ProxyClassAccessibility.Public)
|
||||
{{
|
||||
}}
|
||||
|
||||
public ProxyAttribute(Type type, ProxyClassAccessibility accessibility) : this(type, false, accessibility)
|
||||
{{
|
||||
}}
|
||||
|
||||
public ProxyAttribute(Type type, bool proxyBaseClasses, ProxyClassAccessibility accessibility) : this(type, proxyBaseClasses, accessibility, null)
|
||||
{{
|
||||
}}
|
||||
|
||||
public ProxyAttribute(Type type, string[]? membersToIgnore) : this(type, false, ProxyClassAccessibility.Public, null)
|
||||
{{
|
||||
}}
|
||||
|
||||
public ProxyAttribute(Type type, bool proxyBaseClasses, ProxyClassAccessibility accessibility, string[]? membersToIgnore)
|
||||
{{
|
||||
Type = type;
|
||||
ProxyBaseClasses = proxyBaseClasses;
|
||||
Accessibility = accessibility;
|
||||
MembersToIgnore = membersToIgnore;
|
||||
}}
|
||||
}}
|
||||
|
||||
[Flags]
|
||||
internal enum ProxyClassAccessibility
|
||||
{{
|
||||
Public = 0,
|
||||
|
||||
Internal = 1
|
||||
}}
|
||||
}}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using ProxyInterfaceSourceGenerator.Models;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators;
|
||||
|
||||
internal interface IFileGenerator
|
||||
{
|
||||
FileData GenerateFile();
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using ProxyInterfaceSourceGenerator.Models;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators;
|
||||
|
||||
internal interface IFilesGenerator
|
||||
{
|
||||
IEnumerable<FileData> GenerateFiles();
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using ProxyInterfaceSourceGenerator.Enums;
|
||||
using ProxyInterfaceSourceGenerator.Extensions;
|
||||
using ProxyInterfaceSourceGenerator.Models;
|
||||
using ProxyInterfaceSourceGenerator.Utils;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators;
|
||||
|
||||
internal class PartialInterfacesGenerator : BaseGenerator, IFilesGenerator
|
||||
{
|
||||
private IReadOnlyCollection<INamedTypeSymbol> _implementedInterfaces = new List<INamedTypeSymbol>();
|
||||
|
||||
public PartialInterfacesGenerator(Context context, bool supportsNullable) : base(context, supportsNullable)
|
||||
{
|
||||
}
|
||||
|
||||
public IEnumerable<FileData> GenerateFiles()
|
||||
{
|
||||
foreach (var ci in Context.Candidates)
|
||||
{
|
||||
if (TryGenerateFile(ci.Key, ci.Value, out var file))
|
||||
{
|
||||
yield return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGenerateFile(InterfaceDeclarationSyntax ci, ProxyData pd, [NotNullWhen(true)] out FileData? fileData)
|
||||
{
|
||||
fileData = default;
|
||||
|
||||
if (!TryGetNamedTypeSymbolByFullName(TypeKind.Interface, ci.Identifier.ToString(), pd.Usings, out var sourceInterfaceSymbol))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TryGetNamedTypeSymbolByFullName(TypeKind.Class, pd.FullMetadataTypeName, pd.Usings, out var targetClassSymbol))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var interfaceName = ResolveInterfaceNameWithOptionalTypeConstraints(targetClassSymbol.Symbol, pd.ShortInterfaceName);
|
||||
|
||||
fileData = new FileData(
|
||||
$"{sourceInterfaceSymbol.Symbol.GetFullMetadataName()}.g.cs",
|
||||
CreatePartialInterfaceCode(pd.Namespace, targetClassSymbol, interfaceName, pd)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private string CreatePartialInterfaceCode(
|
||||
string ns,
|
||||
ClassSymbol classSymbol,
|
||||
string interfaceName,
|
||||
ProxyData proxyData)
|
||||
{
|
||||
var extendsProxyClasses = GetExtendsProxyData(proxyData, classSymbol);
|
||||
_implementedInterfaces = classSymbol.Symbol.ResolveImplementedInterfaces(proxyData.ProxyBaseClasses);
|
||||
var implementedInterfacesNames = _implementedInterfaces.Select(i => i.ToFullyQualifiedDisplayString()).ToArray();
|
||||
var implements = implementedInterfacesNames.Any() ? $" : {string.Join(", ", implementedInterfacesNames)}" : string.Empty;
|
||||
var @new = extendsProxyClasses.Any() ? "new " : string.Empty;
|
||||
var (namespaceStart, namespaceEnd) = NamespaceBuilder.Build(ns);
|
||||
var events = GenerateEvents(classSymbol, proxyData);
|
||||
var properties = GenerateProperties(classSymbol, proxyData);
|
||||
var methods = GenerateMethods(classSymbol, proxyData).TrimEnd();
|
||||
|
||||
return $@"//----------------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
{SupportsNullable.IIf("#nullable enable")}
|
||||
using System;
|
||||
|
||||
{namespaceStart}
|
||||
public partial interface {interfaceName}{implements}
|
||||
{{
|
||||
{@new}{classSymbol} _Instance {{ get; }}
|
||||
|
||||
{events +
|
||||
properties +
|
||||
methods}
|
||||
}}
|
||||
{namespaceEnd}
|
||||
{SupportsNullable.IIf("#nullable restore")}";
|
||||
}
|
||||
|
||||
private Func<T, bool> InterfaceFilter<T>() where T : ISymbol
|
||||
{
|
||||
var hashSet = new HashSet<string>();
|
||||
foreach (var @interface in _implementedInterfaces)
|
||||
{
|
||||
var members = @interface.AllInterfaces.Aggregate(@interface.GetMembers(), (xs, x) => xs.AddRange(x.GetMembers()));
|
||||
foreach (var member in members)
|
||||
{
|
||||
hashSet.Add(member.Name);
|
||||
}
|
||||
}
|
||||
|
||||
// Member is not already implemented in another interface.
|
||||
return t => !hashSet.Contains(t.Name);
|
||||
}
|
||||
|
||||
private string GenerateProperties(ClassSymbol targetClassSymbol, ProxyData proxyData)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
|
||||
foreach (var property in MemberHelper.GetPublicProperties(targetClassSymbol, proxyData, InterfaceFilter<IPropertySymbol>()))
|
||||
{
|
||||
var type = GetPropertyType(property, out var isReplaced);
|
||||
|
||||
var getterSetter = isReplaced ? property.ToPropertyDetails(type) : property.ToPropertyDetails();
|
||||
if (getterSetter is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var propertyName = getterSetter.Value.PropertyName;
|
||||
|
||||
if (property.IsIndexer)
|
||||
{
|
||||
var methodParameters = GetMethodParameters(property.Parameters, true);
|
||||
propertyName = $"this[{string.Join(", ", methodParameters)}]";
|
||||
}
|
||||
|
||||
foreach (var attribute in property.GetAttributesAsList())
|
||||
{
|
||||
str.AppendLine($" {attribute}");
|
||||
}
|
||||
|
||||
str.AppendLine($" {getterSetter.Value.PropertyType} {propertyName} {getterSetter.Value.GetSet}");
|
||||
str.AppendLine();
|
||||
}
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
private string GenerateMethods(ClassSymbol targetClassSymbol, ProxyData proxyData)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
foreach (var method in MemberHelper.GetPublicMethods(targetClassSymbol, proxyData, InterfaceFilter<IMethodSymbol>()))
|
||||
{
|
||||
var methodParameters = GetMethodParameters(method.Parameters, true);
|
||||
var whereStatement = GetWhereStatementFromMethod(method);
|
||||
|
||||
foreach (var attribute in method.GetAttributesAsList())
|
||||
{
|
||||
str.AppendLine($" {attribute}");
|
||||
}
|
||||
|
||||
str.AppendLine($" {GetReplacedTypeAsString(method.ReturnType, out _)} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){whereStatement};");
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
private string GenerateEvents(ClassSymbol targetClassSymbol, ProxyData proxyData)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
foreach (var @event in MemberHelper.GetPublicEvents(targetClassSymbol, proxyData, InterfaceFilter<IMethodSymbol>()))
|
||||
{
|
||||
var ps = @event.First().Parameters.First();
|
||||
var type = ps.GetTypeEnum() == TypeEnum.Complex ? GetParameterType(ps, out _) : ps.Type.ToString();
|
||||
|
||||
foreach (var attribute in ps.GetAttributesAsList())
|
||||
{
|
||||
str.AppendLine($" {attribute}");
|
||||
}
|
||||
|
||||
str.AppendLine($" event {type} {@event.Key.GetSanitizedName()};");
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Text;
|
||||
using ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators;
|
||||
|
||||
internal partial class ProxyClassesGenerator
|
||||
{
|
||||
private static string GeneratePrivateAutoMapper()
|
||||
{
|
||||
return " private readonly IMapper _mapper;";
|
||||
}
|
||||
|
||||
private string GenerateMapperConfigurationForAutoMapper()
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
|
||||
str.AppendLine(" _mapper = new MapperConfiguration(cfg =>");
|
||||
str.AppendLine(" {");
|
||||
foreach (var replacedType in Context.ReplacedTypes)
|
||||
{
|
||||
TryFindProxyDataByTypeName(replacedType.Key, out var fullTypeName);
|
||||
var classNameProxy = $"{fullTypeName!.NamespaceDot}{fullTypeName.ShortMetadataName}Proxy";
|
||||
|
||||
var instance = $"instance{(replacedType.Key + replacedType.Value).GetDeterministicHashCodeAsString()}";
|
||||
var proxy = $"proxy{(replacedType.Value + replacedType.Key).GetDeterministicHashCodeAsString()}";
|
||||
|
||||
str.AppendLine($" cfg.CreateMap<{replacedType.Key}, {replacedType.Value}>().ConstructUsing({instance} => new {classNameProxy}({instance}));");
|
||||
str.AppendLine($" cfg.CreateMap<{replacedType.Value}, {replacedType.Key}>().ConstructUsing({proxy} => (({classNameProxy}) {proxy})._Instance);");
|
||||
str.AppendLine();
|
||||
}
|
||||
str.AppendLine(" }).CreateMapper();");
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System.Text;
|
||||
using ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators;
|
||||
|
||||
internal partial class ProxyClassesGenerator
|
||||
{
|
||||
private string GenerateMapperConfigurationForMapster()
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
|
||||
foreach (var replacedType in Context.ReplacedTypes)
|
||||
{
|
||||
TryFindProxyDataByTypeName(replacedType.Key, out var fullTypeName);
|
||||
var classNameProxy = $"global::{fullTypeName!.NamespaceDot}{fullTypeName!.ShortMetadataName}Proxy";
|
||||
|
||||
var instance = $"instance{(replacedType.Key + replacedType.Value).GetDeterministicHashCodeAsString()}";
|
||||
var proxy = $"proxy{(replacedType.Value + replacedType.Key).GetDeterministicHashCodeAsString()}";
|
||||
|
||||
str.AppendLine($" Mapster.TypeAdapterConfig<{replacedType.Key}, {replacedType.Value}>.NewConfig().ConstructUsing({instance} => new {classNameProxy}({instance}));");
|
||||
str.AppendLine($" Mapster.TypeAdapterConfig<{replacedType.Value}, {replacedType.Key}>.NewConfig().MapWith({proxy} => (({classNameProxy}) {proxy})._Instance);");
|
||||
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
}
|
||||
+383
-498
@@ -1,498 +1,383 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Speckle.ProxyGenerator.Builders;
|
||||
using Speckle.ProxyGenerator.Enums;
|
||||
using Speckle.ProxyGenerator.Extensions;
|
||||
using Speckle.ProxyGenerator.Models;
|
||||
using Speckle.ProxyGenerator.Types;
|
||||
using Speckle.ProxyGenerator.Utils;
|
||||
|
||||
namespace Speckle.ProxyGenerator.FileGenerators;
|
||||
|
||||
internal partial class ProxyClassesGenerator : BaseGenerator, IFilesGenerator
|
||||
{
|
||||
private readonly List<ProxyMapItem> _proxyMapItems;
|
||||
|
||||
public ProxyClassesGenerator(
|
||||
List<ProxyMapItem> proxyMapItems,
|
||||
Context context,
|
||||
bool supportsNullable
|
||||
)
|
||||
: base(context, supportsNullable)
|
||||
{
|
||||
_proxyMapItems = proxyMapItems;
|
||||
}
|
||||
|
||||
public IEnumerable<FileData> GenerateFiles()
|
||||
{
|
||||
foreach (var ci in Context.Candidates)
|
||||
{
|
||||
if (TryGenerateFile(ci.Value, out var file))
|
||||
{
|
||||
yield return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage(
|
||||
"MicrosoftCodeAnalysisCorrectness",
|
||||
"RS1024:Compare symbols correctly",
|
||||
Justification = "<Pending>"
|
||||
)]
|
||||
private bool TryGenerateFile(ProxyData pd, [NotNullWhen(true)] out FileData? fileData)
|
||||
{
|
||||
fileData = default;
|
||||
|
||||
if (
|
||||
!TryGetNamedTypeSymbolByFullName(
|
||||
[TypeKind.Class, TypeKind.Struct],
|
||||
pd.FullMetadataTypeName,
|
||||
pd.Usings,
|
||||
out var targetClassSymbol
|
||||
)
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var interfaceName = ResolveInterfaceNameWithOptionalTypeConstraints(
|
||||
targetClassSymbol.Symbol,
|
||||
pd.FullInterfaceName
|
||||
);
|
||||
var className = targetClassSymbol.Symbol.ResolveProxyClassName();
|
||||
var constructorName = $"{targetClassSymbol.Symbol.Name}Proxy";
|
||||
|
||||
var extendsProxyClasses = GetExtendsProxyData(targetClassSymbol, false);
|
||||
var targetClass = targetClassSymbol.Symbol.GetFullMetadataName();
|
||||
if (!targetClassSymbol.Symbol.IsGenericType)
|
||||
{
|
||||
_proxyMapItems.Add(new(targetClass, interfaceName, $"{pd.NamespaceDot}{className}"));
|
||||
}
|
||||
fileData = new FileData(
|
||||
$"{targetClass}Proxy.g.cs",
|
||||
CreateProxyClassCode(
|
||||
pd,
|
||||
targetClassSymbol,
|
||||
extendsProxyClasses,
|
||||
interfaceName,
|
||||
className,
|
||||
constructorName,
|
||||
targetClassSymbol.Symbol.TypeKind
|
||||
)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private string CreateProxyClassCode(
|
||||
ProxyData pd,
|
||||
ClassSymbol targetClassSymbol,
|
||||
IReadOnlyList<ProxyData> extendsProxyClasses,
|
||||
string interfaceName,
|
||||
string className,
|
||||
string constructorName,
|
||||
TypeKind kind
|
||||
)
|
||||
{
|
||||
var firstExtends = extendsProxyClasses.FirstOrDefault();
|
||||
var extends = string.Empty;
|
||||
var @base = string.Empty;
|
||||
var @new = string.Empty;
|
||||
var instanceBaseDefinition = string.Empty;
|
||||
var instanceBaseSetter = string.Empty;
|
||||
|
||||
if (firstExtends is not null)
|
||||
{
|
||||
extends = $"global::{firstExtends.NamespaceDot}{firstExtends.ShortMetadataName}Proxy, ";
|
||||
@base = " : base(instance)";
|
||||
@new = "new ";
|
||||
instanceBaseDefinition =
|
||||
$"public {firstExtends.FullQualifiedTypeName} _Instance{firstExtends.FullQualifiedTypeName.GetLastPart()} {{ get; }}";
|
||||
instanceBaseSetter =
|
||||
$"_Instance{firstExtends.FullQualifiedTypeName.GetLastPart()} = instance;";
|
||||
}
|
||||
|
||||
var @abstract = string.Empty; // targetClassSymbol.Symbol.IsAbstract ? "abstract " : string.Empty;
|
||||
var properties = GeneratePublicProperties(targetClassSymbol, pd);
|
||||
var methods = GeneratePublicMethods(targetClassSymbol, pd);
|
||||
var events = GenerateEvents(targetClassSymbol, pd);
|
||||
var operators = GenerateOperators(targetClassSymbol, pd);
|
||||
|
||||
var configurationForMapster = string.Empty;
|
||||
if (Context.ReplacedTypes.Count > 0)
|
||||
{
|
||||
configurationForMapster = GenerateMapperConfigurationForMapster().Trim();
|
||||
}
|
||||
|
||||
var staticConstructor = string.Empty;
|
||||
if (!string.IsNullOrWhiteSpace(configurationForMapster))
|
||||
{
|
||||
staticConstructor =
|
||||
$@"
|
||||
static {constructorName}()
|
||||
{{
|
||||
{configurationForMapster}
|
||||
}}
|
||||
";
|
||||
}
|
||||
|
||||
var (namespaceStart, namespaceEnd) = NamespaceBuilder.Build(pd.Namespace);
|
||||
|
||||
var accessibility =
|
||||
pd.Accessibility == ProxyClassAccessibility.Internal ? "internal" : "public";
|
||||
|
||||
var kindString = kind == TypeKind.Class ? "class" : "struct";
|
||||
|
||||
return $@"//----------------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by https://github.com/specklesystems/ProxyGenerator.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
{SupportsNullable.IIf("#nullable enable")}
|
||||
using System;
|
||||
|
||||
{namespaceStart}
|
||||
{accessibility} {@abstract}partial {kindString} {className} : {extends}{interfaceName}
|
||||
{{
|
||||
public {@new}{targetClassSymbol} _Instance {{ get; }}
|
||||
{instanceBaseDefinition}
|
||||
{events +
|
||||
properties +
|
||||
methods +
|
||||
operators}
|
||||
public {constructorName}({targetClassSymbol} instance){@base}
|
||||
{{
|
||||
_Instance = instance;
|
||||
{instanceBaseSetter}
|
||||
}}
|
||||
{staticConstructor}
|
||||
}}
|
||||
{namespaceEnd}
|
||||
{SupportsNullable.IIf("#nullable restore")}";
|
||||
}
|
||||
|
||||
private string GeneratePublicProperties(ClassSymbol targetClassSymbol, ProxyData proxyData)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
|
||||
foreach (var property in MemberHelper.GetPublicProperties(targetClassSymbol, proxyData))
|
||||
{
|
||||
var (_, type) = GetPropertyType(property, out var isReplaced);
|
||||
|
||||
var instance = !property.IsStatic ? "_Instance" : $"{targetClassSymbol.Symbol}";
|
||||
|
||||
var propertyName = property.GetSanitizedName();
|
||||
var instancePropertyName = $"{instance}.{propertyName}";
|
||||
if (property.IsIndexer)
|
||||
{
|
||||
var parameters = GetMethodParameters(property.Parameters, true);
|
||||
propertyName = $"this[{string.Join(", ", parameters)}]";
|
||||
|
||||
var instanceParameters = GetMethodParameters(property.Parameters, false);
|
||||
instancePropertyName = $"{instance}[{string.Join(", ", instanceParameters)}]";
|
||||
}
|
||||
|
||||
var overrideOrVirtual = string.Empty;
|
||||
if (property.IsOverride)
|
||||
{
|
||||
overrideOrVirtual = "override ";
|
||||
}
|
||||
else if (property.IsVirtual)
|
||||
{
|
||||
overrideOrVirtual = "virtual ";
|
||||
}
|
||||
|
||||
var getIsPublic = property.GetMethod.IsPublic();
|
||||
var setIsPublic =
|
||||
property.SetMethod.IsPublic()
|
||||
&& targetClassSymbol.Symbol.TypeKind == TypeKind.Class;
|
||||
|
||||
if (!getIsPublic && !setIsPublic)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string get;
|
||||
string set;
|
||||
if (isReplaced)
|
||||
{
|
||||
get = getIsPublic
|
||||
? $"get => Mapster.TypeAdapter.Adapt<{type}>({instancePropertyName}); "
|
||||
: string.Empty;
|
||||
set = setIsPublic
|
||||
? $"set => {instancePropertyName} = Mapster.TypeAdapter.Adapt<{property.Type}>(value); "
|
||||
: string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
get = getIsPublic ? $"get => {instancePropertyName}; " : string.Empty;
|
||||
set = setIsPublic ? $"set => {instancePropertyName} = value; " : string.Empty;
|
||||
}
|
||||
|
||||
foreach (var attribute in property.GetAttributesAsList())
|
||||
{
|
||||
str.AppendLine($" {attribute}");
|
||||
}
|
||||
|
||||
str.AppendLine(
|
||||
$" public {overrideOrVirtual}{type} {propertyName} {{ {get}{set}}}"
|
||||
);
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
private string GeneratePublicMethods(ClassSymbol targetClassSymbol, ProxyData proxyData)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
|
||||
var methods = MemberHelper.GetPublicMethods(targetClassSymbol, proxyData);
|
||||
|
||||
foreach (var method in methods)
|
||||
{
|
||||
var methodParameters = new List<string>();
|
||||
var invokeParameters = new List<string>();
|
||||
|
||||
foreach (var parameterSymbol in method.Parameters)
|
||||
{
|
||||
var (_, type) = GetParameterType(parameterSymbol, out _);
|
||||
|
||||
methodParameters.Add(MethodParameterBuilder.Build(parameterSymbol, type));
|
||||
|
||||
// Do not add the '_' for a 'ref' parameter.
|
||||
invokeParameters.Add(
|
||||
$"{parameterSymbol.GetRefKindPrefix()}{parameterSymbol.GetSanitizedName()}{(!parameterSymbol.IsRef()).IIf("_")}"
|
||||
);
|
||||
}
|
||||
|
||||
string overrideOrVirtual = string.Empty;
|
||||
if (method.IsOverride && method.OverriddenMethod != null)
|
||||
{
|
||||
var baseType = method.OverriddenMethod.ContainingType.GetFullType();
|
||||
if (TryGetNamedTypeSymbolByFullName([TypeKind.Class], baseType, [], out _))
|
||||
{
|
||||
overrideOrVirtual = "override ";
|
||||
}
|
||||
}
|
||||
else if (method.IsVirtual)
|
||||
{
|
||||
overrideOrVirtual = "virtual ";
|
||||
}
|
||||
|
||||
var (_, returnTypeAsString) = GetReplacedTypeAsString(
|
||||
method.ReturnType,
|
||||
null,
|
||||
out var returnIsReplaced
|
||||
);
|
||||
|
||||
var whereStatement = GetWhereStatementFromMethod(method);
|
||||
|
||||
foreach (var attribute in method.GetAttributesAsList())
|
||||
{
|
||||
str.AppendLine($" {attribute}");
|
||||
}
|
||||
|
||||
str.AppendLine(
|
||||
$" public {overrideOrVirtual}{returnTypeAsString} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){whereStatement}"
|
||||
);
|
||||
str.AppendLine(@" {");
|
||||
|
||||
foreach (var ps in method.Parameters.Where(p => !p.IsRef()))
|
||||
{
|
||||
var (wasFixed, type) = FixType(
|
||||
ps.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
|
||||
ps.Type.NullableAnnotation,
|
||||
ps.GetDefaultValue()
|
||||
);
|
||||
string normalOrMap = $" = {ps.GetSanitizedName()}";
|
||||
if (ps.RefKind == RefKind.Out)
|
||||
{
|
||||
normalOrMap = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = GetParameterType(ps, out var isReplaced); // TODO : response is not used?
|
||||
if (isReplaced)
|
||||
{
|
||||
if (wasFixed)
|
||||
{
|
||||
normalOrMap =
|
||||
$" = Speckle.ProxyGenerator.MapsterAdapter.AdaptNull<{type}>({ps.GetSanitizedName()})";
|
||||
}
|
||||
else
|
||||
{
|
||||
normalOrMap =
|
||||
$" = Mapster.TypeAdapter.Adapt<{type}>({ps.GetSanitizedName()})";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
str.AppendLine($" {type} {ps.GetSanitizedName()}_{normalOrMap};");
|
||||
}
|
||||
|
||||
var methodName = method.GetMethodNameWithOptionalTypeParameters();
|
||||
var alternateReturnVariableName =
|
||||
$"result_{methodName.GetDeterministicHashCodeAsString()}";
|
||||
|
||||
string instance = method.IsStatic
|
||||
? targetClassSymbol.Symbol.ToFullyQualifiedDisplayString()
|
||||
: "_Instance";
|
||||
|
||||
if (returnTypeAsString == "void")
|
||||
{
|
||||
str.AppendLine(
|
||||
$" {instance}.{methodName}({string.Join(", ", invokeParameters)});"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
str.AppendLine(
|
||||
$" var {alternateReturnVariableName} = {instance}.{methodName}({string.Join(", ", invokeParameters)});"
|
||||
);
|
||||
}
|
||||
|
||||
foreach (var ps in method.Parameters.Where(p => p.RefKind == RefKind.Out))
|
||||
{
|
||||
string normalOrMap = $" = {ps.GetSanitizedName()}_";
|
||||
var (_, type) = GetParameterType(ps, out var isReplaced);
|
||||
if (isReplaced)
|
||||
{
|
||||
normalOrMap = $" = Mapster.TypeAdapter.Adapt<{type}>({ps.GetSanitizedName()}_)";
|
||||
}
|
||||
|
||||
str.AppendLine($" {ps.GetSanitizedName()}{normalOrMap};");
|
||||
}
|
||||
|
||||
if (returnTypeAsString != "void")
|
||||
{
|
||||
if (returnIsReplaced)
|
||||
{
|
||||
str.AppendLine(
|
||||
$" return Mapster.TypeAdapter.Adapt<{returnTypeAsString}>({alternateReturnVariableName});"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
str.AppendLine($" return {alternateReturnVariableName};");
|
||||
}
|
||||
}
|
||||
|
||||
str.AppendLine(" }");
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
private string GenerateEvents(ClassSymbol targetClassSymbol, ProxyData proxyData)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
foreach (var @event in MemberHelper.GetPublicEvents(targetClassSymbol, proxyData))
|
||||
{
|
||||
if (@event.Key.IsStatic)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var name = @event.Key.GetSanitizedName();
|
||||
var ps = @event.First().Parameters.First();
|
||||
var type = string.Empty;
|
||||
if (ps.GetTypeEnum() == TypeEnum.Complex)
|
||||
{
|
||||
(_, type) = GetParameterType(ps, out _);
|
||||
}
|
||||
else
|
||||
{
|
||||
type = ps.Type.ToString();
|
||||
}
|
||||
|
||||
foreach (var attribute in ps.GetAttributesAsList())
|
||||
{
|
||||
str.AppendLine($" {attribute}");
|
||||
}
|
||||
|
||||
str.Append($" public event {type} {name} {{");
|
||||
|
||||
if (@event.Any(e => e.MethodKind == MethodKind.EventAdd))
|
||||
{
|
||||
str.Append($" add {{ _Instance.{name} += value; }}");
|
||||
}
|
||||
if (@event.Any(e => e.MethodKind == MethodKind.EventRemove))
|
||||
{
|
||||
str.Append($" remove {{ _Instance.{name} -= value; }}");
|
||||
}
|
||||
|
||||
str.AppendLine(" }");
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
private string GenerateOperators(ClassSymbol targetClassSymbol, ProxyData proxyData)
|
||||
{
|
||||
if (targetClassSymbol.Symbol.TypeKind != TypeKind.Class)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
var str = new StringBuilder();
|
||||
foreach (
|
||||
var @operator in MemberHelper.GetPublicStaticOperators(targetClassSymbol, proxyData)
|
||||
)
|
||||
{
|
||||
foreach (var attribute in @operator.GetAttributesAsList())
|
||||
{
|
||||
str.AppendLine($" {attribute}");
|
||||
}
|
||||
|
||||
if (!@operator.Parameters.Any())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var parameter = @operator.Parameters.First();
|
||||
var proxyClassName = targetClassSymbol.Symbol.ResolveProxyClassName();
|
||||
|
||||
var operatorType = @operator.Name.ToLowerInvariant().Replace("op_", string.Empty);
|
||||
if (operatorType == "explicit")
|
||||
{
|
||||
var (_, returnTypeAsString) = GetReplacedTypeAsString(
|
||||
@operator.ReturnType,
|
||||
null,
|
||||
out _
|
||||
);
|
||||
|
||||
str.AppendLine(
|
||||
$" public static explicit operator {returnTypeAsString}({proxyClassName} {parameter.Name})"
|
||||
);
|
||||
str.AppendLine(@" {");
|
||||
str.AppendLine(
|
||||
$" return ({returnTypeAsString}) {parameter.Name}._Instance;"
|
||||
);
|
||||
str.AppendLine(@" }");
|
||||
}
|
||||
else
|
||||
{
|
||||
var (_, returnTypeAsString) = GetReplacedTypeAsString(parameter.Type, null, out _);
|
||||
|
||||
str.AppendLine(
|
||||
$" public static implicit operator {proxyClassName}({returnTypeAsString} {parameter.Name})"
|
||||
);
|
||||
str.AppendLine(@" {");
|
||||
str.AppendLine(
|
||||
$" return new {proxyClassName}(({targetClassSymbol.Symbol.Name}) {parameter.Name});"
|
||||
);
|
||||
str.AppendLine(@" }");
|
||||
}
|
||||
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
}
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using ProxyInterfaceSourceGenerator.Builders;
|
||||
using ProxyInterfaceSourceGenerator.Enums;
|
||||
using ProxyInterfaceSourceGenerator.Extensions;
|
||||
using ProxyInterfaceSourceGenerator.Models;
|
||||
using ProxyInterfaceSourceGenerator.Types;
|
||||
using ProxyInterfaceSourceGenerator.Utils;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators;
|
||||
|
||||
internal partial class ProxyClassesGenerator : BaseGenerator, IFilesGenerator
|
||||
{
|
||||
public ProxyClassesGenerator(Context context, bool supportsNullable) : base(context, supportsNullable)
|
||||
{
|
||||
}
|
||||
|
||||
public IEnumerable<FileData> GenerateFiles()
|
||||
{
|
||||
foreach (var ci in Context.Candidates)
|
||||
{
|
||||
if (TryGenerateFile(ci.Value, out var file))
|
||||
{
|
||||
yield return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1024:Compare symbols correctly", Justification = "<Pending>")]
|
||||
private bool TryGenerateFile(ProxyData pd, [NotNullWhen(true)] out FileData? fileData)
|
||||
{
|
||||
fileData = default;
|
||||
|
||||
if (!TryGetNamedTypeSymbolByFullName(TypeKind.Class, pd.FullMetadataTypeName, pd.Usings, out var targetClassSymbol))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var interfaceName = ResolveInterfaceNameWithOptionalTypeConstraints(targetClassSymbol.Symbol, pd.FullInterfaceName);
|
||||
var className = targetClassSymbol.Symbol.ResolveProxyClassName();
|
||||
var constructorName = $"{targetClassSymbol.Symbol.Name}Proxy";
|
||||
|
||||
var extendsProxyClasses = GetExtendsProxyData(pd, targetClassSymbol);
|
||||
|
||||
fileData = new FileData(
|
||||
$"{targetClassSymbol.Symbol.GetFullMetadataName()}Proxy.g.cs",
|
||||
CreateProxyClassCode(pd, targetClassSymbol, extendsProxyClasses, interfaceName, className, constructorName)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private string CreateProxyClassCode(
|
||||
ProxyData pd,
|
||||
ClassSymbol targetClassSymbol,
|
||||
IReadOnlyList<ProxyData> extendsProxyClasses,
|
||||
string interfaceName,
|
||||
string className,
|
||||
string constructorName)
|
||||
{
|
||||
var firstExtends = extendsProxyClasses.FirstOrDefault();
|
||||
var extends = string.Empty;
|
||||
var @base = string.Empty;
|
||||
var @new = string.Empty;
|
||||
var instanceBaseDefinition = string.Empty;
|
||||
var instanceBaseSetter = string.Empty;
|
||||
|
||||
if (firstExtends is not null)
|
||||
{
|
||||
extends = $"global::{firstExtends.NamespaceDot}{firstExtends.ShortMetadataName}Proxy, ";
|
||||
@base = " : base(instance)";
|
||||
@new = "new ";
|
||||
instanceBaseDefinition = $"public {firstExtends.FullQualifiedTypeName} _Instance{firstExtends.FullQualifiedTypeName.GetLastPart()} {{ get; }}";
|
||||
instanceBaseSetter = $"_Instance{firstExtends.FullQualifiedTypeName.GetLastPart()} = instance;";
|
||||
}
|
||||
|
||||
var @abstract = string.Empty; // targetClassSymbol.Symbol.IsAbstract ? "abstract " : string.Empty;
|
||||
var properties = GeneratePublicProperties(targetClassSymbol, pd);
|
||||
var methods = GeneratePublicMethods(targetClassSymbol, pd);
|
||||
var events = GenerateEvents(targetClassSymbol, pd);
|
||||
var operators = GenerateOperators(targetClassSymbol, pd);
|
||||
|
||||
var configurationForMapster = string.Empty;
|
||||
if (Context.ReplacedTypes.Count > 0)
|
||||
{
|
||||
configurationForMapster = GenerateMapperConfigurationForMapster();
|
||||
}
|
||||
|
||||
var (namespaceStart, namespaceEnd) = NamespaceBuilder.Build(pd.Namespace);
|
||||
|
||||
var accessibility = pd.Accessibility == ProxyClassAccessibility.Internal ? "internal" : "public";
|
||||
|
||||
return $@"//----------------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
{SupportsNullable.IIf("#nullable enable")}
|
||||
using System;
|
||||
|
||||
{namespaceStart}
|
||||
{accessibility} {@abstract}partial class {className} : {extends}{interfaceName}
|
||||
{{
|
||||
public {@new}{targetClassSymbol} _Instance {{ get; }}
|
||||
{instanceBaseDefinition}
|
||||
{events +
|
||||
properties +
|
||||
methods +
|
||||
operators}
|
||||
public {constructorName}({targetClassSymbol} instance){@base}
|
||||
{{
|
||||
_Instance = instance;
|
||||
{instanceBaseSetter}
|
||||
|
||||
{configurationForMapster}
|
||||
}}
|
||||
}}
|
||||
{namespaceEnd}
|
||||
{SupportsNullable.IIf("#nullable restore")}";
|
||||
}
|
||||
|
||||
private string GeneratePublicProperties(ClassSymbol targetClassSymbol, ProxyData proxyData)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
|
||||
foreach (var property in MemberHelper.GetPublicProperties(targetClassSymbol, proxyData))
|
||||
{
|
||||
var type = GetPropertyType(property, out var isReplaced);
|
||||
|
||||
var instance = !property.IsStatic ?
|
||||
"_Instance" :
|
||||
$"{targetClassSymbol.Symbol}";
|
||||
|
||||
var propertyName = property.GetSanitizedName();
|
||||
var instancePropertyName = $"{instance}.{propertyName}";
|
||||
if (property.IsIndexer)
|
||||
{
|
||||
var parameters = GetMethodParameters(property.Parameters, true);
|
||||
propertyName = $"this[{string.Join(", ", parameters)}]";
|
||||
|
||||
var instanceParameters = GetMethodParameters(property.Parameters, false);
|
||||
instancePropertyName = $"{instance}[{string.Join(", ", instanceParameters)}]";
|
||||
}
|
||||
|
||||
var overrideOrVirtual = string.Empty;
|
||||
if (property.IsOverride)
|
||||
{
|
||||
overrideOrVirtual = "override ";
|
||||
}
|
||||
else if (property.IsVirtual)
|
||||
{
|
||||
overrideOrVirtual = "virtual ";
|
||||
}
|
||||
|
||||
var getIsPublic = property.GetMethod.IsPublic();
|
||||
var setIsPublic = property.SetMethod.IsPublic();
|
||||
|
||||
if (!getIsPublic && !setIsPublic)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string get;
|
||||
string set;
|
||||
if (isReplaced)
|
||||
{
|
||||
get = getIsPublic ? $"get => Mapster.TypeAdapter.Adapt<{type}>({instancePropertyName}); " : string.Empty;
|
||||
set = setIsPublic ? $"set => {instancePropertyName} = Mapster.TypeAdapter.Adapt<{property.Type}>(value); " : string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
get = getIsPublic ? $"get => {instancePropertyName}; " : string.Empty;
|
||||
set = setIsPublic ? $"set => {instancePropertyName} = value; " : string.Empty;
|
||||
}
|
||||
|
||||
foreach (var attribute in property.GetAttributesAsList())
|
||||
{
|
||||
str.AppendLine($" {attribute}");
|
||||
}
|
||||
|
||||
str.AppendLine($" public {overrideOrVirtual}{type} {propertyName} {{ {get}{set}}}");
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
private string GeneratePublicMethods(ClassSymbol targetClassSymbol, ProxyData proxyData)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
|
||||
var methods = MemberHelper.GetPublicMethods(targetClassSymbol, proxyData);
|
||||
|
||||
foreach (var method in methods)
|
||||
{
|
||||
var methodParameters = new List<string>();
|
||||
var invokeParameters = new List<string>();
|
||||
|
||||
foreach (var parameterSymbol in method.Parameters)
|
||||
{
|
||||
var type = GetParameterType(parameterSymbol, out _);
|
||||
|
||||
methodParameters.Add(MethodParameterBuilder.Build(parameterSymbol, type));
|
||||
|
||||
// Do not add the '_' for a 'ref' parameter.
|
||||
invokeParameters.Add($"{parameterSymbol.GetRefKindPrefix()}{parameterSymbol.GetSanitizedName()}{(!parameterSymbol.IsRef()).IIf("_")}");
|
||||
}
|
||||
|
||||
string overrideOrVirtual = string.Empty;
|
||||
if (method.IsOverride && method.OverriddenMethod != null)
|
||||
{
|
||||
var baseType = method.OverriddenMethod.ContainingType.GetFullType();
|
||||
if (TryGetNamedTypeSymbolByFullName(TypeKind.Class, baseType, Enumerable.Empty<string>(), out _))
|
||||
{
|
||||
overrideOrVirtual = "override ";
|
||||
}
|
||||
}
|
||||
else if (method.IsVirtual)
|
||||
{
|
||||
overrideOrVirtual = "virtual ";
|
||||
}
|
||||
|
||||
string returnTypeAsString = GetReplacedTypeAsString(method.ReturnType, out var returnIsReplaced);
|
||||
|
||||
var whereStatement = GetWhereStatementFromMethod(method);
|
||||
|
||||
foreach (var attribute in method.GetAttributesAsList())
|
||||
{
|
||||
str.AppendLine($" {attribute}");
|
||||
}
|
||||
|
||||
str.AppendLine($" public {overrideOrVirtual}{returnTypeAsString} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){whereStatement}");
|
||||
str.AppendLine(@" {");
|
||||
|
||||
foreach (var ps in method.Parameters.Where(p => !p.IsRef()))
|
||||
{
|
||||
var type = FixType(ps.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), ps.Type.NullableAnnotation);
|
||||
string normalOrMap = $" = {ps.GetSanitizedName()}";
|
||||
if (ps.RefKind == RefKind.Out)
|
||||
{
|
||||
normalOrMap = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = GetParameterType(ps, out var isReplaced); // TODO : response is not used?
|
||||
if (isReplaced)
|
||||
{
|
||||
normalOrMap = $" = Mapster.TypeAdapter.Adapt<{type}>({ps.GetSanitizedName()})";
|
||||
}
|
||||
}
|
||||
|
||||
str.AppendLine($" {type} {ps.GetSanitizedName()}_{normalOrMap};");
|
||||
}
|
||||
|
||||
var methodName = method.GetMethodNameWithOptionalTypeParameters();
|
||||
var alternateReturnVariableName = $"result_{methodName.GetDeterministicHashCodeAsString()}";
|
||||
|
||||
string instance = method.IsStatic ? targetClassSymbol.Symbol.ToFullyQualifiedDisplayString() : "_Instance";
|
||||
|
||||
if (returnTypeAsString == "void")
|
||||
{
|
||||
str.AppendLine($" {instance}.{methodName}({string.Join(", ", invokeParameters)});");
|
||||
}
|
||||
else
|
||||
{
|
||||
str.AppendLine($" var {alternateReturnVariableName} = {instance}.{methodName}({string.Join(", ", invokeParameters)});");
|
||||
}
|
||||
|
||||
foreach (var ps in method.Parameters.Where(p => p.RefKind == RefKind.Out))
|
||||
{
|
||||
string normalOrMap = $" = {ps.GetSanitizedName()}_";
|
||||
if (ps.GetTypeEnum() == TypeEnum.Complex)
|
||||
{
|
||||
var type = GetParameterType(ps, out var isReplaced);
|
||||
if (isReplaced)
|
||||
{
|
||||
normalOrMap = $" = Mapster.TypeAdapter.Adapt<{type}>({ps.GetSanitizedName()}_)";
|
||||
}
|
||||
}
|
||||
|
||||
str.AppendLine($" {ps.GetSanitizedName()}{normalOrMap};");
|
||||
}
|
||||
|
||||
if (returnTypeAsString != "void")
|
||||
{
|
||||
if (returnIsReplaced)
|
||||
{
|
||||
str.AppendLine($" return Mapster.TypeAdapter.Adapt<{returnTypeAsString}>({alternateReturnVariableName});");
|
||||
}
|
||||
else
|
||||
{
|
||||
str.AppendLine($" return {alternateReturnVariableName};");
|
||||
}
|
||||
}
|
||||
|
||||
str.AppendLine(" }");
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
private string GenerateEvents(ClassSymbol targetClassSymbol, ProxyData proxyData)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
foreach (var @event in MemberHelper.GetPublicEvents(targetClassSymbol, proxyData))
|
||||
{
|
||||
var name = @event.Key.GetSanitizedName();
|
||||
var ps = @event.First().Parameters.First();
|
||||
var type = ps.GetTypeEnum() == TypeEnum.Complex ? GetParameterType(ps, out _) : ps.Type.ToString();
|
||||
|
||||
foreach (var attribute in ps.GetAttributesAsList())
|
||||
{
|
||||
str.AppendLine($" {attribute}");
|
||||
}
|
||||
|
||||
str.Append($" public event {type} {name} {{");
|
||||
|
||||
if (@event.Any(e => e.MethodKind == MethodKind.EventAdd))
|
||||
{
|
||||
str.Append($" add {{ _Instance.{name} += value; }}");
|
||||
}
|
||||
if (@event.Any(e => e.MethodKind == MethodKind.EventRemove))
|
||||
{
|
||||
str.Append($" remove {{ _Instance.{name} -= value; }}");
|
||||
}
|
||||
|
||||
str.AppendLine(" }");
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
private string GenerateOperators(ClassSymbol targetClassSymbol, ProxyData proxyData)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
foreach (var @operator in MemberHelper.GetPublicStaticOperators(targetClassSymbol, proxyData))
|
||||
{
|
||||
foreach (var attribute in @operator.GetAttributesAsList())
|
||||
{
|
||||
str.AppendLine($" {attribute}");
|
||||
}
|
||||
|
||||
if (!@operator.Parameters.Any())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var parameter = @operator.Parameters.First();
|
||||
var proxyClassName = targetClassSymbol.Symbol.ResolveProxyClassName();
|
||||
|
||||
var operatorType = @operator.Name.ToLowerInvariant().Replace("op_", string.Empty);
|
||||
if (operatorType == "explicit")
|
||||
{
|
||||
var returnTypeAsString = GetReplacedTypeAsString(@operator.ReturnType, out _);
|
||||
|
||||
str.AppendLine($" public static explicit operator {returnTypeAsString}({proxyClassName} {parameter.Name})");
|
||||
str.AppendLine(@" {");
|
||||
str.AppendLine($" return ({returnTypeAsString}) {parameter.Name}._Instance;");
|
||||
str.AppendLine(@" }");
|
||||
}
|
||||
else
|
||||
{
|
||||
var returnTypeAsString = GetReplacedTypeAsString(parameter.Type, out _);
|
||||
|
||||
str.AppendLine($" public static implicit operator {proxyClassName}({returnTypeAsString} {parameter.Name})");
|
||||
str.AppendLine(@" {");
|
||||
str.AppendLine($" return new {proxyClassName}(({targetClassSymbol.Symbol.Name}) {parameter.Name});");
|
||||
str.AppendLine(@" }");
|
||||
}
|
||||
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.Models;
|
||||
|
||||
internal record ClassSymbol(INamedTypeSymbol Symbol, List<INamedTypeSymbol> BaseTypes, List<INamedTypeSymbol> Interfaces)
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return Symbol.ToDisplayString(NullableFlowState.None, SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
namespace Speckle.ProxyGenerator.Models;
|
||||
namespace ProxyInterfaceSourceGenerator.Models;
|
||||
|
||||
internal record ConstraintInfo(string Type, List<string> Items)
|
||||
{
|
||||
@@ -6,4 +6,4 @@ internal record ConstraintInfo(string Type, List<string> Items)
|
||||
{
|
||||
return Items.Any() ? $" where {Type} : {string.Join(", ", Items)}" : string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace Speckle.ProxyGenerator.Models;
|
||||
namespace ProxyInterfaceSourceGenerator.Models;
|
||||
|
||||
internal record Context
|
||||
{
|
||||
@@ -10,4 +10,4 @@ internal record Context
|
||||
public IDictionary<InterfaceDeclarationSyntax, ProxyData> Candidates { get; init; } = default!;
|
||||
|
||||
public Dictionary<string, string> ReplacedTypes { get; } = new();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace ProxyInterfaceSourceGenerator.Models;
|
||||
|
||||
internal record FileData(string FileName, string Text);
|
||||
@@ -0,0 +1,52 @@
|
||||
using ProxyInterfaceSourceGenerator.Types;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.Models;
|
||||
|
||||
internal class ProxyData
|
||||
{
|
||||
public string Namespace { get; }
|
||||
|
||||
public string NamespaceDot { get; }
|
||||
|
||||
public string ShortInterfaceName { get; }
|
||||
|
||||
public string FullInterfaceName { get; }
|
||||
|
||||
public string FullQualifiedTypeName { get; }
|
||||
|
||||
public string ShortMetadataName { get; }
|
||||
|
||||
public string FullMetadataTypeName { get; }
|
||||
|
||||
public List<string> Usings { get; }
|
||||
|
||||
public bool ProxyBaseClasses { get; }
|
||||
|
||||
public ProxyClassAccessibility Accessibility { get; }
|
||||
public string[] MembersToIgnore { get; }
|
||||
|
||||
public ProxyData(string @namespace,
|
||||
string namespaceDot,
|
||||
string shortInterfaceName,
|
||||
string fullInterfaceName,
|
||||
string fullQualifiedTypeName,
|
||||
string shortMetadataTypeName,
|
||||
string fullMetadataTypeName,
|
||||
List<string> usings,
|
||||
bool proxyBaseClasses,
|
||||
ProxyClassAccessibility accessibility,
|
||||
string[] membersToIgnore)
|
||||
{
|
||||
Namespace = @namespace ?? throw new ArgumentNullException(nameof(@namespace));
|
||||
NamespaceDot = namespaceDot ?? throw new ArgumentNullException(nameof(namespaceDot));
|
||||
ShortInterfaceName = shortInterfaceName ?? throw new ArgumentNullException(nameof(shortInterfaceName));
|
||||
FullInterfaceName = fullInterfaceName ?? throw new ArgumentNullException(nameof(fullInterfaceName));
|
||||
FullQualifiedTypeName = fullQualifiedTypeName ?? throw new ArgumentNullException(nameof(fullQualifiedTypeName));
|
||||
ShortMetadataName = shortMetadataTypeName ?? throw new ArgumentNullException(nameof(shortMetadataTypeName));
|
||||
FullMetadataTypeName = fullMetadataTypeName ?? throw new ArgumentNullException(nameof(fullMetadataTypeName));
|
||||
Usings = usings ?? throw new ArgumentNullException(nameof(usings));
|
||||
ProxyBaseClasses = proxyBaseClasses;
|
||||
Accessibility = accessibility;
|
||||
MembersToIgnore = membersToIgnore;
|
||||
}
|
||||
}
|
||||
+106
-137
@@ -1,137 +1,106 @@
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using Speckle.ProxyGenerator.FileGenerators;
|
||||
using Speckle.ProxyGenerator.Models;
|
||||
using Speckle.ProxyGenerator.SyntaxReceiver;
|
||||
|
||||
namespace Speckle.ProxyGenerator;
|
||||
|
||||
[Generator]
|
||||
#if DEBUG
|
||||
public
|
||||
#else
|
||||
internal
|
||||
#endif
|
||||
class ProxyInterfaceCodeGenerator : ISourceGenerator
|
||||
{
|
||||
private readonly ExtraFilesGenerator _proxyAttributeGenerator = new();
|
||||
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
#if DEBUGATTACH
|
||||
if (!System.Diagnostics.Debugger.IsAttached)
|
||||
{
|
||||
System.Diagnostics.Debugger.Launch();
|
||||
}
|
||||
#endif
|
||||
context.RegisterForSyntaxNotifications(() => new ProxySyntaxReceiver());
|
||||
}
|
||||
|
||||
public void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (context.ParseOptions is not CSharpParseOptions csharpParseOptions)
|
||||
{
|
||||
throw new NotSupportedException("Only C# is supported.");
|
||||
}
|
||||
|
||||
if (context.SyntaxContextReceiver is not ProxySyntaxReceiver receiver)
|
||||
{
|
||||
throw new NotSupportedException(
|
||||
$"Only {nameof(ProxySyntaxReceiver)} is supported."
|
||||
);
|
||||
}
|
||||
|
||||
// https://github.com/reactiveui/refit/blob/main/InterfaceStubGenerator.Core/InterfaceStubGenerator.cs
|
||||
var supportsNullable = csharpParseOptions.LanguageVersion >= LanguageVersion.CSharp8;
|
||||
|
||||
var proxyItems = new List<ProxyMapItem>();
|
||||
GeneratePartialInterfaces(context, receiver, supportsNullable);
|
||||
GenerateProxyClasses(proxyItems, context, receiver, supportsNullable);
|
||||
GenerateProxyAttribute(proxyItems, context, receiver, supportsNullable);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
GenerateError(context, exception);
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateError(GeneratorExecutionContext context, Exception exception)
|
||||
{
|
||||
var message =
|
||||
$"/*\r\n{nameof(ProxyInterfaceCodeGenerator)}\r\n\r\n[Exception]\r\n{exception}\r\n\r\n[StackTrace]\r\n{exception.StackTrace}*/";
|
||||
context.AddSource("Error.g", SourceText.From(message, Encoding.UTF8));
|
||||
}
|
||||
|
||||
private void GenerateProxyAttribute(
|
||||
List<ProxyMapItem> proxyMapItems,
|
||||
GeneratorExecutionContext ctx,
|
||||
ProxySyntaxReceiver receiver,
|
||||
bool supportsNullable
|
||||
)
|
||||
{
|
||||
var context = new Context
|
||||
{
|
||||
GeneratorExecutionContext = ctx,
|
||||
Candidates = receiver.CandidateInterfaces
|
||||
};
|
||||
|
||||
var attributeData = _proxyAttributeGenerator.GenerateFile(proxyMapItems, supportsNullable);
|
||||
context.GeneratorExecutionContext.AddSource(
|
||||
attributeData.FileName,
|
||||
SourceText.From(attributeData.Text, Encoding.UTF8)
|
||||
);
|
||||
}
|
||||
|
||||
private static void GeneratePartialInterfaces(
|
||||
GeneratorExecutionContext ctx,
|
||||
ProxySyntaxReceiver receiver,
|
||||
bool supportsNullable
|
||||
)
|
||||
{
|
||||
var context = new Context
|
||||
{
|
||||
GeneratorExecutionContext = ctx,
|
||||
Candidates = receiver.CandidateInterfaces
|
||||
};
|
||||
|
||||
var partialInterfacesGenerator = new PartialInterfacesGenerator(context, supportsNullable);
|
||||
foreach (var (fileName, text) in partialInterfacesGenerator.GenerateFiles())
|
||||
{
|
||||
context.GeneratorExecutionContext.AddSource(
|
||||
fileName,
|
||||
SourceText.From(text, Encoding.UTF8)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static void GenerateProxyClasses(
|
||||
List<ProxyMapItem> proxyMapItems,
|
||||
GeneratorExecutionContext ctx,
|
||||
ProxySyntaxReceiver receiver,
|
||||
bool supportsNullable
|
||||
)
|
||||
{
|
||||
var context = new Context
|
||||
{
|
||||
GeneratorExecutionContext = ctx,
|
||||
Candidates = receiver.CandidateInterfaces
|
||||
};
|
||||
|
||||
var proxyClassesGenerator = new ProxyClassesGenerator(
|
||||
proxyMapItems,
|
||||
context,
|
||||
supportsNullable
|
||||
);
|
||||
foreach (var (fileName, text) in proxyClassesGenerator.GenerateFiles())
|
||||
{
|
||||
context.GeneratorExecutionContext.AddSource(
|
||||
fileName,
|
||||
SourceText.From(text, Encoding.UTF8)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using ProxyInterfaceSourceGenerator.FileGenerators;
|
||||
using ProxyInterfaceSourceGenerator.Models;
|
||||
using ProxyInterfaceSourceGenerator.SyntaxReceiver;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator;
|
||||
|
||||
[Generator]
|
||||
#if DEBUG
|
||||
public
|
||||
#else
|
||||
internal
|
||||
#endif
|
||||
class ProxyInterfaceCodeGenerator : ISourceGenerator
|
||||
{
|
||||
private readonly ExtraFilesGenerator _proxyAttributeGenerator = new();
|
||||
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
#if DEBUGATTACH
|
||||
if (!System.Diagnostics.Debugger.IsAttached)
|
||||
{
|
||||
System.Diagnostics.Debugger.Launch();
|
||||
}
|
||||
#endif
|
||||
context.RegisterForSyntaxNotifications(() => new ProxySyntaxReceiver());
|
||||
}
|
||||
|
||||
public void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (context.ParseOptions is not CSharpParseOptions csharpParseOptions)
|
||||
{
|
||||
throw new NotSupportedException("Only C# is supported.");
|
||||
}
|
||||
|
||||
if (context.SyntaxContextReceiver is not ProxySyntaxReceiver receiver)
|
||||
{
|
||||
throw new NotSupportedException($"Only {nameof(ProxySyntaxReceiver)} is supported.");
|
||||
}
|
||||
|
||||
// https://github.com/reactiveui/refit/blob/main/InterfaceStubGenerator.Core/InterfaceStubGenerator.cs
|
||||
var supportsNullable = csharpParseOptions.LanguageVersion >= LanguageVersion.CSharp8;
|
||||
|
||||
GenerateProxyAttribute(context, receiver);
|
||||
GeneratePartialInterfaces(context, receiver, supportsNullable);
|
||||
GenerateProxyClasses(context, receiver, supportsNullable);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
GenerateError(context, exception);
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateError(GeneratorExecutionContext context, Exception exception)
|
||||
{
|
||||
var message = $"/*\r\n{nameof(ProxyInterfaceCodeGenerator)}\r\n\r\n[Exception]\r\n{exception}\r\n\r\n[StackTrace]\r\n{exception.StackTrace}*/";
|
||||
context.AddSource("Error.g", SourceText.From(message, Encoding.UTF8));
|
||||
}
|
||||
|
||||
private void GenerateProxyAttribute(GeneratorExecutionContext ctx, ProxySyntaxReceiver receiver)
|
||||
{
|
||||
var context = new Context
|
||||
{
|
||||
GeneratorExecutionContext = ctx,
|
||||
Candidates = receiver.CandidateInterfaces
|
||||
};
|
||||
|
||||
var attributeData = _proxyAttributeGenerator.GenerateFile();
|
||||
context.GeneratorExecutionContext.AddSource(attributeData.FileName, SourceText.From(attributeData.Text, Encoding.UTF8));
|
||||
}
|
||||
|
||||
private static void GeneratePartialInterfaces(GeneratorExecutionContext ctx, ProxySyntaxReceiver receiver, bool supportsNullable)
|
||||
{
|
||||
var context = new Context
|
||||
{
|
||||
GeneratorExecutionContext = ctx,
|
||||
Candidates = receiver.CandidateInterfaces
|
||||
};
|
||||
|
||||
var partialInterfacesGenerator = new PartialInterfacesGenerator(context, supportsNullable);
|
||||
foreach (var (fileName, text) in partialInterfacesGenerator.GenerateFiles())
|
||||
{
|
||||
context.GeneratorExecutionContext.AddSource(fileName, SourceText.From(text, Encoding.UTF8));
|
||||
}
|
||||
}
|
||||
|
||||
private static void GenerateProxyClasses(GeneratorExecutionContext ctx, ProxySyntaxReceiver receiver, bool supportsNullable)
|
||||
{
|
||||
var context = new Context
|
||||
{
|
||||
GeneratorExecutionContext = ctx,
|
||||
Candidates = receiver.CandidateInterfaces
|
||||
};
|
||||
|
||||
var proxyClassesGenerator = new ProxyClassesGenerator(context, supportsNullable);
|
||||
foreach (var (fileName, text) in proxyClassesGenerator.GenerateFiles())
|
||||
{
|
||||
context.GeneratorExecutionContext.AddSource(fileName, SourceText.From(text, Encoding.UTF8));
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
-10
@@ -1,23 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>0.1.11</Version>
|
||||
<Version>0.1.0</Version>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>Latest</LangVersion>
|
||||
<ProjectGuid>{12344228-91F4-4502-9595-39584E5ABB34}</ProjectGuid>
|
||||
<LangVersion>10</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<Authors>Speckle</Authors>
|
||||
<RootNamespace>Speckle.ProxyGenerator</RootNamespace>
|
||||
<Title>Speckle.ProxyGenerator</Title>
|
||||
<PackageId>Speckle.ProxyGenerator</PackageId>
|
||||
<Authors>Stef Heyenrath</Authors>
|
||||
<Description></Description>
|
||||
<Title>ProxyInterfaceGenerator</Title>
|
||||
<PackageId>ProxyInterfaceGenerator</PackageId>
|
||||
<Description>This project uses Source Generation to generate an interface and a Proxy class for classes. This makes it possible to wrap external classes which do not have an interface, in a Proxy class which makes it easier to Mock and use DI.</Description>
|
||||
<PackageTags>class;interface;proxy;SourceGenerator;Analyzer;Generation;Generate;wrap</PackageTags>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/../../PackageReleaseNotes.txt"))</PackageReleaseNotes>
|
||||
<PackageProjectUrl>https://github.com/specklesystems/ProxyGenerator</PackageProjectUrl>
|
||||
<PackageProjectUrl>https://github.com/StefH/ProxyInterfaceSourceGenerator</PackageProjectUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<RepositoryUrl>https://github.com/specklesystems/ProxyGenerator</RepositoryUrl>
|
||||
<RepositoryUrl>https://github.com/StefH/ProxyInterfaceSourceGenerator</RepositoryUrl>
|
||||
<PackageReadmeFile>PackageReadme.md</PackageReadmeFile>
|
||||
<PackageIcon>icon.png</PackageIcon>
|
||||
<IncludeBuildOutput>false</IncludeBuildOutput>
|
||||
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)Generated</CompilerGeneratedFilesOutputPath>
|
||||
<DevelopmentDependency>true</DevelopmentDependency>
|
||||
@@ -27,6 +29,10 @@
|
||||
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="../../resources/icon.png" Pack="true" PackagePath="" />
|
||||
<None Include="../../PackageReadme.md" Pack="true" PackagePath="" />
|
||||
@@ -37,7 +43,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3">
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
@@ -53,6 +59,12 @@
|
||||
<ProjectCapability Include="DynamicFileNesting" />
|
||||
</ItemGroup>-->
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="ProxyClassesGenerator.AutoMapper.cs">
|
||||
<DependentUpon>ProxyClassesGenerator.cs</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
||||
</ItemGroup>
|
||||
@@ -67,4 +79,4 @@
|
||||
</AssemblyAttribute>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
</Project>
|
||||
+40
-63
@@ -1,18 +1,16 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Speckle.ProxyGenerator.Extensions;
|
||||
using Speckle.ProxyGenerator.Types;
|
||||
using ProxyInterfaceSourceGenerator.Extensions;
|
||||
using ProxyInterfaceSourceGenerator.Types;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Speckle.ProxyGenerator.SyntaxReceiver;
|
||||
namespace ProxyInterfaceSourceGenerator.SyntaxReceiver;
|
||||
|
||||
internal static class AttributeArgumentListParser
|
||||
{
|
||||
public static ProxyInterfaceGeneratorAttributeArguments ParseAttributeArguments(
|
||||
AttributeArgumentListSyntax? argumentList,
|
||||
SemanticModel semanticModel
|
||||
)
|
||||
public static ProxyInterfaceGeneratorAttributeArguments ParseAttributeArguments(AttributeArgumentListSyntax? argumentList, SemanticModel semanticModel)
|
||||
{
|
||||
if (argumentList is null || argumentList.Arguments.Count is < 1 or > 4)
|
||||
{
|
||||
@@ -20,25 +18,13 @@ internal static class AttributeArgumentListParser
|
||||
}
|
||||
|
||||
ProxyInterfaceGeneratorAttributeArguments result;
|
||||
if (
|
||||
TryParseAsType(
|
||||
argumentList.Arguments[0].Expression,
|
||||
semanticModel,
|
||||
out var fullyQualifiedDisplayString,
|
||||
out var metadataName
|
||||
)
|
||||
)
|
||||
if (TryParseAsType(argumentList.Arguments[0].Expression, semanticModel, out var fullyQualifiedDisplayString, out var metadataName))
|
||||
{
|
||||
result = new ProxyInterfaceGeneratorAttributeArguments(
|
||||
fullyQualifiedDisplayString,
|
||||
metadataName
|
||||
);
|
||||
result = new ProxyInterfaceGeneratorAttributeArguments(fullyQualifiedDisplayString, metadataName);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"The first argument from the ProxyAttribute should be a Type."
|
||||
);
|
||||
throw new ArgumentException("The first argument from the ProxyAttribute should be a Type.");
|
||||
}
|
||||
|
||||
foreach (var argument in argumentList.Arguments.Skip(1))
|
||||
@@ -48,26 +34,35 @@ internal static class AttributeArgumentListParser
|
||||
result = result with { MembersToIgnore = membersToIgnore };
|
||||
continue;
|
||||
}
|
||||
if (TryParseAsBoolean(argument.Expression, out var proxyBaseClasses))
|
||||
{
|
||||
result = result with { ProxyBaseClasses = proxyBaseClasses };
|
||||
continue;
|
||||
}
|
||||
|
||||
if (TryParseAsEnum<ProxyClassAccessibility>(argument.Expression, out var accessibility))
|
||||
{
|
||||
result = result with { Accessibility = accessibility };
|
||||
}
|
||||
|
||||
if (TryParseAsEnum<ImplementationOptions>(argument.Expression, out var options))
|
||||
{
|
||||
result = result with { Options = options };
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool TryParseAsType(
|
||||
ExpressionSyntax expressionSyntax,
|
||||
SemanticModel semanticModel,
|
||||
[NotNullWhen(true)] out string? fullyQualifiedDisplayString,
|
||||
[NotNullWhen(true)] out string? metadataName
|
||||
)
|
||||
private static bool TryParseAsBoolean(ExpressionSyntax expressionSyntax, out bool value)
|
||||
{
|
||||
value = default;
|
||||
|
||||
if (expressionSyntax is LiteralExpressionSyntax literalExpressionSyntax)
|
||||
{
|
||||
value = literalExpressionSyntax.Kind() == SyntaxKind.TrueLiteralExpression;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryParseAsType(ExpressionSyntax expressionSyntax, SemanticModel semanticModel, [NotNullWhen(true)] out string? fullyQualifiedDisplayString, [NotNullWhen(true)] out string? metadataName)
|
||||
{
|
||||
fullyQualifiedDisplayString = null;
|
||||
metadataName = null;
|
||||
@@ -86,43 +81,24 @@ internal static class AttributeArgumentListParser
|
||||
}
|
||||
|
||||
private static bool TryParseAsEnum<TEnum>(ExpressionSyntax expressionSyntax, out TEnum value)
|
||||
where TEnum : struct, Enum
|
||||
where TEnum : struct
|
||||
{
|
||||
var enumAsString = expressionSyntax.ToString();
|
||||
value = default;
|
||||
if (!enumAsString.Contains(typeof(TEnum).Name))
|
||||
if (enumAsString.Length > typeof(TEnum).Name.Length && Enum.TryParse(expressionSyntax.ToString().Substring(typeof(TEnum).Name.Length + 1), out value))
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
var splitter = new[] { $"{typeof(TEnum).Name}." };
|
||||
var vals = enumAsString
|
||||
.Split(splitter, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(x => x.TrimEnd(' ', '|'));
|
||||
|
||||
long l = 0;
|
||||
foreach (var v in vals)
|
||||
{
|
||||
if (Enum.TryParse<TEnum>(v, out var e))
|
||||
{
|
||||
l |= Convert.ToInt64(e);
|
||||
}
|
||||
}
|
||||
value = (TEnum)Enum.ToObject(typeof(TEnum), l);
|
||||
;
|
||||
return true;
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryParseAsStringArray(ExpressionSyntax expressionSyntax, out string[] value)
|
||||
private static bool TryParseAsStringArray(ExpressionSyntax expressionSyntax, [NotNullWhen(true)] out string[] value)
|
||||
{
|
||||
if (
|
||||
expressionSyntax
|
||||
is ImplicitArrayCreationExpressionSyntax lmplicitArrayCreationExpressionSyntax
|
||||
)
|
||||
if (expressionSyntax is ImplicitArrayCreationExpressionSyntax implicitArrayCreationExpressionSyntax)
|
||||
{
|
||||
var strings = new List<string>();
|
||||
foreach (
|
||||
var expression in lmplicitArrayCreationExpressionSyntax.Initializer.Expressions
|
||||
)
|
||||
foreach (var expression in implicitArrayCreationExpressionSyntax.Initializer.Expressions)
|
||||
{
|
||||
if (expression.GetFirstToken().Value is string s)
|
||||
{
|
||||
@@ -132,7 +108,8 @@ internal static class AttributeArgumentListParser
|
||||
value = strings.ToArray();
|
||||
return true;
|
||||
}
|
||||
value = [];
|
||||
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+86
-110
@@ -1,110 +1,86 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Speckle.ProxyGenerator.Extensions;
|
||||
using Speckle.ProxyGenerator.Models;
|
||||
using Speckle.ProxyGenerator.Types;
|
||||
|
||||
namespace Speckle.ProxyGenerator.SyntaxReceiver;
|
||||
|
||||
internal class ProxySyntaxReceiver : ISyntaxContextReceiver
|
||||
{
|
||||
private const string GlobalPrefix = "global::";
|
||||
private static readonly string[] GenerateProxyAttributes =
|
||||
[
|
||||
"Speckle.ProxyGenerator.Proxy",
|
||||
"Proxy"
|
||||
];
|
||||
private static readonly string[] Modifiers = ["public", "partial"];
|
||||
public IDictionary<InterfaceDeclarationSyntax, ProxyData> CandidateInterfaces { get; } =
|
||||
new Dictionary<InterfaceDeclarationSyntax, ProxyData>();
|
||||
|
||||
public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
|
||||
{
|
||||
var syntaxNode = context.Node;
|
||||
var semanticModel = context.SemanticModel;
|
||||
|
||||
if (
|
||||
syntaxNode is InterfaceDeclarationSyntax interfaceDeclarationSyntax
|
||||
&& TryGet(interfaceDeclarationSyntax, out var data, semanticModel!)
|
||||
)
|
||||
{
|
||||
CandidateInterfaces.Add(interfaceDeclarationSyntax, data);
|
||||
}
|
||||
}
|
||||
|
||||
private static string CreateFullInterfaceName(
|
||||
string ns,
|
||||
BaseTypeDeclarationSyntax classDeclarationSyntax
|
||||
)
|
||||
{
|
||||
return !string.IsNullOrEmpty(ns)
|
||||
? $"{ns}.{classDeclarationSyntax.Identifier}"
|
||||
: classDeclarationSyntax.Identifier.ToString();
|
||||
}
|
||||
|
||||
private static bool TryGet(
|
||||
InterfaceDeclarationSyntax interfaceDeclarationSyntax,
|
||||
[NotNullWhen(true)] out ProxyData? data,
|
||||
SemanticModel semanticModel
|
||||
)
|
||||
{
|
||||
data = null;
|
||||
|
||||
if (interfaceDeclarationSyntax.Modifiers.Select(m => m.ToString()).Except(Modifiers).Any())
|
||||
{
|
||||
// InterfaceDeclarationSyntax should be "public" and "partial"
|
||||
return false;
|
||||
}
|
||||
|
||||
var attributeList = interfaceDeclarationSyntax.AttributeLists.FirstOrDefault(x =>
|
||||
x.Attributes.Any(a => GenerateProxyAttributes.Contains(a.Name.ToString()))
|
||||
);
|
||||
if (attributeList is null)
|
||||
{
|
||||
// InterfaceDeclarationSyntax should have the correct attribute
|
||||
return false;
|
||||
}
|
||||
|
||||
var usings = new List<string>();
|
||||
|
||||
string ns = interfaceDeclarationSyntax.GetNamespace();
|
||||
if (!string.IsNullOrEmpty(ns))
|
||||
{
|
||||
usings.Add(ns);
|
||||
}
|
||||
|
||||
if (interfaceDeclarationSyntax.TryGetParentSyntax(out CompilationUnitSyntax? cc))
|
||||
{
|
||||
foreach (var @using in cc.Usings)
|
||||
{
|
||||
usings.Add(@using.Name.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
var fluentBuilderAttributeArguments = AttributeArgumentListParser.ParseAttributeArguments(
|
||||
attributeList.Attributes.FirstOrDefault()?.ArgumentList,
|
||||
semanticModel
|
||||
);
|
||||
|
||||
var metadataName = fluentBuilderAttributeArguments.MetadataName;
|
||||
var globalNamespace = string.IsNullOrEmpty(ns) ? string.Empty : $"{GlobalPrefix}{ns}";
|
||||
var namespaceDot = string.IsNullOrEmpty(ns) ? string.Empty : $"{ns}.";
|
||||
|
||||
data = new ProxyData(
|
||||
@namespace: ns,
|
||||
namespaceDot: namespaceDot,
|
||||
shortInterfaceName: interfaceDeclarationSyntax.Identifier.ToString(),
|
||||
fullInterfaceName: CreateFullInterfaceName(globalNamespace, interfaceDeclarationSyntax), // $"{ns}.{interfaceDeclarationSyntax.Identifier}",
|
||||
fullQualifiedTypeName: fluentBuilderAttributeArguments.FullyQualifiedDisplayString,
|
||||
fullMetadataTypeName: metadataName,
|
||||
shortMetadataTypeName: metadataName.Split('.').Last(),
|
||||
usings: usings,
|
||||
options: fluentBuilderAttributeArguments.Options ?? ImplementationOptions.UseExtendedInterfaces | ImplementationOptions.ProxyForBaseInterface,
|
||||
accessibility: fluentBuilderAttributeArguments.Accessibility,
|
||||
membersToIgnore: fluentBuilderAttributeArguments.MembersToIgnore
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using ProxyInterfaceSourceGenerator.Extensions;
|
||||
using ProxyInterfaceSourceGenerator.Models;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.SyntaxReceiver;
|
||||
|
||||
internal class ProxySyntaxReceiver : ISyntaxContextReceiver
|
||||
{
|
||||
private const string GlobalPrefix = "global::";
|
||||
private static readonly string[] GenerateProxyAttributes = { "ProxyInterfaceGenerator.Proxy", "Proxy" };
|
||||
private static readonly string[] Modifiers = { "public", "partial" };
|
||||
public IDictionary<InterfaceDeclarationSyntax, ProxyData> CandidateInterfaces { get; } = new Dictionary<InterfaceDeclarationSyntax, ProxyData>();
|
||||
|
||||
public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
|
||||
{
|
||||
var syntaxNode = context.Node;
|
||||
var semanticModel = context.SemanticModel;
|
||||
|
||||
if (syntaxNode is InterfaceDeclarationSyntax interfaceDeclarationSyntax && TryGet(interfaceDeclarationSyntax, out var data, semanticModel!))
|
||||
{
|
||||
CandidateInterfaces.Add(interfaceDeclarationSyntax, data);
|
||||
}
|
||||
}
|
||||
|
||||
private static string CreateFullInterfaceName(string ns, BaseTypeDeclarationSyntax classDeclarationSyntax)
|
||||
{
|
||||
return !string.IsNullOrEmpty(ns) ? $"{ns}.{classDeclarationSyntax.Identifier}" : classDeclarationSyntax.Identifier.ToString();
|
||||
}
|
||||
private static bool TryGet(InterfaceDeclarationSyntax interfaceDeclarationSyntax, [NotNullWhen(true)] out ProxyData? data, SemanticModel semanticModel)
|
||||
{
|
||||
data = null;
|
||||
|
||||
if (interfaceDeclarationSyntax.Modifiers.Select(m => m.ToString()).Except(Modifiers).Any())
|
||||
{
|
||||
// InterfaceDeclarationSyntax should be "public" and "partial"
|
||||
return false;
|
||||
}
|
||||
|
||||
var attributeList = interfaceDeclarationSyntax.AttributeLists.FirstOrDefault(x => x.Attributes.Any(a => GenerateProxyAttributes.Contains(a.Name.ToString())));
|
||||
if (attributeList is null)
|
||||
{
|
||||
// InterfaceDeclarationSyntax should have the correct attribute
|
||||
return false;
|
||||
}
|
||||
|
||||
var usings = new List<string>();
|
||||
|
||||
string ns = interfaceDeclarationSyntax.GetNamespace();
|
||||
if (!string.IsNullOrEmpty(ns))
|
||||
{
|
||||
usings.Add(ns);
|
||||
}
|
||||
|
||||
if (interfaceDeclarationSyntax.TryGetParentSyntax(out CompilationUnitSyntax? cc))
|
||||
{
|
||||
foreach (var @using in cc.Usings)
|
||||
{
|
||||
usings.Add(@using.Name.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
var fluentBuilderAttributeArguments = AttributeArgumentListParser.ParseAttributeArguments(attributeList.Attributes.FirstOrDefault()?.ArgumentList, semanticModel);
|
||||
|
||||
var metadataName = fluentBuilderAttributeArguments.MetadataName;
|
||||
var globalNamespace = string.IsNullOrEmpty(ns) ? string.Empty : $"{GlobalPrefix}{ns}";
|
||||
var namespaceDot = string.IsNullOrEmpty(ns) ? string.Empty : $"{ns}.";
|
||||
|
||||
data = new ProxyData(
|
||||
@namespace: ns,
|
||||
namespaceDot: namespaceDot,
|
||||
shortInterfaceName: interfaceDeclarationSyntax.Identifier.ToString(),
|
||||
fullInterfaceName: CreateFullInterfaceName(globalNamespace, interfaceDeclarationSyntax), // $"{ns}.{interfaceDeclarationSyntax.Identifier}",
|
||||
fullQualifiedTypeName: fluentBuilderAttributeArguments.FullyQualifiedDisplayString,
|
||||
fullMetadataTypeName: metadataName,
|
||||
shortMetadataTypeName: metadataName.Split('.').Last(),
|
||||
usings: usings,
|
||||
proxyBaseClasses: fluentBuilderAttributeArguments.ProxyBaseClasses,
|
||||
accessibility: fluentBuilderAttributeArguments.Accessibility,
|
||||
membersToIgnore: fluentBuilderAttributeArguments.MembersToIgnore
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace ProxyInterfaceSourceGenerator.Types;
|
||||
|
||||
internal record ProxyInterfaceGeneratorAttributeArguments(string FullyQualifiedDisplayString, string MetadataName)
|
||||
{
|
||||
public bool ProxyBaseClasses { get; set; }
|
||||
|
||||
public ProxyClassAccessibility Accessibility { get; set; }
|
||||
|
||||
public string[] MembersToIgnore { get; set; } = Array.Empty<string>();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace ProxyInterfaceSourceGenerator.Types;
|
||||
|
||||
[Flags]
|
||||
internal enum ProxyClassAccessibility
|
||||
{
|
||||
Public = 0,
|
||||
|
||||
Internal = 1
|
||||
}
|
||||
+125
-140
@@ -1,140 +1,125 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Speckle.ProxyGenerator.Models;
|
||||
using Speckle.ProxyGenerator.Types;
|
||||
|
||||
namespace Speckle.ProxyGenerator.Utils;
|
||||
|
||||
internal static class MemberHelper
|
||||
{
|
||||
private static readonly string[] ExcludedMethods = ["ToString", "GetHashCode"];
|
||||
|
||||
public static IReadOnlyList<IPropertySymbol> GetPublicProperties(
|
||||
ClassSymbol classSymbol,
|
||||
ProxyData proxyData,
|
||||
params Func<IPropertySymbol, bool>[] filters
|
||||
)
|
||||
{
|
||||
var allFilters = new List<Func<IPropertySymbol, bool>>(filters)
|
||||
{
|
||||
p => p.Kind == SymbolKind.Property
|
||||
};
|
||||
|
||||
return GetPublicMembers(classSymbol, proxyData, allFilters.ToArray()).ToArray();
|
||||
}
|
||||
|
||||
public static IReadOnlyList<IMethodSymbol> GetPublicMethods(
|
||||
ClassSymbol classSymbol,
|
||||
ProxyData proxyData,
|
||||
Func<IMethodSymbol, bool>? filter = null
|
||||
)
|
||||
{
|
||||
filter ??= _ => true;
|
||||
|
||||
return GetPublicMembers(
|
||||
classSymbol,
|
||||
proxyData,
|
||||
m => m.Kind == SymbolKind.Method,
|
||||
m => m.MethodKind == MethodKind.Ordinary,
|
||||
m => !ExcludedMethods.Contains(m.Name),
|
||||
filter
|
||||
)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public static IReadOnlyList<IMethodSymbol> GetPublicStaticOperators(
|
||||
ClassSymbol classSymbol,
|
||||
ProxyData proxyData,
|
||||
Func<IMethodSymbol, bool>? filter = null
|
||||
)
|
||||
{
|
||||
filter ??= _ => true;
|
||||
|
||||
return GetPublicMembers(
|
||||
classSymbol,
|
||||
proxyData,
|
||||
m => m.Kind == SymbolKind.Method,
|
||||
m => m.MethodKind == MethodKind.Conversion,
|
||||
m => !ExcludedMethods.Contains(m.Name),
|
||||
filter
|
||||
)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public static IReadOnlyList<IGrouping<ISymbol, IMethodSymbol>> GetPublicEvents(
|
||||
ClassSymbol classSymbol,
|
||||
ProxyData proxyData,
|
||||
Func<IMethodSymbol, bool>? filter = null
|
||||
)
|
||||
{
|
||||
filter ??= _ => true;
|
||||
|
||||
#pragma warning disable CS8619 // Nullability of reference types in value doesn't match target type.
|
||||
#pragma warning disable RS1024 // Compare symbols correctly
|
||||
return GetPublicMembers(
|
||||
classSymbol,
|
||||
proxyData,
|
||||
m =>
|
||||
m.MethodKind
|
||||
is MethodKind.EventAdd
|
||||
or MethodKind.EventRemove /* || m.MethodKind == MethodKind.EventRaise*/
|
||||
,
|
||||
filter
|
||||
)
|
||||
.GroupBy(e => e.AssociatedSymbol)
|
||||
.ToArray();
|
||||
#pragma warning restore RS1024 // Compare symbols correctly
|
||||
#pragma warning restore CS8619 // Nullability of reference types in value doesn't match target type.
|
||||
}
|
||||
|
||||
// TODO : do we need also to check for "SanitizedName()" here?
|
||||
private static IReadOnlyList<T> GetPublicMembers<T>(
|
||||
ClassSymbol classSymbol,
|
||||
ProxyData proxyData,
|
||||
params Func<T, bool>[] filters
|
||||
)
|
||||
where T : ISymbol
|
||||
{
|
||||
var membersQuery = classSymbol
|
||||
.Symbol.GetMembers()
|
||||
.OfType<T>()
|
||||
.Where(m => m.DeclaredAccessibility == Accessibility.Public);
|
||||
|
||||
var f = filters.ToList();
|
||||
f.Add(x => !proxyData.MembersToIgnore.Contains(x.Name));
|
||||
foreach (var filter in f)
|
||||
{
|
||||
membersQuery = membersQuery.Where(filter);
|
||||
}
|
||||
|
||||
var ownMembers = membersQuery.ToList();
|
||||
var ownMemberNames = ownMembers.Select(x => x.Name);
|
||||
|
||||
if (!proxyData.Options.HasFlag(ImplementationOptions.ProxyBaseClasses))
|
||||
{
|
||||
return ownMembers;
|
||||
}
|
||||
|
||||
var allMembers = ownMembers;
|
||||
var baseType = classSymbol.Symbol.BaseType;
|
||||
|
||||
while (baseType != null && baseType.SpecialType != SpecialType.System_Object)
|
||||
{
|
||||
var baseMembers = baseType
|
||||
.GetMembers()
|
||||
.OfType<T>()
|
||||
.Where(m => m.DeclaredAccessibility == Accessibility.Public)
|
||||
.Where(x => !ownMemberNames.Contains(x.Name));
|
||||
|
||||
foreach (var filter in filters)
|
||||
{
|
||||
baseMembers = baseMembers.Where(filter);
|
||||
}
|
||||
|
||||
allMembers.AddRange(baseMembers);
|
||||
|
||||
baseType = baseType.BaseType;
|
||||
}
|
||||
|
||||
return allMembers;
|
||||
}
|
||||
}
|
||||
using Microsoft.CodeAnalysis;
|
||||
using ProxyInterfaceSourceGenerator.Models;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.Utils;
|
||||
|
||||
internal static class MemberHelper
|
||||
{
|
||||
private static readonly string[] ExcludedMethods = { "ToString", "GetHashCode" };
|
||||
|
||||
public static IReadOnlyList<IPropertySymbol> GetPublicProperties(
|
||||
ClassSymbol classSymbol,
|
||||
ProxyData proxyData,
|
||||
params Func<IPropertySymbol, bool>[] filters)
|
||||
{
|
||||
var allFilters = new List<Func<IPropertySymbol, bool>>(filters)
|
||||
{
|
||||
p => p.Kind == SymbolKind.Property
|
||||
};
|
||||
|
||||
return GetPublicMembers(classSymbol, proxyData, allFilters.ToArray()).ToArray();
|
||||
}
|
||||
|
||||
public static IReadOnlyList<IMethodSymbol> GetPublicMethods(
|
||||
ClassSymbol classSymbol,
|
||||
ProxyData proxyData,
|
||||
Func<IMethodSymbol, bool>? filter = null)
|
||||
{
|
||||
filter ??= _ => true;
|
||||
|
||||
return
|
||||
GetPublicMembers(
|
||||
classSymbol,
|
||||
proxyData,
|
||||
m => m.Kind == SymbolKind.Method,
|
||||
m => m.MethodKind == MethodKind.Ordinary,
|
||||
m => !ExcludedMethods.Contains(m.Name),
|
||||
filter)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public static IReadOnlyList<IMethodSymbol> GetPublicStaticOperators(
|
||||
ClassSymbol classSymbol,
|
||||
ProxyData proxyData,
|
||||
Func<IMethodSymbol, bool>? filter = null)
|
||||
{
|
||||
filter ??= _ => true;
|
||||
|
||||
return
|
||||
GetPublicMembers(
|
||||
classSymbol,
|
||||
proxyData,
|
||||
m => m.Kind == SymbolKind.Method,
|
||||
m => m.MethodKind == MethodKind.Conversion,
|
||||
m => !ExcludedMethods.Contains(m.Name),
|
||||
filter)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public static IReadOnlyList<IGrouping<ISymbol, IMethodSymbol>> GetPublicEvents(
|
||||
ClassSymbol classSymbol,
|
||||
ProxyData proxyData,
|
||||
Func<IMethodSymbol, bool>? filter = null)
|
||||
{
|
||||
filter ??= _ => true;
|
||||
|
||||
#pragma warning disable CS8619 // Nullability of reference types in value doesn't match target type.
|
||||
#pragma warning disable RS1024 // Compare symbols correctly
|
||||
return GetPublicMembers(
|
||||
classSymbol,
|
||||
proxyData,
|
||||
m => m.MethodKind is MethodKind.EventAdd or MethodKind.EventRemove/* || m.MethodKind == MethodKind.EventRaise*/,
|
||||
filter)
|
||||
.GroupBy(e => e.AssociatedSymbol)
|
||||
.ToArray();
|
||||
#pragma warning restore RS1024 // Compare symbols correctly
|
||||
#pragma warning restore CS8619 // Nullability of reference types in value doesn't match target type.
|
||||
}
|
||||
|
||||
// TODO : do we need also to check for "SanitizedName()" here?
|
||||
private static IReadOnlyList<T> GetPublicMembers<T>(
|
||||
ClassSymbol classSymbol,
|
||||
ProxyData proxyData,
|
||||
params Func<T, bool>[] filters
|
||||
) where T : ISymbol
|
||||
{
|
||||
var membersQuery = classSymbol.Symbol.GetMembers().OfType<T>()
|
||||
.Where(m => m.DeclaredAccessibility == Accessibility.Public);
|
||||
|
||||
var allFilters = filters.ToList();
|
||||
allFilters.Add(x => !proxyData.MembersToIgnore.Contains(x.Name));
|
||||
foreach (var filter in allFilters)
|
||||
{
|
||||
membersQuery = membersQuery.Where(filter);
|
||||
}
|
||||
|
||||
var ownMembers = membersQuery.ToList();
|
||||
var ownMemberNames = ownMembers.Select(x => x.Name);
|
||||
|
||||
if (!proxyData.ProxyBaseClasses)
|
||||
{
|
||||
return ownMembers;
|
||||
}
|
||||
|
||||
var allMembers = ownMembers;
|
||||
var baseType = classSymbol.Symbol.BaseType;
|
||||
|
||||
while (baseType != null && baseType.SpecialType != SpecialType.System_Object)
|
||||
{
|
||||
var baseMembers = baseType.GetMembers().OfType<T>()
|
||||
.Where(m => m.DeclaredAccessibility == Accessibility.Public)
|
||||
.Where(x => !ownMemberNames.Contains(x.Name));
|
||||
|
||||
foreach (var filter in filters)
|
||||
{
|
||||
baseMembers = baseMembers.Where(filter);
|
||||
}
|
||||
|
||||
allMembers.AddRange(baseMembers);
|
||||
|
||||
baseType = baseType.BaseType;
|
||||
}
|
||||
|
||||
return allMembers;
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -1,4 +1,4 @@
|
||||
namespace Speckle.ProxyGenerator.Utils;
|
||||
namespace ProxyInterfaceSourceGenerator.Utils;
|
||||
|
||||
internal static class NamespaceBuilder
|
||||
{
|
||||
@@ -6,9 +6,10 @@ internal static class NamespaceBuilder
|
||||
{
|
||||
var namespaceDefined = !string.IsNullOrEmpty(ns);
|
||||
|
||||
return (
|
||||
return
|
||||
(
|
||||
namespaceDefined ? $"namespace {ns}\r\n{{" : string.Empty,
|
||||
namespaceDefined ? "}" : string.Empty
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Speckle.ProxyGenerator.Enums;
|
||||
using Speckle.ProxyGenerator.FileGenerators;
|
||||
|
||||
namespace Speckle.ProxyGenerator.Extensions;
|
||||
|
||||
internal static class PropertySymbolExtensions
|
||||
{
|
||||
public static TypeEnum GetTypeEnum(this IPropertySymbol p) => p.Type.GetTypeEnum();
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
using System.Text;
|
||||
using Speckle.ProxyGenerator.Extensions;
|
||||
using Speckle.ProxyGenerator.Models;
|
||||
|
||||
namespace Speckle.ProxyGenerator.FileGenerators;
|
||||
|
||||
internal record ProxyMapItem(string BaseType, string InterfaceType, string ProxyType);
|
||||
|
||||
internal class ExtraFilesGenerator : IFileGenerator
|
||||
{
|
||||
private const string Name = "Speckle.ProxyGenerator.Extra.g.cs";
|
||||
|
||||
public FileData GenerateFile(List<ProxyMapItem> proxyMapItems, bool supportsNullable)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
foreach (var item in proxyMapItems)
|
||||
{
|
||||
sb.AppendLine(
|
||||
$"Add<{item.BaseType}, {item.InterfaceType}, {item.ProxyType}>(x => new {item.ProxyType}(x));"
|
||||
);
|
||||
}
|
||||
return new FileData(
|
||||
$"{Name}",
|
||||
$@"//----------------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by https://github.com/specklesystems/ProxyGenerator
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
{supportsNullable.IIf("#nullable enable")}
|
||||
using System;
|
||||
|
||||
namespace Speckle.ProxyGenerator
|
||||
{{
|
||||
[AttributeUsage(AttributeTargets.Interface)]
|
||||
internal sealed class ProxyAttribute : Attribute
|
||||
{{
|
||||
public Type Type {{ get; }}
|
||||
public ImplementationOptions Options {{ get; }}
|
||||
public ProxyClassAccessibility Accessibility {{ get; }}
|
||||
public string[]? MembersToIgnore {{ get; }}
|
||||
|
||||
public ProxyAttribute(Type type) : this(type, ImplementationOptions.None, ProxyClassAccessibility.Public)
|
||||
{{
|
||||
}}
|
||||
|
||||
public ProxyAttribute(Type type, ImplementationOptions options) : this(type, options, ProxyClassAccessibility.Public)
|
||||
{{
|
||||
}}
|
||||
|
||||
public ProxyAttribute(Type type, ProxyClassAccessibility accessibility) : this(type, ImplementationOptions.None, accessibility)
|
||||
{{
|
||||
}}
|
||||
|
||||
public ProxyAttribute(Type type, ImplementationOptions options, ProxyClassAccessibility accessibility) : this(type, options, accessibility, null)
|
||||
{{
|
||||
}}
|
||||
|
||||
public ProxyAttribute(Type type, string[]? membersToIgnore) : this(type, ImplementationOptions.None, ProxyClassAccessibility.Public, null)
|
||||
{{
|
||||
}}
|
||||
|
||||
public ProxyAttribute(Type type, ImplementationOptions options, string[]? membersToIgnore) : this(type, options, ProxyClassAccessibility.Public, null)
|
||||
{{
|
||||
}}
|
||||
|
||||
public ProxyAttribute(Type type, ImplementationOptions options, ProxyClassAccessibility accessibility, string[]? membersToIgnore)
|
||||
{{
|
||||
Type = type;
|
||||
Options = options;
|
||||
Accessibility = accessibility;
|
||||
MembersToIgnore = membersToIgnore;
|
||||
}}
|
||||
}}
|
||||
|
||||
[Flags]
|
||||
internal enum ProxyClassAccessibility
|
||||
{{
|
||||
Public = 0,
|
||||
|
||||
Internal = 1
|
||||
}}
|
||||
[Flags]
|
||||
internal enum ImplementationOptions
|
||||
{{
|
||||
None = 0,
|
||||
|
||||
ProxyBaseClasses = 1,
|
||||
|
||||
ProxyInterfaces = 2,
|
||||
|
||||
UseExtendedInterfaces = 4,
|
||||
|
||||
ProxyForBaseInterface = 8
|
||||
}}
|
||||
|
||||
public static class ProxyMap
|
||||
{{
|
||||
private static readonly global::System.Collections.Concurrent.ConcurrentDictionary<Type, Type> s_revitToInterfaceMap = new();
|
||||
private static readonly global::System.Collections.Concurrent.ConcurrentDictionary<Type, Type> s_proxyToInterfaceMap = new();
|
||||
private static readonly global::System.Collections.Concurrent.ConcurrentDictionary<Type, Type> s_interfaceToRevit = new();
|
||||
private static readonly global::System.Collections.Concurrent.ConcurrentDictionary<Type, Func<object, object>> s_proxyFactory = new();
|
||||
|
||||
static ProxyMap()
|
||||
{{
|
||||
{sb}
|
||||
}}
|
||||
|
||||
private static void Add<T, TInterface, TProxy>(Func<T, TProxy> f)
|
||||
where TInterface : notnull
|
||||
where TProxy : TInterface
|
||||
{{
|
||||
s_revitToInterfaceMap.TryAdd(typeof(T), typeof(TInterface));
|
||||
s_proxyToInterfaceMap.TryAdd(typeof(TProxy), typeof(TInterface));
|
||||
s_proxyFactory.TryAdd(typeof(TInterface), w => f((T)w));
|
||||
s_interfaceToRevit.TryAdd(typeof(TInterface), typeof(T));
|
||||
}}
|
||||
|
||||
public static Type? GetMappedTypeFromHostType(Type type)
|
||||
{{
|
||||
if (s_revitToInterfaceMap.TryGetValue(type, out var t))
|
||||
{{
|
||||
return t;
|
||||
}}
|
||||
return null;
|
||||
}}
|
||||
|
||||
public static Type? GetMappedTypeFromProxyType(Type type)
|
||||
{{
|
||||
if (s_proxyToInterfaceMap.TryGetValue(type, out var t))
|
||||
{{
|
||||
return t;
|
||||
}}
|
||||
|
||||
return null;
|
||||
}}
|
||||
|
||||
public static Type? GetHostTypeFromMappedType(Type type)
|
||||
{{
|
||||
if (s_interfaceToRevit.TryGetValue(type, out var t))
|
||||
{{
|
||||
return t;
|
||||
}}
|
||||
|
||||
return null;
|
||||
}}
|
||||
|
||||
public static object CreateProxy(Type type, object toWrap) => s_proxyFactory[type](toWrap);
|
||||
public static T CreateProxy<T>(object toWrap) => (T)CreateProxy(typeof(T), toWrap);
|
||||
}}
|
||||
public static class MapsterAdapter
|
||||
{{
|
||||
public static TDestination? AdaptNull<TDestination>(object? source)
|
||||
{{
|
||||
if (source is null)
|
||||
{{
|
||||
return default;
|
||||
}}
|
||||
|
||||
return Mapster.TypeAdapter.Adapt<TDestination>(source);
|
||||
}}
|
||||
}}
|
||||
{supportsNullable.IIf("#nullable restore")}
|
||||
}}"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
using Speckle.ProxyGenerator.Models;
|
||||
|
||||
namespace Speckle.ProxyGenerator.FileGenerators;
|
||||
|
||||
internal interface IFileGenerator
|
||||
{
|
||||
FileData GenerateFile(List<ProxyMapItem> proxyMapItems, bool supportsNullable);
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
using Speckle.ProxyGenerator.Models;
|
||||
|
||||
namespace Speckle.ProxyGenerator.FileGenerators;
|
||||
|
||||
internal interface IFilesGenerator
|
||||
{
|
||||
IEnumerable<FileData> GenerateFiles();
|
||||
}
|
||||
@@ -1,321 +0,0 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Speckle.ProxyGenerator.Enums;
|
||||
using Speckle.ProxyGenerator.Extensions;
|
||||
using Speckle.ProxyGenerator.Models;
|
||||
using Speckle.ProxyGenerator.Types;
|
||||
using Speckle.ProxyGenerator.Utils;
|
||||
|
||||
namespace Speckle.ProxyGenerator.FileGenerators;
|
||||
|
||||
internal class PartialInterfacesGenerator : BaseGenerator, IFilesGenerator
|
||||
{
|
||||
private List<INamedTypeSymbol> _implementedInterfaces = new();
|
||||
|
||||
public PartialInterfacesGenerator(Context context, bool supportsNullable)
|
||||
: base(context, supportsNullable) { }
|
||||
|
||||
public IEnumerable<FileData> GenerateFiles()
|
||||
{
|
||||
foreach (var ci in Context.Candidates)
|
||||
{
|
||||
if (TryGenerateFile(ci.Key, ci.Value, out var file))
|
||||
{
|
||||
yield return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGenerateFile(
|
||||
InterfaceDeclarationSyntax ci,
|
||||
ProxyData pd,
|
||||
[NotNullWhen(true)] out FileData? fileData
|
||||
)
|
||||
{
|
||||
fileData = default;
|
||||
|
||||
if (
|
||||
!TryGetNamedTypeSymbolByFullName(
|
||||
[TypeKind.Interface],
|
||||
ci.Identifier.ToString(),
|
||||
pd.Usings,
|
||||
out var sourceInterfaceSymbol
|
||||
)
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
!TryGetNamedTypeSymbolByFullName(
|
||||
[TypeKind.Class, TypeKind.Struct],
|
||||
pd.FullMetadataTypeName,
|
||||
pd.Usings,
|
||||
out var targetClassSymbol
|
||||
)
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var interfaceName = ResolveInterfaceNameWithOptionalTypeConstraints(
|
||||
targetClassSymbol.Symbol,
|
||||
pd.ShortInterfaceName
|
||||
);
|
||||
|
||||
fileData = new FileData(
|
||||
$"{sourceInterfaceSymbol.Symbol.GetFullMetadataName()}.g.cs",
|
||||
CreatePartialInterfaceCode(
|
||||
pd.Namespace,
|
||||
targetClassSymbol,
|
||||
sourceInterfaceSymbol,
|
||||
interfaceName,
|
||||
pd
|
||||
)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private string CreatePartialInterfaceCode(
|
||||
string ns,
|
||||
ClassSymbol classSymbol,
|
||||
ClassSymbol interfaceSymbol,
|
||||
string interfaceName,
|
||||
ProxyData proxyData
|
||||
)
|
||||
{
|
||||
_implementedInterfaces.Clear();
|
||||
_implementedInterfaces.AddRange(
|
||||
classSymbol.Symbol.ResolveImplementedInterfaces(
|
||||
proxyData.Options.HasFlag(ImplementationOptions.ProxyBaseClasses),
|
||||
proxyData.Options.HasFlag(ImplementationOptions.ProxyInterfaces)
|
||||
)
|
||||
);
|
||||
if (proxyData.Options.HasFlag(ImplementationOptions.UseExtendedInterfaces))
|
||||
{
|
||||
var bases = interfaceSymbol
|
||||
.Symbol.ResolveBaseInterfaces(_implementedInterfaces)
|
||||
.ToList();
|
||||
if (
|
||||
bases.Count == 1
|
||||
&& proxyData.Options.HasFlag(ImplementationOptions.ProxyForBaseInterface)
|
||||
)
|
||||
{
|
||||
proxyData.FullQualifiedMappedTypeName =
|
||||
globalPrefix + bases.Single().GetFullMetadataName();
|
||||
}
|
||||
_implementedInterfaces.AddRange(bases);
|
||||
//don't readd self
|
||||
if (_implementedInterfaces.Contains(interfaceSymbol.Symbol))
|
||||
{
|
||||
_implementedInterfaces.Remove(interfaceSymbol.Symbol);
|
||||
}
|
||||
}
|
||||
|
||||
_implementedInterfaces = _implementedInterfaces.Distinct().ToList();
|
||||
var isNew = GetExtendsProxyData(
|
||||
classSymbol,
|
||||
proxyData.Options.HasFlag(ImplementationOptions.UseExtendedInterfaces)
|
||||
)
|
||||
.Any();
|
||||
|
||||
var implementedInterfacesNames = _implementedInterfaces
|
||||
.Select(i => i.ToFullyQualifiedDisplayString())
|
||||
.ToArray();
|
||||
var implements = implementedInterfacesNames.Any()
|
||||
? $" : {string.Join(", ", implementedInterfacesNames)}"
|
||||
: string.Empty;
|
||||
var @new = isNew ? "new " : string.Empty;
|
||||
var (namespaceStart, namespaceEnd) = NamespaceBuilder.Build(ns);
|
||||
var events = GenerateEvents(classSymbol, proxyData);
|
||||
var properties = GenerateProperties(classSymbol, proxyData);
|
||||
var methods = GenerateMethods(classSymbol, proxyData).TrimEnd();
|
||||
|
||||
return $@"//----------------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by https://github.com/specklesystems/ProxyGenerator.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
{SupportsNullable.IIf("#nullable enable")}
|
||||
using System;
|
||||
|
||||
{namespaceStart}
|
||||
public partial interface {interfaceName}{implements}
|
||||
{{
|
||||
{@new}{classSymbol} _Instance {{ get; }}
|
||||
|
||||
{events +
|
||||
properties +
|
||||
methods}
|
||||
}}
|
||||
{namespaceEnd}
|
||||
{SupportsNullable.IIf("#nullable restore")}";
|
||||
}
|
||||
|
||||
private Func<T, bool> InterfaceFilter<T>()
|
||||
where T : ISymbol
|
||||
{
|
||||
var hashSet = new HashSet<string>();
|
||||
foreach (var @interface in _implementedInterfaces)
|
||||
{
|
||||
var members = @interface.AllInterfaces.Aggregate(
|
||||
@interface.GetMembers(),
|
||||
(xs, x) => xs.AddRange(x.GetMembers())
|
||||
);
|
||||
foreach (var member in members)
|
||||
{
|
||||
hashSet.Add(member.Name);
|
||||
}
|
||||
}
|
||||
|
||||
// Member is not already implemented in another interface.
|
||||
return t => !hashSet.Contains(t.Name);
|
||||
}
|
||||
|
||||
private string GenerateProperties(ClassSymbol targetClassSymbol, ProxyData proxyData)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
|
||||
foreach (
|
||||
var property in MemberHelper.GetPublicProperties(
|
||||
targetClassSymbol,
|
||||
proxyData,
|
||||
InterfaceFilter<IPropertySymbol>()
|
||||
)
|
||||
)
|
||||
{
|
||||
var (_, type) = GetPropertyType(property, out var isReplaced);
|
||||
|
||||
var getterSetter = isReplaced
|
||||
? ToPropertyDetails(property, type)
|
||||
: ToPropertyDetails(property);
|
||||
if (getterSetter is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var propertyName = getterSetter.Value.PropertyName;
|
||||
|
||||
if (property.IsIndexer)
|
||||
{
|
||||
var methodParameters = GetMethodParameters(property.Parameters, true);
|
||||
propertyName = $"this[{string.Join(", ", methodParameters)}]";
|
||||
}
|
||||
|
||||
foreach (var attribute in property.GetAttributesAsList())
|
||||
{
|
||||
str.AppendLine($" {attribute}");
|
||||
}
|
||||
|
||||
str.AppendLine(
|
||||
$" {getterSetter.Value.PropertyType} {propertyName} {getterSetter.Value.GetSet}"
|
||||
);
|
||||
str.AppendLine();
|
||||
}
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
private string GenerateMethods(ClassSymbol targetClassSymbol, ProxyData proxyData)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
foreach (
|
||||
var method in MemberHelper.GetPublicMethods(
|
||||
targetClassSymbol,
|
||||
proxyData,
|
||||
InterfaceFilter<IMethodSymbol>()
|
||||
)
|
||||
)
|
||||
{
|
||||
var methodParameters = GetMethodParameters(method.Parameters, true);
|
||||
var whereStatement = GetWhereStatementFromMethod(method);
|
||||
|
||||
foreach (var attribute in method.GetAttributesAsList())
|
||||
{
|
||||
str.AppendLine($" {attribute}");
|
||||
}
|
||||
|
||||
var (_, type) = GetReplacedTypeAsString(method.ReturnType, null, out _);
|
||||
str.AppendLine(
|
||||
$" {type} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){whereStatement};"
|
||||
);
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
private string GenerateEvents(ClassSymbol targetClassSymbol, ProxyData proxyData)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
foreach (
|
||||
var @event in MemberHelper.GetPublicEvents(
|
||||
targetClassSymbol,
|
||||
proxyData,
|
||||
InterfaceFilter<IMethodSymbol>()
|
||||
)
|
||||
)
|
||||
{
|
||||
var ps = @event.First().Parameters.First();
|
||||
|
||||
string? type;
|
||||
if (ps.GetTypeEnum() == TypeEnum.Complex)
|
||||
{
|
||||
(_, type) = GetParameterType(ps, out _);
|
||||
}
|
||||
else
|
||||
{
|
||||
type = ps.Type.ToString();
|
||||
}
|
||||
|
||||
foreach (var attribute in ps.GetAttributesAsList())
|
||||
{
|
||||
str.AppendLine($" {attribute}");
|
||||
}
|
||||
|
||||
str.AppendLine($" event {type} {@event.Key.GetSanitizedName()};");
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
public (string PropertyType, string? PropertyName, string GetSet)? ToPropertyDetails(
|
||||
IPropertySymbol property,
|
||||
string? overrideType = null
|
||||
)
|
||||
{
|
||||
var getIsPublic = property.GetMethod.IsPublic();
|
||||
var setIsPublic = property.SetMethod.IsPublic();
|
||||
|
||||
if (!getIsPublic && !setIsPublic)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var get = getIsPublic ? "get; " : string.Empty;
|
||||
var set = setIsPublic ? "set; " : string.Empty;
|
||||
|
||||
string? type;
|
||||
if (!string.IsNullOrEmpty(overrideType))
|
||||
{
|
||||
type = overrideType;
|
||||
}
|
||||
else
|
||||
{
|
||||
(_, type) = FixType(
|
||||
property.Type.ToFullyQualifiedDisplayString(),
|
||||
property.NullableAnnotation,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
return (type!, property.GetSanitizedName(), $"{{ {get}{set}}}");
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using System.Text;
|
||||
using Speckle.ProxyGenerator.Extensions;
|
||||
|
||||
namespace Speckle.ProxyGenerator.FileGenerators;
|
||||
|
||||
internal partial class ProxyClassesGenerator
|
||||
{
|
||||
private string GenerateMapperConfigurationForMapster()
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
|
||||
foreach (var replacedType in Context.ReplacedTypes)
|
||||
{
|
||||
TryFindProxyDataByTypeName(replacedType.Key, out var fullTypeName);
|
||||
var classNameProxy =
|
||||
$"global::{fullTypeName!.NamespaceDot}{fullTypeName!.ShortMetadataName}Proxy";
|
||||
|
||||
var instance =
|
||||
$"instance{(replacedType.Key + replacedType.Value).GetDeterministicHashCodeAsString()}";
|
||||
var proxy =
|
||||
$"proxy{(replacedType.Value + replacedType.Key).GetDeterministicHashCodeAsString()}";
|
||||
|
||||
str.AppendLine(
|
||||
$" Mapster.TypeAdapterConfig<{replacedType.Key}, {replacedType.Value}>.NewConfig().ConstructUsing({instance} => new {classNameProxy}({instance}));"
|
||||
);
|
||||
str.AppendLine(
|
||||
$" Mapster.TypeAdapterConfig<{replacedType.Value}, {replacedType.Key}>.NewConfig().MapWith({proxy} => (({classNameProxy}) {proxy})._Instance);"
|
||||
);
|
||||
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Speckle.ProxyGenerator.Models;
|
||||
|
||||
internal record ClassSymbol(
|
||||
INamedTypeSymbol Symbol,
|
||||
List<INamedTypeSymbol> BaseTypes,
|
||||
List<INamedTypeSymbol> Interfaces
|
||||
)
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return Symbol.ToDisplayString(
|
||||
NullableFlowState.None,
|
||||
SymbolDisplayFormat.FullyQualifiedFormat
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace Speckle.ProxyGenerator.Models;
|
||||
|
||||
internal record FileData(string FileName, string Text);
|
||||
@@ -1,61 +0,0 @@
|
||||
using Speckle.ProxyGenerator.Types;
|
||||
|
||||
namespace Speckle.ProxyGenerator.Models;
|
||||
|
||||
internal class ProxyData
|
||||
{
|
||||
public string Namespace { get; }
|
||||
|
||||
public string NamespaceDot { get; }
|
||||
|
||||
public string ShortInterfaceName { get; }
|
||||
|
||||
private string _fullInterfaceName;
|
||||
public string FullInterfaceName => FullQualifiedMappedTypeName ?? _fullInterfaceName;
|
||||
|
||||
public string FullQualifiedTypeName { get; }
|
||||
|
||||
public string? FullQualifiedMappedTypeName { get; set; }
|
||||
|
||||
public string ShortMetadataName { get; }
|
||||
|
||||
public string FullMetadataTypeName { get; }
|
||||
|
||||
public List<string> Usings { get; }
|
||||
|
||||
public ImplementationOptions Options { get; }
|
||||
public ProxyClassAccessibility Accessibility { get; }
|
||||
public string[] MembersToIgnore { get; }
|
||||
|
||||
public ProxyData(
|
||||
string @namespace,
|
||||
string namespaceDot,
|
||||
string shortInterfaceName,
|
||||
string fullInterfaceName,
|
||||
string fullQualifiedTypeName,
|
||||
string shortMetadataTypeName,
|
||||
string fullMetadataTypeName,
|
||||
List<string> usings,
|
||||
ImplementationOptions options,
|
||||
ProxyClassAccessibility accessibility,
|
||||
string[] membersToIgnore
|
||||
)
|
||||
{
|
||||
Namespace = @namespace ?? throw new ArgumentNullException(nameof(@namespace));
|
||||
NamespaceDot = namespaceDot ?? throw new ArgumentNullException(nameof(namespaceDot));
|
||||
ShortInterfaceName =
|
||||
shortInterfaceName ?? throw new ArgumentNullException(nameof(shortInterfaceName));
|
||||
_fullInterfaceName =
|
||||
fullInterfaceName ?? throw new ArgumentNullException(nameof(fullInterfaceName));
|
||||
FullQualifiedTypeName =
|
||||
fullQualifiedTypeName ?? throw new ArgumentNullException(nameof(fullQualifiedTypeName));
|
||||
ShortMetadataName =
|
||||
shortMetadataTypeName ?? throw new ArgumentNullException(nameof(shortMetadataTypeName));
|
||||
FullMetadataTypeName =
|
||||
fullMetadataTypeName ?? throw new ArgumentNullException(nameof(fullMetadataTypeName));
|
||||
Usings = usings ?? throw new ArgumentNullException(nameof(usings));
|
||||
Options = options;
|
||||
Accessibility = accessibility;
|
||||
MembersToIgnore = membersToIgnore;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
namespace Speckle.ProxyGenerator.Types;
|
||||
|
||||
internal record ProxyInterfaceGeneratorAttributeArguments(
|
||||
string FullyQualifiedDisplayString,
|
||||
string MetadataName
|
||||
)
|
||||
{
|
||||
public ImplementationOptions? Options { get; set; }
|
||||
|
||||
public ProxyClassAccessibility Accessibility { get; set; }
|
||||
public string[] MembersToIgnore { get; set; } = [];
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
namespace Speckle.ProxyGenerator.Types;
|
||||
|
||||
[Flags]
|
||||
internal enum ProxyClassAccessibility
|
||||
{
|
||||
Public = 0,
|
||||
|
||||
Internal = 1
|
||||
}
|
||||
|
||||
[Flags]
|
||||
internal enum ImplementationOptions
|
||||
{
|
||||
None = 0,
|
||||
|
||||
ProxyBaseClasses = 1,
|
||||
|
||||
ProxyInterfaces = 2,
|
||||
|
||||
UseExtendedInterfaces = 4,
|
||||
|
||||
ProxyForBaseInterface = 8
|
||||
}
|
||||
@@ -2,7 +2,7 @@ using CSharp.SourceGenerators.Extensions;
|
||||
using CSharp.SourceGenerators.Extensions.Models;
|
||||
using CultureAwareTesting.xUnit;
|
||||
using FluentAssertions;
|
||||
using Speckle.ProxyGenerator;
|
||||
using ProxyInterfaceSourceGenerator;
|
||||
|
||||
namespace ProxyInterfaceSourceGeneratorTests;
|
||||
|
||||
@@ -34,17 +34,16 @@ public class AkkaTests
|
||||
Text = File.ReadAllText(path),
|
||||
AttributeToAddToInterface = new ExtraAttribute
|
||||
{
|
||||
Name = "Speckle.ProxyGenerator.Proxy",
|
||||
ArgumentList = new[]
|
||||
{
|
||||
"typeof(Akka.Actor.LocalActorRefProvider)",
|
||||
"ImplementationOptions.ProxyInterfaces"
|
||||
}
|
||||
Name = "ProxyInterfaceGenerator.Proxy",
|
||||
ArgumentList = "typeof(Akka.Actor.LocalActorRefProvider)"
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _sut.Execute(new[] { sourceFile });
|
||||
var result = _sut.Execute(new[]
|
||||
{
|
||||
sourceFile
|
||||
});
|
||||
|
||||
// Assert
|
||||
result.Valid.Should().BeTrue();
|
||||
@@ -52,17 +51,11 @@ public class AkkaTests
|
||||
|
||||
foreach (var fileName in fileNames.Select((fileName, index) => new { fileName, index }))
|
||||
{
|
||||
var builder = result.Files[fileName.index]; // attribute is last
|
||||
var builder = result.Files[fileName.index + 1]; // +1 means skip the attribute
|
||||
builder.Path.Should().EndWith(fileName.fileName);
|
||||
|
||||
if (Write)
|
||||
File.WriteAllText(
|
||||
$"../../../Destination/AkkaGenerated/{fileName.fileName}",
|
||||
builder.Text
|
||||
);
|
||||
builder
|
||||
.Text.Should()
|
||||
.Be(File.ReadAllText($"../../../Destination/AkkaGenerated/{fileName.fileName}"));
|
||||
if (Write) File.WriteAllText($"../../../Destination/AkkaGenerated/{fileName.fileName}", builder.Text);
|
||||
builder.Text.Should().Be(File.ReadAllText($"../../../Destination/AkkaGenerated/{fileName.fileName}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -1,6 +1,6 @@
|
||||
//----------------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by https://github.com/specklesystems/ProxyGenerator.
|
||||
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -130,8 +130,9 @@ namespace ProxyInterfaceSourceGeneratorTests.Source.AkkaActor
|
||||
{
|
||||
_Instance = instance;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#nullable restore
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//----------------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by https://github.com/specklesystems/ProxyGenerator.
|
||||
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//----------------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by https://github.com/specklesystems/ProxyGenerator.
|
||||
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
|
||||
+3
-5
@@ -1,6 +1,6 @@
|
||||
//----------------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by https://github.com/specklesystems/ProxyGenerator.
|
||||
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -46,10 +46,7 @@ namespace ProxyInterfaceSourceGeneratorTests.Source.PnP
|
||||
{
|
||||
_Instance = instance;
|
||||
_InstanceClientRuntimeContext = instance;
|
||||
}
|
||||
|
||||
static ClientContextProxy()
|
||||
{
|
||||
Mapster.TypeAdapterConfig<global::Microsoft.SharePoint.Client.ClientRuntimeContext, global::ProxyInterfaceSourceGeneratorTests.Source.PnP.IClientRuntimeContext>.NewConfig().ConstructUsing(instance_572349648 => new global::ProxyInterfaceSourceGeneratorTests.Source.PnP.ClientRuntimeContextProxy(instance_572349648));
|
||||
Mapster.TypeAdapterConfig<global::ProxyInterfaceSourceGeneratorTests.Source.PnP.IClientRuntimeContext, global::Microsoft.SharePoint.Client.ClientRuntimeContext>.NewConfig().MapWith(proxy214349770 => ((global::ProxyInterfaceSourceGeneratorTests.Source.PnP.ClientRuntimeContextProxy) proxy214349770)._Instance);
|
||||
|
||||
@@ -64,8 +61,9 @@ namespace ProxyInterfaceSourceGeneratorTests.Source.PnP
|
||||
|
||||
Mapster.TypeAdapterConfig<global::Microsoft.SharePoint.Client.Web, global::ProxyInterfaceSourceGeneratorTests.Source.PnP.IWeb>.NewConfig().ConstructUsing(instance290679610 => new global::ProxyInterfaceSourceGeneratorTests.Source.PnP.WebProxy(instance290679610));
|
||||
Mapster.TypeAdapterConfig<global::ProxyInterfaceSourceGeneratorTests.Source.PnP.IWeb, global::Microsoft.SharePoint.Client.Web>.NewConfig().MapWith(proxy_1534869484 => ((global::ProxyInterfaceSourceGeneratorTests.Source.PnP.WebProxy) proxy_1534869484)._Instance);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#nullable restore
|
||||
+3
-5
@@ -1,6 +1,6 @@
|
||||
//----------------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by https://github.com/specklesystems/ProxyGenerator.
|
||||
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -83,17 +83,15 @@ namespace ProxyInterfaceSourceGeneratorTests.Source.PnP
|
||||
{
|
||||
_Instance = instance;
|
||||
|
||||
}
|
||||
|
||||
static ClientObjectProxy()
|
||||
{
|
||||
Mapster.TypeAdapterConfig<global::Microsoft.SharePoint.Client.ClientRuntimeContext, global::ProxyInterfaceSourceGeneratorTests.Source.PnP.IClientRuntimeContext>.NewConfig().ConstructUsing(instance_572349648 => new global::ProxyInterfaceSourceGeneratorTests.Source.PnP.ClientRuntimeContextProxy(instance_572349648));
|
||||
Mapster.TypeAdapterConfig<global::ProxyInterfaceSourceGeneratorTests.Source.PnP.IClientRuntimeContext, global::Microsoft.SharePoint.Client.ClientRuntimeContext>.NewConfig().MapWith(proxy214349770 => ((global::ProxyInterfaceSourceGeneratorTests.Source.PnP.ClientRuntimeContextProxy) proxy214349770)._Instance);
|
||||
|
||||
Mapster.TypeAdapterConfig<global::Microsoft.SharePoint.Client.ClientObject, global::ProxyInterfaceSourceGeneratorTests.Source.PnP.IClientObject>.NewConfig().ConstructUsing(instance_205438316 => new global::ProxyInterfaceSourceGeneratorTests.Source.PnP.ClientObjectProxy(instance_205438316));
|
||||
Mapster.TypeAdapterConfig<global::ProxyInterfaceSourceGeneratorTests.Source.PnP.IClientObject, global::Microsoft.SharePoint.Client.ClientObject>.NewConfig().MapWith(proxy_437526006 => ((global::ProxyInterfaceSourceGeneratorTests.Source.PnP.ClientObjectProxy) proxy_437526006)._Instance);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#nullable restore
|
||||
+3
-5
@@ -1,6 +1,6 @@
|
||||
//----------------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by https://github.com/specklesystems/ProxyGenerator.
|
||||
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -141,10 +141,7 @@ namespace ProxyInterfaceSourceGeneratorTests.Source.PnP
|
||||
{
|
||||
_Instance = instance;
|
||||
|
||||
}
|
||||
|
||||
static ClientRuntimeContextProxy()
|
||||
{
|
||||
Mapster.TypeAdapterConfig<global::Microsoft.SharePoint.Client.ClientRuntimeContext, global::ProxyInterfaceSourceGeneratorTests.Source.PnP.IClientRuntimeContext>.NewConfig().ConstructUsing(instance_572349648 => new global::ProxyInterfaceSourceGeneratorTests.Source.PnP.ClientRuntimeContextProxy(instance_572349648));
|
||||
Mapster.TypeAdapterConfig<global::ProxyInterfaceSourceGeneratorTests.Source.PnP.IClientRuntimeContext, global::Microsoft.SharePoint.Client.ClientRuntimeContext>.NewConfig().MapWith(proxy214349770 => ((global::ProxyInterfaceSourceGeneratorTests.Source.PnP.ClientRuntimeContextProxy) proxy214349770)._Instance);
|
||||
|
||||
@@ -156,8 +153,9 @@ namespace ProxyInterfaceSourceGeneratorTests.Source.PnP
|
||||
|
||||
Mapster.TypeAdapterConfig<global::Microsoft.SharePoint.Client.ClientContext, global::ProxyInterfaceSourceGeneratorTests.Source.PnP.IClientContext>.NewConfig().ConstructUsing(instance_1483513702 => new global::ProxyInterfaceSourceGeneratorTests.Source.PnP.ClientContextProxy(instance_1483513702));
|
||||
Mapster.TypeAdapterConfig<global::ProxyInterfaceSourceGeneratorTests.Source.PnP.IClientContext, global::Microsoft.SharePoint.Client.ClientContext>.NewConfig().MapWith(proxy343311664 => ((global::ProxyInterfaceSourceGeneratorTests.Source.PnP.ClientContextProxy) proxy343311664)._Instance);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#nullable restore
|
||||
+3
-5
@@ -1,6 +1,6 @@
|
||||
//----------------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by https://github.com/specklesystems/ProxyGenerator.
|
||||
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -44,10 +44,7 @@ namespace ProxyInterfaceSourceGeneratorTests.Source.PnP
|
||||
{
|
||||
_Instance = instance;
|
||||
_InstanceClientObject = instance;
|
||||
}
|
||||
|
||||
static SecurableObjectProxy()
|
||||
{
|
||||
Mapster.TypeAdapterConfig<global::Microsoft.SharePoint.Client.ClientRuntimeContext, global::ProxyInterfaceSourceGeneratorTests.Source.PnP.IClientRuntimeContext>.NewConfig().ConstructUsing(instance_572349648 => new global::ProxyInterfaceSourceGeneratorTests.Source.PnP.ClientRuntimeContextProxy(instance_572349648));
|
||||
Mapster.TypeAdapterConfig<global::ProxyInterfaceSourceGeneratorTests.Source.PnP.IClientRuntimeContext, global::Microsoft.SharePoint.Client.ClientRuntimeContext>.NewConfig().MapWith(proxy214349770 => ((global::ProxyInterfaceSourceGeneratorTests.Source.PnP.ClientRuntimeContextProxy) proxy214349770)._Instance);
|
||||
|
||||
@@ -56,8 +53,9 @@ namespace ProxyInterfaceSourceGeneratorTests.Source.PnP
|
||||
|
||||
Mapster.TypeAdapterConfig<global::Microsoft.SharePoint.Client.SecurableObject, global::ProxyInterfaceSourceGeneratorTests.Source.PnP.ISecurableObject>.NewConfig().ConstructUsing(instance_247129254 => new global::ProxyInterfaceSourceGeneratorTests.Source.PnP.SecurableObjectProxy(instance_247129254));
|
||||
Mapster.TypeAdapterConfig<global::ProxyInterfaceSourceGeneratorTests.Source.PnP.ISecurableObject, global::Microsoft.SharePoint.Client.SecurableObject>.NewConfig().MapWith(proxy_117192422 => ((global::ProxyInterfaceSourceGeneratorTests.Source.PnP.SecurableObjectProxy) proxy_117192422)._Instance);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#nullable restore
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user