| // Copyright (c) 2023, 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/src/dart/error/syntactic_errors.dart'; |
| import 'package:analyzer/src/error/codes.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| import '../../diagnostics/parser_diagnostics.dart'; |
| |
| main() { |
| defineReflectiveSuite(() { |
| defineReflectiveTests(DocCommentParserTest); |
| }); |
| } |
| |
| @reflectiveTest |
| class DocCommentParserTest extends ParserDiagnosticsTest { |
| test_animationDirective_namedArgument_blankValue() { |
| var parseResult = parseStringWithErrors(r''' |
| int x = 0; |
| |
| /// Text. |
| /// {@animation 600 400 http://google.com arg=} |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('animation'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// Text. |
| /// {@animation 600 400 http://google.com arg=} |
| docDirectives |
| SimpleDocDirective |
| tag |
| offset: [26, 70] |
| type: [DocDirectiveType.animation] |
| positionalArguments |
| 600 |
| 400 |
| http://google.com |
| namedArguments |
| arg= |
| '''); |
| } |
| |
| test_animationDirective_namedArgument_missingClosingBrace() { |
| var parseResult = parseStringWithErrors(r''' |
| int x = 0; |
| |
| /// Text. |
| /// {@animation 600 400 http://google.com arg=value |
| class A {} |
| '''); |
| parseResult.assertErrors([ |
| error(WarningCode.docDirectiveMissingClosingBrace, 73, 1), |
| ]); |
| |
| var node = parseResult.findNode.comment('animation'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// Text. |
| /// {@animation 600 400 http://google.com arg=value |
| docDirectives |
| SimpleDocDirective |
| tag |
| offset: [26, 74] |
| type: [DocDirectiveType.animation] |
| positionalArguments |
| 600 |
| 400 |
| http://google.com |
| namedArguments |
| arg=value |
| '''); |
| } |
| |
| test_animationDirective_namedArgument_missingValueAndClosingBrace() async { |
| var parseResult = parseStringWithErrors(r''' |
| int x = 0; |
| |
| /// Text. |
| /// {@animation 600 400 http://google.com arg= |
| class A {} |
| '''); |
| parseResult.assertErrors([ |
| error(WarningCode.docDirectiveMissingClosingBrace, 68, 1), |
| ]); |
| |
| var node = parseResult.findNode.comment('animation'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// Text. |
| /// {@animation 600 400 http://google.com arg= |
| docDirectives |
| SimpleDocDirective |
| tag |
| offset: [26, 69] |
| type: [DocDirectiveType.animation] |
| positionalArguments |
| 600 |
| 400 |
| http://google.com |
| namedArguments |
| arg= |
| '''); |
| } |
| |
| test_codeSpan() { |
| var parseResult = parseStringWithErrors(r''' |
| /// `a[i]` and [b]. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('a[i]'); |
| // TODO(srawlins): Parse code into its own node. |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| expression: SimpleIdentifier |
| token: b |
| tokens |
| /// `a[i]` and [b]. |
| '''); |
| } |
| |
| test_codeSpan_legacy_blockComment() { |
| // TODO(srawlins): I believe we should drop support for `[:` `:]`. |
| var parseResult = parseStringWithErrors(r''' |
| /** [:xxx [a] yyy:] [b] zzz */ |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('[a]'); |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| expression: SimpleIdentifier |
| token: b |
| tokens |
| /** [:xxx [a] yyy:] [b] zzz */ |
| '''); |
| } |
| |
| test_codeSpan_unterminated_blockComment() { |
| var parseResult = parseStringWithErrors(r''' |
| /** `a[i] and [b] */ |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('a['); |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| expression: SimpleIdentifier |
| token: i |
| CommentReference |
| expression: SimpleIdentifier |
| token: b |
| tokens |
| /** `a[i] and [b] */ |
| '''); |
| } |
| |
| test_commentReference_blockComment() { |
| var parseResult = parseStringWithErrors(r''' |
| /** [a]. */ |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('[a]'); |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| expression: SimpleIdentifier |
| token: a |
| tokens |
| /** [a]. */ |
| '''); |
| } |
| |
| test_commentReference_empty() { |
| var parseResult = parseStringWithErrors(r''' |
| /// []. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('[]'); |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| expression: SimpleIdentifier |
| token: <empty> <synthetic> |
| tokens |
| /// []. |
| '''); |
| } |
| |
| test_commentReference_followedByColon() { |
| var parseResult = parseStringWithErrors(r''' |
| /// Regarding [a]: it's an A. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('[a]'); |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| expression: SimpleIdentifier |
| token: a |
| tokens |
| /// Regarding [a]: it's an A. |
| '''); |
| } |
| |
| test_commentReference_multiple() { |
| var parseResult = parseStringWithErrors(r''' |
| /// [a] and [b]. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('[a]'); |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| expression: SimpleIdentifier |
| token: a |
| CommentReference |
| expression: SimpleIdentifier |
| token: b |
| tokens |
| /// [a] and [b]. |
| '''); |
| } |
| |
| test_commentReference_multiple_blockComment() { |
| var parseResult = parseStringWithErrors(r''' |
| /** [a] and [b]. */ |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('[a]'); |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| expression: SimpleIdentifier |
| token: a |
| CommentReference |
| expression: SimpleIdentifier |
| token: b |
| tokens |
| /** [a] and [b]. */ |
| '''); |
| } |
| |
| test_commentReference_new_prefixed() { |
| var parseResult = parseStringWithErrors(r''' |
| /// [new a.A]. |
| class B {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('new'); |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| newKeyword: new |
| expression: PrefixedIdentifier |
| prefix: SimpleIdentifier |
| token: a |
| period: . |
| identifier: SimpleIdentifier |
| token: A |
| tokens |
| /// [new a.A]. |
| '''); |
| } |
| |
| test_commentReference_new_simple() { |
| var parseResult = parseStringWithErrors(r''' |
| /// [new A]. |
| class B {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('new'); |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| newKeyword: new |
| expression: SimpleIdentifier |
| token: A |
| tokens |
| /// [new A]. |
| '''); |
| } |
| |
| test_commentReference_operator_withKeyword_notPrefixed() { |
| var parseResult = parseStringWithErrors(r''' |
| /// [operator ==]. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('=='); |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| expression: SimpleIdentifier |
| token: == |
| tokens |
| /// [operator ==]. |
| '''); |
| } |
| |
| test_commentReference_operator_withKeyword_prefixed() { |
| var parseResult = parseStringWithErrors(r''' |
| /// [Object.operator ==]. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('=='); |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| expression: PrefixedIdentifier |
| prefix: SimpleIdentifier |
| token: Object |
| period: . |
| identifier: SimpleIdentifier |
| token: == |
| tokens |
| /// [Object.operator ==]. |
| '''); |
| } |
| |
| test_commentReference_operator_withoutKeyword_notPrefixed() { |
| var parseResult = parseStringWithErrors(r''' |
| /// [==]. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('=='); |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| expression: SimpleIdentifier |
| token: == |
| tokens |
| /// [==]. |
| '''); |
| } |
| |
| test_commentReference_operator_withoutKeyword_prefixed() { |
| var parseResult = parseStringWithErrors(r''' |
| /// [Object.==]. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('=='); |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| expression: PrefixedIdentifier |
| prefix: SimpleIdentifier |
| token: Object |
| period: . |
| identifier: SimpleIdentifier |
| token: == |
| tokens |
| /// [Object.==]. |
| '''); |
| } |
| |
| test_commentReference_prefixedIdentifier() { |
| var parseResult = parseStringWithErrors(r''' |
| /// [a.b]. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('a.b'); |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| expression: PrefixedIdentifier |
| prefix: SimpleIdentifier |
| token: a |
| period: . |
| identifier: SimpleIdentifier |
| token: b |
| tokens |
| /// [a.b]. |
| '''); |
| } |
| |
| test_commentReference_simpleIdentifier() { |
| var parseResult = parseStringWithErrors(r''' |
| /// [a]. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('[a]'); |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| expression: SimpleIdentifier |
| token: a |
| tokens |
| /// [a]. |
| '''); |
| } |
| |
| test_commentReference_this() { |
| var parseResult = parseStringWithErrors(r''' |
| /// [this]. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('this'); |
| // TODO(srawlins): I think there is an intention to parse this as a comment |
| // reference. |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// [this]. |
| '''); |
| } |
| |
| test_docImport() { |
| var parseResult = parseStringWithErrors(r''' |
| /// @docImport 'dart:html'; |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('docImport'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// @docImport 'dart:html'; |
| docImports |
| DocImport |
| offset: 3 |
| import: ImportDirective |
| importKeyword: import |
| uri: SimpleStringLiteral |
| literal: 'dart:html' |
| semicolon: ; |
| '''); |
| } |
| |
| test_docImport_multiple() { |
| var parseResult = parseStringWithErrors(r''' |
| /// One. |
| /// @docImport 'dart:html'; |
| /// @docImport 'dart:io'; |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('dart:html'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// One. |
| /// @docImport 'dart:html'; |
| /// @docImport 'dart:io'; |
| docImports |
| DocImport |
| offset: 12 |
| import: ImportDirective |
| importKeyword: import |
| uri: SimpleStringLiteral |
| literal: 'dart:html' |
| semicolon: ; |
| DocImport |
| offset: 40 |
| import: ImportDirective |
| importKeyword: import |
| uri: SimpleStringLiteral |
| literal: 'dart:io' |
| semicolon: ; |
| '''); |
| } |
| |
| test_docImport_nonTerminated() { |
| var parseResult = parseStringWithErrors(r''' |
| /// @docImport 'dart:html' |
| class A {} |
| '''); |
| parseResult.assertErrors([error(ParserErrorCode.expectedToken, 15, 11)]); |
| |
| var node = parseResult.findNode.comment('docImport'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// @docImport 'dart:html' |
| docImports |
| DocImport |
| offset: 3 |
| import: ImportDirective |
| importKeyword: import |
| uri: SimpleStringLiteral |
| literal: 'dart:html' |
| semicolon: ; <synthetic> |
| '''); |
| } |
| |
| test_docImport_parseError() { |
| var parseResult = parseStringWithErrors(r''' |
| /// @docImport html |
| class A {} |
| '''); |
| parseResult.assertErrors([ |
| error(ParserErrorCode.expectedToken, 8, 6), |
| error(ParserErrorCode.expectedStringLiteral, 15, 4), |
| error(ParserErrorCode.missingConstFinalVarOrType, 15, 4), |
| error(ParserErrorCode.expectedToken, 15, 4), |
| ]); |
| |
| var node = parseResult.findNode.comment('docImport'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// @docImport html |
| docImports |
| DocImport |
| offset: 3 |
| import: ImportDirective |
| importKeyword: import |
| uri: SimpleStringLiteral |
| literal: "" <synthetic> |
| semicolon: ; <synthetic> |
| '''); |
| } |
| |
| test_docImport_prefixed() { |
| var parseResult = parseStringWithErrors(r''' |
| /// @docImport 'dart:html' as html; |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('docImport'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// @docImport 'dart:html' as html; |
| docImports |
| DocImport |
| offset: 3 |
| import: ImportDirective |
| importKeyword: import |
| uri: SimpleStringLiteral |
| literal: 'dart:html' |
| asKeyword: as |
| prefix: SimpleIdentifier |
| token: html |
| semicolon: ; |
| '''); |
| } |
| |
| test_docImport_show() { |
| var parseResult = parseStringWithErrors(r''' |
| /// @docImport 'dart:html' show Element, HtmlElement; |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('docImport'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// @docImport 'dart:html' show Element, HtmlElement; |
| docImports |
| DocImport |
| offset: 3 |
| import: ImportDirective |
| importKeyword: import |
| uri: SimpleStringLiteral |
| literal: 'dart:html' |
| combinators |
| ShowCombinator |
| keyword: show |
| shownNames |
| SimpleIdentifier |
| token: Element |
| SimpleIdentifier |
| token: HtmlElement |
| semicolon: ; |
| '''); |
| } |
| |
| test_docImport_unterminatedString() { |
| var parseResult = parseStringWithErrors(r''' |
| /// @docImport 'dart:html; |
| class A {} |
| '''); |
| parseResult.assertErrors([ |
| error(ParserErrorCode.expectedToken, 15, 11), |
| error(ScannerErrorCode.unterminatedStringLiteral, 17, 1), |
| ]); |
| |
| var node = parseResult.findNode.comment('docImport'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// @docImport 'dart:html; |
| docImports |
| DocImport |
| offset: 3 |
| import: ImportDirective |
| importKeyword: import |
| uri: SimpleStringLiteral |
| literal: 'dart:html;' <synthetic> |
| semicolon: ; <synthetic> |
| '''); |
| } |
| |
| test_docImport_withOtherData() { |
| var parseResult = parseStringWithErrors(r''' |
| /// ```dart |
| /// x; |
| /// ``` |
| /// @docImport 'dart:html'; |
| /// ```dart |
| /// y; |
| /// ``` |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('docImport'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// ```dart |
| /// x; |
| /// ``` |
| /// @docImport 'dart:html'; |
| /// ```dart |
| /// y; |
| /// ``` |
| codeBlocks |
| MdCodeBlock |
| infoString: dart |
| type: CodeBlockType.fenced |
| lines |
| MdCodeBlockLine |
| offset: 3 |
| length: 8 |
| MdCodeBlockLine |
| offset: 15 |
| length: 3 |
| MdCodeBlockLine |
| offset: 22 |
| length: 4 |
| MdCodeBlock |
| infoString: dart |
| type: CodeBlockType.fenced |
| lines |
| MdCodeBlockLine |
| offset: 58 |
| length: 8 |
| MdCodeBlockLine |
| offset: 70 |
| length: 3 |
| MdCodeBlockLine |
| offset: 77 |
| length: 4 |
| docImports |
| DocImport |
| offset: 30 |
| import: ImportDirective |
| importKeyword: import |
| uri: SimpleStringLiteral |
| literal: 'dart:html' |
| semicolon: ; |
| '''); |
| } |
| |
| test_endTemplate_missingOpeningTag() { |
| var parseResult = parseStringWithErrors(r''' |
| int x = 0; |
| |
| /// Text. |
| /// {@endtemplate} |
| /// More text. |
| class A {} |
| '''); |
| parseResult.assertErrors([ |
| error(WarningCode.docDirectiveMissingOpeningTag, 26, 15), |
| ]); |
| |
| var node = parseResult.findNode.comment('endtemplate'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// Text. |
| /// {@endtemplate} |
| /// More text. |
| docDirectives |
| SimpleDocDirective |
| tag |
| offset: [26, 41] |
| type: [DocDirectiveType.endTemplate] |
| '''); |
| } |
| |
| test_fencedCodeBlock_blockComment() { |
| var parseResult = parseStringWithErrors(r''' |
| /** |
| * One. |
| * ``` |
| * a[i] = b[i]; |
| * ``` |
| * Two. |
| * ```dart |
| * code; |
| * ``` |
| * Three. |
| */ |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('a[i]'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /** |
| * One. |
| * ``` |
| * a[i] = b[i]; |
| * ``` |
| * Two. |
| * ```dart |
| * code; |
| * ``` |
| * Three. |
| */ |
| codeBlocks |
| MdCodeBlock |
| infoString: <empty> |
| type: CodeBlockType.fenced |
| lines |
| MdCodeBlockLine |
| offset: 15 |
| length: 3 |
| MdCodeBlockLine |
| offset: 22 |
| length: 12 |
| MdCodeBlockLine |
| offset: 38 |
| length: 3 |
| MdCodeBlock |
| infoString: dart |
| type: CodeBlockType.fenced |
| lines |
| MdCodeBlockLine |
| offset: 53 |
| length: 7 |
| MdCodeBlockLine |
| offset: 64 |
| length: 5 |
| MdCodeBlockLine |
| offset: 73 |
| length: 3 |
| '''); |
| } |
| |
| test_fencedCodeBlock_empty() { |
| var parseResult = parseStringWithErrors(r''' |
| /// ``` |
| /// ``` |
| /// Text. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('Text.'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// ``` |
| /// ``` |
| /// Text. |
| codeBlocks |
| MdCodeBlock |
| infoString: <empty> |
| type: CodeBlockType.fenced |
| lines |
| MdCodeBlockLine |
| offset: 3 |
| length: 4 |
| MdCodeBlockLine |
| offset: 11 |
| length: 4 |
| '''); |
| } |
| |
| test_fencedCodeBlock_leadingSpaces() { |
| var parseResult = parseStringWithErrors(r''' |
| /// ``` |
| /// a[i] = b[i]; |
| /// ``` |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('a[i]'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// ``` |
| /// a[i] = b[i]; |
| /// ``` |
| codeBlocks |
| MdCodeBlock |
| infoString: <empty> |
| type: CodeBlockType.fenced |
| lines |
| MdCodeBlockLine |
| offset: 3 |
| length: 6 |
| MdCodeBlockLine |
| offset: 13 |
| length: 15 |
| MdCodeBlockLine |
| offset: 32 |
| length: 6 |
| '''); |
| } |
| |
| test_fencedCodeBlock_moreThanThreeBackticks() { |
| var parseResult = parseStringWithErrors(r''' |
| /// ````dart |
| /// A code block can contain multiple backticks, as long as it is fewer than |
| /// the amount in the opening: |
| /// ``` |
| /// ````` |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('A code'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// ````dart |
| /// A code block can contain multiple backticks, as long as it is fewer than |
| /// the amount in the opening: |
| /// ``` |
| /// ````` |
| codeBlocks |
| MdCodeBlock |
| infoString: dart |
| type: CodeBlockType.fenced |
| lines |
| MdCodeBlockLine |
| offset: 3 |
| length: 9 |
| MdCodeBlockLine |
| offset: 16 |
| length: 73 |
| MdCodeBlockLine |
| offset: 93 |
| length: 27 |
| MdCodeBlockLine |
| offset: 124 |
| length: 4 |
| MdCodeBlockLine |
| offset: 132 |
| length: 6 |
| '''); |
| } |
| |
| test_fencedCodeBlock_noLeadingSpaces() { |
| var parseResult = parseStringWithErrors(r''' |
| ///``` |
| ///a[i] = b[i]; |
| ///``` |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('a[i]'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| ///``` |
| ///a[i] = b[i]; |
| ///``` |
| codeBlocks |
| MdCodeBlock |
| infoString: <empty> |
| type: CodeBlockType.fenced |
| lines |
| MdCodeBlockLine |
| offset: 3 |
| length: 3 |
| MdCodeBlockLine |
| offset: 10 |
| length: 12 |
| MdCodeBlockLine |
| offset: 26 |
| length: 3 |
| '''); |
| } |
| |
| test_fencedCodeBlock_nonDocCommentLines() { |
| var parseResult = parseStringWithErrors(r''' |
| /// One. |
| /// ``` |
| // This is not part of the doc comment. |
| /// a[i] = b[i]; |
| |
| /// ``` |
| /// Two. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('a[i]'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// One. |
| /// ``` |
| /// a[i] = b[i]; |
| /// ``` |
| /// Two. |
| codeBlocks |
| MdCodeBlock |
| infoString: <empty> |
| type: CodeBlockType.fenced |
| lines |
| MdCodeBlockLine |
| offset: 12 |
| length: 4 |
| MdCodeBlockLine |
| offset: 60 |
| length: 13 |
| MdCodeBlockLine |
| offset: 78 |
| length: 4 |
| '''); |
| } |
| |
| test_fencedCodeBlock_nonTerminating() { |
| var parseResult = parseStringWithErrors(r''' |
| /// One. |
| /// ``` |
| /// a[i] = b[i]; |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('a[i]'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// One. |
| /// ``` |
| /// a[i] = b[i]; |
| codeBlocks |
| MdCodeBlock |
| infoString: <empty> |
| type: CodeBlockType.fenced |
| lines |
| MdCodeBlockLine |
| offset: 12 |
| length: 4 |
| MdCodeBlockLine |
| offset: 20 |
| length: 13 |
| '''); |
| } |
| |
| test_fencedCodeBlock_nonZeroOffset() { |
| var parseResult = parseStringWithErrors(r''' |
| int x = 0; |
| |
| /// One. |
| /// ``` |
| /// a[i] = b[i]; |
| /// ``` |
| /// Two. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('a[i]'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// One. |
| /// ``` |
| /// a[i] = b[i]; |
| /// ``` |
| /// Two. |
| codeBlocks |
| MdCodeBlock |
| infoString: <empty> |
| type: CodeBlockType.fenced |
| lines |
| MdCodeBlockLine |
| offset: 24 |
| length: 4 |
| MdCodeBlockLine |
| offset: 32 |
| length: 13 |
| MdCodeBlockLine |
| offset: 49 |
| length: 4 |
| '''); |
| } |
| |
| test_fencedCodeBlock_precededByText() { |
| var parseResult = parseStringWithErrors(r''' |
| /// One. ``` |
| /// Two. |
| /// ``` |
| /// Three. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('Two.'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// One. ``` |
| /// Two. |
| /// ``` |
| /// Three. |
| codeBlocks |
| MdCodeBlock |
| infoString: <empty> |
| type: CodeBlockType.fenced |
| lines |
| MdCodeBlockLine |
| offset: 25 |
| length: 4 |
| MdCodeBlockLine |
| offset: 33 |
| length: 7 |
| '''); |
| } |
| |
| test_fencedCodeBlocks() { |
| var parseResult = parseStringWithErrors(r''' |
| /// One. |
| /// ``` |
| /// a[i] = b[i]; |
| /// ``` |
| /// Two. |
| /// ```dart |
| /// code; |
| /// ``` |
| /// Three. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('a[i]'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// One. |
| /// ``` |
| /// a[i] = b[i]; |
| /// ``` |
| /// Two. |
| /// ```dart |
| /// code; |
| /// ``` |
| /// Three. |
| codeBlocks |
| MdCodeBlock |
| infoString: <empty> |
| type: CodeBlockType.fenced |
| lines |
| MdCodeBlockLine |
| offset: 12 |
| length: 4 |
| MdCodeBlockLine |
| offset: 20 |
| length: 13 |
| MdCodeBlockLine |
| offset: 37 |
| length: 4 |
| MdCodeBlock |
| infoString: dart |
| type: CodeBlockType.fenced |
| lines |
| MdCodeBlockLine |
| offset: 54 |
| length: 8 |
| MdCodeBlockLine |
| offset: 66 |
| length: 6 |
| MdCodeBlockLine |
| offset: 76 |
| length: 4 |
| '''); |
| } |
| |
| test_indentedCodeBlock_afterBlankLine() { |
| var parseResult = parseStringWithErrors(r''' |
| /// Text. |
| /// |
| /// a[i] = b[i]; |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('Text'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// Text. |
| /// |
| /// a[i] = b[i]; |
| codeBlocks |
| MdCodeBlock |
| infoString: <empty> |
| type: CodeBlockType.indented |
| lines |
| MdCodeBlockLine |
| offset: 17 |
| length: 16 |
| '''); |
| } |
| |
| test_indentedCodeBlock_afterTextLine_notCodeBlock() { |
| var parseResult = parseStringWithErrors(r''' |
| /// Text. |
| /// a[i] = b[i]; |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('Text'); |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| expression: SimpleIdentifier |
| token: i |
| CommentReference |
| expression: SimpleIdentifier |
| token: i |
| tokens |
| /// Text. |
| /// a[i] = b[i]; |
| '''); |
| } |
| |
| test_indentedCodeBlock_firstLine() { |
| var parseResult = parseStringWithErrors(r''' |
| /// a[i] = b[i]; |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('a[i]'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// a[i] = b[i]; |
| codeBlocks |
| MdCodeBlock |
| infoString: <empty> |
| type: CodeBlockType.indented |
| lines |
| MdCodeBlockLine |
| offset: 3 |
| length: 16 |
| '''); |
| } |
| |
| test_indentedCodeBlock_firstLine_blockComment() { |
| var parseResult = parseStringWithErrors(r''' |
| /** |
| * |
| * a[i] = b[i]; |
| * [c]. |
| */ |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('a[i]'); |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| expression: SimpleIdentifier |
| token: c |
| tokens |
| /** |
| * |
| * a[i] = b[i]; |
| * [c]. |
| */ |
| codeBlocks |
| MdCodeBlock |
| infoString: <empty> |
| type: CodeBlockType.indented |
| lines |
| MdCodeBlockLine |
| offset: 10 |
| length: 16 |
| '''); |
| } |
| |
| test_indentedCodeBlock_withFencedCodeBlock() { |
| var parseResult = parseStringWithErrors(r''' |
| /// Text. |
| /// ``` |
| /// a[i] = b[i]; |
| /// ``` |
| /// More text. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('Text'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// Text. |
| /// ``` |
| /// a[i] = b[i]; |
| /// ``` |
| /// More text. |
| codeBlocks |
| MdCodeBlock |
| infoString: <empty> |
| type: CodeBlockType.fenced |
| lines |
| MdCodeBlockLine |
| offset: 13 |
| length: 8 |
| MdCodeBlockLine |
| offset: 25 |
| length: 17 |
| MdCodeBlockLine |
| offset: 46 |
| length: 8 |
| '''); |
| } |
| |
| test_inlineLink() { |
| var parseResult = parseStringWithErrors(r''' |
| /// [a](http://www.google.com) [b]. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('[a]'); |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| expression: SimpleIdentifier |
| token: b |
| tokens |
| /// [a](http://www.google.com) [b]. |
| '''); |
| } |
| |
| test_linkReference() { |
| var parseResult = parseStringWithErrors(r''' |
| /// [a]: http://www.google.com Google [b] |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('[a]'); |
| // TODO(srawlins): Ideally this should not parse `[b]` as a comment |
| // reference. |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| expression: SimpleIdentifier |
| token: b |
| tokens |
| /// [a]: http://www.google.com Google [b] |
| '''); |
| } |
| |
| test_nodoc_eol() { |
| var parseResult = parseStringWithErrors(r''' |
| /// Text. |
| /// |
| /// @nodoc |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('Text.'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// Text. |
| /// |
| /// @nodoc |
| hasNodoc: true |
| '''); |
| } |
| |
| test_nodoc_more() { |
| var parseResult = parseStringWithErrors(r''' |
| /// Text. |
| /// |
| /// @nodocxx |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('Text.'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// Text. |
| /// |
| /// @nodocxx |
| '''); |
| } |
| |
| test_nodoc_space() { |
| var parseResult = parseStringWithErrors(r''' |
| /// Text. |
| /// |
| /// @nodoc This is not super public. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('Text.'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// Text. |
| /// |
| /// @nodoc This is not super public. |
| hasNodoc: true |
| '''); |
| } |
| |
| test_onlyWhitespace() { |
| var parseResult = parseStringWithErrors(''' |
| ///${" "} |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment(' '); |
| assertParsedNodeText(node, ''' |
| Comment |
| tokens |
| ///${" "} |
| '''); |
| } |
| |
| test_referenceLink() { |
| var parseResult = parseStringWithErrors(r''' |
| /// [a link][c] [b]. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('[a'); |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| expression: SimpleIdentifier |
| token: b |
| tokens |
| /// [a link][c] [b]. |
| '''); |
| } |
| |
| test_referenceLink_multiline() { |
| var parseResult = parseStringWithErrors(r''' |
| /// [a link split across multiple |
| /// lines][c] [b]. |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('[a'); |
| assertParsedNodeText(node, r''' |
| Comment |
| references |
| CommentReference |
| expression: SimpleIdentifier |
| token: a |
| CommentReference |
| expression: SimpleIdentifier |
| token: b |
| tokens |
| /// [a link split across multiple |
| /// lines][c] [b]. |
| '''); |
| } |
| |
| test_template() { |
| var parseResult = parseStringWithErrors(r''' |
| int x = 0; |
| |
| /// Text. |
| /// {@template name} |
| /// More text. |
| /// {@endtemplate} |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('template name'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// Text. |
| /// {@template name} |
| /// More text. |
| /// {@endtemplate} |
| docDirectives |
| BlockDocDirective |
| openingTag |
| offset: [26, 43] |
| type: [DocDirectiveType.template] |
| positionalArguments |
| name |
| closingTag |
| offset: [62, 77] |
| type: [DocDirectiveType.endTemplate] |
| '''); |
| } |
| |
| test_template_containingInnerTags() { |
| var parseResult = parseStringWithErrors(r''' |
| int x = 0; |
| |
| /// Text. |
| /// {@template name} |
| /// More text. |
| /// {@macro name} |
| /// {@endtemplate} |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('template name'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// Text. |
| /// {@template name} |
| /// More text. |
| /// {@macro name} |
| /// {@endtemplate} |
| docDirectives |
| BlockDocDirective |
| openingTag |
| offset: [26, 43] |
| type: [DocDirectiveType.template] |
| positionalArguments |
| name |
| closingTag |
| offset: [80, 95] |
| type: [DocDirectiveType.endTemplate] |
| SimpleDocDirective |
| tag |
| offset: [62, 76] |
| type: [DocDirectiveType.macro] |
| positionalArguments |
| name |
| '''); |
| } |
| |
| test_template_containingInnerTemplate() { |
| var parseResult = parseStringWithErrors(r''' |
| int x = 0; |
| |
| /// Text. |
| /// {@template name} |
| /// More text. |
| /// {@template name2} |
| /// Text three. |
| /// {@endtemplate} |
| /// Text four. |
| /// {@endtemplate} |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('template name2'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// Text. |
| /// {@template name} |
| /// More text. |
| /// {@template name2} |
| /// Text three. |
| /// {@endtemplate} |
| /// Text four. |
| /// {@endtemplate} |
| docDirectives |
| BlockDocDirective |
| openingTag |
| offset: [26, 43] |
| type: [DocDirectiveType.template] |
| positionalArguments |
| name |
| closingTag |
| offset: [134, 149] |
| type: [DocDirectiveType.endTemplate] |
| BlockDocDirective |
| openingTag |
| offset: [62, 80] |
| type: [DocDirectiveType.template] |
| positionalArguments |
| name2 |
| closingTag |
| offset: [100, 115] |
| type: [DocDirectiveType.endTemplate] |
| '''); |
| } |
| |
| test_template_missingClosingTag() { |
| var parseResult = parseStringWithErrors(r''' |
| int x = 0; |
| |
| /// Text. |
| /// {@template name} |
| /// More text. |
| class A {} |
| '''); |
| parseResult.assertErrors([ |
| error(WarningCode.docDirectiveMissingClosingTag, 26, 17), |
| ]); |
| |
| var node = parseResult.findNode.comment('template name'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// Text. |
| /// {@template name} |
| /// More text. |
| docDirectives |
| BlockDocDirective |
| openingTag |
| offset: [26, 43] |
| type: [DocDirectiveType.template] |
| positionalArguments |
| name |
| '''); |
| } |
| |
| test_template_missingClosingTag_multiple() { |
| var parseResult = parseStringWithErrors(r''' |
| int x = 0; |
| |
| /// Text. |
| /// {@template name} |
| /// More text. |
| /// {@template name2} |
| /// More text. |
| class A {} |
| '''); |
| parseResult.assertErrors([ |
| error(WarningCode.docDirectiveMissingClosingTag, 26, 17), |
| error(WarningCode.docDirectiveMissingClosingTag, 62, 18), |
| ]); |
| |
| var node = parseResult.findNode.comment('template name2'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// Text. |
| /// {@template name} |
| /// More text. |
| /// {@template name2} |
| /// More text. |
| docDirectives |
| BlockDocDirective |
| openingTag |
| offset: [26, 43] |
| type: [DocDirectiveType.template] |
| positionalArguments |
| name |
| BlockDocDirective |
| openingTag |
| offset: [62, 80] |
| type: [DocDirectiveType.template] |
| positionalArguments |
| name2 |
| '''); |
| } |
| |
| test_template_missingClosingTag_withInnerTag() { |
| var parseResult = parseStringWithErrors(r''' |
| int x = 0; |
| |
| /// Text. |
| /// {@template name} |
| /// More text. |
| /// {@animation 600 400 http://google.com} |
| class A {} |
| '''); |
| parseResult.assertErrors([ |
| error(WarningCode.docDirectiveMissingClosingTag, 26, 17), |
| ]); |
| |
| var node = parseResult.findNode.comment('template name'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// Text. |
| /// {@template name} |
| /// More text. |
| /// {@animation 600 400 http://google.com} |
| docDirectives |
| BlockDocDirective |
| openingTag |
| offset: [26, 43] |
| type: [DocDirectiveType.template] |
| positionalArguments |
| name |
| SimpleDocDirective |
| tag |
| offset: [62, 101] |
| type: [DocDirectiveType.animation] |
| positionalArguments |
| 600 |
| 400 |
| http://google.com |
| '''); |
| } |
| |
| test_template_outOfOrderClosingTag() { |
| var parseResult = parseStringWithErrors(r''' |
| int x = 0; |
| |
| /// Text. |
| /// {@template name} |
| /// More text. |
| /// {@inject-html} |
| /// HTML. |
| /// {@endtemplate} |
| /// {@end-inject-html} |
| class A {} |
| '''); |
| parseResult.assertErrors([ |
| error(WarningCode.docDirectiveMissingClosingTag, 62, 15), |
| error(WarningCode.docDirectiveMissingOpeningTag, 110, 19), |
| ]); |
| |
| var node = parseResult.findNode.comment('template name'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// Text. |
| /// {@template name} |
| /// More text. |
| /// {@inject-html} |
| /// HTML. |
| /// {@endtemplate} |
| /// {@end-inject-html} |
| docDirectives |
| BlockDocDirective |
| openingTag |
| offset: [26, 43] |
| type: [DocDirectiveType.template] |
| positionalArguments |
| name |
| closingTag |
| offset: [91, 106] |
| type: [DocDirectiveType.endTemplate] |
| BlockDocDirective |
| openingTag |
| offset: [62, 77] |
| type: [DocDirectiveType.injectHtml] |
| SimpleDocDirective |
| tag |
| offset: [110, 129] |
| type: [DocDirectiveType.endInjectHtml] |
| '''); |
| } |
| |
| test_tool_withRestArguments() { |
| var parseResult = parseStringWithErrors(r''' |
| int x = 0; |
| |
| /// Text. |
| /// {@tool snippets one two three} |
| /// More text. |
| /// {@end-tool} |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('tool snippets'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// Text. |
| /// {@tool snippets one two three} |
| /// More text. |
| /// {@end-tool} |
| docDirectives |
| BlockDocDirective |
| openingTag |
| offset: [26, 57] |
| type: [DocDirectiveType.tool] |
| positionalArguments |
| snippets |
| one |
| two |
| three |
| closingTag |
| offset: [76, 88] |
| type: [DocDirectiveType.endTool] |
| '''); |
| } |
| |
| test_unknownDocDirective() { |
| var parseResult = parseStringWithErrors(r''' |
| int x = 0; |
| |
| /// Text. |
| /// {@yotube 123} |
| class A {} |
| '''); |
| parseResult.assertErrors([error(WarningCode.docDirectiveUnknown, 28, 6)]); |
| |
| var node = parseResult.findNode.comment('yotube'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// Text. |
| /// {@yotube 123} |
| '''); |
| } |
| |
| test_youTubeDirective() { |
| var parseResult = parseStringWithErrors(r''' |
| int x = 0; |
| |
| /// Text. |
| /// {@youtube 600 400 http://google.com} |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('youtube'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// Text. |
| /// {@youtube 600 400 http://google.com} |
| docDirectives |
| SimpleDocDirective |
| tag |
| offset: [26, 63] |
| type: [DocDirectiveType.youtube] |
| positionalArguments |
| 600 |
| 400 |
| http://google.com |
| '''); |
| } |
| |
| test_youTubeDirective_missingEndBrace() { |
| var parseResult = parseStringWithErrors(r''' |
| /// {@youtube 600 400 http://google.com |
| class A {} |
| '''); |
| parseResult.assertErrors([ |
| error(WarningCode.docDirectiveMissingClosingBrace, 39, 1), |
| ]); |
| |
| var node = parseResult.findNode.comment('youtube'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// {@youtube 600 400 http://google.com |
| docDirectives |
| SimpleDocDirective |
| tag |
| offset: [4, 40] |
| type: [DocDirectiveType.youtube] |
| positionalArguments |
| 600 |
| 400 |
| http://google.com |
| '''); |
| } |
| |
| test_youTubeDirective_missingUrl() { |
| var parseResult = parseStringWithErrors(r''' |
| /// {@youtube 600 400} |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('youtube'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// {@youtube 600 400} |
| docDirectives |
| SimpleDocDirective |
| tag |
| offset: [4, 23] |
| type: [DocDirectiveType.youtube] |
| positionalArguments |
| 600 |
| 400 |
| '''); |
| } |
| |
| test_youTubeDirective_missingUrlAndHeight() { |
| var parseResult = parseStringWithErrors(r''' |
| /// {@youtube 600} |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('youtube'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// {@youtube 600} |
| docDirectives |
| SimpleDocDirective |
| tag |
| offset: [4, 19] |
| type: [DocDirectiveType.youtube] |
| positionalArguments |
| 600 |
| '''); |
| } |
| |
| test_youTubeDirective_missingUrlAndHeightAndWidth() { |
| var parseResult = parseStringWithErrors(r''' |
| /// {@youtube } |
| class A {} |
| '''); |
| parseResult.assertNoErrors(); |
| |
| var node = parseResult.findNode.comment('youtube'); |
| assertParsedNodeText(node, r''' |
| Comment |
| tokens |
| /// {@youtube } |
| docDirectives |
| SimpleDocDirective |
| tag |
| offset: [4, 16] |
| type: [DocDirectiveType.youtube] |
| '''); |
| } |
| } |