OLD | NEW |
---|---|
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 /** | 5 /** |
6 * **docgen** is a tool for creating machine readable representations of Dart | 6 * **docgen** is a tool for creating machine readable representations of Dart |
7 * code metadata, including: classes, members, comments and annotations. | 7 * code metadata, including: classes, members, comments and annotations. |
8 * | 8 * |
9 * docgen is run on a `.dart` file or a directory containing `.dart` files. | 9 * docgen is run on a `.dart` file or a directory containing `.dart` files. |
10 * | 10 * |
11 * $ dart docgen.dart [OPTIONS] [FILE/DIR] | 11 * $ dart docgen.dart [OPTIONS] [FILE/DIR] |
12 * | 12 * |
13 * This creates files called `docs/<library_name>.yaml` in your current | 13 * This creates files called `docs/<library_name>.yaml` in your current |
14 * working directory. | 14 * working directory. |
15 */ | 15 */ |
16 library docgen; | 16 library docgen; |
17 | 17 |
18 import 'dart:io'; | 18 import 'dart:io'; |
19 import 'dart:json'; | 19 import 'dart:json'; |
20 import 'dart:async'; | 20 import 'dart:async'; |
21 | 21 |
22 import 'package:logging/logging.dart'; | 22 import 'package:logging/logging.dart'; |
23 import 'package:markdown/markdown.dart' as markdown; | 23 import 'package:markdown/markdown.dart' as markdown; |
24 import 'package:path/path.dart' as path; | 24 import 'package:pathos/path.dart' as path; |
Bob Nystrom
2013/07/15 23:11:13
This should be "path" now. Is there a reason you n
| |
25 | 25 |
26 import 'dart2yaml.dart'; | 26 import 'dart2yaml.dart'; |
27 import 'src/io.dart'; | 27 import 'src/io.dart'; |
28 import '../../../sdk/lib/_internal/compiler/compiler.dart' as api; | 28 import '../../../sdk/lib/_internal/compiler/compiler.dart' as api; |
29 import '../../../sdk/lib/_internal/compiler/implementation/filenames.dart'; | 29 import '../../../sdk/lib/_internal/compiler/implementation/filenames.dart'; |
30 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirro r.dart' | 30 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirro r.dart' |
31 as dart2js; | 31 as dart2js; |
32 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart' ; | 32 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart' ; |
33 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util. dart'; | 33 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util. dart'; |
34 import '../../../sdk/lib/_internal/compiler/implementation/source_file_provider. dart'; | 34 import '../../../sdk/lib/_internal/compiler/implementation/source_file_provider. dart'; |
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
259 CommentInstanceMirror comment = metadata; | 259 CommentInstanceMirror comment = metadata; |
260 if (comment.isDocComment) { | 260 if (comment.isDocComment) { |
261 if (commentText == null) { | 261 if (commentText == null) { |
262 commentText = comment.trimmedText; | 262 commentText = comment.trimmedText; |
263 } else { | 263 } else { |
264 commentText = '$commentText ${comment.trimmedText}'; | 264 commentText = '$commentText ${comment.trimmedText}'; |
265 } | 265 } |
266 } | 266 } |
267 } | 267 } |
268 }); | 268 }); |
269 commentText = commentText == null ? '' : | 269 |
270 markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver) | 270 commentText = commentText == null ? '' : |
271 .replaceAll('\n', ' '); | 271 markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver); |
272 return commentText; | 272 return commentText; |
273 } | 273 } |
274 | 274 |
275 /** | 275 /** |
276 * Converts all [foo] references in comments to <a>libraryName.foo</a>. | 276 * Converts all [foo] references in comments to <a>libraryName.foo</a>. |
277 */ | 277 */ |
278 markdown.Node fixReference(String name, LibraryMirror currentLibrary, | 278 markdown.Node fixReference(String name, LibraryMirror currentLibrary, |
279 ClassMirror currentClass, MemberMirror currentMember) { | 279 ClassMirror currentClass, MemberMirror currentMember) { |
280 var reference; | 280 var reference; |
281 var memberScope = currentMember == null ? | 281 var memberScope = currentMember == null ? |
(...skipping 11 matching lines...) Expand all Loading... | |
293 * Returns a map of [Variable] objects constructed from inputted mirrors. | 293 * Returns a map of [Variable] objects constructed from inputted mirrors. |
294 */ | 294 */ |
295 Map<String, Variable> _getVariables(Map<String, VariableMirror> mirrorMap, | 295 Map<String, Variable> _getVariables(Map<String, VariableMirror> mirrorMap, |
296 bool includePrivate) { | 296 bool includePrivate) { |
297 var data = {}; | 297 var data = {}; |
298 // TODO(janicejl): When map to map feature is created, replace the below with | 298 // TODO(janicejl): When map to map feature is created, replace the below with |
299 // a filter. Issue(#9590). | 299 // a filter. Issue(#9590). |
300 mirrorMap.forEach((String mirrorName, VariableMirror mirror) { | 300 mirrorMap.forEach((String mirrorName, VariableMirror mirror) { |
301 if (includePrivate || !mirror.isPrivate) { | 301 if (includePrivate || !mirror.isPrivate) { |
302 _currentMember = mirror; | 302 _currentMember = mirror; |
303 data[mirrorName] = new Variable(mirrorName, mirror.qualifiedName, | 303 data[mirrorName] = new Variable(mirrorName, mirror.isFinal, |
304 mirror.isFinal, mirror.isStatic, mirror.type.qualifiedName, | 304 mirror.isStatic, mirror.type.qualifiedName, _getComment(mirror), |
305 _getComment(mirror), _getAnnotations(mirror)); | 305 _getAnnotations(mirror)); |
306 } | 306 } |
307 }); | 307 }); |
308 return data; | 308 return data; |
309 } | 309 } |
310 | 310 |
311 /** | 311 /** |
312 * Returns a map of [Method] objects constructed from inputted mirrors. | 312 * Returns a map of [Method] objects constructed from inputted mirrors. |
313 */ | 313 */ |
314 Map<String, Method> _getMethods(Map<String, MethodMirror> mirrorMap, | 314 Map<String, Map<String, Method>> _getMethods |
315 bool includePrivate) { | 315 (Map<String, MethodMirror> mirrorMap, bool includePrivate) { |
316 var data = {}; | 316 |
317 var setters = {}; | |
318 var getters = {}; | |
319 var constructors = {}; | |
320 var operators = {}; | |
321 var methods = {}; | |
322 | |
317 mirrorMap.forEach((String mirrorName, MethodMirror mirror) { | 323 mirrorMap.forEach((String mirrorName, MethodMirror mirror) { |
318 if (includePrivate || !mirror.isPrivate) { | 324 if (includePrivate || !mirror.isPrivate) { |
325 var method = new Method(mirrorName, mirror.isStatic, | |
326 mirror.returnType.qualifiedName, _getComment(mirror), | |
327 _getParameters(mirror.parameters), _getAnnotations(mirror)); | |
319 _currentMember = mirror; | 328 _currentMember = mirror; |
320 data[mirrorName] = new Method(mirrorName, mirror.qualifiedName, | 329 if (mirror.isSetter) { |
321 mirror.isSetter, mirror.isGetter, mirror.isConstructor, | 330 setters[mirrorName] = method; |
322 mirror.isOperator, mirror.isStatic, mirror.returnType.qualifiedName, | 331 } else if (mirror.isGetter) { |
323 _getComment(mirror), _getParameters(mirror.parameters), | 332 getters[mirrorName] = method; |
324 _getAnnotations(mirror)); | 333 } else if (mirror.isConstructor) { |
334 constructors[mirrorName] = method; | |
335 } else if (mirror.isOperator) { | |
336 operators[mirrorName] = method; | |
337 } else if (mirror.isRegularMethod) { | |
338 methods[mirrorName] = method; | |
339 } else { | |
340 throw new StateError('${mirror.qualifiedName} - no method type match'); | |
341 } | |
325 } | 342 } |
326 }); | 343 }); |
327 return data; | 344 return {'setters' : setters, |
328 } | 345 'getters' : getters, |
346 'constructors' : constructors, | |
347 'operators' : operators, | |
348 'methods' : methods}; | |
349 } | |
329 | 350 |
330 /** | 351 /** |
331 * Returns a map of [Class] objects constructed from inputted mirrors. | 352 * Returns a map of [Class] objects constructed from inputted mirrors. |
332 */ | 353 */ |
333 Map<String, Class> _getClasses(Map<String, ClassMirror> mirrorMap, | 354 Map<String, Class> _getClasses(Map<String, ClassMirror> mirrorMap, |
334 bool includePrivate) { | 355 bool includePrivate) { |
335 var data = {}; | 356 var data = {}; |
336 mirrorMap.forEach((String mirrorName, ClassMirror mirror) { | 357 mirrorMap.forEach((String mirrorName, ClassMirror mirror) { |
337 if (includePrivate || !mirror.isPrivate) { | 358 if (includePrivate || !mirror.isPrivate) { |
338 _currentClass = mirror; | 359 _currentClass = mirror; |
339 var superclass = (mirror.superclass != null) ? | 360 var superclass = (mirror.superclass != null) ? |
340 mirror.superclass.qualifiedName : ''; | 361 mirror.superclass.qualifiedName : ''; |
341 var interfaces = | 362 var interfaces = |
342 mirror.superinterfaces.map((interface) => interface.qualifiedName); | 363 mirror.superinterfaces.map((interface) => interface.qualifiedName); |
343 data[mirrorName] = new Class(mirrorName, mirror.qualifiedName, | 364 data[mirrorName] = new Class(mirrorName, superclass, mirror.isAbstract, |
344 superclass, mirror.isAbstract, mirror.isTypedef, | 365 mirror.isTypedef, _getComment(mirror), interfaces.toList(), |
345 _getComment(mirror), interfaces.toList(), | |
346 _getVariables(mirror.variables, includePrivate), | 366 _getVariables(mirror.variables, includePrivate), |
347 _getMethods(mirror.methods, includePrivate), | 367 _getMethods(mirror.methods, includePrivate), |
348 _getAnnotations(mirror)); | 368 _getAnnotations(mirror)); |
349 } | 369 } |
350 }); | 370 }); |
351 return data; | 371 return data; |
352 } | 372 } |
353 | 373 |
354 /** | 374 /** |
355 * Returns a map of [Parameter] objects constructed from inputted mirrors. | 375 * Returns a map of [Parameter] objects constructed from inputted mirrors. |
356 */ | 376 */ |
357 Map<String, Parameter> _getParameters(List<ParameterMirror> mirrorList) { | 377 Map<String, Parameter> _getParameters(List<ParameterMirror> mirrorList) { |
358 var data = {}; | 378 var data = {}; |
359 mirrorList.forEach((ParameterMirror mirror) { | 379 mirrorList.forEach((ParameterMirror mirror) { |
360 _currentMember = mirror; | 380 _currentMember = mirror; |
361 data[mirror.simpleName] = new Parameter(mirror.simpleName, | 381 data[mirror.simpleName] = new Parameter(mirror.simpleName, |
362 mirror.qualifiedName, mirror.isOptional, mirror.isNamed, | 382 mirror.isOptional, mirror.isNamed, mirror.hasDefaultValue, |
363 mirror.hasDefaultValue, mirror.type.qualifiedName, | 383 mirror.type.qualifiedName, mirror.defaultValue, |
364 mirror.defaultValue, _getAnnotations(mirror)); | 384 _getAnnotations(mirror)); |
365 }); | 385 }); |
366 return data; | 386 return data; |
367 } | 387 } |
368 | 388 |
369 /** | 389 /** |
370 * Writes text to a file in the 'docs' directory. | 390 * Writes text to a file in the 'docs' directory. |
371 */ | 391 */ |
372 void _writeToFile(String text, String filename) { | 392 void _writeToFile(String text, String filename) { |
373 Directory dir = new Directory('docs'); | 393 Directory dir = new Directory('docs'); |
374 if (!dir.existsSync()) { | 394 if (!dir.existsSync()) { |
375 dir.createSync(); | 395 dir.createSync(); |
376 } | 396 } |
377 File file = new File('docs/$filename'); | 397 File file = new File('docs/$filename'); |
378 if (!file.existsSync()) { | 398 if (!file.existsSync()) { |
379 file.createSync(); | 399 file.createSync(); |
380 } | 400 } |
381 file.openSync(); | 401 file.openSync(); |
382 file.writeAsString(text); | 402 file.writeAsString(text); |
383 } | 403 } |
384 | 404 |
385 /** | 405 /** |
386 * Transforms the map by calling toMap on each value in it. | 406 * Transforms the map by calling toMap on each value in it. |
387 */ | 407 */ |
388 Map recurseMap(Map inputMap) { | 408 Map recurseMap(Map inputMap) { |
389 var outputMap = {}; | 409 var outputMap = {}; |
390 inputMap.forEach((key, value) { | 410 inputMap.forEach((key, value) { |
391 outputMap[key] = value.toMap(); | 411 if (value is Map) { |
412 outputMap[key] = recurseMap(value); | |
413 } else { | |
414 outputMap[key] = value.toMap(); | |
415 } | |
392 }); | 416 }); |
393 return outputMap; | 417 return outputMap; |
394 } | 418 } |
395 | 419 |
396 /** | 420 /** |
397 * A class containing contents of a Dart library. | 421 * A class containing contents of a Dart library. |
398 */ | 422 */ |
399 class Library { | 423 class Library { |
400 | 424 |
401 /// Documentation comment with converted markdown. | 425 /// Documentation comment with converted markdown. |
402 String comment; | 426 String comment; |
403 | 427 |
404 /// Top-level variables in the library. | 428 /// Top-level variables in the library. |
405 Map<String, Variable> variables; | 429 Map<String, Variable> variables; |
406 | 430 |
407 /// Top-level functions in the library. | 431 /// Top-level functions in the library. |
408 Map<String, Method> functions; | 432 Map<String, Map<String, Method>> functions; |
409 | 433 |
410 /// Classes defined within the library | 434 /// Classes defined within the library |
411 Map<String, Class> classes; | 435 Map<String, Class> classes; |
412 | 436 |
413 String name; | 437 String name; |
414 | 438 |
415 Library(this.name, this.comment, this.variables, | 439 Library(this.name, this.comment, this.variables, |
416 this.functions, this.classes); | 440 this.functions, this.classes); |
417 | 441 |
418 /// Generates a map describing the [Library] object. | 442 /// Generates a map describing the [Library] object. |
419 Map toMap() { | 443 Map toMap() { |
(...skipping 16 matching lines...) Expand all Loading... | |
436 /// Documentation comment with converted markdown. | 460 /// Documentation comment with converted markdown. |
437 String comment; | 461 String comment; |
438 | 462 |
439 /// List of the names of interfaces that this class implements. | 463 /// List of the names of interfaces that this class implements. |
440 List<String> interfaces; | 464 List<String> interfaces; |
441 | 465 |
442 /// Top-level variables in the class. | 466 /// Top-level variables in the class. |
443 Map<String, Variable> variables; | 467 Map<String, Variable> variables; |
444 | 468 |
445 /// Methods in the class. | 469 /// Methods in the class. |
446 Map<String, Method> methods; | 470 Map<String, Map<String, Method>> methods; |
447 | 471 |
448 String name; | 472 String name; |
449 String qualifiedName; | |
450 String superclass; | 473 String superclass; |
451 bool isAbstract; | 474 bool isAbstract; |
452 bool isTypedef; | 475 bool isTypedef; |
453 | 476 |
454 /// List of the meta annotations on the class. | 477 /// List of the meta annotations on the class. |
455 List<String> annotations; | 478 List<String> annotations; |
456 | 479 |
457 Class(this.name, this.qualifiedName, this.superclass, this.isAbstract, | 480 Class(this.name, this.superclass, this.isAbstract, this.isTypedef, |
458 this.isTypedef, this.comment, this.interfaces, this.variables, | 481 this.comment, this.interfaces, this.variables, this.methods, |
459 this.methods, this.annotations); | 482 this.annotations); |
460 | 483 |
461 /// Generates a map describing the [Class] object. | 484 /// Generates a map describing the [Class] object. |
462 Map toMap() { | 485 Map toMap() { |
463 var classMap = {}; | 486 var classMap = {}; |
464 classMap['name'] = name; | 487 classMap['name'] = name; |
465 classMap['qualifiedname'] = qualifiedName; | |
466 classMap['comment'] = comment; | 488 classMap['comment'] = comment; |
467 classMap['superclass'] = superclass; | 489 classMap['superclass'] = superclass; |
468 classMap['abstract'] = isAbstract.toString(); | 490 classMap['abstract'] = isAbstract.toString(); |
469 classMap['typedef'] = isTypedef.toString(); | 491 classMap['typedef'] = isTypedef.toString(); |
470 classMap['implements'] = new List.from(interfaces); | 492 classMap['implements'] = new List.from(interfaces); |
471 classMap['variables'] = recurseMap(variables); | 493 classMap['variables'] = recurseMap(variables); |
472 classMap['methods'] = recurseMap(methods); | 494 classMap['methods'] = recurseMap(methods); |
473 classMap['annotations'] = new List.from(annotations); | 495 classMap['annotations'] = new List.from(annotations); |
474 return classMap; | 496 return classMap; |
475 } | 497 } |
476 } | 498 } |
477 | 499 |
478 /** | 500 /** |
479 * A class containing properties of a Dart variable. | 501 * A class containing properties of a Dart variable. |
480 */ | 502 */ |
481 class Variable { | 503 class Variable { |
482 | 504 |
483 /// Documentation comment with converted markdown. | 505 /// Documentation comment with converted markdown. |
484 String comment; | 506 String comment; |
485 | 507 |
486 String name; | 508 String name; |
487 String qualifiedName; | |
488 bool isFinal; | 509 bool isFinal; |
489 bool isStatic; | 510 bool isStatic; |
490 String type; | 511 String type; |
491 | 512 |
492 /// List of the meta annotations on the variable. | 513 /// List of the meta annotations on the variable. |
493 List<String> annotations; | 514 List<String> annotations; |
494 | 515 |
495 Variable(this.name, this.qualifiedName, this.isFinal, this.isStatic, | 516 Variable(this.name, this.isFinal, this.isStatic, this.type, this.comment, |
496 this.type, this.comment, this.annotations); | 517 this.annotations); |
497 | 518 |
498 /// Generates a map describing the [Variable] object. | 519 /// Generates a map describing the [Variable] object. |
499 Map toMap() { | 520 Map toMap() { |
500 var variableMap = {}; | 521 var variableMap = {}; |
501 variableMap['name'] = name; | 522 variableMap['name'] = name; |
502 variableMap['qualifiedname'] = qualifiedName; | |
503 variableMap['comment'] = comment; | 523 variableMap['comment'] = comment; |
504 variableMap['final'] = isFinal.toString(); | 524 variableMap['final'] = isFinal.toString(); |
505 variableMap['static'] = isStatic.toString(); | 525 variableMap['static'] = isStatic.toString(); |
506 variableMap['type'] = type; | 526 variableMap['type'] = type; |
507 variableMap['annotations'] = new List.from(annotations); | 527 variableMap['annotations'] = new List.from(annotations); |
508 return variableMap; | 528 return variableMap; |
509 } | 529 } |
510 } | 530 } |
511 | 531 |
512 /** | 532 /** |
513 * A class containing properties of a Dart method. | 533 * A class containing properties of a Dart method. |
514 */ | 534 */ |
515 class Method { | 535 class Method { |
516 | 536 |
517 /// Documentation comment with converted markdown. | 537 /// Documentation comment with converted markdown. |
518 String comment; | 538 String comment; |
519 | 539 |
520 /// Parameters for this method. | 540 /// Parameters for this method. |
521 Map<String, Parameter> parameters; | 541 Map<String, Parameter> parameters; |
522 | 542 |
523 String name; | 543 String name; |
524 String qualifiedName; | |
525 bool isSetter; | |
526 bool isGetter; | |
527 bool isConstructor; | |
528 bool isOperator; | |
529 bool isStatic; | 544 bool isStatic; |
530 String returnType; | 545 String returnType; |
531 | 546 |
532 /// List of the meta annotations on the method. | 547 /// List of the meta annotations on the method. |
533 List<String> annotations; | 548 List<String> annotations; |
534 | 549 |
535 Method(this.name, this.qualifiedName, this.isSetter, this.isGetter, | 550 Method(this.name, this.isStatic, this.returnType, this.comment, |
536 this.isConstructor, this.isOperator, this.isStatic, this.returnType, | 551 this.parameters, this.annotations); |
537 this.comment, this.parameters, this.annotations); | 552 |
538 | |
539 /// Generates a map describing the [Method] object. | 553 /// Generates a map describing the [Method] object. |
540 Map toMap() { | 554 Map toMap() { |
541 var methodMap = {}; | 555 var methodMap = {}; |
542 methodMap['name'] = name; | 556 methodMap['name'] = name; |
543 methodMap['qualifiedname'] = qualifiedName; | |
544 methodMap['comment'] = comment; | 557 methodMap['comment'] = comment; |
545 methodMap['type'] = isSetter ? 'setter' : isGetter ? 'getter' : | |
546 isOperator ? 'operator' : isConstructor ? 'constructor' : 'method'; | |
547 methodMap['static'] = isStatic.toString(); | 558 methodMap['static'] = isStatic.toString(); |
548 methodMap['return'] = returnType; | 559 methodMap['return'] = returnType; |
549 methodMap['parameters'] = recurseMap(parameters); | 560 methodMap['parameters'] = recurseMap(parameters); |
550 methodMap['annotations'] = new List.from(annotations); | 561 methodMap['annotations'] = new List.from(annotations); |
551 return methodMap; | 562 return methodMap; |
552 } | 563 } |
553 } | 564 } |
554 | 565 |
555 /** | 566 /** |
556 * A class containing properties of a Dart method/function parameter. | 567 * A class containing properties of a Dart method/function parameter. |
557 */ | 568 */ |
558 class Parameter { | 569 class Parameter { |
559 | 570 |
560 String name; | 571 String name; |
561 String qualifiedName; | |
562 bool isOptional; | 572 bool isOptional; |
563 bool isNamed; | 573 bool isNamed; |
564 bool hasDefaultValue; | 574 bool hasDefaultValue; |
565 String type; | 575 String type; |
566 String defaultValue; | 576 String defaultValue; |
567 | 577 |
568 /// List of the meta annotations on the parameter. | 578 /// List of the meta annotations on the parameter. |
569 List<String> annotations; | 579 List<String> annotations; |
570 | 580 |
571 Parameter(this.name, this.qualifiedName, this.isOptional, this.isNamed, | 581 Parameter(this.name, this.isOptional, this.isNamed, this.hasDefaultValue, |
572 this.hasDefaultValue, this.type, this.defaultValue, this.annotations); | 582 this.type, this.defaultValue, this.annotations); |
573 | 583 |
574 /// Generates a map describing the [Parameter] object. | 584 /// Generates a map describing the [Parameter] object. |
575 Map toMap() { | 585 Map toMap() { |
576 var parameterMap = {}; | 586 var parameterMap = {}; |
577 parameterMap['name'] = name; | 587 parameterMap['name'] = name; |
578 parameterMap['qualifiedname'] = qualifiedName; | |
579 parameterMap['optional'] = isOptional.toString(); | 588 parameterMap['optional'] = isOptional.toString(); |
580 parameterMap['named'] = isNamed.toString(); | 589 parameterMap['named'] = isNamed.toString(); |
581 parameterMap['default'] = hasDefaultValue.toString(); | 590 parameterMap['default'] = hasDefaultValue.toString(); |
582 parameterMap['type'] = type; | 591 parameterMap['type'] = type; |
583 parameterMap['value'] = defaultValue; | 592 parameterMap['value'] = defaultValue; |
584 parameterMap['annotations'] = new List.from(annotations); | 593 parameterMap['annotations'] = new List.from(annotations); |
585 return parameterMap; | 594 return parameterMap; |
586 } | 595 } |
587 } | 596 } |
OLD | NEW |