Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions lib/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
analyzer:
plugins:
- custom_lint
exclude:
# General generated files
- "**/*.g.dart"
Expand Down
14 changes: 12 additions & 2 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'package:analysis_server_plugin/plugin.dart';
import 'package:analysis_server_plugin/registry.dart';
import 'package:analyzer/analysis_rule/analysis_rule.dart';
import 'package:solid_lints/src/common/constants.dart';
import 'package:solid_lints/src/common/parameter_parser/analysis_options_loader.dart';
import 'package:solid_lints/src/lints/avoid_debug_print_in_release/avoid_debug_print_in_release_rule.dart';
import 'package:solid_lints/src/lints/avoid_final_with_getter/avoid_final_with_getter_rule.dart';
Expand Down Expand Up @@ -30,6 +32,8 @@ import 'package:solid_lints/src/lints/prefer_last/prefer_last_rule.dart';
import 'package:solid_lints/src/lints/prefer_match_file_name/prefer_match_file_name_rule.dart';
import 'package:solid_lints/src/lints/proper_super_calls/proper_super_calls_rule.dart';
import 'package:solid_lints/src/lints/use_nearest_context/use_nearest_context_rule.dart';
import 'package:solid_lints/src/models/proxy_analysis_rule.dart';
import 'package:solid_lints/src/models/proxy_multi_analysis_rule.dart';
import 'package:solid_lints/src/models/rule_with_fixes.dart';

/// The entry point for the Solid Lints analyser server plugin.
Expand All @@ -44,7 +48,7 @@ final plugin = SolidLintsPlugin();
/// by the Dart analyzer during code analysis.
class SolidLintsPlugin extends Plugin {
@override
String get name => 'solid_lints';
String get name => kPluginName;

@override
void register(PluginRegistry registry) {
Expand Down Expand Up @@ -83,7 +87,13 @@ class SolidLintsPlugin extends Plugin {
];

for (final lintRule in lintRules) {
registry.registerLintRule(lintRule);
final ruleToRegister = switch (lintRule) {
MultiAnalysisRule() => ProxyMultiAnalysisRule(lintRule, analysisLoader),
AnalysisRule() => ProxyAnalysisRule(lintRule, analysisLoader),
};
Comment thread
solid-illiaaihistov marked this conversation as resolved.
Comment thread
solid-illiaaihistov marked this conversation as resolved.

registry.registerWarningRule(ruleToRegister);

if (lintRule is RuleWithFixes) {
for (final entry in (lintRule as RuleWithFixes).fixesForCodes) {
registry.registerFixForRule(entry.key, entry.value);
Expand Down
2 changes: 2 additions & 0 deletions lib/src/common/constants.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// Shared constants for the solid_lints package.
const kPluginName = 'solid_lints';
77 changes: 34 additions & 43 deletions lib/src/common/parameter_parser/analysis_options_loader.dart
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
import 'package:analyzer/analysis_rule/rule_context.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:solid_lints/src/common/parameter_parser/analysis_options_parser.dart';
import 'package:solid_lints/src/common/parameter_parser/cached_package_rules.dart';
import 'package:yaml/yaml.dart';
import 'package:solid_lints/src/common/parameter_parser/package_config_resolver.dart';

/// Loads and parses analysis options from a Dart project's YAML file.
class AnalysisOptionsLoader {
final ResourceProvider _resourceProvider;
final Map<String, CachedPackageRules> _rulesCache = {};

/// Creates an instance of [AnalysisOptionsLoader]
AnalysisOptionsLoader({ResourceProvider? resourceProvider})
: _resourceProvider = resourceProvider ?? PhysicalResourceProvider.INSTANCE;


late final AnalysisOptionsParser _parser;

/// Creates an instance of [AnalysisOptionsLoader].
AnalysisOptionsLoader({
ResourceProvider? resourceProvider,
AnalysisOptionsParser? parser,
}) : _resourceProvider =
resourceProvider ?? PhysicalResourceProvider.INSTANCE {
_parser = parser ??
AnalysisOptionsParser(
_resourceProvider,
PackageConfigResolver(_resourceProvider),
);
}

/// Gets the options for a specific rule by its name.
Map<String, Object?>? getRuleOptions(RuleContext context, String ruleName) =>
Expand All @@ -36,6 +50,17 @@ class AnalysisOptionsLoader {
return _rulesCache[yamlPath]?.rules[ruleName];
}

/// Checks if a rule is explicitly disabled.
bool isRuleDisabled(RuleContext context, String ruleName) =>
_withNearestAnalysisOptionsFilePathForContext<bool>(
context,
(path) {
_loadRulesOptionsIfNewer(path);
return _rulesCache[path]?.disabledRules.contains(ruleName) ?? false;
},
) ??
false;

/// Loads lint rules from the analysis options file for all rules
/// using the provided [RuleContext].
void loadRulesOptionsFromContext(RuleContext context) =>
Expand Down Expand Up @@ -66,18 +91,19 @@ class AnalysisOptionsLoader {
return;
}

final rules = _getRules(analysisOptionsFile);
final rulesData = _parser.parse(analysisOptionsFile);
_rulesCache[yamlPath] = CachedPackageRules(
modificationStamp: modificationStamp,
rules: rules,
rules: rulesData.rules,
disabledRules: rulesData.disabledRules,
);
}

String? _findNearestAnalysisOptionsFilePath(String startDirectoryPath) {
final pathContext = _resourceProvider.pathContext;
String currentDirectoryPath = startDirectoryPath;
var currentDirectoryPath = startDirectoryPath;

while (true) {
while (currentDirectoryPath.isNotEmpty) {
final candidatePath = pathContext.join(
currentDirectoryPath,
'analysis_options.yaml',
Expand All @@ -97,39 +123,4 @@ class AnalysisOptionsLoader {

return null;
}
Comment thread
solid-illiaaihistov marked this conversation as resolved.

Map<String, Map<String, Object?>> _getRules(File? analysisOptionsFile) {
if (analysisOptionsFile == null || !analysisOptionsFile.exists) {
return {};
}

Object? yaml;
try {
final optionsString = analysisOptionsFile.readAsStringSync();
yaml = loadYaml(optionsString);
} catch (_) {
return {};
}

Object? rawDiagnostics;
if (yaml case {'solid_lints': {'diagnostics': final diagnostics}}) {
rawDiagnostics = diagnostics;
} else if (yaml case {
'plugins': {'solid_lints': {'diagnostics': final diagnostics}},
}) {
rawDiagnostics = diagnostics;
}

if (rawDiagnostics is! Map) return {};

return {
for (final entry in rawDiagnostics.entries)
if (entry.key is String && entry.value is Map)
entry.key as String: <String, Object?>{
for (final optionEntry in (entry.value as Map).entries)
if (optionEntry.key is String)
optionEntry.key as String: optionEntry.value,
},
};
}
}
Loading
Loading