| Index: packages/analyzer/lib/src/plugin/plugin_configuration.dart
|
| diff --git a/packages/analyzer/lib/src/plugin/plugin_configuration.dart b/packages/analyzer/lib/src/plugin/plugin_configuration.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9365a3c3eefe8a75fa4c31c718874ec12896077f
|
| --- /dev/null
|
| +++ b/packages/analyzer/lib/src/plugin/plugin_configuration.dart
|
| @@ -0,0 +1,198 @@
|
| +// 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 analyzer.src.plugin.plugin_configuration;
|
| +
|
| +import 'package:analyzer/plugin/options.dart';
|
| +import 'package:analyzer/src/generated/engine.dart';
|
| +import 'package:yaml/yaml.dart';
|
| +
|
| +const _analyzerOptionScope = 'analyzer';
|
| +
|
| +const _pluginOptionScope = 'plugins';
|
| +
|
| +/// Parse the given string into a plugin manifest.
|
| +PluginManifest parsePluginManifestString(String manifestSource) {
|
| + var yaml = loadYaml(manifestSource);
|
| + if (yaml == null) {
|
| + return null;
|
| + }
|
| + _verifyMap(yaml, 'plugin manifest');
|
| + Iterable<String> pluginHost = _parseHosts(yaml['contributes_to']);
|
| + PluginInfo plugin = _parsePlugin(yaml);
|
| + return new PluginManifest(contributesTo: pluginHost, plugin: plugin);
|
| +}
|
| +
|
| +String _asString(dynamic yaml) {
|
| + if (yaml != null && yaml is! String) {
|
| + throw new PluginConfigFormatException(
|
| + 'Unable to parse pugin manifest, '
|
| + 'expected `String`, got `${yaml.runtimeType}`',
|
| + yaml);
|
| + }
|
| + return yaml;
|
| +}
|
| +
|
| +Iterable<String> _parseHosts(dynamic yaml) {
|
| + List<String> hosts = <String>[];
|
| + if (yaml is String) {
|
| + hosts.add(yaml);
|
| + } else if (yaml is YamlList) {
|
| + yaml.forEach((h) => hosts.add(_asString(h)));
|
| + }
|
| + return hosts;
|
| +}
|
| +
|
| +PluginInfo _parsePlugin(dynamic yaml) {
|
| + if (yaml != null) {
|
| + _verifyMap(yaml, 'plugin manifest');
|
| + return new PluginInfo._fromYaml(details: yaml);
|
| + }
|
| + return null;
|
| +}
|
| +
|
| +PluginInfo _processPluginMapping(dynamic name, dynamic details) {
|
| + if (name is String) {
|
| + if (details is String) {
|
| + return new PluginInfo(name: name, version: details);
|
| + }
|
| + if (details is YamlMap) {
|
| + return new PluginInfo._fromYaml(name: name, details: details);
|
| + }
|
| + }
|
| +
|
| + return null;
|
| +}
|
| +
|
| +_verifyMap(dynamic yaml, String context) {
|
| + if (yaml is! YamlMap) {
|
| + throw new PluginConfigFormatException(
|
| + 'Unable to parse $context, '
|
| + 'expected `YamlMap`, got `${yaml.runtimeType}`',
|
| + yaml);
|
| + }
|
| +}
|
| +
|
| +/// A callback for error handling.
|
| +typedef ErrorHandler(Exception e);
|
| +
|
| +/// Describes plugin configuration information as extracted from an
|
| +/// analysis options map or plugin manifest.
|
| +class PluginConfig {
|
| + final Iterable<PluginInfo> plugins;
|
| + PluginConfig(this.plugins);
|
| +
|
| + /// Create a plugin configuration from an options map.
|
| + factory PluginConfig.fromOptions(Map<String, YamlNode> options) {
|
| + List<PluginInfo> plugins = [];
|
| + var analyzerOptions = options[_analyzerOptionScope];
|
| + if (analyzerOptions != null) {
|
| + if (analyzerOptions is YamlMap) {
|
| + var pluginConfig = analyzerOptions[_pluginOptionScope];
|
| + if (pluginConfig is YamlMap) {
|
| + pluginConfig.forEach((name, details) {
|
| + var plugin = _processPluginMapping(name, details);
|
| + if (plugin != null) {
|
| + plugins.add(plugin);
|
| + }
|
| + });
|
| + } else {
|
| + // Anything but an empty list of plugins is treated as a format error.
|
| + if (pluginConfig != null) {
|
| + throw new PluginConfigFormatException(
|
| + 'Unrecognized plugin config format, expected `YamlMap`, '
|
| + 'got `${pluginConfig.runtimeType}`',
|
| + pluginConfig);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + return new PluginConfig(plugins);
|
| + }
|
| +}
|
| +
|
| +/// Thrown on bad plugin config format.
|
| +class PluginConfigFormatException implements Exception {
|
| + /// Descriptive message.
|
| + final message;
|
| +
|
| + /// The `plugin:` yaml node for generating detailed error feedback.
|
| + final yamlNode;
|
| + PluginConfigFormatException(this.message, this.yamlNode);
|
| +}
|
| +
|
| +/// Extracts plugin config details from analysis options.
|
| +class PluginConfigOptionsProcessor extends OptionsProcessor {
|
| + final ErrorHandler _errorHandler;
|
| +
|
| + PluginConfig _config;
|
| +
|
| + PluginConfigOptionsProcessor([this._errorHandler]);
|
| +
|
| + /// The processed plugin config.
|
| + PluginConfig get config => _config;
|
| +
|
| + @override
|
| + void onError(Exception exception) {
|
| + if (_errorHandler != null) {
|
| + _errorHandler(exception);
|
| + }
|
| + }
|
| +
|
| + @override
|
| + void optionsProcessed(
|
| + AnalysisContext context, Map<String, YamlNode> options) {
|
| + _config = new PluginConfig.fromOptions(options);
|
| + }
|
| +}
|
| +
|
| +/// Describes plugin information.
|
| +class PluginInfo {
|
| + final String name;
|
| + final String className;
|
| + final String version;
|
| + final String libraryUri;
|
| + final String packageName;
|
| + final String path;
|
| + PluginInfo(
|
| + {this.name,
|
| + this.version,
|
| + this.className,
|
| + this.libraryUri,
|
| + this.packageName,
|
| + this.path});
|
| +
|
| + factory PluginInfo._fromYaml({String name, YamlMap details}) =>
|
| + new PluginInfo(
|
| + name: name,
|
| + version: _asString(details['version']),
|
| + className: _asString(details['class_name']),
|
| + libraryUri: _asString(details['library_uri']),
|
| + packageName: _asString(details['package_name']),
|
| + path: _asString(details['path']));
|
| +}
|
| +
|
| +/// Plugin manifests accompany plugin packages, providing
|
| +/// configuration information for published plugins.
|
| +///
|
| +/// Provisionally, plugin manifests live in a file `plugin.yaml`
|
| +/// at the root of the plugin package.
|
| +///
|
| +/// my_plugin/
|
| +/// bin/
|
| +/// lib/
|
| +/// plugin.yaml
|
| +/// pubspec.yaml
|
| +///
|
| +/// Provisional manifest file format:
|
| +///
|
| +/// class_name: MyAnalyzerPlugin
|
| +/// library_uri: 'my_plugin/my_analyzer_plugin.dart'
|
| +/// contributes_to: analyzer
|
| +class PluginManifest {
|
| + PluginInfo plugin;
|
| + Iterable<String> contributesTo;
|
| + PluginManifest({this.plugin, this.contributesTo});
|
| +}
|
|
|