@sun-asterisk/sunlint 1.3.43 → 1.3.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dart_analyzer/README.md +226 -0
- package/dart_analyzer/analysis_options.yaml +66 -0
- package/dart_analyzer/bin/sunlint-dart-macos +0 -0
- package/dart_analyzer/bin/sunlint_dart_analyzer.dart +124 -0
- package/dart_analyzer/lib/analyzer_service.dart +625 -0
- package/dart_analyzer/lib/json_rpc_server.dart +275 -0
- package/dart_analyzer/lib/models/rule.dart +67 -0
- package/dart_analyzer/lib/models/symbol_table.dart +607 -0
- package/dart_analyzer/lib/models/violation.dart +69 -0
- package/dart_analyzer/lib/rules/base_analyzer.dart +52 -0
- package/dart_analyzer/lib/rules/common/C002_no_duplicate_code.dart +344 -0
- package/dart_analyzer/lib/rules/common/C003_no_vague_abbreviations.dart +318 -0
- package/dart_analyzer/lib/rules/common/C006_function_naming.dart +219 -0
- package/dart_analyzer/lib/rules/common/C008_variable_declaration_locality.dart +205 -0
- package/dart_analyzer/lib/rules/common/C010_limit_block_nesting.dart +162 -0
- package/dart_analyzer/lib/rules/common/C012_command_query_separation.dart +214 -0
- package/dart_analyzer/lib/rules/common/C013_no_dead_code.dart +225 -0
- package/dart_analyzer/lib/rules/common/C014_dependency_injection.dart +249 -0
- package/dart_analyzer/lib/rules/common/C017_constructor_logic.dart +158 -0
- package/dart_analyzer/lib/rules/common/C018_no_throw_generic_error.dart +141 -0
- package/dart_analyzer/lib/rules/common/C019_log_level_usage.dart +165 -0
- package/dart_analyzer/lib/rules/common/C020_unused_imports.dart +128 -0
- package/dart_analyzer/lib/rules/common/C021_import_organization.dart +86 -0
- package/dart_analyzer/lib/rules/common/C023_no_duplicate_variable.dart +112 -0
- package/dart_analyzer/lib/rules/common/C024_no_scatter_hardcoded_constants.dart +79 -0
- package/dart_analyzer/lib/rules/common/C029_catch_block_logging.dart +81 -0
- package/dart_analyzer/lib/rules/common/C030_use_custom_error_classes.dart +77 -0
- package/dart_analyzer/lib/rules/common/C031_validation_separation.dart +90 -0
- package/dart_analyzer/lib/rules/common/C033_separate_service_repository.dart +80 -0
- package/dart_analyzer/lib/rules/common/C035_error_logging_context.dart +148 -0
- package/dart_analyzer/lib/rules/common/C040_centralized_validation.dart +84 -0
- package/dart_analyzer/lib/rules/common/C041_no_sensitive_hardcode.dart +103 -0
- package/dart_analyzer/lib/rules/common/C042_boolean_name_prefix.dart +105 -0
- package/dart_analyzer/lib/rules/common/C043_no_console_or_print.dart +101 -0
- package/dart_analyzer/lib/rules/common/C047_no_duplicate_retry_logic.dart +94 -0
- package/dart_analyzer/lib/rules/common/C048_no_bypass_architectural_layers.dart +132 -0
- package/dart_analyzer/lib/rules/common/C052_parsing_or_data_transformation.dart +95 -0
- package/dart_analyzer/lib/rules/common/C060_no_override_superclass.dart +81 -0
- package/dart_analyzer/lib/rules/common/C065_one_behavior_per_test.dart +83 -0
- package/dart_analyzer/lib/rules/common/C067_no_hardcoded_config.dart +89 -0
- package/dart_analyzer/lib/rules/common/C070_no_real_time_tests.dart +99 -0
- package/dart_analyzer/lib/rules/common/C072_single_test_behavior.dart +78 -0
- package/dart_analyzer/lib/rules/common/C073_validate_required_config_on_startup.dart +82 -0
- package/dart_analyzer/lib/rules/common/C075_explicit_return_types.dart +85 -0
- package/dart_analyzer/lib/rules/common/C076_explicit_function_types.dart +104 -0
- package/dart_analyzer/lib/rules/dart/D001_recommended_lint_rules.dart +309 -0
- package/dart_analyzer/lib/rules/dart/D002_dispose_resources.dart +338 -0
- package/dart_analyzer/lib/rules/dart/D003_prefer_widgets_over_methods.dart +273 -0
- package/dart_analyzer/lib/rules/dart/D004_avoid_shrinkwrap_listview.dart +154 -0
- package/dart_analyzer/lib/rules/dart/D005_limit_widget_nesting.dart +265 -0
- package/dart_analyzer/lib/rules/dart/D006_prefer_extracting_large_callbacks.dart +135 -0
- package/dart_analyzer/lib/rules/dart/D007_prefer_init_first_dispose_last.dart +150 -0
- package/dart_analyzer/lib/rules/dart/D008_avoid_long_functions.dart +394 -0
- package/dart_analyzer/lib/rules/dart/D009_limit_function_parameters.dart +179 -0
- package/dart_analyzer/lib/rules/dart/D010_limit_cyclomatic_complexity.dart +257 -0
- package/dart_analyzer/lib/rules/dart/D011_prefer_named_parameters.dart +152 -0
- package/dart_analyzer/lib/rules/dart/D012_prefer_named_boolean_parameters.dart +156 -0
- package/dart_analyzer/lib/rules/dart/D013_single_public_class.dart +246 -0
- package/dart_analyzer/lib/rules/dart/D014_unsafe_collection_access.dart +202 -0
- package/dart_analyzer/lib/rules/dart/D015_copywith_all_parameters.dart +125 -0
- package/dart_analyzer/lib/rules/dart/D016_project_should_have_tests.dart +134 -0
- package/dart_analyzer/lib/rules/dart/D017_pubspec_dependencies_review.dart +187 -0
- package/dart_analyzer/lib/rules/dart/D018_remove_commented_code.dart +196 -0
- package/dart_analyzer/lib/rules/dart/D019_avoid_single_child_multi_child_widget.dart +161 -0
- package/dart_analyzer/lib/rules/dart/D020_limit_if_else_branches.dart +125 -0
- package/dart_analyzer/lib/rules/dart/D021_avoid_negated_boolean_checks.dart +227 -0
- package/dart_analyzer/lib/rules/dart/D022_use_setstate_correctly.dart +269 -0
- package/dart_analyzer/lib/rules/dart/D023_avoid_unnecessary_method_overrides.dart +191 -0
- package/dart_analyzer/lib/rules/dart/D024_avoid_unnecessary_stateful_widget.dart +194 -0
- package/dart_analyzer/lib/rules/dart/D025_avoid_nested_conditional_expressions.dart +90 -0
- package/dart_analyzer/lib/rules/security/S001_backend_auth_communications.dart +155 -0
- package/dart_analyzer/lib/rules/security/S002_os_command_injection.dart +159 -0
- package/dart_analyzer/lib/rules/security/S003_open_redirect_protection.dart +208 -0
- package/dart_analyzer/lib/rules/security/S004_sensitive_data_logging.dart +391 -0
- package/dart_analyzer/lib/rules/security/S005_trusted_service_authorization.dart +182 -0
- package/dart_analyzer/lib/rules/security/S006_no_default_credentials.dart +208 -0
- package/dart_analyzer/lib/rules/security/S007_output_encoding.dart +224 -0
- package/dart_analyzer/lib/rules/security/S008_svg_content_sanitization.dart +211 -0
- package/dart_analyzer/lib/rules/security/S009_no_insecure_encryption.dart +160 -0
- package/dart_analyzer/lib/rules/security/S010_use_csprng.dart +184 -0
- package/dart_analyzer/lib/rules/security/S011_ech_tls_config.dart +175 -0
- package/dart_analyzer/lib/rules/security/S012_hardcoded_secrets.dart +255 -0
- package/dart_analyzer/lib/rules/security/S013_tls_enforcement.dart +148 -0
- package/dart_analyzer/lib/rules/security/S014_tls_version_enforcement.dart +117 -0
- package/dart_analyzer/lib/rules/security/S015_insecure_tls_certificate.dart +315 -0
- package/dart_analyzer/lib/rules/security/S016_no_sensitive_querystring.dart +244 -0
- package/dart_analyzer/lib/rules/security/S017_use_parameterized_queries.dart +191 -0
- package/dart_analyzer/lib/rules/security/S018_no_sensitive_browser_storage.dart +175 -0
- package/dart_analyzer/lib/rules/security/S019_smtp_injection_protection.dart +166 -0
- package/dart_analyzer/lib/rules/security/S020_no_eval_dynamic_code.dart +149 -0
- package/dart_analyzer/lib/rules/security/S021_referrer_policy.dart +146 -0
- package/dart_analyzer/lib/rules/security/S022_escape_output_context.dart +111 -0
- package/dart_analyzer/lib/rules/security/S023_no_json_injection.dart +550 -0
- package/dart_analyzer/lib/rules/security/S024_xpath_xxe_protection.dart +299 -0
- package/dart_analyzer/lib/rules/security/S025_server_side_validation.dart +140 -0
- package/dart_analyzer/lib/rules/security/S026_tls_all_connections.dart +196 -0
- package/dart_analyzer/lib/rules/security/S027_mtls_certificate_validation.dart +195 -0
- package/dart_analyzer/lib/rules/security/S028_file_upload_size_limits.dart +186 -0
- package/dart_analyzer/lib/rules/security/S029_csrf_protection.dart +171 -0
- package/dart_analyzer/lib/rules/security/S030_directory_browsing_protection.dart +144 -0
- package/dart_analyzer/lib/rules/security/S031_secure_session_cookies.dart +118 -0
- package/dart_analyzer/lib/rules/security/S032_httponly_session_cookies.dart +114 -0
- package/dart_analyzer/lib/rules/security/S033_samesite_session_cookies.dart +120 -0
- package/dart_analyzer/lib/rules/security/S034_host_prefix_session_cookies.dart +160 -0
- package/dart_analyzer/lib/rules/security/S035_separate_app_hostnames.dart +117 -0
- package/dart_analyzer/lib/rules/security/S036_lfi_rfi_protection.dart +188 -0
- package/dart_analyzer/lib/rules/security/S037_cache_headers.dart +113 -0
- package/dart_analyzer/lib/rules/security/S038_no_version_headers.dart +114 -0
- package/dart_analyzer/lib/rules/security/S039_tls_certificate_validation.dart +131 -0
- package/dart_analyzer/lib/rules/security/S040_session_fixation_protection.dart +155 -0
- package/dart_analyzer/lib/rules/security/S041_session_token_invalidation.dart +201 -0
- package/dart_analyzer/lib/rules/security/S042_require_re_authentication_for_long_lived.dart +158 -0
- package/dart_analyzer/lib/rules/security/S043_password_changes_invalidate_all_sessions.dart +88 -0
- package/dart_analyzer/lib/rules/security/S044_re_authentication_required.dart +119 -0
- package/dart_analyzer/lib/rules/security/S045_brute_force_protection.dart +253 -0
- package/dart_analyzer/lib/rules/security/S046_jwt_algorithm_allowlist.dart +113 -0
- package/dart_analyzer/lib/rules/security/S047_oauth_pkce_protection.dart +124 -0
- package/dart_analyzer/lib/rules/security/S048_oauth_redirect_uri_validation.dart +134 -0
- package/dart_analyzer/lib/rules/security/S049_short_validity_tokens.dart +145 -0
- package/dart_analyzer/lib/rules/security/S050_reference_tokens_entropy.dart +234 -0
- package/dart_analyzer/lib/rules/security/S051_password_length_policy.dart +171 -0
- package/dart_analyzer/lib/rules/security/S052_weak_otp_entropy.dart +107 -0
- package/dart_analyzer/lib/rules/security/S053_generic_error_messages.dart +159 -0
- package/dart_analyzer/lib/rules/security/S054_no_default_accounts.dart +141 -0
- package/dart_analyzer/lib/rules/security/S055_content_type_validation.dart +324 -0
- package/dart_analyzer/lib/rules/security/S056_log_injection_protection.dart +119 -0
- package/dart_analyzer/lib/rules/security/S057_utc_logging.dart +114 -0
- package/dart_analyzer/lib/rules/security/S058_no_ssrf.dart +175 -0
- package/dart_analyzer/lib/rules/security/S059_disable_debug_mode.dart +172 -0
- package/dart_analyzer/lib/rules/security/S060_password_minimum_length.dart +170 -0
- package/dart_analyzer/lib/symbol_table_extractor.dart +510 -0
- package/dart_analyzer/lib/utils/common_utils.dart +26 -0
- package/dart_analyzer/pubspec.lock +557 -0
- package/dart_analyzer/pubspec.yaml +39 -0
- package/dart_analyzer/test/fixtures/complex_code.dart +95 -0
- package/docs/GENERATED_FILE_HANDLING_SUMMARY.md +2 -2
- package/package.json +3 -2
|
@@ -0,0 +1,607 @@
|
|
|
1
|
+
/// Represents a symbol table for a Dart file
|
|
2
|
+
/// Compatible with SunLint's TypeScript symbol table structure
|
|
3
|
+
class SymbolTable {
|
|
4
|
+
/// Absolute path to the file
|
|
5
|
+
final String filePath;
|
|
6
|
+
|
|
7
|
+
/// Base name of the file
|
|
8
|
+
final String fileName;
|
|
9
|
+
|
|
10
|
+
/// Import declarations
|
|
11
|
+
final List<ImportInfo> imports;
|
|
12
|
+
|
|
13
|
+
/// Export declarations
|
|
14
|
+
final List<ExportInfo> exports;
|
|
15
|
+
|
|
16
|
+
/// Function declarations
|
|
17
|
+
final List<FunctionInfo> functions;
|
|
18
|
+
|
|
19
|
+
/// Class declarations
|
|
20
|
+
final List<ClassInfo> classes;
|
|
21
|
+
|
|
22
|
+
/// Mixin declarations
|
|
23
|
+
final List<MixinInfo> mixins;
|
|
24
|
+
|
|
25
|
+
/// Extension declarations
|
|
26
|
+
final List<ExtensionInfo> extensions;
|
|
27
|
+
|
|
28
|
+
/// Enum declarations
|
|
29
|
+
final List<EnumInfo> enums;
|
|
30
|
+
|
|
31
|
+
/// Top-level variable declarations
|
|
32
|
+
final List<VariableInfo> variables;
|
|
33
|
+
|
|
34
|
+
/// Top-level constant declarations
|
|
35
|
+
final List<ConstantInfo> constants;
|
|
36
|
+
|
|
37
|
+
/// Function call expressions
|
|
38
|
+
final List<FunctionCallInfo> functionCalls;
|
|
39
|
+
|
|
40
|
+
/// Method call expressions
|
|
41
|
+
final List<MethodCallInfo> methodCalls;
|
|
42
|
+
|
|
43
|
+
/// Timestamp
|
|
44
|
+
final int lastModified;
|
|
45
|
+
|
|
46
|
+
/// Analysis duration in ms
|
|
47
|
+
final int analysisTime;
|
|
48
|
+
|
|
49
|
+
SymbolTable({
|
|
50
|
+
required this.filePath,
|
|
51
|
+
required this.fileName,
|
|
52
|
+
this.imports = const [],
|
|
53
|
+
this.exports = const [],
|
|
54
|
+
this.functions = const [],
|
|
55
|
+
this.classes = const [],
|
|
56
|
+
this.mixins = const [],
|
|
57
|
+
this.extensions = const [],
|
|
58
|
+
this.enums = const [],
|
|
59
|
+
this.variables = const [],
|
|
60
|
+
this.constants = const [],
|
|
61
|
+
this.functionCalls = const [],
|
|
62
|
+
this.methodCalls = const [],
|
|
63
|
+
required this.lastModified,
|
|
64
|
+
required this.analysisTime,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
Map<String, dynamic> toJson() => {
|
|
68
|
+
'filePath': filePath,
|
|
69
|
+
'fileName': fileName,
|
|
70
|
+
'imports': imports.map((e) => e.toJson()).toList(),
|
|
71
|
+
'exports': exports.map((e) => e.toJson()).toList(),
|
|
72
|
+
'functions': functions.map((e) => e.toJson()).toList(),
|
|
73
|
+
'classes': classes.map((e) => e.toJson()).toList(),
|
|
74
|
+
'mixins': mixins.map((e) => e.toJson()).toList(),
|
|
75
|
+
'extensions': extensions.map((e) => e.toJson()).toList(),
|
|
76
|
+
'enums': enums.map((e) => e.toJson()).toList(),
|
|
77
|
+
'variables': variables.map((e) => e.toJson()).toList(),
|
|
78
|
+
'constants': constants.map((e) => e.toJson()).toList(),
|
|
79
|
+
'functionCalls': functionCalls.map((e) => e.toJson()).toList(),
|
|
80
|
+
'methodCalls': methodCalls.map((e) => e.toJson()).toList(),
|
|
81
|
+
'lastModified': lastModified,
|
|
82
|
+
'analysisTime': analysisTime,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/// Import declaration info
|
|
87
|
+
class ImportInfo {
|
|
88
|
+
final String uri;
|
|
89
|
+
final String? prefix;
|
|
90
|
+
final List<String> showNames;
|
|
91
|
+
final List<String> hideNames;
|
|
92
|
+
final int line;
|
|
93
|
+
final bool isDeferred;
|
|
94
|
+
|
|
95
|
+
ImportInfo({
|
|
96
|
+
required this.uri,
|
|
97
|
+
this.prefix,
|
|
98
|
+
this.showNames = const [],
|
|
99
|
+
this.hideNames = const [],
|
|
100
|
+
required this.line,
|
|
101
|
+
this.isDeferred = false,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
Map<String, dynamic> toJson() => {
|
|
105
|
+
'uri': uri,
|
|
106
|
+
if (prefix != null) 'prefix': prefix,
|
|
107
|
+
if (showNames.isNotEmpty) 'showNames': showNames,
|
|
108
|
+
if (hideNames.isNotEmpty) 'hideNames': hideNames,
|
|
109
|
+
'line': line,
|
|
110
|
+
if (isDeferred) 'isDeferred': isDeferred,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/// Export declaration info
|
|
115
|
+
class ExportInfo {
|
|
116
|
+
final String uri;
|
|
117
|
+
final List<String> showNames;
|
|
118
|
+
final List<String> hideNames;
|
|
119
|
+
final int line;
|
|
120
|
+
|
|
121
|
+
ExportInfo({
|
|
122
|
+
required this.uri,
|
|
123
|
+
this.showNames = const [],
|
|
124
|
+
this.hideNames = const [],
|
|
125
|
+
required this.line,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
Map<String, dynamic> toJson() => {
|
|
129
|
+
'uri': uri,
|
|
130
|
+
if (showNames.isNotEmpty) 'showNames': showNames,
|
|
131
|
+
if (hideNames.isNotEmpty) 'hideNames': hideNames,
|
|
132
|
+
'line': line,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/// Function declaration info
|
|
137
|
+
class FunctionInfo {
|
|
138
|
+
final String name;
|
|
139
|
+
final String? returnType;
|
|
140
|
+
final List<ParameterInfo> parameters;
|
|
141
|
+
final int line;
|
|
142
|
+
final int column;
|
|
143
|
+
final bool isAsync;
|
|
144
|
+
final bool isGenerator;
|
|
145
|
+
final bool isExternal;
|
|
146
|
+
final String? documentation;
|
|
147
|
+
|
|
148
|
+
FunctionInfo({
|
|
149
|
+
required this.name,
|
|
150
|
+
this.returnType,
|
|
151
|
+
this.parameters = const [],
|
|
152
|
+
required this.line,
|
|
153
|
+
required this.column,
|
|
154
|
+
this.isAsync = false,
|
|
155
|
+
this.isGenerator = false,
|
|
156
|
+
this.isExternal = false,
|
|
157
|
+
this.documentation,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
Map<String, dynamic> toJson() => {
|
|
161
|
+
'name': name,
|
|
162
|
+
if (returnType != null) 'returnType': returnType,
|
|
163
|
+
'parameters': parameters.map((e) => e.toJson()).toList(),
|
|
164
|
+
'line': line,
|
|
165
|
+
'column': column,
|
|
166
|
+
if (isAsync) 'isAsync': isAsync,
|
|
167
|
+
if (isGenerator) 'isGenerator': isGenerator,
|
|
168
|
+
if (isExternal) 'isExternal': isExternal,
|
|
169
|
+
if (documentation != null) 'documentation': documentation,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/// Parameter info
|
|
174
|
+
class ParameterInfo {
|
|
175
|
+
final String name;
|
|
176
|
+
final String? type;
|
|
177
|
+
final bool isRequired;
|
|
178
|
+
final bool isNamed;
|
|
179
|
+
final bool isOptional;
|
|
180
|
+
final String? defaultValue;
|
|
181
|
+
|
|
182
|
+
ParameterInfo({
|
|
183
|
+
required this.name,
|
|
184
|
+
this.type,
|
|
185
|
+
this.isRequired = true,
|
|
186
|
+
this.isNamed = false,
|
|
187
|
+
this.isOptional = false,
|
|
188
|
+
this.defaultValue,
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
Map<String, dynamic> toJson() => {
|
|
192
|
+
'name': name,
|
|
193
|
+
if (type != null) 'type': type,
|
|
194
|
+
if (!isRequired) 'isRequired': isRequired,
|
|
195
|
+
if (isNamed) 'isNamed': isNamed,
|
|
196
|
+
if (isOptional) 'isOptional': isOptional,
|
|
197
|
+
if (defaultValue != null) 'defaultValue': defaultValue,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/// Class declaration info
|
|
202
|
+
class ClassInfo {
|
|
203
|
+
final String name;
|
|
204
|
+
final String? superclass;
|
|
205
|
+
final List<String> interfaces;
|
|
206
|
+
final List<String> mixins;
|
|
207
|
+
final List<String> typeParameters;
|
|
208
|
+
final List<MethodInfo> methods;
|
|
209
|
+
final List<FieldInfo> fields;
|
|
210
|
+
final List<ConstructorInfo> constructors;
|
|
211
|
+
final int line;
|
|
212
|
+
final int column;
|
|
213
|
+
final bool isAbstract;
|
|
214
|
+
final bool isSealed;
|
|
215
|
+
final bool isFinal;
|
|
216
|
+
final bool isBase;
|
|
217
|
+
final bool isInterface;
|
|
218
|
+
final bool isMixin;
|
|
219
|
+
final String? documentation;
|
|
220
|
+
|
|
221
|
+
ClassInfo({
|
|
222
|
+
required this.name,
|
|
223
|
+
this.superclass,
|
|
224
|
+
this.interfaces = const [],
|
|
225
|
+
this.mixins = const [],
|
|
226
|
+
this.typeParameters = const [],
|
|
227
|
+
this.methods = const [],
|
|
228
|
+
this.fields = const [],
|
|
229
|
+
this.constructors = const [],
|
|
230
|
+
required this.line,
|
|
231
|
+
required this.column,
|
|
232
|
+
this.isAbstract = false,
|
|
233
|
+
this.isSealed = false,
|
|
234
|
+
this.isFinal = false,
|
|
235
|
+
this.isBase = false,
|
|
236
|
+
this.isInterface = false,
|
|
237
|
+
this.isMixin = false,
|
|
238
|
+
this.documentation,
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
Map<String, dynamic> toJson() => {
|
|
242
|
+
'name': name,
|
|
243
|
+
if (superclass != null) 'superclass': superclass,
|
|
244
|
+
if (interfaces.isNotEmpty) 'interfaces': interfaces,
|
|
245
|
+
if (mixins.isNotEmpty) 'mixins': mixins,
|
|
246
|
+
if (typeParameters.isNotEmpty) 'typeParameters': typeParameters,
|
|
247
|
+
'methods': methods.map((e) => e.toJson()).toList(),
|
|
248
|
+
'fields': fields.map((e) => e.toJson()).toList(),
|
|
249
|
+
'constructors': constructors.map((e) => e.toJson()).toList(),
|
|
250
|
+
'line': line,
|
|
251
|
+
'column': column,
|
|
252
|
+
if (isAbstract) 'isAbstract': isAbstract,
|
|
253
|
+
if (isSealed) 'isSealed': isSealed,
|
|
254
|
+
if (isFinal) 'isFinal': isFinal,
|
|
255
|
+
if (isBase) 'isBase': isBase,
|
|
256
|
+
if (isInterface) 'isInterface': isInterface,
|
|
257
|
+
if (isMixin) 'isMixin': isMixin,
|
|
258
|
+
if (documentation != null) 'documentation': documentation,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/// Method info
|
|
263
|
+
class MethodInfo {
|
|
264
|
+
final String name;
|
|
265
|
+
final String? returnType;
|
|
266
|
+
final List<ParameterInfo> parameters;
|
|
267
|
+
final int line;
|
|
268
|
+
final int column;
|
|
269
|
+
final bool isStatic;
|
|
270
|
+
final bool isAsync;
|
|
271
|
+
final bool isGenerator;
|
|
272
|
+
final bool isGetter;
|
|
273
|
+
final bool isSetter;
|
|
274
|
+
final bool isOperator;
|
|
275
|
+
final bool isAbstract;
|
|
276
|
+
final bool isExternal;
|
|
277
|
+
final String? documentation;
|
|
278
|
+
|
|
279
|
+
MethodInfo({
|
|
280
|
+
required this.name,
|
|
281
|
+
this.returnType,
|
|
282
|
+
this.parameters = const [],
|
|
283
|
+
required this.line,
|
|
284
|
+
required this.column,
|
|
285
|
+
this.isStatic = false,
|
|
286
|
+
this.isAsync = false,
|
|
287
|
+
this.isGenerator = false,
|
|
288
|
+
this.isGetter = false,
|
|
289
|
+
this.isSetter = false,
|
|
290
|
+
this.isOperator = false,
|
|
291
|
+
this.isAbstract = false,
|
|
292
|
+
this.isExternal = false,
|
|
293
|
+
this.documentation,
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
Map<String, dynamic> toJson() => {
|
|
297
|
+
'name': name,
|
|
298
|
+
if (returnType != null) 'returnType': returnType,
|
|
299
|
+
'parameters': parameters.map((e) => e.toJson()).toList(),
|
|
300
|
+
'line': line,
|
|
301
|
+
'column': column,
|
|
302
|
+
if (isStatic) 'isStatic': isStatic,
|
|
303
|
+
if (isAsync) 'isAsync': isAsync,
|
|
304
|
+
if (isGenerator) 'isGenerator': isGenerator,
|
|
305
|
+
if (isGetter) 'isGetter': isGetter,
|
|
306
|
+
if (isSetter) 'isSetter': isSetter,
|
|
307
|
+
if (isOperator) 'isOperator': isOperator,
|
|
308
|
+
if (isAbstract) 'isAbstract': isAbstract,
|
|
309
|
+
if (isExternal) 'isExternal': isExternal,
|
|
310
|
+
if (documentation != null) 'documentation': documentation,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/// Field info
|
|
315
|
+
class FieldInfo {
|
|
316
|
+
final String name;
|
|
317
|
+
final String? type;
|
|
318
|
+
final int line;
|
|
319
|
+
final int column;
|
|
320
|
+
final bool isStatic;
|
|
321
|
+
final bool isFinal;
|
|
322
|
+
final bool isConst;
|
|
323
|
+
final bool isLate;
|
|
324
|
+
final String? initialValue;
|
|
325
|
+
final String? documentation;
|
|
326
|
+
|
|
327
|
+
FieldInfo({
|
|
328
|
+
required this.name,
|
|
329
|
+
this.type,
|
|
330
|
+
required this.line,
|
|
331
|
+
required this.column,
|
|
332
|
+
this.isStatic = false,
|
|
333
|
+
this.isFinal = false,
|
|
334
|
+
this.isConst = false,
|
|
335
|
+
this.isLate = false,
|
|
336
|
+
this.initialValue,
|
|
337
|
+
this.documentation,
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
Map<String, dynamic> toJson() => {
|
|
341
|
+
'name': name,
|
|
342
|
+
if (type != null) 'type': type,
|
|
343
|
+
'line': line,
|
|
344
|
+
'column': column,
|
|
345
|
+
if (isStatic) 'isStatic': isStatic,
|
|
346
|
+
if (isFinal) 'isFinal': isFinal,
|
|
347
|
+
if (isConst) 'isConst': isConst,
|
|
348
|
+
if (isLate) 'isLate': isLate,
|
|
349
|
+
if (initialValue != null) 'initialValue': initialValue,
|
|
350
|
+
if (documentation != null) 'documentation': documentation,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/// Constructor info
|
|
355
|
+
class ConstructorInfo {
|
|
356
|
+
final String? name;
|
|
357
|
+
final List<ParameterInfo> parameters;
|
|
358
|
+
final int line;
|
|
359
|
+
final int column;
|
|
360
|
+
final bool isConst;
|
|
361
|
+
final bool isFactory;
|
|
362
|
+
final bool isExternal;
|
|
363
|
+
final String? redirectedConstructor;
|
|
364
|
+
|
|
365
|
+
ConstructorInfo({
|
|
366
|
+
this.name,
|
|
367
|
+
this.parameters = const [],
|
|
368
|
+
required this.line,
|
|
369
|
+
required this.column,
|
|
370
|
+
this.isConst = false,
|
|
371
|
+
this.isFactory = false,
|
|
372
|
+
this.isExternal = false,
|
|
373
|
+
this.redirectedConstructor,
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
Map<String, dynamic> toJson() => {
|
|
377
|
+
if (name != null) 'name': name,
|
|
378
|
+
'parameters': parameters.map((e) => e.toJson()).toList(),
|
|
379
|
+
'line': line,
|
|
380
|
+
'column': column,
|
|
381
|
+
if (isConst) 'isConst': isConst,
|
|
382
|
+
if (isFactory) 'isFactory': isFactory,
|
|
383
|
+
if (isExternal) 'isExternal': isExternal,
|
|
384
|
+
if (redirectedConstructor != null)
|
|
385
|
+
'redirectedConstructor': redirectedConstructor,
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/// Mixin info
|
|
390
|
+
class MixinInfo {
|
|
391
|
+
final String name;
|
|
392
|
+
final List<String> onTypes;
|
|
393
|
+
final List<String> interfaces;
|
|
394
|
+
final List<MethodInfo> methods;
|
|
395
|
+
final List<FieldInfo> fields;
|
|
396
|
+
final int line;
|
|
397
|
+
final int column;
|
|
398
|
+
final String? documentation;
|
|
399
|
+
|
|
400
|
+
MixinInfo({
|
|
401
|
+
required this.name,
|
|
402
|
+
this.onTypes = const [],
|
|
403
|
+
this.interfaces = const [],
|
|
404
|
+
this.methods = const [],
|
|
405
|
+
this.fields = const [],
|
|
406
|
+
required this.line,
|
|
407
|
+
required this.column,
|
|
408
|
+
this.documentation,
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
Map<String, dynamic> toJson() => {
|
|
412
|
+
'name': name,
|
|
413
|
+
if (onTypes.isNotEmpty) 'onTypes': onTypes,
|
|
414
|
+
if (interfaces.isNotEmpty) 'interfaces': interfaces,
|
|
415
|
+
'methods': methods.map((e) => e.toJson()).toList(),
|
|
416
|
+
'fields': fields.map((e) => e.toJson()).toList(),
|
|
417
|
+
'line': line,
|
|
418
|
+
'column': column,
|
|
419
|
+
if (documentation != null) 'documentation': documentation,
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/// Extension info
|
|
424
|
+
class ExtensionInfo {
|
|
425
|
+
final String? name;
|
|
426
|
+
final String onType;
|
|
427
|
+
final List<MethodInfo> methods;
|
|
428
|
+
final List<FieldInfo> fields;
|
|
429
|
+
final int line;
|
|
430
|
+
final int column;
|
|
431
|
+
final String? documentation;
|
|
432
|
+
|
|
433
|
+
ExtensionInfo({
|
|
434
|
+
this.name,
|
|
435
|
+
required this.onType,
|
|
436
|
+
this.methods = const [],
|
|
437
|
+
this.fields = const [],
|
|
438
|
+
required this.line,
|
|
439
|
+
required this.column,
|
|
440
|
+
this.documentation,
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
Map<String, dynamic> toJson() => {
|
|
444
|
+
if (name != null) 'name': name,
|
|
445
|
+
'onType': onType,
|
|
446
|
+
'methods': methods.map((e) => e.toJson()).toList(),
|
|
447
|
+
'fields': fields.map((e) => e.toJson()).toList(),
|
|
448
|
+
'line': line,
|
|
449
|
+
'column': column,
|
|
450
|
+
if (documentation != null) 'documentation': documentation,
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/// Enum info
|
|
455
|
+
class EnumInfo {
|
|
456
|
+
final String name;
|
|
457
|
+
final List<String> values;
|
|
458
|
+
final List<MethodInfo> methods;
|
|
459
|
+
final List<FieldInfo> fields;
|
|
460
|
+
final int line;
|
|
461
|
+
final int column;
|
|
462
|
+
final String? documentation;
|
|
463
|
+
|
|
464
|
+
EnumInfo({
|
|
465
|
+
required this.name,
|
|
466
|
+
required this.values,
|
|
467
|
+
this.methods = const [],
|
|
468
|
+
this.fields = const [],
|
|
469
|
+
required this.line,
|
|
470
|
+
required this.column,
|
|
471
|
+
this.documentation,
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
Map<String, dynamic> toJson() => {
|
|
475
|
+
'name': name,
|
|
476
|
+
'values': values,
|
|
477
|
+
'methods': methods.map((e) => e.toJson()).toList(),
|
|
478
|
+
'fields': fields.map((e) => e.toJson()).toList(),
|
|
479
|
+
'line': line,
|
|
480
|
+
'column': column,
|
|
481
|
+
if (documentation != null) 'documentation': documentation,
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/// Variable declaration info
|
|
486
|
+
class VariableInfo {
|
|
487
|
+
final String name;
|
|
488
|
+
final String? type;
|
|
489
|
+
final int line;
|
|
490
|
+
final int column;
|
|
491
|
+
final bool isFinal;
|
|
492
|
+
final bool isConst;
|
|
493
|
+
final bool isLate;
|
|
494
|
+
final String? initialValue;
|
|
495
|
+
final String? documentation;
|
|
496
|
+
|
|
497
|
+
VariableInfo({
|
|
498
|
+
required this.name,
|
|
499
|
+
this.type,
|
|
500
|
+
required this.line,
|
|
501
|
+
required this.column,
|
|
502
|
+
this.isFinal = false,
|
|
503
|
+
this.isConst = false,
|
|
504
|
+
this.isLate = false,
|
|
505
|
+
this.initialValue,
|
|
506
|
+
this.documentation,
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
Map<String, dynamic> toJson() => {
|
|
510
|
+
'name': name,
|
|
511
|
+
if (type != null) 'type': type,
|
|
512
|
+
'line': line,
|
|
513
|
+
'column': column,
|
|
514
|
+
if (isFinal) 'isFinal': isFinal,
|
|
515
|
+
if (isConst) 'isConst': isConst,
|
|
516
|
+
if (isLate) 'isLate': isLate,
|
|
517
|
+
if (initialValue != null) 'initialValue': initialValue,
|
|
518
|
+
if (documentation != null) 'documentation': documentation,
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/// Constant declaration info (for top-level consts)
|
|
523
|
+
class ConstantInfo {
|
|
524
|
+
final String name;
|
|
525
|
+
final String? type;
|
|
526
|
+
final String value;
|
|
527
|
+
final int line;
|
|
528
|
+
final int column;
|
|
529
|
+
final String? documentation;
|
|
530
|
+
|
|
531
|
+
ConstantInfo({
|
|
532
|
+
required this.name,
|
|
533
|
+
this.type,
|
|
534
|
+
required this.value,
|
|
535
|
+
required this.line,
|
|
536
|
+
required this.column,
|
|
537
|
+
this.documentation,
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
Map<String, dynamic> toJson() => {
|
|
541
|
+
'name': name,
|
|
542
|
+
if (type != null) 'type': type,
|
|
543
|
+
'value': value,
|
|
544
|
+
'line': line,
|
|
545
|
+
'column': column,
|
|
546
|
+
if (documentation != null) 'documentation': documentation,
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/// Function call info
|
|
551
|
+
class FunctionCallInfo {
|
|
552
|
+
final String functionName;
|
|
553
|
+
final List<String> arguments;
|
|
554
|
+
final int line;
|
|
555
|
+
final int column;
|
|
556
|
+
final bool isConditional;
|
|
557
|
+
final String? parentContext;
|
|
558
|
+
|
|
559
|
+
FunctionCallInfo({
|
|
560
|
+
required this.functionName,
|
|
561
|
+
this.arguments = const [],
|
|
562
|
+
required this.line,
|
|
563
|
+
required this.column,
|
|
564
|
+
this.isConditional = false,
|
|
565
|
+
this.parentContext,
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
Map<String, dynamic> toJson() => {
|
|
569
|
+
'functionName': functionName,
|
|
570
|
+
'arguments': arguments,
|
|
571
|
+
'line': line,
|
|
572
|
+
'column': column,
|
|
573
|
+
if (isConditional) 'isConditional': isConditional,
|
|
574
|
+
if (parentContext != null) 'parentContext': parentContext,
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/// Method call info
|
|
579
|
+
class MethodCallInfo {
|
|
580
|
+
final String target;
|
|
581
|
+
final String methodName;
|
|
582
|
+
final List<String> arguments;
|
|
583
|
+
final int line;
|
|
584
|
+
final int column;
|
|
585
|
+
final bool isNullAware;
|
|
586
|
+
final bool isCascade;
|
|
587
|
+
|
|
588
|
+
MethodCallInfo({
|
|
589
|
+
required this.target,
|
|
590
|
+
required this.methodName,
|
|
591
|
+
this.arguments = const [],
|
|
592
|
+
required this.line,
|
|
593
|
+
required this.column,
|
|
594
|
+
this.isNullAware = false,
|
|
595
|
+
this.isCascade = false,
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
Map<String, dynamic> toJson() => {
|
|
599
|
+
'target': target,
|
|
600
|
+
'methodName': methodName,
|
|
601
|
+
'arguments': arguments,
|
|
602
|
+
'line': line,
|
|
603
|
+
'column': column,
|
|
604
|
+
if (isNullAware) 'isNullAware': isNullAware,
|
|
605
|
+
if (isCascade) 'isCascade': isCascade,
|
|
606
|
+
};
|
|
607
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/// Represents a code violation found by an analyzer
|
|
2
|
+
class Violation {
|
|
3
|
+
/// Rule ID (e.g., 'C001', 'N001', 'S003')
|
|
4
|
+
final String ruleId;
|
|
5
|
+
|
|
6
|
+
/// Absolute path to the file
|
|
7
|
+
final String filePath;
|
|
8
|
+
|
|
9
|
+
/// Line number (1-based)
|
|
10
|
+
final int line;
|
|
11
|
+
|
|
12
|
+
/// Column number (1-based)
|
|
13
|
+
final int column;
|
|
14
|
+
|
|
15
|
+
/// Human-readable message
|
|
16
|
+
final String message;
|
|
17
|
+
|
|
18
|
+
/// Severity level
|
|
19
|
+
final String severity;
|
|
20
|
+
|
|
21
|
+
/// Analysis method used
|
|
22
|
+
final String analysisMethod;
|
|
23
|
+
|
|
24
|
+
/// Confidence score (0-100)
|
|
25
|
+
final int? confidence;
|
|
26
|
+
|
|
27
|
+
/// Additional metadata
|
|
28
|
+
final Map<String, dynamic>? metadata;
|
|
29
|
+
|
|
30
|
+
Violation({
|
|
31
|
+
required this.ruleId,
|
|
32
|
+
required this.filePath,
|
|
33
|
+
required this.line,
|
|
34
|
+
required this.column,
|
|
35
|
+
required this.message,
|
|
36
|
+
this.severity = 'warning',
|
|
37
|
+
this.analysisMethod = 'ast',
|
|
38
|
+
this.confidence,
|
|
39
|
+
this.metadata,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
Map<String, dynamic> toJson() => {
|
|
43
|
+
'ruleId': ruleId,
|
|
44
|
+
'filePath': filePath,
|
|
45
|
+
'line': line,
|
|
46
|
+
'column': column,
|
|
47
|
+
'message': message,
|
|
48
|
+
'severity': severity,
|
|
49
|
+
'analysisMethod': analysisMethod,
|
|
50
|
+
if (confidence != null) 'confidence': confidence,
|
|
51
|
+
if (metadata != null) 'metadata': metadata,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
factory Violation.fromJson(Map<String, dynamic> json) => Violation(
|
|
55
|
+
ruleId: json['ruleId'] as String,
|
|
56
|
+
filePath: json['filePath'] as String,
|
|
57
|
+
line: json['line'] as int,
|
|
58
|
+
column: json['column'] as int,
|
|
59
|
+
message: json['message'] as String,
|
|
60
|
+
severity: json['severity'] as String? ?? 'warning',
|
|
61
|
+
analysisMethod: json['analysisMethod'] as String? ?? 'ast',
|
|
62
|
+
confidence: json['confidence'] as int?,
|
|
63
|
+
metadata: json['metadata'] as Map<String, dynamic>?,
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
@override
|
|
67
|
+
String toString() =>
|
|
68
|
+
'Violation($ruleId at $filePath:$line:$column - $message)';
|
|
69
|
+
}
|