From aa783b32da54e7629a54d1feddba1462a3fef18a Mon Sep 17 00:00:00 2001 From: pquitslund Date: Tue, 12 May 2015 11:42:15 -0700 Subject: [PATCH 1/2] Plugin babysteps. --- lib/plugin/linter.dart | 16 +++++++ lib/src/plugin/linter_plugin.dart | 78 +++++++++++++++++++++++++++++++ pubspec.yaml | 1 + test/linter_test.dart | 31 ++++++++++++ 4 files changed, 126 insertions(+) create mode 100644 lib/plugin/linter.dart create mode 100644 lib/src/plugin/linter_plugin.dart diff --git a/lib/plugin/linter.dart b/lib/plugin/linter.dart new file mode 100644 index 000000000..af222f0e9 --- /dev/null +++ b/lib/plugin/linter.dart @@ -0,0 +1,16 @@ +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Support for client code that extends the analysis engine by adding new +/// lint rules. +library analyzer.plugin.linter; + +import 'package:linter/src/linter.dart'; +import 'package:linter/src/plugin/linter_plugin.dart'; +import 'package:plugin/plugin.dart'; + +/// The identifier of the extension point that allows plugins to register new +/// lints. The object used as an extension must implement [LintRule]. +final String LINT_RULE_EXTENSION_POINT_ID = Plugin.join( + LinterPlugin.UNIQUE_IDENTIFIER, LinterPlugin.LINT_RULE_EXTENSION_POINT); diff --git a/lib/src/plugin/linter_plugin.dart b/lib/src/plugin/linter_plugin.dart new file mode 100644 index 000000000..e5f5af7cd --- /dev/null +++ b/lib/src/plugin/linter_plugin.dart @@ -0,0 +1,78 @@ +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +library linter.src.plugin.linter_plugin; + +import 'package:linter/plugin/linter.dart'; +import 'package:linter/src/linter.dart'; +import 'package:linter/src/rules/camel_case_types.dart'; +import 'package:linter/src/rules/constant_identifier_names.dart'; +import 'package:linter/src/rules/empty_constructor_bodies.dart'; +import 'package:linter/src/rules/library_names.dart'; +import 'package:linter/src/rules/library_prefixes.dart'; +import 'package:linter/src/rules/non_constant_identifier_names.dart'; +import 'package:linter/src/rules/one_member_abstracts.dart'; +import 'package:linter/src/rules/slash_for_doc_comments.dart'; +import 'package:linter/src/rules/super_goes_last.dart'; +import 'package:linter/src/rules/type_init_formals.dart'; +import 'package:linter/src/rules/unnecessary_brace_in_string_interp.dart'; +import 'package:plugin/plugin.dart'; + +/// The shared linter plugin instance. +final LinterPlugin linterPlugin = new LinterPlugin(); + +/// A plugin that defines the extension points and extensions that are +/// inherently defined by the linter. +class LinterPlugin implements Plugin { + + /// A subset of rules that we are considering enabled by "default". + static final List _rules = [ + new CamelCaseTypes(), + new ConstantIdentifierNames(), + new EmptyConstructorBodies(), + new LibraryNames(), + new LibraryPrefixes(), + new NonConstantIdentifierNames(), + new OneMemberAbstracts(), + new SlashForDocComments(), + new SuperGoesLast(), + new TypeInitFormals(), + new UnnecessaryBraceInStringInterp() + ]; + + /// The unique identifier of this plugin. + static const String UNIQUE_IDENTIFIER = 'linter.core'; + + /// The simple identifier of the extension point that allows plugins to + /// register new lint rules. + static const String LINT_RULE_EXTENSION_POINT = 'rule'; + + /// The extension point that allows plugins to register new lint rules. + ExtensionPoint lintRuleExtensionPoint; + + /// Return a list containing all contributed lint rules. + List get lintRules => lintRuleExtensionPoint.extensions; + + @override + String get uniqueIdentifier => UNIQUE_IDENTIFIER; + + @override + void registerExtensionPoints(RegisterExtensionPoint registerExtensionPoint) { + lintRuleExtensionPoint = registerExtensionPoint( + LINT_RULE_EXTENSION_POINT, _validateTaskExtension); + } + + @override + void registerExtensions(RegisterExtension registerExtension) { + _rules.forEach((LintRule rule) => + registerExtension(LINT_RULE_EXTENSION_POINT_ID, rule)); + } + + void _validateTaskExtension(Object extension) { + if (extension is! LintRule) { + String id = lintRuleExtensionPoint.uniqueIdentifier; + throw new ExtensionError('Extensions to $id must implement LintRule'); + } + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 8905fad36..1ff87bcaa 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,6 +8,7 @@ dependencies: args: '>=0.12.1 <0.14.0' cli_util: '>=0.0.1 <0.1.0' glob: '>=1.0.3 <2.0.0' + plugin: '<0.2.0' source_span: '>=1.0.2 <2.0.0' yaml: '>=2.1.2 <3.0.0' dev_dependencies: diff --git a/test/linter_test.dart b/test/linter_test.dart index 9d608a869..d55f5251d 100644 --- a/test/linter_test.dart +++ b/test/linter_test.dart @@ -16,6 +16,7 @@ import 'package:linter/src/analysis.dart'; import 'package:linter/src/ast.dart'; import 'package:linter/src/io.dart'; import 'package:linter/src/linter.dart'; +import 'package:linter/src/plugin/linter_plugin.dart'; import 'package:linter/src/pub.dart'; import 'package:linter/src/rules.dart'; import 'package:linter/src/rules/camel_case_types.dart'; @@ -23,6 +24,7 @@ import 'package:linter/src/rules/package_prefixed_library_names.dart'; import 'package:linter/src/util.dart'; import 'package:mockito/mockito.dart'; import 'package:path/path.dart' as p; +import 'package:plugin/manager.dart'; import 'package:unittest/unittest.dart'; import '../bin/linter.dart' as dartlint; @@ -33,6 +35,7 @@ main() { defineSanityTests(); defineLinterEngineTests(); + definePluginTests(); defineRuleTests(); defineRuleUnitTests(); } @@ -255,6 +258,34 @@ void defineLinterEngineTests() { }); } +/// Default contributed lint rules. +var builtinRules = [ + 'camel_case_types', + 'constant_identifier_names', + 'empty_constructor_bodies', + 'library_names', + 'library_prefixes', + 'non_constant_identifier_names', + 'one_member_abstracts', + 'slash_for_doc_comments', + 'super_goes_last', + 'type_init_formals', + 'unnecessary_brace_in_string_interp' +]; + +/// Plugin tests +definePluginTests() { + group('plugin', () { + test('contributed rules', () { + LinterPlugin linterPlugin = new LinterPlugin(); + ExtensionManager manager = new ExtensionManager(); + manager.processPlugins([linterPlugin]); + var contributedRules = linterPlugin.lintRules.map((rule) => rule.name); + expect(contributedRules, unorderedEquals(builtinRules)); + }); + }); +} + /// Rule tests defineRuleTests() { From b9c31b7b4e43ec65ae7166f45dcd1e6e9f759861 Mon Sep 17 00:00:00 2001 From: pquitslund Date: Tue, 12 May 2015 16:10:30 -0700 Subject: [PATCH 2/2] Inlined rules. --- lib/src/plugin/linter_plugin.dart | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/lib/src/plugin/linter_plugin.dart b/lib/src/plugin/linter_plugin.dart index e5f5af7cd..f3211fa48 100644 --- a/lib/src/plugin/linter_plugin.dart +++ b/lib/src/plugin/linter_plugin.dart @@ -26,21 +26,6 @@ final LinterPlugin linterPlugin = new LinterPlugin(); /// inherently defined by the linter. class LinterPlugin implements Plugin { - /// A subset of rules that we are considering enabled by "default". - static final List _rules = [ - new CamelCaseTypes(), - new ConstantIdentifierNames(), - new EmptyConstructorBodies(), - new LibraryNames(), - new LibraryPrefixes(), - new NonConstantIdentifierNames(), - new OneMemberAbstracts(), - new SlashForDocComments(), - new SuperGoesLast(), - new TypeInitFormals(), - new UnnecessaryBraceInStringInterp() - ]; - /// The unique identifier of this plugin. static const String UNIQUE_IDENTIFIER = 'linter.core'; @@ -65,7 +50,20 @@ class LinterPlugin implements Plugin { @override void registerExtensions(RegisterExtension registerExtension) { - _rules.forEach((LintRule rule) => + /// A subset of rules that we are considering enabled by "default". + [ + new CamelCaseTypes(), + new ConstantIdentifierNames(), + new EmptyConstructorBodies(), + new LibraryNames(), + new LibraryPrefixes(), + new NonConstantIdentifierNames(), + new OneMemberAbstracts(), + new SlashForDocComments(), + new SuperGoesLast(), + new TypeInitFormals(), + new UnnecessaryBraceInStringInterp() + ].forEach((LintRule rule) => registerExtension(LINT_RULE_EXTENSION_POINT_ID, rule)); }