import 'package:analyzer/error/error.dart' show ErrorSeverity; import 'package:analyzer/error/listener.dart'; import 'package:custom_lint_builder/custom_lint_builder.dart'; // ignore: depend_on_referenced_packages import 'package:glob/glob.dart'; PluginBase createPlugin() => ImLinter(); class ImLinter extends PluginBase { @override List getLintRules(CustomLintConfigs configs) { final List rules = []; for (final entry in configs.rules.entries) { if (entry.value.enabled && entry.key.startsWith("import_rule_")) { final code = makeCode(entry.key, entry.value); final allowedPaths = getStrings(entry.value, "allowed"); final forbiddenPaths = getStrings(entry.value, "forbidden"); final restrict = getStrings(entry.value, "restrict"); rules.add(ImportRule(code, buildGlob(allowedPaths), buildGlob(forbiddenPaths), restrict)); } } return rules; } static makeCode(String name, LintOptions options) => LintCode( name: name, problemMessage: options.json["message"] as String, errorSeverity: ErrorSeverity.WARNING, ); static List getStrings(LintOptions options, String field) { final List result = []; final excludeOption = options.json[field]; if (excludeOption is String) { result.add(excludeOption); } else if (excludeOption is List) { result.addAll(excludeOption.map((option) => option)); } return result; } Glob? buildGlob(List globs) { if (globs.isEmpty) return null; if (globs.length == 1) return Glob(globs[0], caseSensitive: true); return Glob("{${globs.join(",")}}", caseSensitive: true); } } // ignore: must_be_immutable class ImportRule extends DartLintRule { ImportRule(LintCode code, this._allowed, this._forbidden, this._restrict) : super(code: code); final Glob? _allowed; final Glob? _forbidden; final List _restrict; int rootOffset = -1; @override Future startUp( CustomLintResolver resolver, CustomLintContext context, ) async { if (rootOffset == -1) { rootOffset = resolver.path.toLowerCase().lastIndexOf("immich/"); rootOffset = resolver.path.indexOf("lib/", rootOffset); } return super.startUp(resolver, context); } @override void run( CustomLintResolver resolver, ErrorReporter reporter, CustomLintContext context, ) { if (rootOffset == -1) { print("Cannot find project root. Skipping ${resolver.path}"); return; } final path = resolver.path.substring(rootOffset); if ((_allowed != null && _allowed!.matches(path)) && (_forbidden == null || !_forbidden!.matches(path))) return; context.registry.addImportDirective((node) { final uri = node.uri.stringValue; if (uri == null) return; for (final restricted in _restrict) { if (uri.startsWith(restricted) == true) { reporter.atNode(node, code); return; } } }); } }