| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library analyzer.src.task.html; | 5 library analyzer.src.task.html; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 | 8 |
| 9 import 'package:analyzer/src/context/cache.dart'; |
| 9 import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask; | 10 import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask; |
| 10 import 'package:analyzer/src/generated/error.dart'; | 11 import 'package:analyzer/src/generated/error.dart'; |
| 12 import 'package:analyzer/src/generated/java_engine.dart'; |
| 13 import 'package:analyzer/src/generated/scanner.dart'; |
| 11 import 'package:analyzer/src/generated/source.dart'; | 14 import 'package:analyzer/src/generated/source.dart'; |
| 12 import 'package:analyzer/src/task/dart.dart'; | 15 import 'package:analyzer/src/plugin/engine_plugin.dart'; |
| 13 import 'package:analyzer/src/task/general.dart'; | 16 import 'package:analyzer/src/task/general.dart'; |
| 14 import 'package:analyzer/task/dart.dart'; | 17 import 'package:analyzer/task/dart.dart'; |
| 15 import 'package:analyzer/task/general.dart'; | 18 import 'package:analyzer/task/general.dart'; |
| 16 import 'package:analyzer/task/html.dart'; | 19 import 'package:analyzer/task/html.dart'; |
| 17 import 'package:analyzer/task/model.dart'; | 20 import 'package:analyzer/task/model.dart'; |
| 18 import 'package:html/dom.dart'; | 21 import 'package:html/dom.dart'; |
| 19 import 'package:html/parser.dart'; | 22 import 'package:html/parser.dart'; |
| 20 import 'package:source_span/source_span.dart'; | 23 import 'package:source_span/source_span.dart'; |
| 21 import 'package:analyzer/src/context/cache.dart'; | |
| 22 import 'package:analyzer/src/generated/java_engine.dart'; | |
| 23 import 'package:analyzer/src/generated/scanner.dart'; | |
| 24 | 24 |
| 25 /** | 25 /** |
| 26 * The Dart scripts that are embedded in an HTML file. | 26 * The Dart scripts that are embedded in an HTML file. |
| 27 */ | 27 */ |
| 28 final ListResultDescriptor<DartScript> DART_SCRIPTS = | 28 final ListResultDescriptor<DartScript> DART_SCRIPTS = |
| 29 new ListResultDescriptor<DartScript>('DART_SCRIPTS', DartScript.EMPTY_LIST); | 29 new ListResultDescriptor<DartScript>('DART_SCRIPTS', DartScript.EMPTY_LIST); |
| 30 | 30 |
| 31 /** | 31 /** |
| 32 * The errors found while parsing an HTML file. | 32 * The errors found while parsing an HTML file. |
| 33 */ | 33 */ |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 */ | 100 */ |
| 101 class DartScriptsTask extends SourceBasedAnalysisTask { | 101 class DartScriptsTask extends SourceBasedAnalysisTask { |
| 102 /** | 102 /** |
| 103 * The name of the [HTML_DOCUMENT] input. | 103 * The name of the [HTML_DOCUMENT] input. |
| 104 */ | 104 */ |
| 105 static const String DOCUMENT_INPUT = 'DOCUMENT'; | 105 static const String DOCUMENT_INPUT = 'DOCUMENT'; |
| 106 | 106 |
| 107 /** | 107 /** |
| 108 * The task descriptor describing this kind of task. | 108 * The task descriptor describing this kind of task. |
| 109 */ | 109 */ |
| 110 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('DartScriptsTask', | 110 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 111 createTask, buildInputs, <ResultDescriptor>[ | 111 'DartScriptsTask', |
| 112 DART_SCRIPTS, | 112 createTask, |
| 113 REFERENCED_LIBRARIES | 113 buildInputs, |
| 114 ]); | 114 <ResultDescriptor>[DART_SCRIPTS, REFERENCED_LIBRARIES]); |
| 115 | 115 |
| 116 DartScriptsTask(InternalAnalysisContext context, AnalysisTarget target) | 116 DartScriptsTask(InternalAnalysisContext context, AnalysisTarget target) |
| 117 : super(context, target); | 117 : super(context, target); |
| 118 | 118 |
| 119 @override | 119 @override |
| 120 TaskDescriptor get descriptor => DESCRIPTOR; | 120 TaskDescriptor get descriptor => DESCRIPTOR; |
| 121 | 121 |
| 122 @override | 122 @override |
| 123 void internalPerform() { | 123 void internalPerform() { |
| 124 // | 124 // |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 return new DartScriptsTask(context, target); | 183 return new DartScriptsTask(context, target); |
| 184 } | 184 } |
| 185 } | 185 } |
| 186 | 186 |
| 187 /** | 187 /** |
| 188 * A task that merges all of the errors for a single source into a single list | 188 * A task that merges all of the errors for a single source into a single list |
| 189 * of errors. | 189 * of errors. |
| 190 */ | 190 */ |
| 191 class HtmlErrorsTask extends SourceBasedAnalysisTask { | 191 class HtmlErrorsTask extends SourceBasedAnalysisTask { |
| 192 /** | 192 /** |
| 193 * The suffix to add to the names of contributed error results. |
| 194 */ |
| 195 static const String INPUT_SUFFIX = '_input'; |
| 196 |
| 197 /** |
| 193 * The name of the input that is a list of errors from each of the embedded | 198 * The name of the input that is a list of errors from each of the embedded |
| 194 * Dart scripts. | 199 * Dart scripts. |
| 195 */ | 200 */ |
| 196 static const String DART_ERRORS_INPUT = 'DART_ERRORS'; | 201 static const String DART_ERRORS_INPUT = 'DART_ERRORS'; |
| 197 | 202 |
| 198 /** | 203 /** |
| 199 * The name of the [HTML_DOCUMENT_ERRORS] input. | |
| 200 */ | |
| 201 static const String DOCUMENT_ERRORS_INPUT = 'DOCUMENT_ERRORS'; | |
| 202 | |
| 203 /** | |
| 204 * The task descriptor describing this kind of task. | 204 * The task descriptor describing this kind of task. |
| 205 */ | 205 */ |
| 206 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('HtmlErrorsTask', | 206 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('HtmlErrorsTask', |
| 207 createTask, buildInputs, <ResultDescriptor>[HTML_ERRORS]); | 207 createTask, buildInputs, <ResultDescriptor>[HTML_ERRORS]); |
| 208 | 208 |
| 209 HtmlErrorsTask(InternalAnalysisContext context, AnalysisTarget target) | 209 HtmlErrorsTask(InternalAnalysisContext context, AnalysisTarget target) |
| 210 : super(context, target); | 210 : super(context, target); |
| 211 | 211 |
| 212 @override | 212 @override |
| 213 TaskDescriptor get descriptor => DESCRIPTOR; | 213 TaskDescriptor get descriptor => DESCRIPTOR; |
| 214 | 214 |
| 215 @override | 215 @override |
| 216 void internalPerform() { | 216 void internalPerform() { |
| 217 EnginePlugin enginePlugin = AnalysisEngine.instance.enginePlugin; |
| 217 // | 218 // |
| 218 // Prepare inputs. | 219 // Prepare inputs. |
| 219 // | 220 // |
| 220 List<List<AnalysisError>> dartErrors = getRequiredInput(DART_ERRORS_INPUT); | 221 List<List<AnalysisError>> dartErrors = getRequiredInput(DART_ERRORS_INPUT); |
| 221 List<AnalysisError> documentErrors = | 222 List<List<AnalysisError>> htmlErrors = <List<AnalysisError>>[]; |
| 222 getRequiredInput(DOCUMENT_ERRORS_INPUT); | 223 for (ResultDescriptor result in enginePlugin.htmlErrors) { |
| 224 String inputName = result.name + INPUT_SUFFIX; |
| 225 htmlErrors.add(getRequiredInput(inputName)); |
| 226 } |
| 223 // | 227 // |
| 224 // Compute the error list. | 228 // Compute the error list. |
| 225 // | 229 // |
| 226 List<AnalysisError> errors = <AnalysisError>[]; | 230 List<List<AnalysisError>> errorLists = <List<AnalysisError>>[]; |
| 227 errors.addAll(documentErrors); | 231 errorLists.addAll(dartErrors); |
| 228 for (List<AnalysisError> scriptErrors in dartErrors) { | 232 errorLists.addAll(htmlErrors); |
| 229 errors.addAll(scriptErrors); | |
| 230 } | |
| 231 // | 233 // |
| 232 // Record outputs. | 234 // Record outputs. |
| 233 // | 235 // |
| 234 outputs[HTML_ERRORS] = removeDuplicateErrors(errors); | 236 outputs[HTML_ERRORS] = AnalysisError.mergeLists(errorLists); |
| 235 } | 237 } |
| 236 | 238 |
| 237 /** | 239 /** |
| 238 * Return a map from the names of the inputs of this kind of task to the task | 240 * Return a map from the names of the inputs of this kind of task to the task |
| 239 * input descriptors describing those inputs for a task with the | 241 * input descriptors describing those inputs for a task with the |
| 240 * given [target]. | 242 * given [target]. |
| 241 */ | 243 */ |
| 242 static Map<String, TaskInput> buildInputs(Source target) { | 244 static Map<String, TaskInput> buildInputs(Source target) { |
| 243 return <String, TaskInput>{ | 245 EnginePlugin enginePlugin = AnalysisEngine.instance.enginePlugin; |
| 244 DOCUMENT_ERRORS_INPUT: HTML_DOCUMENT_ERRORS.of(target), | 246 Map<String, TaskInput> inputs = <String, TaskInput>{ |
| 245 DART_ERRORS_INPUT: DART_SCRIPTS.of(target).toListOf(DART_ERRORS) | 247 DART_ERRORS_INPUT: DART_SCRIPTS.of(target).toListOf(DART_ERRORS) |
| 246 }; | 248 }; |
| 249 for (ResultDescriptor result in enginePlugin.htmlErrors) { |
| 250 String inputName = result.name + INPUT_SUFFIX; |
| 251 inputs[inputName] = result.of(target); |
| 252 } |
| 253 return inputs; |
| 247 } | 254 } |
| 248 | 255 |
| 249 /** | 256 /** |
| 250 * Create an [HtmlErrorsTask] based on the given [target] in the given | 257 * Create an [HtmlErrorsTask] based on the given [target] in the given |
| 251 * [context]. | 258 * [context]. |
| 252 */ | 259 */ |
| 253 static HtmlErrorsTask createTask( | 260 static HtmlErrorsTask createTask( |
| 254 AnalysisContext context, AnalysisTarget target) { | 261 AnalysisContext context, AnalysisTarget target) { |
| 255 return new HtmlErrorsTask(context, target); | 262 return new HtmlErrorsTask(context, target); |
| 256 } | 263 } |
| 257 } | 264 } |
| 258 | 265 |
| 259 /** | 266 /** |
| 260 * A task that scans the content of a file, producing a set of Dart tokens. | 267 * A task that scans the content of a file, producing a set of Dart tokens. |
| 261 */ | 268 */ |
| 262 class ParseHtmlTask extends SourceBasedAnalysisTask { | 269 class ParseHtmlTask extends SourceBasedAnalysisTask { |
| 263 /** | 270 /** |
| 264 * The name of the input whose value is the content of the file. | 271 * The name of the input whose value is the content of the file. |
| 265 */ | 272 */ |
| 266 static const String CONTENT_INPUT_NAME = 'CONTENT_INPUT_NAME'; | 273 static const String CONTENT_INPUT_NAME = 'CONTENT_INPUT_NAME'; |
| 267 | 274 |
| 268 /** | 275 /** |
| 269 * The task descriptor describing this kind of task. | 276 * The task descriptor describing this kind of task. |
| 270 */ | 277 */ |
| 271 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('ParseHtmlTask', | 278 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 272 createTask, buildInputs, <ResultDescriptor>[ | 279 'ParseHtmlTask', |
| 273 HTML_DOCUMENT, | 280 createTask, |
| 274 HTML_DOCUMENT_ERRORS | 281 buildInputs, |
| 275 ]); | 282 <ResultDescriptor>[HTML_DOCUMENT, HTML_DOCUMENT_ERRORS, LINE_INFO]); |
| 276 | 283 |
| 277 /** | 284 /** |
| 278 * Initialize a newly created task to access the content of the source | 285 * Initialize a newly created task to access the content of the source |
| 279 * associated with the given [target] in the given [context]. | 286 * associated with the given [target] in the given [context]. |
| 280 */ | 287 */ |
| 281 ParseHtmlTask(InternalAnalysisContext context, AnalysisTarget target) | 288 ParseHtmlTask(InternalAnalysisContext context, AnalysisTarget target) |
| 282 : super(context, target); | 289 : super(context, target); |
| 283 | 290 |
| 284 @override | 291 @override |
| 285 TaskDescriptor get descriptor => DESCRIPTOR; | 292 TaskDescriptor get descriptor => DESCRIPTOR; |
| 286 | 293 |
| 287 @override | 294 @override |
| 288 void internalPerform() { | 295 void internalPerform() { |
| 289 String content = getRequiredInput(CONTENT_INPUT_NAME); | 296 String content = getRequiredInput(CONTENT_INPUT_NAME); |
| 290 | 297 |
| 291 if (context.getModificationStamp(target.source) < 0) { | 298 if (context.getModificationStamp(target.source) < 0) { |
| 292 String message = 'Content could not be read'; | 299 String message = 'Content could not be read'; |
| 293 if (context is InternalAnalysisContext) { | 300 if (context is InternalAnalysisContext) { |
| 294 CacheEntry entry = (context as InternalAnalysisContext).getCacheEntry(ta
rget); | 301 CacheEntry entry = |
| 302 (context as InternalAnalysisContext).getCacheEntry(target); |
| 295 CaughtException exception = entry.exception; | 303 CaughtException exception = entry.exception; |
| 296 if (exception != null) { | 304 if (exception != null) { |
| 297 message = exception.toString(); | 305 message = exception.toString(); |
| 298 } | 306 } |
| 299 } | 307 } |
| 300 | 308 |
| 301 outputs[HTML_DOCUMENT] = new Document(); | 309 outputs[HTML_DOCUMENT] = new Document(); |
| 302 outputs[HTML_DOCUMENT_ERRORS] = <AnalysisError>[new AnalysisError( | 310 outputs[HTML_DOCUMENT_ERRORS] = <AnalysisError>[ |
| 303 target.source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [message])]; | 311 new AnalysisError( |
| 312 target.source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [message]) |
| 313 ]; |
| 314 outputs[LINE_INFO] = new LineInfo(<int>[0]); |
| 304 } else { | 315 } else { |
| 305 HtmlParser parser = new HtmlParser(content, generateSpans: true); | 316 HtmlParser parser = new HtmlParser(content, generateSpans: true); |
| 306 parser.compatMode = 'quirks'; | 317 parser.compatMode = 'quirks'; |
| 307 Document document = parser.parse(); | 318 Document document = parser.parse(); |
| 319 // |
| 320 // Convert errors. |
| 321 // |
| 308 List<ParseError> parseErrors = parser.errors; | 322 List<ParseError> parseErrors = parser.errors; |
| 309 List<AnalysisError> errors = <AnalysisError>[]; | 323 List<AnalysisError> errors = <AnalysisError>[]; |
| 310 for (ParseError parseError in parseErrors) { | 324 for (ParseError parseError in parseErrors) { |
| 311 SourceSpan span = parseError.span; | 325 SourceSpan span = parseError.span; |
| 312 errors.add(new AnalysisError(target.source, span.start.offset, | 326 errors.add(new AnalysisError(target.source, span.start.offset, |
| 313 span.length, HtmlErrorCode.PARSE_ERROR, [parseError.message])); | 327 span.length, HtmlErrorCode.PARSE_ERROR, [parseError.message])); |
| 314 } | 328 } |
| 315 | 329 // |
| 330 // Record outputs. |
| 331 // |
| 316 outputs[HTML_DOCUMENT] = document; | 332 outputs[HTML_DOCUMENT] = document; |
| 317 outputs[HTML_DOCUMENT_ERRORS] = errors; | 333 outputs[HTML_DOCUMENT_ERRORS] = errors; |
| 334 outputs[LINE_INFO] = _computeLineInfo(content); |
| 318 } | 335 } |
| 319 } | 336 } |
| 320 | 337 |
| 321 /** | 338 /** |
| 322 * Return a map from the names of the inputs of this kind of task to the task | 339 * Return a map from the names of the inputs of this kind of task to the task |
| 323 * input descriptors describing those inputs for a task with the given | 340 * input descriptors describing those inputs for a task with the given |
| 324 * [source]. | 341 * [source]. |
| 325 */ | 342 */ |
| 326 static Map<String, TaskInput> buildInputs(Source source) { | 343 static Map<String, TaskInput> buildInputs(Source source) { |
| 327 return <String, TaskInput>{CONTENT_INPUT_NAME: CONTENT.of(source)}; | 344 return <String, TaskInput>{CONTENT_INPUT_NAME: CONTENT.of(source)}; |
| 328 } | 345 } |
| 329 | 346 |
| 330 /** | 347 /** |
| 331 * Create a [ParseHtmlTask] based on the given [target] in the given [context]
. | 348 * Create a [ParseHtmlTask] based on the given [target] in the given [context]
. |
| 332 */ | 349 */ |
| 333 static ParseHtmlTask createTask( | 350 static ParseHtmlTask createTask( |
| 334 AnalysisContext context, AnalysisTarget target) { | 351 AnalysisContext context, AnalysisTarget target) { |
| 335 return new ParseHtmlTask(context, target); | 352 return new ParseHtmlTask(context, target); |
| 336 } | 353 } |
| 354 |
| 355 /** |
| 356 * Compute [LineInfo] for the given [content]. |
| 357 */ |
| 358 static LineInfo _computeLineInfo(String content) { |
| 359 List<int> lineStarts = <int>[0]; |
| 360 for (int index = 0; index < content.length; index++) { |
| 361 if (content.codeUnitAt(index) == 0x0A) { |
| 362 lineStarts.add(index + 1); |
| 363 } |
| 364 } |
| 365 return new LineInfo(lineStarts); |
| 366 } |
| 337 } | 367 } |
| 338 | 368 |
| 339 /** | 369 /** |
| 340 * A fragment of a [DartScript]. | 370 * A fragment of a [DartScript]. |
| 341 */ | 371 */ |
| 342 class ScriptFragment { | 372 class ScriptFragment { |
| 343 /** | 373 /** |
| 344 * The offset of the first character of the fragment, relative to the start of | 374 * The offset of the first character of the fragment, relative to the start of |
| 345 * the containing source. | 375 * the containing source. |
| 346 */ | 376 */ |
| (...skipping 14 matching lines...) Expand all Loading... |
| 361 * The content of the fragment. | 391 * The content of the fragment. |
| 362 */ | 392 */ |
| 363 final String content; | 393 final String content; |
| 364 | 394 |
| 365 /** | 395 /** |
| 366 * Initialize a newly created script fragment to have the given [offset] and | 396 * Initialize a newly created script fragment to have the given [offset] and |
| 367 * [content]. | 397 * [content]. |
| 368 */ | 398 */ |
| 369 ScriptFragment(this.offset, this.line, this.column, this.content); | 399 ScriptFragment(this.offset, this.line, this.column, this.content); |
| 370 } | 400 } |
| OLD | NEW |