| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library analyzer.src.plugin.plugin_configuration; | |
| 6 | |
| 7 import 'package:analyzer/plugin/options.dart'; | |
| 8 import 'package:analyzer/src/generated/engine.dart'; | |
| 9 import 'package:yaml/yaml.dart'; | |
| 10 | |
| 11 const _analyzerOptionScope = 'analyzer'; | |
| 12 | |
| 13 const _pluginOptionScope = 'plugins'; | |
| 14 | |
| 15 /// Parse the given string into a plugin manifest. | |
| 16 PluginManifest parsePluginManifestString(String manifestSource) { | |
| 17 var yaml = loadYaml(manifestSource); | |
| 18 if (yaml == null) { | |
| 19 return null; | |
| 20 } | |
| 21 _verifyMap(yaml, 'plugin manifest'); | |
| 22 Iterable<String> pluginHost = _parseHosts(yaml['contributes_to']); | |
| 23 PluginInfo plugin = _parsePlugin(yaml); | |
| 24 return new PluginManifest(contributesTo: pluginHost, plugin: plugin); | |
| 25 } | |
| 26 | |
| 27 String _asString(dynamic yaml) { | |
| 28 if (yaml != null && yaml is! String) { | |
| 29 throw new PluginConfigFormatException( | |
| 30 'Unable to parse pugin manifest, ' | |
| 31 'expected `String`, got `${yaml.runtimeType}`', | |
| 32 yaml); | |
| 33 } | |
| 34 return yaml; | |
| 35 } | |
| 36 | |
| 37 Iterable<String> _parseHosts(dynamic yaml) { | |
| 38 List<String> hosts = <String>[]; | |
| 39 if (yaml is String) { | |
| 40 hosts.add(yaml); | |
| 41 } else if (yaml is YamlList) { | |
| 42 yaml.forEach((h) => hosts.add(_asString(h))); | |
| 43 } | |
| 44 return hosts; | |
| 45 } | |
| 46 | |
| 47 PluginInfo _parsePlugin(dynamic yaml) { | |
| 48 if (yaml != null) { | |
| 49 _verifyMap(yaml, 'plugin manifest'); | |
| 50 return new PluginInfo._fromYaml(details: yaml); | |
| 51 } | |
| 52 return null; | |
| 53 } | |
| 54 | |
| 55 PluginInfo _processPluginMapping(dynamic name, dynamic details) { | |
| 56 if (name is String) { | |
| 57 if (details is String) { | |
| 58 return new PluginInfo(name: name, version: details); | |
| 59 } | |
| 60 if (details is YamlMap) { | |
| 61 return new PluginInfo._fromYaml(name: name, details: details); | |
| 62 } | |
| 63 } | |
| 64 | |
| 65 return null; | |
| 66 } | |
| 67 | |
| 68 _verifyMap(dynamic yaml, String context) { | |
| 69 if (yaml is! YamlMap) { | |
| 70 throw new PluginConfigFormatException( | |
| 71 'Unable to parse $context, ' | |
| 72 'expected `YamlMap`, got `${yaml.runtimeType}`', | |
| 73 yaml); | |
| 74 } | |
| 75 } | |
| 76 | |
| 77 /// A callback for error handling. | |
| 78 typedef ErrorHandler(Exception e); | |
| 79 | |
| 80 /// Describes plugin configuration information as extracted from an | |
| 81 /// analysis options map or plugin manifest. | |
| 82 class PluginConfig { | |
| 83 final Iterable<PluginInfo> plugins; | |
| 84 PluginConfig(this.plugins); | |
| 85 | |
| 86 /// Create a plugin configuration from an options map. | |
| 87 factory PluginConfig.fromOptions(Map<String, Object> options) { | |
| 88 List<PluginInfo> plugins = []; | |
| 89 var analyzerOptions = options[_analyzerOptionScope]; | |
| 90 if (analyzerOptions != null) { | |
| 91 //TODO(pq): handle "raw" maps (https://github.com/dart-lang/sdk/issues/251
26) | |
| 92 if (analyzerOptions is YamlMap) { | |
| 93 var pluginConfig = analyzerOptions[_pluginOptionScope]; | |
| 94 if (pluginConfig is YamlMap) { | |
| 95 pluginConfig.forEach((name, details) { | |
| 96 var plugin = _processPluginMapping(name, details); | |
| 97 if (plugin != null) { | |
| 98 plugins.add(plugin); | |
| 99 } | |
| 100 }); | |
| 101 } else { | |
| 102 // Anything but an empty list of plugins is treated as a format error. | |
| 103 if (pluginConfig != null) { | |
| 104 throw new PluginConfigFormatException( | |
| 105 'Unrecognized plugin config format, expected `YamlMap`, ' | |
| 106 'got `${pluginConfig.runtimeType}`', | |
| 107 pluginConfig); | |
| 108 } | |
| 109 } | |
| 110 } | |
| 111 } | |
| 112 | |
| 113 return new PluginConfig(plugins); | |
| 114 } | |
| 115 } | |
| 116 | |
| 117 /// Thrown on bad plugin config format. | |
| 118 class PluginConfigFormatException implements Exception { | |
| 119 /// Descriptive message. | |
| 120 final message; | |
| 121 | |
| 122 /// The `plugin:` yaml node for generating detailed error feedback. | |
| 123 final yamlNode; | |
| 124 PluginConfigFormatException(this.message, this.yamlNode); | |
| 125 } | |
| 126 | |
| 127 /// Extracts plugin config details from analysis options. | |
| 128 class PluginConfigOptionsProcessor extends OptionsProcessor { | |
| 129 final ErrorHandler _errorHandler; | |
| 130 | |
| 131 PluginConfig _config; | |
| 132 | |
| 133 PluginConfigOptionsProcessor([this._errorHandler]); | |
| 134 | |
| 135 /// The processed plugin config. | |
| 136 PluginConfig get config => _config; | |
| 137 | |
| 138 @override | |
| 139 void onError(Exception exception) { | |
| 140 if (_errorHandler != null) { | |
| 141 _errorHandler(exception); | |
| 142 } | |
| 143 } | |
| 144 | |
| 145 @override | |
| 146 void optionsProcessed(AnalysisContext context, Map<String, Object> options) { | |
| 147 _config = new PluginConfig.fromOptions(options); | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 /// Describes plugin information. | |
| 152 class PluginInfo { | |
| 153 final String name; | |
| 154 final String className; | |
| 155 final String version; | |
| 156 final String libraryUri; | |
| 157 final String packageName; | |
| 158 final String path; | |
| 159 PluginInfo( | |
| 160 {this.name, | |
| 161 this.version, | |
| 162 this.className, | |
| 163 this.libraryUri, | |
| 164 this.packageName, | |
| 165 this.path}); | |
| 166 | |
| 167 factory PluginInfo._fromYaml({String name, YamlMap details}) => | |
| 168 new PluginInfo( | |
| 169 name: name, | |
| 170 version: _asString(details['version']), | |
| 171 className: _asString(details['class_name']), | |
| 172 libraryUri: _asString(details['library_uri']), | |
| 173 packageName: _asString(details['package_name']), | |
| 174 path: _asString(details['path'])); | |
| 175 } | |
| 176 | |
| 177 /// Plugin manifests accompany plugin packages, providing | |
| 178 /// configuration information for published plugins. | |
| 179 /// | |
| 180 /// Provisionally, plugin manifests live in a file `plugin.yaml` | |
| 181 /// at the root of the plugin package. | |
| 182 /// | |
| 183 /// my_plugin/ | |
| 184 /// bin/ | |
| 185 /// lib/ | |
| 186 /// plugin.yaml | |
| 187 /// pubspec.yaml | |
| 188 /// | |
| 189 /// Provisional manifest file format: | |
| 190 /// | |
| 191 /// class_name: MyAnalyzerPlugin | |
| 192 /// library_uri: 'my_plugin/my_analyzer_plugin.dart' | |
| 193 /// contributes_to: analyzer | |
| 194 class PluginManifest { | |
| 195 PluginInfo plugin; | |
| 196 Iterable<String> contributesTo; | |
| 197 PluginManifest({this.plugin, this.contributesTo}); | |
| 198 } | |
| OLD | NEW |