| // Copyright (c) 2016, 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.task.yaml; |
| |
| import 'package:analyzer/error/error.dart'; |
| import 'package:analyzer/exception/exception.dart'; |
| import 'package:analyzer/src/context/cache.dart'; |
| import 'package:analyzer/src/dart/scanner/scanner.dart'; |
| import 'package:analyzer/src/generated/engine.dart'; |
| import 'package:analyzer/src/generated/source.dart'; |
| import 'package:analyzer/src/task/general.dart'; |
| import 'package:analyzer/task/general.dart'; |
| import 'package:analyzer/task/model.dart'; |
| import 'package:analyzer/task/yaml.dart'; |
| import 'package:source_span/source_span.dart'; |
| import 'package:yaml/yaml.dart'; |
| |
| /** |
| * A task that scans the content of a YAML file, producing a YAML document. |
| */ |
| class ParseYamlTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the input whose value is the content of the file. |
| */ |
| static const String CONTENT_INPUT_NAME = 'CONTENT_INPUT_NAME'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 'ParseYamlTask', |
| createTask, |
| buildInputs, |
| <ResultDescriptor>[YAML_DOCUMENT, YAML_ERRORS, LINE_INFO], |
| suitabilityFor: suitabilityFor); |
| |
| /** |
| * Initialize a newly created task to access the content of the source |
| * associated with the given [target] in the given [context]. |
| */ |
| ParseYamlTask(InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| Source source = target.source; |
| String uri = source.uri.toString(); |
| String content = getRequiredInput(CONTENT_INPUT_NAME); |
| |
| if (context.getModificationStamp(source) < 0) { |
| String message = 'Content could not be read'; |
| if (context is InternalAnalysisContext) { |
| CacheEntry entry = |
| (context as InternalAnalysisContext).getCacheEntry(target); |
| CaughtException exception = entry.exception; |
| if (exception != null) { |
| message = exception.toString(); |
| } |
| } |
| // |
| // Record outputs. |
| // |
| outputs[YAML_DOCUMENT] = loadYamlDocument('', sourceUrl: uri); |
| outputs[YAML_ERRORS] = <AnalysisError>[ |
| new AnalysisError( |
| source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [message]) |
| ]; |
| outputs[LINE_INFO] = new LineInfo(<int>[0]); |
| } else { |
| YamlDocument document; |
| List<AnalysisError> errors = <AnalysisError>[]; |
| try { |
| document = loadYamlDocument(content, sourceUrl: uri); |
| } on YamlException catch (exception) { |
| SourceSpan span = exception.span; |
| int offset = span.start.offset; |
| int length = span.end.offset - offset; |
| errors.add(new AnalysisError(source, offset, length, |
| YamlErrorCode.PARSE_ERROR, [exception.message])); |
| } catch (exception, stackTrace) { |
| throw new AnalysisException('Error while parsing ${source.fullName}', |
| new CaughtException(exception, stackTrace)); |
| } |
| // |
| // Record outputs. |
| // |
| outputs[YAML_DOCUMENT] = document; |
| outputs[YAML_ERRORS] = errors; |
| outputs[LINE_INFO] = new LineInfo.fromContent(content); |
| } |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the given |
| * [source]. |
| */ |
| static Map<String, TaskInput> buildInputs(AnalysisTarget source) { |
| return <String, TaskInput>{CONTENT_INPUT_NAME: CONTENT.of(source)}; |
| } |
| |
| /** |
| * Create a [ParseYamlTask] based on the given [target] in the given [context]. |
| */ |
| static ParseYamlTask createTask( |
| AnalysisContext context, AnalysisTarget target) { |
| return new ParseYamlTask(context, target); |
| } |
| |
| /** |
| * Return an indication of how suitable this task is for the given [target]. |
| */ |
| static TaskSuitability suitabilityFor(AnalysisTarget target) { |
| if (target is Source && target.shortName.endsWith('.yaml')) { |
| return TaskSuitability.HIGHEST; |
| } |
| return TaskSuitability.NONE; |
| } |
| } |
| |
| /** |
| * The error codes used for errors in YAML files. |
| */ |
| class YamlErrorCode extends ErrorCode { |
| // TODO(brianwilkerson) Move this class to error.dart. |
| |
| /** |
| * An error code indicating that there is a syntactic error in the file. |
| * |
| * Parameters: |
| * 0: the error message from the parse error |
| */ |
| static const YamlErrorCode PARSE_ERROR = |
| const YamlErrorCode('PARSE_ERROR', '{0}'); |
| |
| /** |
| * Initialize a newly created error code to have the given [name]. The message |
| * associated with the error will be created from the given [message] |
| * template. The correction associated with the error will be created from the |
| * given [correction] template. |
| */ |
| const YamlErrorCode(String name, String message, [String correction]) |
| : super(name, message, correction); |
| |
| @override |
| ErrorSeverity get errorSeverity => ErrorSeverity.ERROR; |
| |
| @override |
| ErrorType get type => ErrorType.COMPILE_TIME_ERROR; |
| } |