blob: 431cf3052d553c107af485e7f768809b5338c2eb [file] [log] [blame]
// 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.
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/api/general.dart';
import 'package:analyzer/src/task/api/model.dart';
import 'package:analyzer/src/task/api/yaml.dart';
import 'package:analyzer/src/task/general.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.temporary(name, message, correction: correction);
@override
ErrorSeverity get errorSeverity => ErrorSeverity.ERROR;
@override
ErrorType get type => ErrorType.COMPILE_TIME_ERROR;
}