├── .github ├── dependabot.yaml └── workflows │ ├── crash_test.yaml │ ├── flutter_markdown.yaml │ ├── no-response.yml │ ├── publish.yaml │ └── test-package.yml ├── .gitignore ├── AUTHORS ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── benchmark ├── benchmark.dart ├── input.md └── output.html ├── bin └── markdown.dart ├── dart_test.yaml ├── example ├── app.dart ├── favicon.png ├── highlight.dart ├── index.html └── style.css ├── lib ├── markdown.dart └── src │ ├── assets │ ├── case_folding.dart │ └── html_entities.dart │ ├── ast.dart │ ├── block_parser.dart │ ├── block_syntaxes │ ├── alert_block_syntax.dart │ ├── block_syntax.dart │ ├── blockquote_syntax.dart │ ├── code_block_syntax.dart │ ├── dummy_block_syntax.dart │ ├── empty_block_syntax.dart │ ├── fenced_blockquote_syntax.dart │ ├── fenced_code_block_syntax.dart │ ├── footnote_def_syntax.dart │ ├── header_syntax.dart │ ├── header_with_id_syntax.dart │ ├── horizontal_rule_syntax.dart │ ├── html_block_syntax.dart │ ├── link_reference_definition_syntax.dart │ ├── list_syntax.dart │ ├── ordered_list_syntax.dart │ ├── ordered_list_with_checkbox_syntax.dart │ ├── paragraph_syntax.dart │ ├── setext_header_syntax.dart │ ├── setext_header_with_id_syntax.dart │ ├── table_syntax.dart │ ├── unordered_list_syntax.dart │ └── unordered_list_with_checkbox_syntax.dart │ ├── charcode.dart │ ├── document.dart │ ├── emojis.dart │ ├── extension_set.dart │ ├── html_renderer.dart │ ├── inline_parser.dart │ ├── inline_syntaxes │ ├── autolink_extension_syntax.dart │ ├── autolink_syntax.dart │ ├── code_syntax.dart │ ├── color_swatch_syntax.dart │ ├── decode_html_syntax.dart │ ├── delimiter_syntax.dart │ ├── email_autolink_syntax.dart │ ├── emoji_syntax.dart │ ├── emphasis_syntax.dart │ ├── escape_html_syntax.dart │ ├── escape_syntax.dart │ ├── footnote_ref_syntax.dart │ ├── image_syntax.dart │ ├── inline_html_syntax.dart │ ├── inline_syntax.dart │ ├── line_break_syntax.dart │ ├── link_syntax.dart │ ├── soft_line_break_syntax.dart │ ├── strikethrough_syntax.dart │ └── text_syntax.dart │ ├── legacy_emojis.dart │ ├── line.dart │ ├── link_parser.dart │ ├── patterns.dart │ ├── text_parser.dart │ ├── util.dart │ └── version.dart ├── peanut.yaml ├── pubspec.yaml ├── test ├── blns.dart ├── blns_test.dart ├── common_mark │ ├── atx_headings.unit │ ├── autolinks.unit │ ├── backslash_escapes.unit │ ├── blank_lines.unit │ ├── block_quotes.unit │ ├── code_spans.unit │ ├── emphasis_and_strong_emphasis.unit │ ├── entity_and_numeric_character_references.unit │ ├── fenced_code_blocks.unit │ ├── hard_line_breaks.unit │ ├── html_blocks.unit │ ├── images.unit │ ├── indented_code_blocks.unit │ ├── inlines.unit │ ├── link_reference_definitions.unit │ ├── links.unit │ ├── list_items.unit │ ├── lists.unit │ ├── paragraphs.unit │ ├── precedence.unit │ ├── raw_html.unit │ ├── setext_headings.unit │ ├── soft_line_breaks.unit │ ├── tabs.unit │ ├── textual_content.unit │ └── thematic_breaks.unit ├── crash_test.dart ├── document_test.dart ├── extensions │ ├── alert_extension.unit │ ├── autolink_extension.unit │ ├── emojis.unit │ ├── fenced_blockquotes.unit │ ├── fenced_code_blocks.unit │ ├── footnote_block.unit │ ├── headers_with_ids.unit │ ├── inline_html.unit │ ├── ordered_list_with_checkboxes.unit │ ├── setext_headers_with_ids.unit │ ├── strikethrough.unit │ ├── tables.unit │ └── unordered_list_with_checkboxes.unit ├── gfm │ ├── atx_headings.unit │ ├── autolinks.unit │ ├── autolinks_extension.unit │ ├── backslash_escapes.unit │ ├── blank_lines.unit │ ├── block_quotes.unit │ ├── code_spans.unit │ ├── disallowed_raw_html_extension.unit │ ├── emphasis_and_strong_emphasis.unit │ ├── entity_and_numeric_character_references.unit │ ├── fenced_code_blocks.unit │ ├── hard_line_breaks.unit │ ├── html_blocks.unit │ ├── images.unit │ ├── indented_code_blocks.unit │ ├── inlines.unit │ ├── link_reference_definitions.unit │ ├── links.unit │ ├── list_items.unit │ ├── lists.unit │ ├── paragraphs.unit │ ├── precedence.unit │ ├── raw_html.unit │ ├── setext_headings.unit │ ├── soft_line_breaks.unit │ ├── strikethrough_extension.unit │ ├── tables_extension.unit │ ├── tabs.unit │ ├── textual_content.unit │ └── thematic_breaks.unit ├── html_renderer_test.dart ├── markdown_test.dart ├── original │ ├── autolinks.unit │ ├── backslash_escapes.unit │ ├── block_level_html.unit │ ├── block_quotes.unit │ ├── code_blocks.unit │ ├── emphasis_and_strong.unit │ ├── fenced_code_block.unit │ ├── hard_line_breaks.unit │ ├── headers.unit │ ├── horizontal_rules.unit │ ├── html_block.unit │ ├── html_encoding.unit │ ├── inline_code.unit │ ├── inline_images.unit │ ├── inline_links.unit │ ├── ordered_lists.unit │ ├── paragraphs.unit │ ├── reference_images.unit │ ├── reference_links.unit │ ├── setext_headers.unit │ ├── strong.unit │ └── unordered_lists.unit ├── util.dart ├── util_test.dart └── version_test.dart └── tool ├── README.md ├── case_folding.txt ├── common_mark_stats.json ├── common_mark_stats.txt ├── common_mark_tests.json ├── dartdoc_compare.dart ├── entities.json ├── expected_output.dart ├── gfm_stats.json ├── gfm_stats.txt ├── gfm_tests.json ├── stats.dart ├── stats_lib.dart ├── update-gh-pages.sh ├── update_blns.dart ├── update_case_folding.dart ├── update_emojis.dart ├── update_entities.dart ├── update_github_emojis.dart └── update_shared.dart /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | # Dependabot configuration file. 2 | version: 2 3 | 4 | updates: 5 | - package-ecosystem: github-actions 6 | directory: / 7 | schedule: 8 | interval: monthly 9 | labels: 10 | - autosubmit 11 | groups: 12 | github-actions: 13 | patterns: 14 | - "*" 15 | -------------------------------------------------------------------------------- /.github/workflows/crash_test.yaml: -------------------------------------------------------------------------------- 1 | # Run against all markdown files in latest version of packages on pub.dev to 2 | # see if any can provoke a crash 3 | 4 | name: Crash Tests 5 | 6 | on: 7 | schedule: 8 | # “At 00:00 (UTC) on Sunday.” 9 | - cron: '0 0 * * 0' 10 | 11 | jobs: 12 | crash-test: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 16 | - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 17 | - name: Install dependencies 18 | run: dart pub get 19 | - name: Run crash_test.dart 20 | run: dart test -P crash_test test/crash_test.dart 21 | -------------------------------------------------------------------------------- /.github/workflows/flutter_markdown.yaml: -------------------------------------------------------------------------------- 1 | # Run a smoke test against package:flutter_markdown. 2 | 3 | name: flutter_markdown 4 | 5 | on: 6 | schedule: 7 | # “At 00:00 (UTC) on Sunday.” 8 | - cron: '0 0 * * 0' 9 | push: 10 | branches: [ master ] 11 | pull_request: 12 | branches: [ master ] 13 | 14 | permissions: read-all 15 | 16 | jobs: 17 | smoke-test: 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - name: clone dart-lang/markdown 22 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 23 | with: 24 | repository: dart-lang/markdown 25 | path: markdown 26 | 27 | - name: clone flutter/packages 28 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 29 | with: 30 | repository: flutter/packages 31 | path: flutter_packages 32 | 33 | # Install the Flutter SDK using the subosito/flutter-action GitHub action. 34 | - name: install the flutter sdk 35 | uses: subosito/flutter-action@f2c4f6686ca8e8d6e6d0f28410eeef506ed66aff 36 | with: 37 | channel: 'beta' 38 | 39 | - name: flutter --version 40 | run: flutter --version 41 | 42 | - name: create pubspec_overrides.yaml 43 | working-directory: flutter_packages/packages/flutter_markdown 44 | run: | 45 | echo "dependency_overrides:" > pubspec_overrides.yaml 46 | echo " markdown:" >> pubspec_overrides.yaml 47 | echo " path: ../../../markdown" >> pubspec_overrides.yaml 48 | 49 | - name: flutter pub get 50 | working-directory: flutter_packages/packages/flutter_markdown 51 | run: flutter pub get 52 | 53 | - name: flutter analyze package:flutter_markdown 54 | working-directory: flutter_packages/packages/flutter_markdown 55 | run: flutter analyze 56 | 57 | - name: flutter test package:flutter_markdown 58 | working-directory: flutter_packages/packages/flutter_markdown 59 | run: flutter test 60 | -------------------------------------------------------------------------------- /.github/workflows/no-response.yml: -------------------------------------------------------------------------------- 1 | # A workflow to close issues where the author hasn't responded to a request for 2 | # more information; see https://github.com/actions/stale. 3 | 4 | name: No Response 5 | 6 | # Run as a daily cron. 7 | on: 8 | schedule: 9 | # Every day at 8am 10 | - cron: '0 8 * * *' 11 | 12 | # All permissions not specified are set to 'none'. 13 | permissions: 14 | issues: write 15 | pull-requests: write 16 | 17 | jobs: 18 | no-response: 19 | runs-on: ubuntu-latest 20 | if: ${{ github.repository_owner == 'dart-lang' }} 21 | steps: 22 | - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 23 | with: 24 | days-before-stale: -1 25 | days-before-close: 14 26 | stale-issue-label: "needs-info" 27 | close-issue-message: > 28 | Without additional information we're not able to resolve this issue. 29 | Feel free to add more info or respond to any questions above and we 30 | can reopen the case. Thanks for your contribution! 31 | stale-pr-label: "needs-info" 32 | close-pr-message: > 33 | Without additional information we're not able to resolve this PR. 34 | Feel free to add more info or respond to any questions above. 35 | Thanks for your contribution! 36 | -------------------------------------------------------------------------------- /.github/workflows/publish.yaml: -------------------------------------------------------------------------------- 1 | # A CI configuration to auto-publish pub packages. 2 | 3 | name: Publish 4 | 5 | on: 6 | pull_request: 7 | branches: [ master ] 8 | push: 9 | tags: [ 'v[0-9]+.[0-9]+.[0-9]+*' ] 10 | 11 | jobs: 12 | publish: 13 | if: ${{ github.repository_owner == 'dart-lang' }} 14 | uses: dart-lang/ecosystem/.github/workflows/publish.yaml@main 15 | -------------------------------------------------------------------------------- /.github/workflows/test-package.yml: -------------------------------------------------------------------------------- 1 | name: Dart CI 2 | 3 | on: 4 | # Run on PRs and pushes to the default branch. 5 | push: 6 | branches: [ master ] 7 | pull_request: 8 | branches: [ master ] 9 | schedule: 10 | - cron: "0 0 * * 0" 11 | 12 | env: 13 | PUB_ENVIRONMENT: bot.github 14 | 15 | jobs: 16 | # Check code formatting and static analysis on a single OS (linux) 17 | # against Dart dev. 18 | analyze: 19 | runs-on: ubuntu-latest 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | sdk: [dev] 24 | steps: 25 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 26 | - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 27 | with: 28 | sdk: ${{ matrix.sdk }} 29 | - id: install 30 | name: Install dependencies 31 | run: dart pub get 32 | - name: Check formatting 33 | run: dart format --output=none --set-exit-if-changed . 34 | if: always() && steps.install.outcome == 'success' 35 | - name: Analyze code 36 | run: dart analyze --fatal-infos 37 | if: always() && steps.install.outcome == 'success' 38 | 39 | # Run tests on a matrix consisting of two dimensions: 40 | # 1. OS: ubuntu-latest, (macos-latest, windows-latest) 41 | # 2. release channel: dev 42 | test: 43 | needs: analyze 44 | runs-on: ${{ matrix.os }} 45 | strategy: 46 | fail-fast: false 47 | matrix: 48 | # Add macos-latest and/or windows-latest if relevant for this package. 49 | os: [ubuntu-latest] 50 | sdk: [3.2, dev] 51 | steps: 52 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 53 | - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 54 | with: 55 | sdk: ${{ matrix.sdk }} 56 | - id: install 57 | name: Install dependencies 58 | run: dart pub get 59 | - name: Run VM tests 60 | run: dart test --platform vm 61 | if: always() && steps.install.outcome == 'success' 62 | 63 | coverage: 64 | needs: test 65 | runs-on: ubuntu-latest 66 | steps: 67 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 68 | - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 69 | with: 70 | sdk: dev 71 | - name: Install dependencies 72 | run: dart pub get 73 | - name: Install coverage 74 | run: dart pub global activate coverage 75 | - name: Collect and report coverage 76 | run: dart pub global run coverage:test_with_coverage 77 | - name: Upload coverage 78 | uses: coverallsapp/github-action@master 79 | with: 80 | github-token: ${{ secrets.GITHUB_TOKEN }} 81 | path-to-lcov: coverage/lcov.info 82 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .dart_tool 2 | .packages 3 | .pub 4 | pubspec.lock 5 | doc/ 6 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # Below is a list of people and organizations that have contributed 2 | # to the Dart project. Names should be added to the list like so: 3 | # 4 | # Name/Organization 5 | 6 | Google Inc. 7 | 8 | David Peek 9 | Daniel Schubert 10 | Jirka Daněk 11 | Seth Westphal 12 | Tim Maffett 13 | Alex Li 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2012, the Dart project authors. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following 11 | disclaimer in the documentation and/or other materials provided 12 | with the distribution. 13 | * Neither the name of Google LLC nor the names of its 14 | contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # https://dart.dev/tools/analysis 2 | include: package:dart_flutter_team_lints/analysis_options.yaml 3 | 4 | analyzer: 5 | language: 6 | strict-casts: true 7 | strict-inference: true 8 | strict-raw-types: true 9 | 10 | errors: 11 | # The example app explicitly takes a String of user-generated HTML and 12 | # inserts it straight into a
using innerHtml. 13 | unsafe_html: ignore 14 | # Waiting on a couple of bug fixes and new features before this should be enabled 15 | comment_references: ignore 16 | 17 | linter: 18 | rules: 19 | # https://github.com/dart-lang/linter/issues/574 20 | #- comment_references 21 | - avoid_private_typedef_functions 22 | - avoid_redundant_argument_values 23 | - avoid_unused_constructor_parameters 24 | - avoid_void_async 25 | - cancel_subscriptions 26 | - literal_only_boolean_expressions 27 | - missing_whitespace_between_adjacent_strings 28 | - no_adjacent_strings_in_list 29 | - prefer_const_declarations 30 | - prefer_final_locals 31 | - prefer_final_in_for_each 32 | - unnecessary_await_in_return 33 | - unnecessary_raw_strings 34 | - use_if_null_to_convert_nulls_to_bools 35 | - use_raw_strings 36 | - use_string_buffers 37 | -------------------------------------------------------------------------------- /benchmark/benchmark.dart: -------------------------------------------------------------------------------- 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 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | import 'dart:io'; 6 | 7 | import 'package:markdown/markdown.dart'; 8 | import 'package:path/path.dart' as p; 9 | 10 | const numTrials = 100; 11 | const runsPerTrial = 50; 12 | 13 | final source = _loadFile('input.md'); 14 | final expected = _loadFile('output.html'); 15 | 16 | void main() { 17 | var best = double.infinity; 18 | 19 | // Run the benchmark several times. This ensures the VM is warmed up and lets 20 | // us see how much variance there is. 21 | for (var i = 0; i <= numTrials; i++) { 22 | final stopwatch = Stopwatch()..start(); 23 | 24 | // For a single benchmark, convert the source multiple times. 25 | late String result; 26 | for (var j = 0; j < runsPerTrial; j++) { 27 | result = markdownToHtml(source); 28 | } 29 | 30 | stopwatch.stop(); 31 | final elapsed = stopwatch.elapsedMilliseconds / runsPerTrial; 32 | 33 | // Keep track of the best run so far. 34 | if (elapsed >= best) continue; 35 | best = elapsed; 36 | 37 | // Sanity check to make sure the output is what we expect and to make sure 38 | // the VM doesn't optimize "dead" code away. 39 | if (result != expected) { 40 | print('Incorrect output:\n$result'); 41 | exitCode = 1; 42 | return; 43 | } 44 | 45 | // Don't print the first run. It's always terrible since the VM hasn't 46 | // warmed up yet. 47 | if (i == 0) continue; 48 | _printResult("Run ${'#$i'.padLeft(3)}", elapsed); 49 | } 50 | 51 | _printResult('Best ', best); 52 | } 53 | 54 | String _loadFile(String name) { 55 | final path = p.join(p.dirname(p.fromUri(Platform.script)), name); 56 | return File(path).readAsStringSync(); 57 | } 58 | 59 | void _printResult(String label, double time) { 60 | print( 61 | '$label: ${time.toStringAsFixed(2).padLeft(4)}ms ' 62 | "${'=' * ((time * 20).toInt())}", 63 | ); 64 | } 65 | -------------------------------------------------------------------------------- /bin/markdown.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import 'dart:async'; 6 | import 'dart:io'; 7 | 8 | import 'package:args/args.dart'; 9 | import 'package:markdown/markdown.dart'; 10 | 11 | final extensionSets = { 12 | 'none': ExtensionSet.none, 13 | 'CommonMark': ExtensionSet.commonMark, 14 | 'GitHubFlavored': ExtensionSet.gitHubFlavored, 15 | 'GitHubWeb': ExtensionSet.gitHubWeb, 16 | }; 17 | 18 | Future main(List args) async { 19 | final parser = ArgParser() 20 | ..addFlag('help', negatable: false, help: 'Print help text and exit') 21 | ..addFlag('version', negatable: false, help: 'Print version and exit') 22 | ..addOption( 23 | 'extension-set', 24 | allowed: ['none', 'CommonMark', 'GitHubFlavored', 'GitHubWeb'], 25 | defaultsTo: 'CommonMark', 26 | help: 'Specify a set of extensions', 27 | allowedHelp: { 28 | 'none': 'No extensions; similar to Markdown.pl', 29 | 'CommonMark': 'Parse like CommonMark Markdown (default)', 30 | 'GitHubFlavored': 'Parse like GitHub Flavored Markdown', 31 | 'GitHubWeb': 'Parse like GitHub\'s Markdown-enabled web input fields', 32 | }, 33 | ); 34 | final results = parser.parse(args); 35 | 36 | if (results['help'] as bool) { 37 | printUsage(parser); 38 | return; 39 | } 40 | 41 | if (results['version'] as bool) { 42 | print(version); 43 | return; 44 | } 45 | 46 | final extensionSet = extensionSets[results['extension-set']]; 47 | 48 | if (results.rest.length > 1) { 49 | printUsage(parser); 50 | exitCode = 1; 51 | return; 52 | } 53 | 54 | if (results.rest.length == 1) { 55 | // Read argument as a file path. 56 | final input = File(results.rest.first).readAsStringSync(); 57 | print(markdownToHtml(input, extensionSet: extensionSet)); 58 | return; 59 | } 60 | 61 | // Read from stdin. 62 | final buffer = StringBuffer(); 63 | String? line; 64 | while ((line = stdin.readLineSync()) != null) { 65 | buffer.writeln(line); 66 | } 67 | print(markdownToHtml(buffer.toString(), extensionSet: extensionSet)); 68 | } 69 | 70 | void printUsage(ArgParser parser) { 71 | print('''Usage: markdown.dart [options] [file] 72 | 73 | Parse [file] as Markdown and print resulting HTML. If [file] is omitted, 74 | use stdin as input. 75 | 76 | By default, CommonMark Markdown will be parsed. This can be changed with 77 | the --extensionSet flag. 78 | 79 | ${parser.usage} 80 | '''); 81 | } 82 | -------------------------------------------------------------------------------- /dart_test.yaml: -------------------------------------------------------------------------------- 1 | tags: 2 | crash_test: 3 | skip: 'Only run crash_test tests manually with `dart test -P crash_test`' 4 | presets: 5 | crash_test: 6 | skip: false # Don't skip when running in -P crash_test 7 | -------------------------------------------------------------------------------- /example/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/markdown/62f78c64d963ba6f73bd70ed65630dc934a264e6/example/favicon.png -------------------------------------------------------------------------------- /example/highlight.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | @JS('hljs') 6 | library; 7 | 8 | import 'dart:js_interop'; 9 | 10 | import 'package:web/web.dart'; 11 | 12 | @JS() 13 | external void highlightElement(Node block); 14 | -------------------------------------------------------------------------------- /example/style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | background-color: rgb(250, 250, 250); 3 | font-family: Roboto,"Helvetica Neue",sans-serif; 4 | font-size: 16px; 5 | margin: 0; 6 | } 7 | 8 | .container { 9 | box-sizing: border-box; 10 | display: flex; 11 | flex-direction: column; 12 | height: 100%; 13 | width: 100%; 14 | } 15 | 16 | .main { 17 | align-items: stretch; 18 | box-sizing: border-box; 19 | display: flex; 20 | flex-direction: row; 21 | height: 100%; 22 | margin: 32px; 23 | } 24 | 25 | .version { 26 | color: rgba(0, 0, 0, 0.54); 27 | margin-right: 16px; 28 | } 29 | 30 | .card { 31 | /* Styled like Material Cards. */ 32 | color: rgba(0, 0, 0, 0.87); 33 | background-color: white; 34 | border-radius: 2px; 35 | box-sizing: border-box; 36 | box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .2), 37 | 0 1px 1px 0 rgba(0, 0, 0, .14), 38 | 0 2px 1px -1px rgba(0, 0, 0, .12); 39 | margin: 8px; 40 | 41 | /* Positioned next to each other. */ 42 | display: flex; 43 | flex: 1 1 50%; 44 | flex-direction: column; 45 | max-height: 100%; 46 | max-width: 50%; 47 | min-height: 400px; 48 | } 49 | 50 | .toolbar { 51 | /* Styled like Material Toolbar. */ 52 | align-items: center; 53 | background-color: #22d3c5; 54 | box-sizing: border-box; 55 | color: rgba(0, 0, 0, 0.87); 56 | display: flex; 57 | font-size: 20px; 58 | line-height: 1.4; 59 | margin: 0; 60 | min-height: 64px; 61 | padding: 0 16px; 62 | position: relative; 63 | width: 100%; 64 | } 65 | 66 | .toolbar h2 { 67 | font-size: inherit; 68 | font-weight: inherit; 69 | margin: inherit; 70 | } 71 | 72 | .toolbar a:link, 73 | .toolbar a:visited { 74 | color: rgba(0, 0, 0, 0.87); 75 | } 76 | 77 | .toolbar svg { 78 | fill: currentColor; 79 | } 80 | 81 | .card .toolbar { 82 | border-radius: 3px 3px 0 0; 83 | } 84 | 85 | .textarea-container { 86 | display: flex; 87 | height: 100%; 88 | padding: 8px; 89 | } 90 | 91 | textarea { 92 | border-color: rgba(0, 0, 0, 0.12); 93 | border-width: 0 0 1px; 94 | box-sizing: border-box; 95 | color: rgba(0, 0, 0, 0.87); 96 | font-family: "Roboto Mono",monospace; 97 | font-size: 100%; 98 | line-height: 26px; 99 | overflow: auto; 100 | padding: 2px 2px 1px; 101 | width: 100%; 102 | } 103 | 104 | textarea:focus { 105 | border-color: #22d3c5; 106 | border-width: 0 0 2px; 107 | outline: 0; 108 | padding-bottom: 0; 109 | } 110 | 111 | #html { 112 | overflow: auto; 113 | padding: 8px; 114 | } 115 | 116 | footer { 117 | box-sizing: border-box; 118 | display: flex; 119 | font-size: 20px; 120 | height: 64px; 121 | padding: 0 16px; 122 | } 123 | 124 | footer a:link, 125 | footer a:visited { 126 | color: rgba(0, 0, 0, 0.87); 127 | } 128 | 129 | .radio { 130 | cursor: pointer; 131 | display: inline-block; 132 | margin-right: 16px; 133 | } 134 | 135 | i.glyph { 136 | display: inline-block; 137 | font-family: 'Material Icons Extended'; 138 | font-size: 16px; 139 | font-style: normal; 140 | font-weight: normal; 141 | line-height: 1; 142 | } 143 | 144 | .radio[checked] i.glyph { 145 | color: #22d3c5; 146 | } 147 | 148 | i.glyph.big { 149 | font-size: 32px; 150 | height: 32px; 151 | width: 32px; 152 | } 153 | -------------------------------------------------------------------------------- /lib/src/ast.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | typedef Resolver = Node? Function(String name, [String? title]); 6 | 7 | /// Base class for any AST item. 8 | /// 9 | /// Roughly corresponds to Node in the DOM. Will be either an Element or Text. 10 | abstract class Node { 11 | void accept(NodeVisitor visitor); 12 | 13 | String get textContent; 14 | } 15 | 16 | /// A named tag that can contain other nodes. 17 | class Element implements Node { 18 | final String tag; 19 | final List? children; 20 | final Map attributes; 21 | String? generatedId; 22 | String? footnoteLabel; 23 | 24 | /// Instantiates a [tag] Element with [children]. 25 | Element(this.tag, this.children) : attributes = {}; 26 | 27 | /// Instantiates an empty, self-closing [tag] Element. 28 | Element.empty(this.tag) 29 | : children = null, 30 | attributes = {}; 31 | 32 | /// Instantiates a [tag] Element with no [children]. 33 | Element.withTag(this.tag) 34 | : children = const [], 35 | attributes = {}; 36 | 37 | /// Instantiates a [tag] Element with a single Text child. 38 | Element.text(this.tag, String text) 39 | : children = [Text(text)], 40 | attributes = {}; 41 | 42 | /// Whether this element is self-closing. 43 | bool get isEmpty => children == null; 44 | 45 | @override 46 | void accept(NodeVisitor visitor) { 47 | if (visitor.visitElementBefore(this)) { 48 | if (children != null) { 49 | for (final child in children!) { 50 | child.accept(visitor); 51 | } 52 | } 53 | visitor.visitElementAfter(this); 54 | } 55 | } 56 | 57 | @override 58 | String get textContent { 59 | final children = this.children; 60 | return children == null 61 | ? '' 62 | : children.map((child) => child.textContent).join(); 63 | } 64 | } 65 | 66 | /// A plain text element. 67 | class Text implements Node { 68 | final String text; 69 | 70 | Text(this.text); 71 | 72 | @override 73 | void accept(NodeVisitor visitor) => visitor.visitText(this); 74 | 75 | @override 76 | String get textContent => text; 77 | } 78 | 79 | /// Inline content that has not been parsed into inline nodes (strong, links, 80 | /// etc). 81 | /// 82 | /// These placeholder nodes should only remain in place while the block nodes 83 | /// of a document are still being parsed, in order to gather all reference link 84 | /// definitions. 85 | class UnparsedContent implements Node { 86 | @override 87 | final String textContent; 88 | 89 | UnparsedContent(this.textContent); 90 | 91 | @override 92 | void accept(NodeVisitor visitor) {} 93 | } 94 | 95 | /// Visitor pattern for the AST. 96 | /// 97 | /// Renderers or other AST transformers should implement this. 98 | abstract class NodeVisitor { 99 | /// Called when a Text node has been reached. 100 | void visitText(Text text); 101 | 102 | /// Called when an Element has been reached, before its children have been 103 | /// visited. 104 | /// 105 | /// Returns `false` to skip its children. 106 | bool visitElementBefore(Element element); 107 | 108 | /// Called when an Element has been reached, after its children have been 109 | /// visited. 110 | /// 111 | /// Will not be called if [visitElementBefore] returns `false`. 112 | void visitElementAfter(Element element); 113 | } 114 | -------------------------------------------------------------------------------- /lib/src/block_syntaxes/block_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../block_parser.dart'; 7 | import '../line.dart'; 8 | 9 | abstract class BlockSyntax { 10 | const BlockSyntax(); 11 | 12 | /// Gets the regex used to identify the beginning of this block, if any. 13 | RegExp get pattern; 14 | 15 | bool canEndBlock(BlockParser parser) => true; 16 | 17 | bool canParse(BlockParser parser) { 18 | return pattern.hasMatch(parser.current.content); 19 | } 20 | 21 | Node? parse(BlockParser parser); 22 | 23 | List parseChildLines(BlockParser parser) { 24 | // Grab all of the lines that form the block element. 25 | final childLines = []; 26 | 27 | while (!parser.isDone) { 28 | final match = pattern.firstMatch(parser.current.content); 29 | if (match == null) break; 30 | childLines.add(parser.current); 31 | parser.advance(); 32 | } 33 | 34 | return childLines; 35 | } 36 | 37 | /// Returns the block which interrupts current syntax parsing if there is one, 38 | /// otherwise returns `null`. 39 | /// 40 | /// Make sure to check if [parser] `isDone` is `false` first. 41 | BlockSyntax? interruptedBy(BlockParser parser) { 42 | for (final syntax in parser.blockSyntaxes) { 43 | if (syntax.canParse(parser) && syntax.canEndBlock(parser)) { 44 | return syntax; 45 | } 46 | } 47 | return null; 48 | } 49 | 50 | /// Gets whether or not [parser]'s current line should end the previous block. 51 | static bool isAtBlockEnd(BlockParser parser) { 52 | if (parser.isDone) return true; 53 | return parser.blockSyntaxes 54 | .any((s) => s.canParse(parser) && s.canEndBlock(parser)); 55 | } 56 | 57 | /// Generates a valid HTML anchor from the inner text of [element]. 58 | static String generateAnchorHash(Element element) => 59 | element.children!.first.textContent 60 | .toLowerCase() 61 | .trim() 62 | .replaceAll(RegExp('[^a-z0-9 _-]'), '') 63 | .replaceAll(RegExp(r'\s'), '-'); 64 | } 65 | -------------------------------------------------------------------------------- /lib/src/block_syntaxes/code_block_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../block_parser.dart'; 7 | import '../line.dart'; 8 | import '../patterns.dart'; 9 | import '../util.dart'; 10 | import 'block_syntax.dart'; 11 | 12 | /// Parses preformatted code blocks that are indented four spaces. 13 | class CodeBlockSyntax extends BlockSyntax { 14 | @override 15 | RegExp get pattern => indentPattern; 16 | 17 | @override 18 | bool canEndBlock(BlockParser parser) => false; 19 | 20 | const CodeBlockSyntax(); 21 | 22 | @override 23 | List parseChildLines(BlockParser parser) { 24 | final childLines = []; 25 | 26 | while (!parser.isDone) { 27 | final isBlankLine = parser.current.isBlankLine; 28 | if (isBlankLine && _shouldEnd(parser)) { 29 | break; 30 | } 31 | 32 | if (!isBlankLine && 33 | childLines.isNotEmpty && 34 | !pattern.hasMatch(parser.current.content)) { 35 | break; 36 | } 37 | 38 | childLines.add(Line( 39 | parser.current.content.dedent().text, 40 | tabRemaining: parser.current.tabRemaining, 41 | )); 42 | 43 | parser.advance(); 44 | } 45 | 46 | return childLines; 47 | } 48 | 49 | @override 50 | Node parse(BlockParser parser) { 51 | final childLines = parseChildLines(parser); 52 | 53 | // The Markdown tests expect a trailing newline. 54 | childLines.add(Line('')); 55 | 56 | var content = childLines 57 | .map((e) => e.content.prependSpace(e.tabRemaining ?? 0)) 58 | .join('\n'); 59 | if (parser.document.encodeHtml) { 60 | content = escapeHtml(content, escapeApos: false); 61 | } 62 | 63 | return Element('pre', [Element.text('code', content)]); 64 | } 65 | 66 | bool _shouldEnd(BlockParser parser) { 67 | var i = 1; 68 | while (true) { 69 | final nextLine = parser.peek(i); 70 | // EOF 71 | if (nextLine == null) { 72 | return true; 73 | } 74 | 75 | // It does not matter how many blank lines between chunks: 76 | // https://spec.commonmark.org/0.30/#example-111 77 | if (nextLine.isBlankLine) { 78 | i++; 79 | continue; 80 | } 81 | 82 | return !pattern.hasMatch(nextLine.content); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /lib/src/block_syntaxes/dummy_block_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../block_parser.dart'; 7 | import '../patterns.dart'; 8 | import 'block_syntax.dart'; 9 | 10 | /// Walks the parser forward through the lines does not match any [BlockSyntax]. 11 | /// 12 | /// Returns a [UnparsedContent] with the unmatched lines as `textContent`. 13 | class DummyBlockSyntax extends BlockSyntax { 14 | const DummyBlockSyntax(); 15 | 16 | @override 17 | RegExp get pattern => dummyPattern; 18 | 19 | @override 20 | bool canEndBlock(BlockParser parser) => false; 21 | 22 | @override 23 | bool canParse(BlockParser parser) => true; 24 | 25 | @override 26 | Node parse(BlockParser parser) { 27 | final childLines = []; 28 | 29 | while (!BlockSyntax.isAtBlockEnd(parser)) { 30 | childLines.add(parser.current.content); 31 | parser.advance(); 32 | } 33 | 34 | return UnparsedContent(childLines.join('\n')); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/src/block_syntaxes/empty_block_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../block_parser.dart'; 7 | import '../patterns.dart'; 8 | import 'block_syntax.dart'; 9 | 10 | class EmptyBlockSyntax extends BlockSyntax { 11 | @override 12 | RegExp get pattern => emptyPattern; 13 | 14 | const EmptyBlockSyntax(); 15 | 16 | @override 17 | Node? parse(BlockParser parser) { 18 | parser.encounteredBlankLine = true; 19 | parser.advance(); 20 | 21 | // Don't actually emit anything. 22 | return null; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/src/block_syntaxes/fenced_blockquote_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../block_parser.dart'; 7 | import '../line.dart'; 8 | import '../patterns.dart'; 9 | import 'block_syntax.dart'; 10 | 11 | /// Parses lines fenced by `>>>` to blockquotes 12 | class FencedBlockquoteSyntax extends BlockSyntax { 13 | const FencedBlockquoteSyntax(); 14 | 15 | @override 16 | RegExp get pattern => blockquoteFencePattern; 17 | 18 | @override 19 | List parseChildLines(BlockParser parser) { 20 | final childLines = []; 21 | parser.advance(); 22 | 23 | while (!parser.isDone) { 24 | final match = pattern.hasMatch(parser.current.content); 25 | if (!match) { 26 | childLines.add(parser.current); 27 | parser.advance(); 28 | } else { 29 | parser.advance(); 30 | break; 31 | } 32 | } 33 | 34 | return childLines; 35 | } 36 | 37 | @override 38 | Node? parse(BlockParser parser) { 39 | final childLines = parseChildLines(parser); 40 | 41 | // Recursively parse the contents of the blockquote. 42 | final children = BlockParser(childLines, parser.document).parseLines(); 43 | return Element('blockquote', children); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/src/block_syntaxes/footnote_def_syntax.dart: -------------------------------------------------------------------------------- 1 | import '../ast.dart' show Element, Node; 2 | import '../block_parser.dart' show BlockParser; 3 | import '../line.dart'; 4 | import '../patterns.dart' show dummyPattern, emptyPattern, footnotePattern; 5 | import 'block_syntax.dart' show BlockSyntax; 6 | 7 | /// The spec of GFM about footnotes is [missing](https://github.com/github/cmark-gfm/issues/283#issuecomment-1378868725). 8 | /// For online source code of cmark-gfm, see [master@c32ef78](https://github.com/github/cmark-gfm/blob/c32ef78/src/blocks.c#L1212). 9 | /// A Rust implementation is also [available](https://github.com/wooorm/markdown-rs/blob/2498e31eecead798efc649502bbf5f86feaa94be/src/construct/gfm_footnote_definition.rs). 10 | /// Footnote definition could contain multiple line-children and children could 11 | /// be separated by one empty line. 12 | /// Its first child-line would be the remaining part of the first line after 13 | /// taking definition leading, combining with other child lines parsed by 14 | /// [parseChildLines], is fed into [BlockParser]. 15 | class FootnoteDefSyntax extends BlockSyntax { 16 | const FootnoteDefSyntax(); 17 | 18 | @override 19 | RegExp get pattern => footnotePattern; 20 | 21 | @override 22 | Node? parse(BlockParser parser) { 23 | final current = parser.current.content; 24 | final match = pattern.firstMatch(current)!; 25 | final label = match[2]!; 26 | final refs = parser.document.footnoteReferences; 27 | refs[label] = 0; 28 | 29 | final id = Uri.encodeComponent(label); 30 | parser.advance(); 31 | final lines = [ 32 | Line(current.substring(match[0]!.length)), 33 | ...parseChildLines(parser), 34 | ]; 35 | final children = BlockParser(lines, parser.document).parseLines(); 36 | return Element('li', children) 37 | ..attributes['id'] = 'fn-$id' 38 | ..footnoteLabel = label; 39 | } 40 | 41 | @override 42 | List parseChildLines(BlockParser parser) { 43 | final children = []; 44 | // As one empty line should not split footnote definition, use this flag. 45 | var shouldBeBlock = false; 46 | late final syntaxList = parser.blockSyntaxes 47 | .where((s) => !_excludingPattern.contains(s.pattern)); 48 | 49 | // Every line is footnote's children util two blank lines or a block. 50 | while (!parser.isDone) { 51 | final line = parser.current.content; 52 | if (line.trim().isEmpty) { 53 | children.add(line); 54 | parser.advance(); 55 | shouldBeBlock = true; 56 | continue; 57 | } else if (line.startsWith(' ')) { 58 | children.add(line.substring(4)); 59 | parser.advance(); 60 | shouldBeBlock = false; 61 | } else if (shouldBeBlock || _isBlock(syntaxList, line)) { 62 | break; 63 | } else { 64 | children.add(line); 65 | parser.advance(); 66 | } 67 | } 68 | return children.map(Line.new).toList(growable: false); 69 | } 70 | 71 | /// Patterns that would be used to decide if one line is a block. 72 | static final _excludingPattern = { 73 | emptyPattern, 74 | dummyPattern, 75 | }; 76 | 77 | /// Whether this line is any kind of block. 78 | /// If `true`, the footnote block should end. 79 | static bool _isBlock(Iterable syntaxList, String line) { 80 | return syntaxList.any((s) => s.pattern.hasMatch(line)); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /lib/src/block_syntaxes/header_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../block_parser.dart'; 7 | import '../patterns.dart'; 8 | import 'block_syntax.dart'; 9 | 10 | /// Parses atx-style headers: `## Header ##`. 11 | class HeaderSyntax extends BlockSyntax { 12 | @override 13 | RegExp get pattern => headerPattern; 14 | 15 | const HeaderSyntax(); 16 | 17 | @override 18 | Node parse(BlockParser parser) { 19 | final match = pattern.firstMatch(parser.current.content)!; 20 | final matchedText = match[0]!; 21 | final openMarker = match[1]!; 22 | final closeMarker = match[2]; 23 | final level = openMarker.length; 24 | final openMarkerStart = matchedText.indexOf(openMarker); 25 | final openMarkerEnd = openMarkerStart + level; 26 | 27 | String? content; 28 | if (closeMarker == null) { 29 | content = parser.current.content.substring(openMarkerEnd); 30 | } else { 31 | final closeMarkerStart = matchedText.lastIndexOf(closeMarker); 32 | content = parser.current.content.substring( 33 | openMarkerEnd, 34 | closeMarkerStart, 35 | ); 36 | } 37 | content = content.trim(); 38 | 39 | // https://spec.commonmark.org/0.30/#example-79 40 | if (closeMarker == null && RegExp(r'^#+$').hasMatch(content)) { 41 | content = null; 42 | } 43 | 44 | parser.advance(); 45 | return Element('h$level', [if (content != null) UnparsedContent(content)]); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/src/block_syntaxes/header_with_id_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../block_parser.dart'; 7 | import 'block_syntax.dart'; 8 | import 'header_syntax.dart'; 9 | 10 | /// Parses atx-style headers, and adds generated IDs to the generated elements. 11 | class HeaderWithIdSyntax extends HeaderSyntax { 12 | const HeaderWithIdSyntax(); 13 | 14 | @override 15 | Node parse(BlockParser parser) { 16 | final element = super.parse(parser) as Element; 17 | 18 | if (element.children?.isNotEmpty ?? false) { 19 | element.generatedId = BlockSyntax.generateAnchorHash(element); 20 | } 21 | 22 | return element; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/src/block_syntaxes/horizontal_rule_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../block_parser.dart'; 7 | import '../patterns.dart'; 8 | import 'block_syntax.dart'; 9 | 10 | /// Parses horizontal rules like `---`, `_ _ _`, `* * *`, etc. 11 | class HorizontalRuleSyntax extends BlockSyntax { 12 | @override 13 | RegExp get pattern => hrPattern; 14 | 15 | const HorizontalRuleSyntax(); 16 | 17 | @override 18 | Node parse(BlockParser parser) { 19 | parser.advance(); 20 | return Element.empty('hr'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/src/block_syntaxes/html_block_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../block_parser.dart'; 7 | import '../line.dart'; 8 | import '../patterns.dart'; 9 | import 'block_syntax.dart'; 10 | import 'list_syntax.dart'; 11 | 12 | /// Parse HTML blocks. 13 | // There are seven kinds of HTML block defined in the CommonMark spec: 14 | // https://spec.commonmark.org/0.30/#html-blocks. 15 | // These matching conditions and HTML block types mentioned in this syntax 16 | // correspond to these ones in the CommonMark spec. 17 | class HtmlBlockSyntax extends BlockSyntax { 18 | @override 19 | RegExp get pattern => htmlBlockPattern; 20 | 21 | // All types of HTML blocks except type 7 may interrupt a paragraph, see the 22 | // second paragraph after https://spec.commonmark.org/0.30/#example-148 for 23 | // more detail. 24 | @override 25 | bool canEndBlock(BlockParser parser) => 26 | pattern.firstMatch(parser.current.content)!.namedGroup('condition_7') == 27 | null; 28 | 29 | static final _endConditions = [ 30 | // For condition 1, it does not need to match the start tag, see 31 | // https://spec.commonmark.org/0.30/#end-condition 32 | RegExp('', caseSensitive: false), 33 | RegExp('-->'), 34 | RegExp(r'\?>'), 35 | RegExp('>'), 36 | RegExp(']]>'), 37 | emptyPattern, 38 | emptyPattern, 39 | ]; 40 | 41 | const HtmlBlockSyntax(); 42 | 43 | @override 44 | List parseChildLines(BlockParser parser) { 45 | final lines = []; 46 | 47 | final match = pattern.firstMatch(parser.current.content); 48 | var matchedCondition = 0; 49 | for (var i = 0; i < match!.groupCount; i++) { 50 | if (match.group(i + 1) != null) { 51 | matchedCondition = i; 52 | break; 53 | } 54 | } 55 | 56 | final endCondition = _endConditions[matchedCondition]; 57 | if (endCondition == emptyPattern) { 58 | lines.add(parser.current); 59 | parser.advance(); 60 | 61 | while (!parser.isDone && !endCondition.hasMatch(parser.current.content)) { 62 | lines.add(parser.current); 63 | parser.advance(); 64 | } 65 | } else { 66 | while (!parser.isDone) { 67 | lines.add(parser.current); 68 | if (endCondition.hasMatch(parser.current.content)) { 69 | break; 70 | } 71 | parser.advance(); 72 | } 73 | parser.advance(); 74 | } 75 | 76 | // If the current line start an HTML block again, put them together with 77 | // the previous HTML block. 78 | if (!parser.isDone && pattern.hasMatch(parser.current.content)) { 79 | lines.addAll(parseChildLines(parser)); 80 | } 81 | 82 | return lines; 83 | } 84 | 85 | @override 86 | Node parse(BlockParser parser) { 87 | final childLines = parseChildLines(parser); 88 | 89 | var text = childLines.map((e) => e.content).join('\n').trimRight(); 90 | if (parser.previousSyntax != null || parser.parentSyntax != null) { 91 | text = '\n$text'; 92 | if (parser.parentSyntax is ListSyntax) { 93 | text = '$text\n'; 94 | } 95 | } 96 | 97 | return Text(text); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /lib/src/block_syntaxes/link_reference_definition_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../block_parser.dart'; 7 | import '../document.dart'; 8 | import '../line.dart'; 9 | import '../link_parser.dart'; 10 | import '../patterns.dart'; 11 | import '../util.dart'; 12 | import 'block_syntax.dart'; 13 | 14 | class LinkReferenceDefinitionSyntax extends BlockSyntax { 15 | @override 16 | RegExp get pattern => linkReferenceDefinitionPattern; 17 | 18 | @override 19 | bool canEndBlock(BlockParser parser) => false; 20 | 21 | const LinkReferenceDefinitionSyntax(); 22 | 23 | @override 24 | Node? parse(BlockParser parser) { 25 | final lines = [parser.current]; 26 | parser.advance(); 27 | 28 | while (!BlockSyntax.isAtBlockEnd(parser)) { 29 | lines.add(parser.current); 30 | parser.advance(); 31 | } 32 | 33 | if (!_parseLinkReferenceDefinition(lines, parser)) { 34 | parser.retreatBy(lines.length); 35 | } 36 | 37 | return null; 38 | } 39 | 40 | bool _parseLinkReferenceDefinition(List lines, BlockParser parser) { 41 | final linkParser = LinkParser(lines.map((e) => e.content).join('\n')) 42 | ..parseDefinition(); 43 | 44 | if (!linkParser.valid) { 45 | return false; 46 | } 47 | 48 | // Retreat the parsing position back to where the link reference definition 49 | // ends, so that the next syntax can continue parsing from there. 50 | parser.retreatBy(linkParser.unconsumedLines); 51 | 52 | final labelString = normalizeLinkLabel(linkParser.label!); 53 | 54 | parser.document.linkReferences.putIfAbsent( 55 | labelString, 56 | () => LinkReference( 57 | labelString, 58 | linkParser.destination!, 59 | linkParser.title, 60 | ), 61 | ); 62 | 63 | return true; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lib/src/block_syntaxes/ordered_list_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../patterns.dart'; 6 | import 'list_syntax.dart'; 7 | 8 | /// Parses ordered lists. 9 | class OrderedListSyntax extends ListSyntax { 10 | @override 11 | RegExp get pattern => listPattern; 12 | 13 | const OrderedListSyntax(); 14 | } 15 | -------------------------------------------------------------------------------- /lib/src/block_syntaxes/ordered_list_with_checkbox_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import 'ordered_list_syntax.dart'; 6 | 7 | /// Parses ordered lists with checkboxes. 8 | class OrderedListWithCheckboxSyntax extends OrderedListSyntax { 9 | const OrderedListWithCheckboxSyntax(); 10 | } 11 | -------------------------------------------------------------------------------- /lib/src/block_syntaxes/paragraph_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../block_parser.dart'; 7 | import '../patterns.dart'; 8 | import 'block_syntax.dart'; 9 | import 'setext_header_syntax.dart'; 10 | 11 | /// Parses paragraphs of regular text. 12 | class ParagraphSyntax extends BlockSyntax { 13 | @override 14 | RegExp get pattern => dummyPattern; 15 | 16 | @override 17 | bool canEndBlock(BlockParser parser) => false; 18 | 19 | const ParagraphSyntax(); 20 | 21 | @override 22 | bool canParse(BlockParser parser) => true; 23 | 24 | @override 25 | Node? parse(BlockParser parser) { 26 | final childLines = [parser.current.content]; 27 | 28 | parser.advance(); 29 | var interruptedBySetextHeading = false; 30 | // Eat until we hit something that ends a paragraph. 31 | while (!parser.isDone) { 32 | final syntax = interruptedBy(parser); 33 | if (syntax != null) { 34 | interruptedBySetextHeading = syntax is SetextHeaderSyntax; 35 | break; 36 | } 37 | childLines.add(parser.current.content); 38 | parser.advance(); 39 | } 40 | 41 | // It is not a paragraph, but a setext heading. 42 | if (interruptedBySetextHeading) { 43 | return null; 44 | } 45 | 46 | final contents = UnparsedContent(childLines.join('\n').trimRight()); 47 | return Element('p', [contents]); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/src/block_syntaxes/setext_header_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../block_parser.dart'; 7 | import '../patterns.dart'; 8 | import 'block_syntax.dart'; 9 | import 'paragraph_syntax.dart'; 10 | 11 | /// Parses setext-style headers. 12 | class SetextHeaderSyntax extends BlockSyntax { 13 | @override 14 | RegExp get pattern => setextPattern; 15 | 16 | const SetextHeaderSyntax(); 17 | 18 | @override 19 | bool canParse(BlockParser parser) { 20 | final lastSyntax = parser.currentSyntax; 21 | if (parser.setextHeadingDisabled || lastSyntax is! ParagraphSyntax) { 22 | return false; 23 | } 24 | return pattern.hasMatch(parser.current.content); 25 | } 26 | 27 | @override 28 | Node? parse(BlockParser parser) { 29 | final lines = parser.linesToConsume; 30 | if (lines.length < 2) { 31 | return null; 32 | } 33 | 34 | // Remove the last line which is a marker. 35 | lines.removeLast(); 36 | 37 | final marker = parser.current.content.trim(); 38 | final level = (marker[0] == '=') ? '1' : '2'; 39 | final content = lines.map((e) => e.content).join('\n').trimRight(); 40 | 41 | parser.advance(); 42 | return Element('h$level', [UnparsedContent(content)]); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/src/block_syntaxes/setext_header_with_id_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../block_parser.dart'; 7 | import 'block_syntax.dart'; 8 | import 'setext_header_syntax.dart'; 9 | 10 | /// Parses setext-style headers, and adds generated IDs to the generated 11 | /// elements. 12 | class SetextHeaderWithIdSyntax extends SetextHeaderSyntax { 13 | const SetextHeaderWithIdSyntax(); 14 | 15 | @override 16 | Node parse(BlockParser parser) { 17 | final element = super.parse(parser) as Element; 18 | element.generatedId = BlockSyntax.generateAnchorHash(element); 19 | return element; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/src/block_syntaxes/unordered_list_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../block_parser.dart'; 6 | import '../patterns.dart'; 7 | import 'list_syntax.dart'; 8 | 9 | /// Parses unordered lists. 10 | class UnorderedListSyntax extends ListSyntax { 11 | @override 12 | RegExp get pattern => listPattern; 13 | 14 | @override 15 | bool canParse(BlockParser parser) { 16 | // Check if it matches `hrPattern`, otherwise it will produce an infinite 17 | // loop if put `UnorderedListSyntax` or `UnorderedListWithCheckboxSyntax` 18 | // bofore `HorizontalRuleSyntax` and parse: 19 | // ``` 20 | // * * * 21 | // ``` 22 | if (hrPattern.hasMatch(parser.current.content)) { 23 | return false; 24 | } 25 | 26 | return pattern.hasMatch(parser.current.content); 27 | } 28 | 29 | const UnorderedListSyntax(); 30 | } 31 | -------------------------------------------------------------------------------- /lib/src/block_syntaxes/unordered_list_with_checkbox_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import 'unordered_list_syntax.dart'; 6 | 7 | /// Parses unordered lists with checkboxes. 8 | class UnorderedListWithCheckboxSyntax extends UnorderedListSyntax { 9 | const UnorderedListWithCheckboxSyntax(); 10 | } 11 | -------------------------------------------------------------------------------- /lib/src/charcode.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source is governed by a 3 | // BSD-style license that can be found in the LICENSE file 4 | 5 | /// "Horizontal Tab" control character, common name. 6 | const int $tab = 0x09; 7 | 8 | /// "Line feed" control character. 9 | const int $lf = 0x0A; 10 | 11 | /// "Vertical Tab" control character. 12 | const int $vt = 0x0B; 13 | 14 | /// "Form feed" control character. 15 | const int $ff = 0x0C; 16 | 17 | /// "Carriage return" control character. 18 | const int $cr = 0x0D; 19 | 20 | /// Space character. 21 | const int $space = 0x20; 22 | 23 | /// Character `!`. 24 | const int $exclamation = 0x21; 25 | 26 | /// Character `"`. 27 | const int $quote = 0x22; 28 | 29 | /// Character `"`. 30 | const int $double_quote = 0x22; // ignore: constant_identifier_names 31 | 32 | /// Character `#`. 33 | const int $hash = 0x23; 34 | 35 | /// Character `$`. 36 | const int $dollar = 0x24; 37 | 38 | /// Character `%`. 39 | const int $percent = 0x25; 40 | 41 | /// Character `&`. 42 | const int $ampersand = 0x26; 43 | 44 | /// Character `'`. 45 | const int $apostrophe = 0x27; 46 | 47 | /// Character `(`. 48 | const int $lparen = 0x28; 49 | 50 | /// Character `)`. 51 | const int $rparen = 0x29; 52 | 53 | /// Character `*`. 54 | const int $asterisk = 0x2A; 55 | 56 | /// Character `+`. 57 | const int $plus = 0x2B; 58 | 59 | /// Character `,`. 60 | const int $comma = 0x2C; 61 | 62 | /// Character `-`. 63 | const int $dash = 0x2D; 64 | 65 | /// Character `.`. 66 | const int $dot = 0x2E; 67 | 68 | /// Character `/`. 69 | const int $slash = 0x2F; 70 | 71 | /// Character `:`. 72 | const int $colon = 0x3A; 73 | 74 | /// Character `;`. 75 | const int $semicolon = 0x3B; 76 | 77 | /// Character `<`. 78 | const int $lt = 0x3C; 79 | 80 | /// Character `=`. 81 | const int $equal = 0x3D; 82 | 83 | /// Character `>`. 84 | const int $gt = 0x3E; 85 | 86 | /// Character `?`. 87 | const int $question = 0x3F; 88 | 89 | /// Character `@`. 90 | const int $at = 0x40; 91 | 92 | /// Character `[`. 93 | const int $lbracket = 0x5B; 94 | 95 | /// Character `\`. 96 | const int $backslash = 0x5C; 97 | 98 | /// Character `]`. 99 | const int $rbracket = 0x5D; 100 | 101 | /// Character `^`. 102 | const int $caret = 0x5E; 103 | 104 | /// Character `_`. 105 | const int $underscore = 0x5F; 106 | 107 | /// Character `` ` ``. 108 | const int $backquote = 0x60; 109 | 110 | /// Character `{`. 111 | const int $lbrace = 0x7B; 112 | 113 | /// Character `|`. 114 | const int $pipe = 0x7C; 115 | 116 | /// Character `|`. 117 | const int $bar = 0x7C; 118 | 119 | /// Character `}`. 120 | const int $rbrace = 0x7D; 121 | 122 | /// Character `~`. 123 | const int $tilde = 0x7E; 124 | -------------------------------------------------------------------------------- /lib/src/inline_syntaxes/autolink_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../inline_parser.dart'; 7 | import '../util.dart'; 8 | import 'inline_syntax.dart'; 9 | 10 | /// Matches autolinks like ``. 11 | class AutolinkSyntax extends InlineSyntax { 12 | AutolinkSyntax() : super(r'<(([a-zA-Z][a-zA-Z\-\+\.]+):(?://)?[^\s>]*)>'); 13 | 14 | @override 15 | bool onMatch(InlineParser parser, Match match) { 16 | final url = match[1]!; 17 | final text = parser.encodeHtml ? escapeHtml(url) : url; 18 | final anchor = Element.text('a', text); 19 | 20 | final destination = normalizeLinkDestination(url); 21 | anchor.attributes['href'] = 22 | parser.encodeHtml ? escapeHtml(destination) : destination; 23 | parser.addNode(anchor); 24 | 25 | return true; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/src/inline_syntaxes/code_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../charcode.dart'; 7 | import '../inline_parser.dart'; 8 | import '../util.dart'; 9 | import 'inline_syntax.dart'; 10 | 11 | /// Matches backtick-enclosed inline code blocks. 12 | class CodeSyntax extends InlineSyntax { 13 | // This pattern matches: 14 | // 15 | // * a string of backticks (not followed by any more), followed by 16 | // * a non-greedy string of anything, including newlines, ending with anything 17 | // except a backtick, followed by 18 | // * a string of backticks the same length as the first, not followed by any 19 | // more. 20 | // 21 | // This conforms to the delimiters of inline code, both in Markdown.pl, and 22 | // CommonMark. 23 | static const _pattern = r'(`+(?!`))((?:.|\n)*?[^`])\1(?!`)'; 24 | 25 | CodeSyntax() : super(_pattern); 26 | 27 | @override 28 | bool tryMatch(InlineParser parser, [int? startMatchPos]) { 29 | if (parser.pos > 0 && parser.charAt(parser.pos - 1) == $backquote) { 30 | // Not really a match! We can't just sneak past one backtick to try the 31 | // next character. An example of this situation would be: 32 | // 33 | // before ``` and `` after. 34 | // ^--parser.pos 35 | return false; 36 | } 37 | 38 | final match = pattern.matchAsPrefix(parser.source, parser.pos); 39 | if (match == null) { 40 | return false; 41 | } 42 | parser.writeText(); 43 | if (onMatch(parser, match)) parser.consume(match.match.length); 44 | return true; 45 | } 46 | 47 | @override 48 | bool onMatch(InlineParser parser, Match match) { 49 | final markerLength = match[1]!.length; 50 | final contentLength = match.match.length - markerLength * 2; 51 | final contentStart = parser.pos + markerLength; 52 | final contentEnd = contentStart + contentLength; 53 | 54 | var code = parser.source.substring(contentStart, contentEnd); 55 | if (_shouldStrip(code)) { 56 | code = code.substring(1, code.length - 1); 57 | } 58 | code = code.replaceAll('\n', ' '); 59 | 60 | if (parser.encodeHtml) { 61 | code = escapeHtml(code, escapeApos: false); 62 | } 63 | 64 | parser.addNode(Element.text('code', code)); 65 | return true; 66 | } 67 | 68 | bool _shouldStrip(String code) { 69 | // No stripping occurs if the code span contains only spaces: 70 | // https://spec.commonmark.org/0.30/#example-334. 71 | if (code.trim().isEmpty) { 72 | return false; 73 | } 74 | 75 | // Only spaces, and not unicode whitespace in general, are stripped in this 76 | // way, see https://spec.commonmark.org/0.30/#example-333. 77 | final startsWithSpace = code.startsWith(' ') || code.startsWith('\n'); 78 | final endsWithSpace = code.endsWith(' ') || code.endsWith('\n'); 79 | 80 | // The stripping only happens if the space is on both sides of the string: 81 | // https://spec.commonmark.org/0.30/#example-332. 82 | if (!startsWithSpace || !endsWithSpace) { 83 | return false; 84 | } 85 | 86 | return true; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /lib/src/inline_syntaxes/color_swatch_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../charcode.dart'; 7 | import '../inline_parser.dart'; 8 | import '../util.dart'; 9 | import 'inline_syntax.dart'; 10 | 11 | /// Matches code blocks containing a subset of CSS color syntax. 12 | class ColorSwatchSyntax extends InlineSyntax { 13 | /// This pattern matches: 14 | /// * GitHub Flavored Markup supports fewer of these options, GitLab Flavored 15 | /// Markup supports all of these. Presumably GitHub will be more complete at 16 | /// some point. 17 | /// * CSS style '#' prefixed color hex codes in 3,4,6 or 8 digits in length. 18 | /// * CSS style RGB()/RgbA()/Hsl()/HSLA() style color declarations, of any 19 | /// capitalization. 20 | /// EXAMPLES: 21 | /// * `#f00` 22 | /// * `#BA` (2 digit hex, regex will not match) 23 | /// * `#F00a` 24 | /// * `#F0BAD` (5 digit hex, regex will not match) 25 | /// * `#FF0000` 26 | /// * `#F000BAD` (7 digit hex, regex will not match) 27 | /// * `#FF0000aA` (GitHub supports only this style) 28 | /// * `RGB(0,255,0)` 29 | /// * `rgb(0,255,0)` 30 | /// * `RGB(0%,100%,0%)` 31 | /// * `rgb(0%,100%,0%)` 32 | /// * `RGBA(0,255,0,0.3)` 33 | /// * `rgba(0,255,0,0.3)` 34 | /// * `HSL(540,70%,50%)` 35 | /// * `hsl(540,70%,50%)` 36 | /// * `HSLA(540,70%,50%,0.3)` 37 | /// * `Hsla(540,70%,50%,0.3)` 38 | static const _pattern = 39 | '`((#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{4}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{8}))|' 40 | r'([Rr][Gg][Bb][Aa]?\((\d+[%]?),(\d+[%]?),(\d+[%]?),?(\d+\.?\d+[%]?)?\))|' 41 | r'([Hh][Ss][Ll][Aa]?\((\d+[%]?),(\d+[%]?),(\d+[%]?),?(\d+\.?\d+[%]?)?\)))`'; 42 | 43 | ColorSwatchSyntax() : super(_pattern); 44 | 45 | @override 46 | bool tryMatch(InlineParser parser, [int? startMatchPos]) { 47 | if (parser.pos > 0 && parser.charAt(parser.pos - 1) == $backquote) { 48 | // Not really a match! We can't just sneak past one backtick to try the 49 | // next character. An example of this situation would be: 50 | // 51 | // before ``` and `` after. 52 | // ^--parser.pos 53 | return false; 54 | } 55 | 56 | final match = pattern.matchAsPrefix(parser.source, parser.pos); 57 | if (match == null) { 58 | return false; 59 | } 60 | parser.writeText(); 61 | if (onMatch(parser, match)) parser.consume(match.match.length); 62 | return true; 63 | } 64 | 65 | @override 66 | bool onMatch(InlineParser parser, Match match) { 67 | var code = match[1]!.trim().replaceAll('\n', ' '); 68 | 69 | if (parser.encodeHtml) code = escapeHtml(code); 70 | 71 | parser.addNode(Element('code', [ 72 | Text(code), 73 | Element.withTag('span')..attributes['style'] = 'background-color:$code;', 74 | ]) 75 | ..attributes['class'] = 'gfm-color_chip'); 76 | 77 | return true; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /lib/src/inline_syntaxes/decode_html_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../assets/html_entities.dart'; 6 | import '../ast.dart'; 7 | import '../charcode.dart'; 8 | import '../inline_parser.dart'; 9 | import '../patterns.dart'; 10 | import '../util.dart'; 11 | import 'inline_syntax.dart'; 12 | 13 | /// Decodes numeric character references, for example decode `#` to `#`. 14 | // https://spec.commonmark.org/0.30/#entity-and-numeric-character-references 15 | class DecodeHtmlSyntax extends InlineSyntax { 16 | DecodeHtmlSyntax() 17 | : super(htmlCharactersPattern.pattern, 18 | caseSensitive: false, startCharacter: $ampersand); 19 | 20 | @override 21 | bool tryMatch(InlineParser parser, [int? startMatchPos]) { 22 | if (parser.pos > 0 && parser.charAt(parser.pos - 1) == $backquote) { 23 | return false; 24 | } 25 | 26 | final match = pattern.matchAsPrefix(parser.source, parser.pos); 27 | if (match == null) { 28 | return false; 29 | } 30 | 31 | if (match[1] != null && htmlEntitiesMap[match.match] == null) { 32 | return false; 33 | } 34 | 35 | parser.writeText(); 36 | if (onMatch(parser, match)) parser.consume(match.match.length); 37 | return true; 38 | } 39 | 40 | @override 41 | bool onMatch(InlineParser parser, Match match) { 42 | var decodedText = decodeHtmlCharacterFromMatch(match); 43 | 44 | if (parser.encodeHtml) { 45 | decodedText = escapeHtml(decodedText); 46 | } 47 | 48 | parser.addNode(Text(decodedText)); 49 | return true; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/src/inline_syntaxes/email_autolink_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../charcode.dart'; 7 | import '../inline_parser.dart'; 8 | import '../util.dart'; 9 | import 'inline_syntax.dart'; 10 | 11 | /// Matches autolinks like ``. 12 | /// 13 | /// See . 14 | class EmailAutolinkSyntax extends InlineSyntax { 15 | static const _email = 16 | r'''[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}''' 17 | r'''[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*'''; 18 | 19 | EmailAutolinkSyntax() : super('<($_email)>', startCharacter: $lt); 20 | 21 | @override 22 | bool onMatch(InlineParser parser, Match match) { 23 | final url = match[1]!; 24 | final text = parser.encodeHtml ? escapeHtml(url) : url; 25 | final anchor = Element.text('a', text); 26 | anchor.attributes['href'] = Uri.encodeFull('mailto:$url'); 27 | parser.addNode(anchor); 28 | 29 | return true; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/src/inline_syntaxes/emoji_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../emojis.dart'; 7 | import '../inline_parser.dart'; 8 | import 'inline_syntax.dart'; 9 | 10 | /// Matches GitHub Markdown emoji syntax like `:smile:`. 11 | /// 12 | /// There is no formal specification of GitHub's support for this colon-based 13 | /// emoji support, so this syntax is based on the results of Markdown-enabled 14 | /// text fields at github.com. 15 | class EmojiSyntax extends InlineSyntax { 16 | // Emoji "aliases" are mostly limited to lower-case letters, numbers, and 17 | // underscores, but GitHub also supports `:+1:` and `:-1:`. 18 | EmojiSyntax() : super(':([a-z0-9_+-]+):'); 19 | 20 | @override 21 | bool onMatch(InlineParser parser, Match match) { 22 | final alias = match[1]!; 23 | final emoji = emojis[alias]; 24 | if (emoji == null) { 25 | parser.advanceBy(1); 26 | return false; 27 | } 28 | parser.addNode(Text(emoji)); 29 | 30 | return true; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/src/inline_syntaxes/emphasis_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../charcode.dart'; 6 | import 'delimiter_syntax.dart'; 7 | 8 | class EmphasisSyntax extends DelimiterSyntax { 9 | /// Parses `__strong__` and `_emphasis_`. 10 | EmphasisSyntax.underscore() 11 | : super( 12 | '_+', 13 | requiresDelimiterRun: true, 14 | tags: _tags, 15 | startCharacter: $underscore, 16 | ); 17 | 18 | /// Parses `**strong**` and `*emphasis*`. 19 | EmphasisSyntax.asterisk() 20 | : super( 21 | r'\*+', 22 | requiresDelimiterRun: true, 23 | allowIntraWord: true, 24 | tags: _tags, 25 | startCharacter: $asterisk, 26 | ); 27 | 28 | static final _tags = [DelimiterTag('em', 1), DelimiterTag('strong', 2)]; 29 | } 30 | -------------------------------------------------------------------------------- /lib/src/inline_syntaxes/escape_html_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../inline_parser.dart'; 7 | import '../util.dart'; 8 | import 'inline_syntax.dart'; 9 | 10 | /// Encodes (`"`), (`<`), (`>`) and (`&`). 11 | class EscapeHtmlSyntax extends InlineSyntax { 12 | EscapeHtmlSyntax() : super('["<>&]'); 13 | @override 14 | bool onMatch(InlineParser parser, Match match) { 15 | final text = escapeHtml(match[0]!); 16 | parser.addNode(Text(text)); 17 | 18 | return true; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/src/inline_syntaxes/escape_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../charcode.dart'; 7 | import '../inline_parser.dart'; 8 | import '../patterns.dart'; 9 | import '../util.dart'; 10 | import 'inline_syntax.dart'; 11 | 12 | /// Escape ASCII punctuation preceded by a backslash. 13 | /// 14 | /// Backslashes before other characters are treated as literal backslashes. 15 | // See https://spec.commonmark.org/0.30/#backslash-escapes. 16 | class EscapeSyntax extends InlineSyntax { 17 | EscapeSyntax() 18 | : super('\\\\([$asciiPunctuationEscaped])', startCharacter: $backslash); 19 | 20 | @override 21 | bool onMatch(InlineParser parser, Match match) { 22 | final chars = match.match; 23 | 24 | String text; 25 | if ('&"<>'.contains(match[1]!) && parser.encodeHtml) { 26 | text = escapeHtml(match[1]!); 27 | } else { 28 | text = chars[1]; 29 | } 30 | 31 | parser.addNode(Text(text)); 32 | return true; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/src/inline_syntaxes/footnote_ref_syntax.dart: -------------------------------------------------------------------------------- 1 | import '../ast.dart' show Element, Node, Text; 2 | import '../charcode.dart'; 3 | import 'link_syntax.dart' show LinkContext; 4 | 5 | /// The spec of GFM about footnotes is 6 | /// [missing](https://github.com/github/cmark-gfm/issues/283#issuecomment-1378868725). 7 | /// For source code of cmark-gfm, see the `noMatch` label of the 8 | /// `handle_close_bracket` function in [master@c32ef78](https://github.com/github/cmark-gfm/blob/c32ef78/src/inlines.c#L1236). 9 | /// A Rust implementation is also [available](https://github.com/wooorm/markdown-rs/blob/2498e31eecead798efc649502bbf5f86feaa94be/src/construct/gfm_label_start_footnote.rs). 10 | /// Footnotes shares the same syntax with [LinkSyntax], 11 | /// but have a different branch of handling the close bracket. 12 | class FootnoteRefSyntax { 13 | static String? _footnoteLabel(String key) { 14 | if (key.isEmpty || key.codeUnitAt(0) != $caret) { 15 | return null; 16 | } 17 | key = key.substring(1).trim().toLowerCase(); 18 | if (key.isEmpty) { 19 | return null; 20 | } 21 | return key; 22 | } 23 | 24 | static Iterable? tryCreateFootnoteLink( 25 | LinkContext context, 26 | String text, { 27 | bool? secondary, 28 | }) { 29 | secondary ??= false; 30 | final parser = context.parser; 31 | final key = _footnoteLabel(text); 32 | final refs = parser.document.footnoteReferences; 33 | // `label` is what footnoteReferences stored, it is case sensitive. 34 | final label = 35 | refs.keys.firstWhere((k) => k.toLowerCase() == key, orElse: () => ''); 36 | // `count != null` means footnote was valid. 37 | var count = refs[label]; 38 | // And then check if footnote was matched. 39 | if (key == null || count == null) { 40 | return null; 41 | } 42 | final result = []; 43 | // There are 4 cases here: ![^...], [^...], ![...][^...], [...][^...] 44 | if (context.opener.char == $exclamation) { 45 | result.add(Text('!')); 46 | } 47 | refs[label] = ++count; 48 | final labels = parser.document.footnoteLabels; 49 | var pos = labels.indexOf(key); 50 | if (pos < 0) { 51 | pos = labels.length; 52 | labels.add(key); 53 | } 54 | 55 | // `children` are text segments after '[^' before ']'. 56 | final children = context.getChildren(); 57 | if (secondary) { 58 | result.add(Text('[')); 59 | result.addAll(children); 60 | result.add(Text(']')); 61 | } 62 | final id = Uri.encodeComponent(label); 63 | final suffix = count > 1 ? '-$count' : ''; 64 | final link = Element('a', [Text('${pos + 1}')]) 65 | // Ignore GitHub's attribute: . 66 | ..attributes['href'] = '#fn-$id' 67 | ..attributes['id'] = 'fnref-$id$suffix'; 68 | final sup = Element('sup', [link])..attributes['class'] = 'footnote-ref'; 69 | result.add(sup); 70 | return result; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/src/inline_syntaxes/image_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../charcode.dart'; 7 | import '../util.dart'; 8 | import 'link_syntax.dart'; 9 | 10 | /// Matches images like `![alternate text](url "optional title")` and 11 | /// `![alternate text][label]`. 12 | class ImageSyntax extends LinkSyntax { 13 | ImageSyntax({super.linkResolver}) 14 | : super( 15 | pattern: r'!\[', 16 | startCharacter: $exclamation, 17 | ); 18 | 19 | @override 20 | Element createNode( 21 | String destination, 22 | String? title, { 23 | required List Function() getChildren, 24 | }) { 25 | final element = Element.empty('img'); 26 | final children = getChildren(); 27 | element.attributes['src'] = normalizeLinkDestination( 28 | escapePunctuation(destination), 29 | ); 30 | element.attributes['alt'] = children.map((node) { 31 | // See https://spec.commonmark.org/0.30/#image-description. 32 | // An image description may contain links. Fetch text from the alt 33 | // attribute if this nested link is an image. 34 | if (node is Element && node.tag == 'img') { 35 | return node.attributes['alt']; 36 | } 37 | return node.textContent; 38 | }).join(); 39 | if (title != null && title.isNotEmpty) { 40 | element.attributes['title'] = normalizeLinkTitle(title); 41 | } 42 | return element; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/src/inline_syntaxes/inline_html_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../../markdown.dart'; 6 | import '../charcode.dart'; 7 | import '../patterns.dart'; 8 | 9 | /// Leave inline HTML tags alone, from 10 | /// [CommonMark 0.30](https://spec.commonmark.org/0.30/#raw-html). 11 | /// 12 | /// This is not actually a good definition (nor CommonMark's) of an HTML tag, 13 | /// but it is fast. It will leave text like `]+-[^-<>]+)+|[^-<>]+)-->' 26 | '|' 27 | 28 | // Processing-instruction, see 29 | // https://spec.commonmark.org/0.30/#processing-instruction 30 | r'<\?.*?\?>' 31 | '|' 32 | 33 | // Declaration, see 34 | // https://spec.commonmark.org/0.30/#declaration. 35 | '()' 36 | '|' 37 | 38 | // CDATA section, see 39 | // https://spec.commonmark.org/0.30/#cdata-section. 40 | r'()'; 41 | 42 | InlineHtmlSyntax() 43 | : super(_pattern, startCharacter: $lt, caseSensitive: false); 44 | } 45 | -------------------------------------------------------------------------------- /lib/src/inline_syntaxes/inline_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../inline_parser.dart'; 6 | import '../util.dart'; 7 | 8 | /// Represents one kind of Markdown tag that can be parsed. 9 | abstract class InlineSyntax { 10 | final RegExp pattern; 11 | 12 | /// The first character of [pattern], to be used as an efficient first check 13 | /// that this syntax matches the current parser position. 14 | final int? _startCharacter; 15 | 16 | /// Create a new [InlineSyntax] which matches text on [pattern]. 17 | /// 18 | /// If [startCharacter] is passed, it is used as a pre-matching check which 19 | /// is faster than matching against [pattern]. 20 | /// 21 | /// If [caseSensitive] is disabled, then case is ignored when matching 22 | /// the [pattern]. 23 | InlineSyntax(String pattern, {int? startCharacter, bool caseSensitive = true}) 24 | : pattern = 25 | RegExp(pattern, multiLine: true, caseSensitive: caseSensitive), 26 | _startCharacter = startCharacter; 27 | 28 | /// Tries to match at the parser's current position. 29 | /// 30 | /// The parser's position can be overriden with [startMatchPos]. 31 | /// Returns whether or not the pattern successfully matched. 32 | bool tryMatch(InlineParser parser, [int? startMatchPos]) { 33 | startMatchPos ??= parser.pos; 34 | 35 | // Before matching with the regular expression [pattern], which can be 36 | // expensive on some platforms, check if even the first character matches 37 | // this syntax. 38 | if (_startCharacter != null && 39 | parser.source.codeUnitAt(startMatchPos) != _startCharacter) { 40 | return false; 41 | } 42 | 43 | final startMatch = pattern.matchAsPrefix(parser.source, startMatchPos); 44 | if (startMatch == null) return false; 45 | 46 | // Write any existing plain text up to this point. 47 | parser.writeText(); 48 | 49 | if (onMatch(parser, startMatch)) parser.consume(startMatch.match.length); 50 | return true; 51 | } 52 | 53 | /// Processes [match], adding nodes to [parser] and possibly advancing 54 | /// [parser]. 55 | /// 56 | /// Returns whether the caller should advance [parser] by `match[0].length`. 57 | bool onMatch(InlineParser parser, Match match); 58 | } 59 | -------------------------------------------------------------------------------- /lib/src/inline_syntaxes/line_break_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../inline_parser.dart'; 7 | import 'inline_syntax.dart'; 8 | 9 | /// Represents a hard line break. 10 | class LineBreakSyntax extends InlineSyntax { 11 | LineBreakSyntax() : super(r'(?:\\| +)\n'); 12 | 13 | /// Create a void
element. 14 | @override 15 | bool onMatch(InlineParser parser, Match match) { 16 | parser.addNode(Element.empty('br')); 17 | return true; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/src/inline_syntaxes/soft_line_break_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../charcode.dart'; 6 | import '../inline_parser.dart'; 7 | import 'inline_syntax.dart'; 8 | 9 | /// Removes the single space before the line ending. 10 | // https://spec.commonmark.org/0.30/#soft-line-breaks. 11 | // If there are more than one spaces before the line ending, it may hit the hard 12 | // break syntax. 13 | class SoftLineBreakSyntax extends InlineSyntax { 14 | SoftLineBreakSyntax() : super(' \n', startCharacter: $space); 15 | 16 | @override 17 | bool onMatch(InlineParser parser, Match match) { 18 | parser.consume(1); 19 | return false; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/src/inline_syntaxes/strikethrough_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../charcode.dart'; 6 | import 'delimiter_syntax.dart'; 7 | 8 | /// Matches strikethrough syntax according to the GFM spec. 9 | class StrikethroughSyntax extends DelimiterSyntax { 10 | StrikethroughSyntax() 11 | : super( 12 | '~+', 13 | requiresDelimiterRun: true, 14 | allowIntraWord: true, 15 | startCharacter: $tilde, 16 | tags: [DelimiterTag('del', 1), DelimiterTag('del', 2)], 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /lib/src/inline_syntaxes/text_syntax.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import '../ast.dart'; 6 | import '../inline_parser.dart'; 7 | import '../util.dart'; 8 | import 'inline_syntax.dart'; 9 | 10 | /// Matches stuff that should just be passed through as straight text. 11 | class TextSyntax extends InlineSyntax { 12 | final String substitute; 13 | 14 | /// Create a new [TextSyntax] which matches text on [pattern]. 15 | /// 16 | /// If [sub] is passed, it is used as a simple replacement for [pattern]. If 17 | /// [startCharacter] is passed, it is used as a pre-matching check which is 18 | /// faster than matching against [pattern]. 19 | TextSyntax( 20 | super.pattern, { 21 | String sub = '', 22 | super.startCharacter, 23 | super.caseSensitive, 24 | }) : substitute = sub; 25 | 26 | /// Adds a [Text] node to [parser] and returns `true` if there is a 27 | /// [substitute], as long as the preceding character (if any) is not a `/`. 28 | /// 29 | /// Otherwise, the parser is advanced by the length of [match] and `false` is 30 | /// returned. 31 | @override 32 | bool onMatch(InlineParser parser, Match match) { 33 | if (substitute.isEmpty || 34 | (match.start > 0 && 35 | match.input.substring(match.start - 1, match.start) == '/')) { 36 | // Just use the original matched text. 37 | parser.advanceBy(match.match.length); 38 | return false; 39 | } 40 | 41 | // Insert the substitution. 42 | parser.addNode(Text(substitute)); 43 | return true; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/src/line.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import 'patterns.dart'; 6 | 7 | /// A [Line] is a sequence of zero or more characters other than line feed 8 | /// (`U+000A`) or carriage return (`U+000D`), followed by a line ending or by 9 | /// the end of file. 10 | // See https://spec.commonmark.org/0.30/#line. 11 | class Line { 12 | /// A sequence of zero or more characters other than the line ending. 13 | final String content; 14 | 15 | /// How many spaces of a tab that remains after part of it has been consumed. 16 | // See: https://spec.commonmark.org/0.30/#example-6 17 | // We cannot simply expand the `tabRemaining` to spaces, for example 18 | // 19 | // `>\t\tfoo` 20 | // 21 | // If we expand the 2 space width `tabRemaining` from blockquote block into 2 22 | // spaces, so the string segment for the indented code block is: 23 | // 24 | // ` \tfoo`, 25 | // 26 | // then the output will be: 27 | // ```html 28 | //
foo
29 |   // 
30 | // ``` 31 | // instead of the expected: 32 | // ```html 33 | //
  foo
34 |   // 
35 | // ``` 36 | final int? tabRemaining; 37 | 38 | // A line containing no characters, or a line containing only spaces 39 | // (`U+0020`) or tabs (`U+0009`), is called a blank line. 40 | // https://spec.commonmark.org/0.30/#blank-line 41 | final bool isBlankLine; 42 | 43 | Line( 44 | this.content, { 45 | this.tabRemaining, 46 | }) : isBlankLine = emptyPattern.hasMatch(content); 47 | } 48 | -------------------------------------------------------------------------------- /lib/src/text_parser.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | import 'charcode.dart'; 5 | 6 | /// A parser to parse a segment of source text. 7 | class TextParser { 8 | final String source; 9 | 10 | TextParser(this.source); 11 | 12 | /// The current read position. 13 | var _position = 0; 14 | int get pos => _position; 15 | 16 | /// Whether the read position has reached the end of [source]. 17 | bool get isDone => _position == length; 18 | 19 | /// The length of [source]. 20 | int get length => source.length; 21 | 22 | /// Walk the parser forward through any whitespace. 23 | /// 24 | /// Set [multiLine] `true` to support multiline, otherwise it will stop before 25 | /// the line feed [$lf]. 26 | int moveThroughWhitespace({bool multiLine = false}) { 27 | var i = 0; 28 | while (!isDone) { 29 | final char = charAt(); 30 | if (char != $space && 31 | char != $tab && 32 | char != $vt && 33 | char != $cr && 34 | char != $ff && 35 | !(multiLine && char == $lf)) { 36 | return i; 37 | } 38 | 39 | i++; 40 | advance(); 41 | } 42 | return i; 43 | } 44 | 45 | int charAt([int? position]) => source.codeUnitAt(position ?? _position); 46 | 47 | /// Moves the read position one character ahead. 48 | void advance() => advanceBy(1); 49 | 50 | /// Moves the read position for [length] characters. [length] can be negative. 51 | void advanceBy(int length) { 52 | _position += length; 53 | } 54 | 55 | /// Substrings the [source] and returns a [String]. 56 | String substring(int start, [int? end]) => source.substring(start, end); 57 | } 58 | -------------------------------------------------------------------------------- /lib/src/version.dart: -------------------------------------------------------------------------------- 1 | // Generated code. Do not modify. 2 | const packageVersion = '7.2.3'; 3 | -------------------------------------------------------------------------------- /peanut.yaml: -------------------------------------------------------------------------------- 1 | # Configuration for https://pub.dev/packages/peanut 2 | directories: 3 | - example 4 | 5 | builder-options: 6 | build_web_compilers|dart2js_archive_extractor: 7 | # Ensures --dump-info .dart.js.info.json file is preserved. 8 | # Useful to track compiled size change 9 | filter_outputs: false 10 | build_web_compilers|entrypoint: 11 | dart2js_args: 12 | - --dump-info 13 | - --minify 14 | - --no-frequency-based-minification 15 | - --no-source-maps 16 | - -O4 17 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: markdown 2 | version: 7.2.3 3 | description: >- 4 | A portable Markdown library written in Dart that can parse Markdown into HTML. 5 | repository: https://github.com/dart-lang/markdown 6 | 7 | topics: 8 | - markdown 9 | 10 | executables: 11 | markdown: 12 | 13 | environment: 14 | sdk: ^3.2.0 15 | 16 | dependencies: 17 | args: ^2.0.0 18 | meta: ^1.3.0 19 | 20 | dev_dependencies: 21 | build_runner: ^2.0.5 22 | build_version: ^2.0.3 23 | build_web_compilers: ^4.0.0 24 | collection: ^1.15.0 25 | dart_flutter_team_lints: ^3.0.0 26 | html: ^0.15.0 27 | http: ^1.0.0 28 | io: ^1.0.0 29 | path: ^1.8.0 30 | pool: ^1.5.1 31 | tar: ^1.0.3 32 | test: ^1.16.0 33 | web: '>=0.4.2 <2.0.0' 34 | yaml: ^3.0.0 35 | -------------------------------------------------------------------------------- /test/blns_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import 'package:markdown/markdown.dart'; 6 | import 'package:test/test.dart'; 7 | 8 | import 'blns.dart'; 9 | 10 | // The BLNS tests merely test that `markdownToHtml` does not throw or hang while 11 | // processing "naughty string" inputs. While there are examples of multi-byte 12 | // characters, non-visible characters, etc., these tests should not be _relied 13 | // upon_ for testing multi-byte character support, etc. 14 | void main() { 15 | test('parsing blns', () { 16 | // This is more a test of update_blns.dart: we're testing that the strings 17 | // were encoded half-decently, and nothing got globbed up into a big 18 | // multiline string. 19 | expect(blns, hasLength(515)); 20 | }); 21 | 22 | var index = 0; 23 | for (final str in blns) { 24 | test('blns string $index', () { 25 | final result = markdownToHtml(str); 26 | expect(result, const TypeMatcher()); 27 | }); 28 | index++; 29 | } 30 | 31 | index = 0; 32 | for (final str in blns) { 33 | test('blns string $index w/ gitHubWeb', () { 34 | final result = markdownToHtml(str, extensionSet: ExtensionSet.gitHubWeb); 35 | expect(result, const TypeMatcher()); 36 | }); 37 | index++; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/common_mark/atx_headings.unit: -------------------------------------------------------------------------------- 1 | >>> ATX headings - 62 2 | # foo 3 | ## foo 4 | ### foo 5 | #### foo 6 | ##### foo 7 | ###### foo 8 | <<< 9 |

foo

10 |

foo

11 |

foo

12 |

foo

13 |
foo
14 |
foo
15 | >>> ATX headings - 63 16 | ####### foo 17 | <<< 18 |

####### foo

19 | >>> ATX headings - 64 20 | #5 bolt 21 | 22 | #hashtag 23 | <<< 24 |

#5 bolt

25 |

#hashtag

26 | >>> ATX headings - 65 27 | \## foo 28 | <<< 29 |

## foo

30 | >>> ATX headings - 66 31 | # foo *bar* \*baz\* 32 | <<< 33 |

foo bar *baz*

34 | >>> ATX headings - 67 35 | # foo 36 | <<< 37 |

foo

38 | >>> ATX headings - 68 39 | ### foo 40 | ## foo 41 | # foo 42 | <<< 43 |

foo

44 |

foo

45 |

foo

46 | >>> ATX headings - 69 47 | # foo 48 | <<< 49 |
# foo
 50 | 
51 | >>> ATX headings - 70 52 | foo 53 | # bar 54 | <<< 55 |

foo 56 | # bar

57 | >>> ATX headings - 71 58 | ## foo ## 59 | ### bar ### 60 | <<< 61 |

foo

62 |

bar

63 | >>> ATX headings - 72 64 | # foo ################################## 65 | ##### foo ## 66 | <<< 67 |

foo

68 |
foo
69 | >>> ATX headings - 73 70 | ### foo ### 71 | <<< 72 |

foo

73 | >>> ATX headings - 74 74 | ### foo ### b 75 | <<< 76 |

foo ### b

77 | >>> ATX headings - 75 78 | # foo# 79 | <<< 80 |

foo#

81 | >>> ATX headings - 76 82 | ### foo \### 83 | ## foo #\## 84 | # foo \# 85 | <<< 86 |

foo ###

87 |

foo ###

88 |

foo #

89 | >>> ATX headings - 77 90 | **** 91 | ## foo 92 | **** 93 | <<< 94 |
95 |

foo

96 |
97 | >>> ATX headings - 78 98 | Foo bar 99 | # baz 100 | Bar foo 101 | <<< 102 |

Foo bar

103 |

baz

104 |

Bar foo

105 | >>> ATX headings - 79 106 | ## 107 | # 108 | ### ### 109 | <<< 110 |

111 |

112 |

113 | -------------------------------------------------------------------------------- /test/common_mark/autolinks.unit: -------------------------------------------------------------------------------- 1 | >>> Autolinks - 594 2 | 3 | <<< 4 |

http://foo.bar.baz

5 | >>> Autolinks - 595 6 | 7 | <<< 8 |

https://foo.bar.baz/test?q=hello&id=22&boolean

9 | >>> Autolinks - 596 10 | 11 | <<< 12 |

irc://foo.bar:2233/baz

13 | >>> Autolinks - 597 14 | 15 | <<< 16 |

MAILTO:FOO@BAR.BAZ

17 | >>> Autolinks - 598 18 | 19 | <<< 20 |

a+b+c:d

21 | >>> Autolinks - 599 22 | 23 | <<< 24 |

made-up-scheme://foo,bar

25 | >>> Autolinks - 600 26 | 27 | <<< 28 |

https://../

29 | >>> Autolinks - 601 30 | 31 | <<< 32 |

localhost:5001/foo

33 | >>> Autolinks - 602 34 | 35 | <<< 36 |

<https://foo.bar/baz bim>

37 | >>> Autolinks - 603 38 | 39 | <<< 40 |

https://example.com/\[\

41 | >>> Autolinks - 604 42 | 43 | <<< 44 |

foo@bar.example.com

45 | >>> Autolinks - 605 46 | 47 | <<< 48 |

foo+special@Bar.baz-bar0.com

49 | >>> Autolinks - 606 50 | 51 | <<< 52 |

<foo+@bar.example.com>

53 | >>> Autolinks - 607 54 | <> 55 | <<< 56 |

<>

57 | >>> Autolinks - 608 58 | < https://foo.bar > 59 | <<< 60 |

< https://foo.bar >

61 | >>> Autolinks - 609 62 | 63 | <<< 64 |

<m:abc>

65 | >>> Autolinks - 610 66 | 67 | <<< 68 |

<foo.bar.baz>

69 | >>> Autolinks - 611 70 | https://example.com 71 | <<< 72 |

https://example.com

73 | >>> Autolinks - 612 74 | foo@bar.example.com 75 | <<< 76 |

foo@bar.example.com

77 | -------------------------------------------------------------------------------- /test/common_mark/backslash_escapes.unit: -------------------------------------------------------------------------------- 1 | >>> Backslash escapes - 12 2 | \!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~ 3 | <<< 4 |

!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

5 | >>> Backslash escapes - 13 6 | \ \A\a\ \3\φ\« 7 | <<< 8 |

\ \A\a\ \3\φ\«

9 | >>> Backslash escapes - 14 10 | \*not emphasized* 11 | \
not a tag 12 | \[not a link](/foo) 13 | \`not code` 14 | 1\. not a list 15 | \* not a list 16 | \# not a heading 17 | \[foo]: /url "not a reference" 18 | \ö not a character entity 19 | <<< 20 |

*not emphasized* 21 | <br/> not a tag 22 | [not a link](/foo) 23 | `not code` 24 | 1. not a list 25 | * not a list 26 | # not a heading 27 | [foo]: /url "not a reference" 28 | &ouml; not a character entity

29 | >>> Backslash escapes - 15 30 | \\*emphasis* 31 | <<< 32 |

\emphasis

33 | >>> Backslash escapes - 16 34 | foo\ 35 | bar 36 | <<< 37 |

foo
38 | bar

39 | >>> Backslash escapes - 17 40 | `` \[\` `` 41 | <<< 42 |

\[\`

43 | >>> Backslash escapes - 18 44 | \[\] 45 | <<< 46 |
\[\]
47 | 
48 | >>> Backslash escapes - 19 49 | ~~~ 50 | \[\] 51 | ~~~ 52 | <<< 53 |
\[\]
54 | 
55 | >>> Backslash escapes - 20 56 | 57 | <<< 58 |

https://example.com?find=\*

59 | >>> Backslash escapes - 21 60 | 61 | <<< 62 | 63 | >>> Backslash escapes - 22 64 | [foo](/bar\* "ti\*tle") 65 | <<< 66 |

foo

67 | >>> Backslash escapes - 23 68 | [foo] 69 | 70 | [foo]: /bar\* "ti\*tle" 71 | <<< 72 |

foo

73 | >>> Backslash escapes - 24 74 | ``` foo\+bar 75 | foo 76 | ``` 77 | <<< 78 |
foo
79 | 
80 | -------------------------------------------------------------------------------- /test/common_mark/blank_lines.unit: -------------------------------------------------------------------------------- 1 | >>> Blank lines - 227 2 | 3 | 4 | aaa 5 | 6 | 7 | # aaa 8 | 9 | 10 | <<< 11 |

aaa

12 |

aaa

13 | -------------------------------------------------------------------------------- /test/common_mark/block_quotes.unit: -------------------------------------------------------------------------------- 1 | >>> Block quotes - 228 2 | > # Foo 3 | > bar 4 | > baz 5 | <<< 6 |
7 |

Foo

8 |

bar 9 | baz

10 |
11 | >>> Block quotes - 229 12 | ># Foo 13 | >bar 14 | > baz 15 | <<< 16 |
17 |

Foo

18 |

bar 19 | baz

20 |
21 | >>> Block quotes - 230 22 | > # Foo 23 | > bar 24 | > baz 25 | <<< 26 |
27 |

Foo

28 |

bar 29 | baz

30 |
31 | >>> Block quotes - 231 32 | > # Foo 33 | > bar 34 | > baz 35 | <<< 36 |
> # Foo
 37 | > bar
 38 | > baz
 39 | 
40 | >>> Block quotes - 232 41 | > # Foo 42 | > bar 43 | baz 44 | <<< 45 |
46 |

Foo

47 |

bar 48 | baz

49 |
50 | >>> Block quotes - 233 51 | > bar 52 | baz 53 | > foo 54 | <<< 55 |
56 |

bar 57 | baz 58 | foo

59 |
60 | >>> Block quotes - 234 61 | > foo 62 | --- 63 | <<< 64 |
65 |

foo

66 |
67 |
68 | >>> Block quotes - 235 69 | > - foo 70 | - bar 71 | <<< 72 |
73 |
    74 |
  • foo
  • 75 |
76 |
77 |
    78 |
  • bar
  • 79 |
80 | >>> Block quotes - 236 81 | > foo 82 | bar 83 | <<< 84 |
85 |
foo
 86 | 
87 |
88 |
bar
 89 | 
90 | >>> Block quotes - 237 91 | > ``` 92 | foo 93 | ``` 94 | <<< 95 |
96 |
97 |
98 |

foo

99 |
100 | >>> Block quotes - 238 101 | > foo 102 | - bar 103 | <<< 104 |
105 |

foo 106 | - bar

107 |
108 | >>> Block quotes - 239 109 | > 110 | <<< 111 |
112 |
113 | >>> Block quotes - 240 114 | > 115 | > 116 | > 117 | <<< 118 |
119 |
120 | >>> Block quotes - 241 121 | > 122 | > foo 123 | > 124 | <<< 125 |
126 |

foo

127 |
128 | >>> Block quotes - 242 129 | > foo 130 | 131 | > bar 132 | <<< 133 |
134 |

foo

135 |
136 |
137 |

bar

138 |
139 | >>> Block quotes - 243 140 | > foo 141 | > bar 142 | <<< 143 |
144 |

foo 145 | bar

146 |
147 | >>> Block quotes - 244 148 | > foo 149 | > 150 | > bar 151 | <<< 152 |
153 |

foo

154 |

bar

155 |
156 | >>> Block quotes - 245 157 | foo 158 | > bar 159 | <<< 160 |

foo

161 |
162 |

bar

163 |
164 | >>> Block quotes - 246 165 | > aaa 166 | *** 167 | > bbb 168 | <<< 169 |
170 |

aaa

171 |
172 |
173 |
174 |

bbb

175 |
176 | >>> Block quotes - 247 177 | > bar 178 | baz 179 | <<< 180 |
181 |

bar 182 | baz

183 |
184 | >>> Block quotes - 248 185 | > bar 186 | 187 | baz 188 | <<< 189 |
190 |

bar

191 |
192 |

baz

193 | >>> Block quotes - 249 194 | > bar 195 | > 196 | baz 197 | <<< 198 |
199 |

bar

200 |
201 |

baz

202 | >>> Block quotes - 250 203 | > > > foo 204 | bar 205 | <<< 206 |
207 |
208 |
209 |

foo 210 | bar

211 |
212 |
213 |
214 | >>> Block quotes - 251 215 | >>> foo 216 | > bar 217 | >>baz 218 | <<< 219 |
220 |
221 |
222 |

foo 223 | bar 224 | baz

225 |
226 |
227 |
228 | >>> Block quotes - 252 229 | > code 230 | 231 | > not code 232 | <<< 233 |
234 |
code
235 | 
236 |
237 |
238 |

not code

239 |
240 | -------------------------------------------------------------------------------- /test/common_mark/code_spans.unit: -------------------------------------------------------------------------------- 1 | >>> Code spans - 328 2 | `foo` 3 | <<< 4 |

foo

5 | >>> Code spans - 329 6 | `` foo ` bar `` 7 | <<< 8 |

foo ` bar

9 | >>> Code spans - 330 10 | ` `` ` 11 | <<< 12 |

``

13 | >>> Code spans - 331 14 | ` `` ` 15 | <<< 16 |

``

17 | >>> Code spans - 332 18 | ` a` 19 | <<< 20 |

a

21 | >>> Code spans - 333 22 | ` b ` 23 | <<< 24 |

 b 

25 | >>> Code spans - 334 26 | ` ` 27 | ` ` 28 | <<< 29 |

  30 |

31 | >>> Code spans - 335 32 | `` 33 | foo 34 | bar 35 | baz 36 | `` 37 | <<< 38 |

foo bar baz

39 | >>> Code spans - 336 40 | `` 41 | foo 42 | `` 43 | <<< 44 |

foo

45 | >>> Code spans - 337 46 | `foo bar 47 | baz` 48 | <<< 49 |

foo bar baz

50 | >>> Code spans - 338 51 | `foo\`bar` 52 | <<< 53 |

foo\bar`

54 | >>> Code spans - 339 55 | ``foo`bar`` 56 | <<< 57 |

foo`bar

58 | >>> Code spans - 340 59 | ` foo `` bar ` 60 | <<< 61 |

foo `` bar

62 | >>> Code spans - 341 63 | *foo`*` 64 | <<< 65 |

*foo*

66 | >>> Code spans - 342 67 | [not a `link](/foo`) 68 | <<< 69 |

[not a link](/foo)

70 | >>> Code spans - 343 71 | `` 72 | <<< 73 |

<a href="">`

74 | >>> Code spans - 344 75 |
` 76 | <<< 77 |

`

78 | >>> Code spans - 345 79 | `` 80 | <<< 81 |

<https://foo.bar.baz>`

82 | >>> Code spans - 346 83 | ` 84 | <<< 85 |

https://foo.bar.`baz`

86 | >>> Code spans - 347 87 | ```foo`` 88 | <<< 89 |

```foo``

90 | >>> Code spans - 348 91 | `foo 92 | <<< 93 |

`foo

94 | >>> Code spans - 349 95 | `foo``bar`` 96 | <<< 97 |

`foobar

98 | -------------------------------------------------------------------------------- /test/common_mark/entity_and_numeric_character_references.unit: -------------------------------------------------------------------------------- 1 | >>> Entity and numeric character references - 25 2 |   & © Æ Ď 3 | ¾ ℋ ⅆ 4 | ∲ ≧̸ 5 | <<< 6 |

& © Æ Ď 7 | ¾ ℋ ⅆ 8 | ∲ ≧̸

9 | >>> Entity and numeric character references - 26 10 | # Ӓ Ϡ � 11 | <<< 12 |

# Ӓ Ϡ �

13 | >>> Entity and numeric character references - 27 14 | " ആ ಫ 15 | <<< 16 |

" ആ ಫ

17 | >>> Entity and numeric character references - 28 18 |   &x; &#; &#x; 19 | � 20 | &#abcdef0; 21 | &ThisIsNotDefined; &hi?; 22 | <<< 23 |

&nbsp &x; &#; &#x; 24 | &#87654321; 25 | &#abcdef0; 26 | &ThisIsNotDefined; &hi?;

27 | >>> Entity and numeric character references - 29 28 | © 29 | <<< 30 |

&copy

31 | >>> Entity and numeric character references - 30 32 | &MadeUpEntity; 33 | <<< 34 |

&MadeUpEntity;

35 | >>> Entity and numeric character references - 31 36 | 37 | <<< 38 | 39 | >>> Entity and numeric character references - 32 40 | [foo](/föö "föö") 41 | <<< 42 |

foo

43 | >>> Entity and numeric character references - 33 44 | [foo] 45 | 46 | [foo]: /föö "föö" 47 | <<< 48 |

foo

49 | >>> Entity and numeric character references - 34 50 | ``` föö 51 | foo 52 | ``` 53 | <<< 54 |
foo
55 | 
56 | >>> Entity and numeric character references - 35 57 | `föö` 58 | <<< 59 |

f&ouml;&ouml;

60 | >>> Entity and numeric character references - 36 61 | föfö 62 | <<< 63 |
f&ouml;f&ouml;
64 | 
65 | >>> Entity and numeric character references - 37 66 | *foo* 67 | *foo* 68 | <<< 69 |

*foo* 70 | foo

71 | >>> Entity and numeric character references - 38 72 | * foo 73 | 74 | * foo 75 | <<< 76 |

* foo

77 |
    78 |
  • foo
  • 79 |
80 | >>> Entity and numeric character references - 39 81 | foo bar 82 | <<< 83 |

foo 84 | 85 | bar

86 | >>> Entity and numeric character references - 40 87 | foo 88 | <<< 89 |

foo

90 | >>> Entity and numeric character references - 41 91 | [a](url "tit") 92 | <<< 93 |

[a](url "tit")

94 | -------------------------------------------------------------------------------- /test/common_mark/fenced_code_blocks.unit: -------------------------------------------------------------------------------- 1 | >>> Fenced code blocks - 119 2 | ``` 3 | < 4 | > 5 | ``` 6 | <<< 7 |
<
  8 |  >
  9 | 
10 | >>> Fenced code blocks - 120 11 | ~~~ 12 | < 13 | > 14 | ~~~ 15 | <<< 16 |
<
 17 |  >
 18 | 
19 | >>> Fenced code blocks - 121 20 | `` 21 | foo 22 | `` 23 | <<< 24 |

foo

25 | >>> Fenced code blocks - 122 26 | ``` 27 | aaa 28 | ~~~ 29 | ``` 30 | <<< 31 |
aaa
 32 | ~~~
 33 | 
34 | >>> Fenced code blocks - 123 35 | ~~~ 36 | aaa 37 | ``` 38 | ~~~ 39 | <<< 40 |
aaa
 41 | ```
 42 | 
43 | >>> Fenced code blocks - 124 44 | ```` 45 | aaa 46 | ``` 47 | `````` 48 | <<< 49 |
aaa
 50 | ```
 51 | 
52 | >>> Fenced code blocks - 125 53 | ~~~~ 54 | aaa 55 | ~~~ 56 | ~~~~ 57 | <<< 58 |
aaa
 59 | ~~~
 60 | 
61 | >>> Fenced code blocks - 126 62 | ``` 63 | <<< 64 |
65 | >>> Fenced code blocks - 127 66 | ````` 67 | 68 | ``` 69 | aaa 70 | <<< 71 |

 72 | ```
 73 | aaa
 74 | 
75 | >>> Fenced code blocks - 128 76 | > ``` 77 | > aaa 78 | 79 | bbb 80 | <<< 81 |
82 |
aaa
 83 | 
84 |
85 |

bbb

86 | >>> Fenced code blocks - 129 87 | ``` 88 | 89 | 90 | ``` 91 | <<< 92 |

 93 |   
 94 | 
95 | >>> Fenced code blocks - 130 96 | ``` 97 | ``` 98 | <<< 99 |
100 | >>> Fenced code blocks - 131 101 | ``` 102 | aaa 103 | aaa 104 | ``` 105 | <<< 106 |
aaa
107 | aaa
108 | 
109 | >>> Fenced code blocks - 132 110 | ``` 111 | aaa 112 | aaa 113 | aaa 114 | ``` 115 | <<< 116 |
aaa
117 | aaa
118 | aaa
119 | 
120 | >>> Fenced code blocks - 133 121 | ``` 122 | aaa 123 | aaa 124 | aaa 125 | ``` 126 | <<< 127 |
aaa
128 |  aaa
129 | aaa
130 | 
131 | >>> Fenced code blocks - 134 132 | ``` 133 | aaa 134 | ``` 135 | <<< 136 |
```
137 | aaa
138 | ```
139 | 
140 | >>> Fenced code blocks - 135 141 | ``` 142 | aaa 143 | ``` 144 | <<< 145 |
aaa
146 | 
147 | >>> Fenced code blocks - 136 148 | ``` 149 | aaa 150 | ``` 151 | <<< 152 |
aaa
153 | 
154 | >>> Fenced code blocks - 137 155 | ``` 156 | aaa 157 | ``` 158 | <<< 159 |
aaa
160 |     ```
161 | 
162 | >>> Fenced code blocks - 138 163 | ``` ``` 164 | aaa 165 | <<< 166 |

167 | aaa

168 | >>> Fenced code blocks - 139 169 | ~~~~~~ 170 | aaa 171 | ~~~ ~~ 172 | <<< 173 |
aaa
174 | ~~~ ~~
175 | 
176 | >>> Fenced code blocks - 140 177 | foo 178 | ``` 179 | bar 180 | ``` 181 | baz 182 | <<< 183 |

foo

184 |
bar
185 | 
186 |

baz

187 | >>> Fenced code blocks - 141 188 | foo 189 | --- 190 | ~~~ 191 | bar 192 | ~~~ 193 | # baz 194 | <<< 195 |

foo

196 |
bar
197 | 
198 |

baz

199 | >>> Fenced code blocks - 142 200 | ```ruby 201 | def foo(x) 202 | return 3 203 | end 204 | ``` 205 | <<< 206 |
def foo(x)
207 |   return 3
208 | end
209 | 
210 | >>> Fenced code blocks - 143 211 | ~~~~ ruby startline=3 $%@#$ 212 | def foo(x) 213 | return 3 214 | end 215 | ~~~~~~~ 216 | <<< 217 |
def foo(x)
218 |   return 3
219 | end
220 | 
221 | >>> Fenced code blocks - 144 222 | ````; 223 | ```` 224 | <<< 225 |
226 | >>> Fenced code blocks - 145 227 | ``` aa ``` 228 | foo 229 | <<< 230 |

aa 231 | foo

232 | >>> Fenced code blocks - 146 233 | ~~~ aa ``` ~~~ 234 | foo 235 | ~~~ 236 | <<< 237 |
foo
238 | 
239 | >>> Fenced code blocks - 147 240 | ``` 241 | ``` aaa 242 | ``` 243 | <<< 244 |
``` aaa
245 | 
246 | -------------------------------------------------------------------------------- /test/common_mark/hard_line_breaks.unit: -------------------------------------------------------------------------------- 1 | >>> Hard line breaks - 633 2 | foo 3 | baz 4 | <<< 5 |

foo
6 | baz

7 | >>> Hard line breaks - 634 8 | foo\ 9 | baz 10 | <<< 11 |

foo
12 | baz

13 | >>> Hard line breaks - 635 14 | foo 15 | baz 16 | <<< 17 |

foo
18 | baz

19 | >>> Hard line breaks - 636 20 | foo 21 | bar 22 | <<< 23 |

foo
24 | bar

25 | >>> Hard line breaks - 637 26 | foo\ 27 | bar 28 | <<< 29 |

foo
30 | bar

31 | >>> Hard line breaks - 638 32 | *foo 33 | bar* 34 | <<< 35 |

foo
36 | bar

37 | >>> Hard line breaks - 639 38 | *foo\ 39 | bar* 40 | <<< 41 |

foo
42 | bar

43 | >>> Hard line breaks - 640 44 | `code 45 | span` 46 | <<< 47 |

code span

48 | >>> Hard line breaks - 641 49 | `code\ 50 | span` 51 | <<< 52 |

code\ span

53 | >>> Hard line breaks - 642 54 | 56 | <<< 57 |

59 | >>> Hard line breaks - 643 60 | 62 | <<< 63 |

65 | >>> Hard line breaks - 644 66 | foo\ 67 | <<< 68 |

foo\

69 | >>> Hard line breaks - 645 70 | foo 71 | <<< 72 |

foo

73 | >>> Hard line breaks - 646 74 | ### foo\ 75 | <<< 76 |

foo\

77 | >>> Hard line breaks - 647 78 | ### foo 79 | <<< 80 |

foo

81 | -------------------------------------------------------------------------------- /test/common_mark/images.unit: -------------------------------------------------------------------------------- 1 | >>> Images - 572 2 | ![foo](/url "title") 3 | <<< 4 |

foo

5 | >>> Images - 573 6 | ![foo *bar*] 7 | 8 | [foo *bar*]: train.jpg "train & tracks" 9 | <<< 10 |

foo bar

11 | >>> Images - 574 12 | ![foo ![bar](/url)](/url2) 13 | <<< 14 |

foo bar

15 | >>> Images - 575 16 | ![foo [bar](/url)](/url2) 17 | <<< 18 |

foo bar

19 | >>> Images - 576 20 | ![foo *bar*][] 21 | 22 | [foo *bar*]: train.jpg "train & tracks" 23 | <<< 24 |

foo bar

25 | >>> Images - 577 26 | ![foo *bar*][foobar] 27 | 28 | [FOOBAR]: train.jpg "train & tracks" 29 | <<< 30 |

foo bar

31 | >>> Images - 578 32 | ![foo](train.jpg) 33 | <<< 34 |

foo

35 | >>> Images - 579 36 | My ![foo bar](/path/to/train.jpg "title" ) 37 | <<< 38 |

My foo bar

39 | >>> Images - 580 40 | ![foo]() 41 | <<< 42 |

foo

43 | >>> Images - 581 44 | ![](/url) 45 | <<< 46 |

47 | >>> Images - 582 48 | ![foo][bar] 49 | 50 | [bar]: /url 51 | <<< 52 |

foo

53 | >>> Images - 583 54 | ![foo][bar] 55 | 56 | [BAR]: /url 57 | <<< 58 |

foo

59 | >>> Images - 584 60 | ![foo][] 61 | 62 | [foo]: /url "title" 63 | <<< 64 |

foo

65 | >>> Images - 585 66 | ![*foo* bar][] 67 | 68 | [*foo* bar]: /url "title" 69 | <<< 70 |

foo bar

71 | >>> Images - 586 72 | ![Foo][] 73 | 74 | [foo]: /url "title" 75 | <<< 76 |

Foo

77 | >>> Images - 587 78 | ![foo] 79 | [] 80 | 81 | [foo]: /url "title" 82 | <<< 83 |

foo 84 | []

85 | >>> Images - 588 86 | ![foo] 87 | 88 | [foo]: /url "title" 89 | <<< 90 |

foo

91 | >>> Images - 589 92 | ![*foo* bar] 93 | 94 | [*foo* bar]: /url "title" 95 | <<< 96 |

foo bar

97 | >>> Images - 590 98 | ![[foo]] 99 | 100 | [[foo]]: /url "title" 101 | <<< 102 |

![[foo]]

103 |

[[foo]]: /url "title"

104 | >>> Images - 591 105 | ![Foo] 106 | 107 | [foo]: /url "title" 108 | <<< 109 |

Foo

110 | >>> Images - 592 111 | !\[foo] 112 | 113 | [foo]: /url "title" 114 | <<< 115 |

![foo]

116 | >>> Images - 593 117 | \![foo] 118 | 119 | [foo]: /url "title" 120 | <<< 121 |

!foo

122 | -------------------------------------------------------------------------------- /test/common_mark/indented_code_blocks.unit: -------------------------------------------------------------------------------- 1 | >>> Indented code blocks - 107 2 | a simple 3 | indented code block 4 | <<< 5 |
a simple
  6 |   indented code block
  7 | 
8 | >>> Indented code blocks - 108 9 | - foo 10 | 11 | bar 12 | <<< 13 |
    14 |
  • 15 |

    foo

    16 |

    bar

    17 |
  • 18 |
19 | >>> Indented code blocks - 109 20 | 1. foo 21 | 22 | - bar 23 | <<< 24 |
    25 |
  1. 26 |

    foo

    27 |
      28 |
    • bar
    • 29 |
    30 |
  2. 31 |
32 | >>> Indented code blocks - 110 33 | 34 | *hi* 35 | 36 | - one 37 | <<< 38 |
<a/>
 39 | *hi*
 40 | 
 41 | - one
 42 | 
43 | >>> Indented code blocks - 111 44 | chunk1 45 | 46 | chunk2 47 | 48 | 49 | 50 | chunk3 51 | <<< 52 |
chunk1
 53 | 
 54 | chunk2
 55 | 
 56 | 
 57 | 
 58 | chunk3
 59 | 
60 | >>> Indented code blocks - 112 61 | chunk1 62 | 63 | chunk2 64 | <<< 65 |
chunk1
 66 |   
 67 |   chunk2
 68 | 
69 | >>> Indented code blocks - 113 70 | Foo 71 | bar 72 | 73 | <<< 74 |

Foo 75 | bar

76 | >>> Indented code blocks - 114 77 | foo 78 | bar 79 | <<< 80 |
foo
 81 | 
82 |

bar

83 | >>> Indented code blocks - 115 84 | # Heading 85 | foo 86 | Heading 87 | ------ 88 | foo 89 | ---- 90 | <<< 91 |

Heading

92 |
foo
 93 | 
94 |

Heading

95 |
foo
 96 | 
97 |
98 | >>> Indented code blocks - 116 99 | foo 100 | bar 101 | <<< 102 |
    foo
103 | bar
104 | 
105 | >>> Indented code blocks - 117 106 | 107 | 108 | foo 109 | 110 | 111 | <<< 112 |
foo
113 | 
114 | >>> Indented code blocks - 118 115 | foo 116 | <<< 117 |
foo  
118 | 
119 | -------------------------------------------------------------------------------- /test/common_mark/inlines.unit: -------------------------------------------------------------------------------- 1 | >>> Inlines - 327 2 | `hi`lo` 3 | <<< 4 |

hilo`

5 | -------------------------------------------------------------------------------- /test/common_mark/paragraphs.unit: -------------------------------------------------------------------------------- 1 | >>> Paragraphs - 219 2 | aaa 3 | 4 | bbb 5 | <<< 6 |

aaa

7 |

bbb

8 | >>> Paragraphs - 220 9 | aaa 10 | bbb 11 | 12 | ccc 13 | ddd 14 | <<< 15 |

aaa 16 | bbb

17 |

ccc 18 | ddd

19 | >>> Paragraphs - 221 20 | aaa 21 | 22 | 23 | bbb 24 | <<< 25 |

aaa

26 |

bbb

27 | >>> Paragraphs - 222 28 | aaa 29 | bbb 30 | <<< 31 |

aaa 32 | bbb

33 | >>> Paragraphs - 223 34 | aaa 35 | bbb 36 | ccc 37 | <<< 38 |

aaa 39 | bbb 40 | ccc

41 | >>> Paragraphs - 224 42 | aaa 43 | bbb 44 | <<< 45 |

aaa 46 | bbb

47 | >>> Paragraphs - 225 48 | aaa 49 | bbb 50 | <<< 51 |
aaa
52 | 
53 |

bbb

54 | >>> Paragraphs - 226 55 | aaa 56 | bbb 57 | <<< 58 |

aaa
59 | bbb

60 | -------------------------------------------------------------------------------- /test/common_mark/precedence.unit: -------------------------------------------------------------------------------- 1 | >>> Precedence - 42 2 | - `one 3 | - two` 4 | <<< 5 |
    6 |
  • `one
  • 7 |
  • two`
  • 8 |
9 | -------------------------------------------------------------------------------- /test/common_mark/raw_html.unit: -------------------------------------------------------------------------------- 1 | >>> Raw HTML - 613 2 |
3 | <<< 4 |

5 | >>> Raw HTML - 614 6 | 7 | <<< 8 |

9 | >>> Raw HTML - 615 10 | 12 | <<< 13 |

15 | >>> Raw HTML - 616 16 | 18 | <<< 19 |

21 | >>> Raw HTML - 617 22 | Foo 23 | <<< 24 |

Foo

25 | >>> Raw HTML - 618 26 | <33> <__> 27 | <<< 28 |

<33> <__>

29 | >>> Raw HTML - 619 30 |
31 | <<< 32 |

<a h*#ref="hi">

33 | >>> Raw HTML - 620 34 |
57 | <<< 58 |

</a href="foo">

59 | >>> Raw HTML - 625 60 | foo 62 | <<< 63 |

foo <!-- this is a -- 64 | comment - with hyphens -->

65 | >>> Raw HTML - 626 66 | foo foo --> 67 | 68 | foo foo --> 69 | <<< 70 |

foo <!--> foo -->

71 |

foo <!---> foo -->

72 | >>> Raw HTML - 627 73 | foo 74 | <<< 75 |

foo

76 | >>> Raw HTML - 628 77 | foo 78 | <<< 79 |

foo

80 | >>> Raw HTML - 629 81 | foo &<]]> 82 | <<< 83 |

foo &<]]>

84 | >>> Raw HTML - 630 85 | foo
86 | <<< 87 |

foo

88 | >>> Raw HTML - 631 89 | foo 90 | <<< 91 |

foo

92 | >>> Raw HTML - 632 93 | 94 | <<< 95 |

<a href=""">

96 | -------------------------------------------------------------------------------- /test/common_mark/setext_headings.unit: -------------------------------------------------------------------------------- 1 | >>> Setext headings - 80 2 | Foo *bar* 3 | ========= 4 | 5 | Foo *bar* 6 | --------- 7 | <<< 8 |

Foo bar

9 |

Foo bar

10 | >>> Setext headings - 81 11 | Foo *bar 12 | baz* 13 | ==== 14 | <<< 15 |

Foo bar 16 | baz

17 | >>> Setext headings - 82 18 | Foo *bar 19 | baz* 20 | ==== 21 | <<< 22 |

Foo bar 23 | baz

24 | >>> Setext headings - 83 25 | Foo 26 | ------------------------- 27 | 28 | Foo 29 | = 30 | <<< 31 |

Foo

32 |

Foo

33 | >>> Setext headings - 84 34 | Foo 35 | --- 36 | 37 | Foo 38 | ----- 39 | 40 | Foo 41 | === 42 | <<< 43 |

Foo

44 |

Foo

45 |

Foo

46 | >>> Setext headings - 85 47 | Foo 48 | --- 49 | 50 | Foo 51 | --- 52 | <<< 53 |
Foo
 54 | ---
 55 | 
 56 | Foo
 57 | 
58 |
59 | >>> Setext headings - 86 60 | Foo 61 | ---- 62 | <<< 63 |

Foo

64 | >>> Setext headings - 87 65 | Foo 66 | --- 67 | <<< 68 |

Foo 69 | ---

70 | >>> Setext headings - 88 71 | Foo 72 | = = 73 | 74 | Foo 75 | --- - 76 | <<< 77 |

Foo 78 | = =

79 |

Foo

80 |
81 | >>> Setext headings - 89 82 | Foo 83 | ----- 84 | <<< 85 |

Foo

86 | >>> Setext headings - 90 87 | Foo\ 88 | ---- 89 | <<< 90 |

Foo\

91 | >>> Setext headings - 91 92 | `Foo 93 | ---- 94 | ` 95 | 96 |
99 | <<< 100 |

`Foo

101 |

`

102 |

<a title="a lot

103 |

of dashes"/>

104 | >>> Setext headings - 92 105 | > Foo 106 | --- 107 | <<< 108 |
109 |

Foo

110 |
111 |
112 | >>> Setext headings - 93 113 | > foo 114 | bar 115 | === 116 | <<< 117 |
118 |

foo 119 | bar 120 | ===

121 |
122 | >>> Setext headings - 94 123 | - Foo 124 | --- 125 | <<< 126 |
    127 |
  • Foo
  • 128 |
129 |
130 | >>> Setext headings - 95 131 | Foo 132 | Bar 133 | --- 134 | <<< 135 |

Foo 136 | Bar

137 | >>> Setext headings - 96 138 | --- 139 | Foo 140 | --- 141 | Bar 142 | --- 143 | Baz 144 | <<< 145 |
146 |

Foo

147 |

Bar

148 |

Baz

149 | >>> Setext headings - 97 150 | 151 | ==== 152 | <<< 153 |

====

154 | >>> Setext headings - 98 155 | --- 156 | --- 157 | <<< 158 |
159 |
160 | >>> Setext headings - 99 161 | - foo 162 | ----- 163 | <<< 164 |
    165 |
  • foo
  • 166 |
167 |
168 | >>> Setext headings - 100 169 | foo 170 | --- 171 | <<< 172 |
foo
173 | 
174 |
175 | >>> Setext headings - 101 176 | > foo 177 | ----- 178 | <<< 179 |
180 |

foo

181 |
182 |
183 | >>> Setext headings - 102 184 | \> foo 185 | ------ 186 | <<< 187 |

> foo

188 | >>> Setext headings - 103 189 | Foo 190 | 191 | bar 192 | --- 193 | baz 194 | <<< 195 |

Foo

196 |

bar

197 |

baz

198 | >>> Setext headings - 104 199 | Foo 200 | bar 201 | 202 | --- 203 | 204 | baz 205 | <<< 206 |

Foo 207 | bar

208 |
209 |

baz

210 | >>> Setext headings - 105 211 | Foo 212 | bar 213 | * * * 214 | baz 215 | <<< 216 |

Foo 217 | bar

218 |
219 |

baz

220 | >>> Setext headings - 106 221 | Foo 222 | bar 223 | \--- 224 | baz 225 | <<< 226 |

Foo 227 | bar 228 | --- 229 | baz

230 | -------------------------------------------------------------------------------- /test/common_mark/soft_line_breaks.unit: -------------------------------------------------------------------------------- 1 | >>> Soft line breaks - 648 2 | foo 3 | baz 4 | <<< 5 |

foo 6 | baz

7 | >>> Soft line breaks - 649 8 | foo 9 | baz 10 | <<< 11 |

foo 12 | baz

13 | -------------------------------------------------------------------------------- /test/common_mark/tabs.unit: -------------------------------------------------------------------------------- 1 | >>> Tabs - 1 2 | foo baz bim 3 | <<< 4 |
foo	baz		bim
 5 | 
6 | >>> Tabs - 2 7 | foo baz bim 8 | <<< 9 |
foo	baz		bim
10 | 
11 | >>> Tabs - 3 12 | a a 13 | ὐ a 14 | <<< 15 |
a	a
16 | ὐ	a
17 | 
18 | >>> Tabs - 4 19 | - foo 20 | 21 | bar 22 | <<< 23 |
    24 |
  • 25 |

    foo

    26 |

    bar

    27 |
  • 28 |
29 | >>> Tabs - 5 30 | - foo 31 | 32 | bar 33 | <<< 34 |
    35 |
  • 36 |

    foo

    37 |
      bar
    38 | 
    39 |
  • 40 |
41 | >>> Tabs - 6 42 | > foo 43 | <<< 44 |
45 |
foo
46 | 
47 |
48 | >>> Tabs - 7 49 | - foo 50 | <<< 51 |
    52 |
  • 53 |
      foo
    54 | 
    55 |
  • 56 |
57 | >>> Tabs - 8 58 | foo 59 | bar 60 | <<< 61 |
foo
62 | bar
63 | 
64 | >>> Tabs - 9 65 | - foo 66 | - bar 67 | - baz 68 | <<< 69 |
    70 |
  • foo 71 |
      72 |
    • bar 73 |
        74 |
      • baz
      • 75 |
      76 |
    • 77 |
    78 |
  • 79 |
80 | >>> Tabs - 10 81 | # Foo 82 | <<< 83 |

Foo

84 | >>> Tabs - 11 85 | * * * 86 | <<< 87 |
88 | -------------------------------------------------------------------------------- /test/common_mark/textual_content.unit: -------------------------------------------------------------------------------- 1 | >>> Textual content - 650 2 | hello $.;'there 3 | <<< 4 |

hello $.;'there

5 | >>> Textual content - 651 6 | Foo χρῆν 7 | <<< 8 |

Foo χρῆν

9 | >>> Textual content - 652 10 | Multiple spaces 11 | <<< 12 |

Multiple spaces

13 | -------------------------------------------------------------------------------- /test/common_mark/thematic_breaks.unit: -------------------------------------------------------------------------------- 1 | >>> Thematic breaks - 43 2 | *** 3 | --- 4 | ___ 5 | <<< 6 |
7 |
8 |
9 | >>> Thematic breaks - 44 10 | +++ 11 | <<< 12 |

+++

13 | >>> Thematic breaks - 45 14 | === 15 | <<< 16 |

===

17 | >>> Thematic breaks - 46 18 | -- 19 | ** 20 | __ 21 | <<< 22 |

-- 23 | ** 24 | __

25 | >>> Thematic breaks - 47 26 | *** 27 | *** 28 | *** 29 | <<< 30 |
31 |
32 |
33 | >>> Thematic breaks - 48 34 | *** 35 | <<< 36 |
***
 37 | 
38 | >>> Thematic breaks - 49 39 | Foo 40 | *** 41 | <<< 42 |

Foo 43 | ***

44 | >>> Thematic breaks - 50 45 | _____________________________________ 46 | <<< 47 |
48 | >>> Thematic breaks - 51 49 | - - - 50 | <<< 51 |
52 | >>> Thematic breaks - 52 53 | ** * ** * ** * ** 54 | <<< 55 |
56 | >>> Thematic breaks - 53 57 | - - - - 58 | <<< 59 |
60 | >>> Thematic breaks - 54 61 | - - - - 62 | <<< 63 |
64 | >>> Thematic breaks - 55 65 | _ _ _ _ a 66 | 67 | a------ 68 | 69 | ---a--- 70 | <<< 71 |

_ _ _ _ a

72 |

a------

73 |

---a---

74 | >>> Thematic breaks - 56 75 | *-* 76 | <<< 77 |

-

78 | >>> Thematic breaks - 57 79 | - foo 80 | *** 81 | - bar 82 | <<< 83 |
    84 |
  • foo
  • 85 |
86 |
87 |
    88 |
  • bar
  • 89 |
90 | >>> Thematic breaks - 58 91 | Foo 92 | *** 93 | bar 94 | <<< 95 |

Foo

96 |
97 |

bar

98 | >>> Thematic breaks - 59 99 | Foo 100 | --- 101 | bar 102 | <<< 103 |

Foo

104 |

bar

105 | >>> Thematic breaks - 60 106 | * Foo 107 | * * * 108 | * Bar 109 | <<< 110 |
    111 |
  • Foo
  • 112 |
113 |
114 |
    115 |
  • Bar
  • 116 |
117 | >>> Thematic breaks - 61 118 | - Foo 119 | - * * * 120 | <<< 121 |
    122 |
  • Foo
  • 123 |
  • 124 |
    125 |
  • 126 |
127 | -------------------------------------------------------------------------------- /test/extensions/autolink_extension.unit: -------------------------------------------------------------------------------- 1 | >>> not a link 2 | mhttp://www.foo.com 3 | <<< 4 |

mhttp://www.foo.com

5 | >>> following a newline 6 | m 7 | http://www.foo.com 8 | <<< 9 |

m 10 | http://www.foo.com

-------------------------------------------------------------------------------- /test/extensions/emojis.unit: -------------------------------------------------------------------------------- 1 | >>> within a paragraph 2 | I love to :smile:. 3 | 4 | <<< 5 |

I love to 😄.

6 | >>> within other inline syntax 7 | I *love to :smile:* 8 | <<< 9 |

I love to 😄

10 | >>> within blockquote 11 | > I love to :smile:. 12 | <<< 13 |
14 |

I love to 😄.

15 |
16 | >>> within code block 17 | I love to :smile: 18 | <<< 19 |
I love to :smile:
20 | 
21 | >>> within a link 22 | I love [to :smile:](http://www.google.com). 23 | <<< 24 |

I love to 😄.

25 | >>> within a reference link 26 | I love [to :smile:][]. 27 | 28 | [to :smile:]: http://www.google.com 29 | <<< 30 |

I love to 😄.

31 | >>> within inline code 32 | I love to `:smile:`. 33 | <<< 34 |

I love to :smile:.

35 | >>> with multiple code points 36 | Yay :australia: 37 | <<< 38 |

Yay 🇦🇺

39 | >>> leaves unknown emojis alone 40 | I love :smiles:. 41 | <<< 42 |

I love :smiles:.

43 | -------------------------------------------------------------------------------- /test/extensions/fenced_blockquotes.unit: -------------------------------------------------------------------------------- 1 | >>> simple block quote 2 | >>> 3 | # Foo 4 | bar 5 | baz 6 | >>> 7 | 8 | <<< 9 |
10 |

Foo

11 |

bar 12 | baz

13 |
14 | >>> has blank lines 15 | >>> 16 | 17 | foo 18 | 19 | 20 | 21 | 22 | bar 23 | 24 | 25 | >>> 26 | 27 | <<< 28 |
29 |

foo

30 |

bar

31 |
32 | >>> with nested block quote 33 | >>> 34 | foo 35 | > bar 36 | >>> 37 | 38 | <<< 39 |
40 |

foo

41 |
42 |

bar

43 |
44 |
45 | >>> with nested indented clode block 46 | >>> 47 | foo 48 | bar 49 | >>> 50 | 51 | <<< 52 |
53 |
foo
54 | bar
55 | 
56 |
57 | >>> with nested fenced clode block 58 | >>> 59 | ``` 60 | foo 61 | bar 62 | ``` 63 | >>> 64 | 65 | <<< 66 |
67 |
foo
68 | bar
69 | 
70 |
-------------------------------------------------------------------------------- /test/extensions/fenced_code_blocks.unit: -------------------------------------------------------------------------------- 1 | >>> without an optional language identifier 2 | ``` 3 | code 4 | ``` 5 | 6 | <<< 7 |
code
 8 | 
9 | >>> with an optional language identifier 10 | ```dart 11 | code 12 | ``` 13 | 14 | <<< 15 |
code
16 | 
17 | >>> escape HTML characters 18 | ``` 19 | <&> 20 | ``` 21 | 22 | <<< 23 |
<&>
24 | 
25 | >>> Pandoc style without language identifier 26 | ~~~~~ 27 | code 28 | ~~~~~ 29 | 30 | <<< 31 |
code
32 | 
33 | >>> Pandoc style with language identifier 34 | ~~~~~dart 35 | code 36 | ~~~~~ 37 | 38 | <<< 39 |
code
40 | 
41 | >>> Pandoc style with inner tildes row 42 | ~~~~~ 43 | ~~~ 44 | code 45 | ~~~ 46 | ~~~~~ 47 | 48 | <<< 49 |
~~~
50 | code
51 | ~~~
52 | 
53 | -------------------------------------------------------------------------------- /test/extensions/headers_with_ids.unit: -------------------------------------------------------------------------------- 1 | >>> simple header 2 | # header 3 | 4 | <<< 5 |

header

6 | >>> header that starts with garbage 7 | ## 2. header again 8 | 9 | <<< 10 |

2. header again

11 | >>> header with inline syntaxes 12 | ### headers **rock** `etc.` 13 | 14 | <<< 15 |

headers rock etc.

16 | >>> non-unique headers 17 | # header 18 | 19 | ## header 20 | 21 | <<< 22 |

header

23 |

header

24 | >>> header starts with inline syntax 25 | # *headers* etc. 26 | <<< 27 |

headers etc.

28 | >>> numbers-only headers (like a changelog) 29 | # 1.2.34 30 | 31 | ## 1.23.4 32 | 33 | ## 1.2.3+4 34 | <<< 35 |

1.2.34

36 |

1.23.4

37 |

1.2.3+4

38 | >>> no id 39 | # # 40 | <<< 41 |

42 | -------------------------------------------------------------------------------- /test/extensions/inline_html.unit: -------------------------------------------------------------------------------- 1 | >>> within a paragraph 2 | Within a paragraph. 3 | 4 | <<< 5 |

Within a paragraph.

6 | >>> not HTML 7 | Obviously, 3 < 5 and 7 > 2. 8 | Not HTML: <3>, <_a>, <> 9 | 10 | <<< 11 |

Obviously, 3 < 5 and 7 > 2. 12 | Not HTML: <3>, <_a>, <>

13 | >>> "markdown" within a tag is not parsed 14 | Text And "_foo_". 15 | 16 | <<< 17 |

Text And "foo".

18 | -------------------------------------------------------------------------------- /test/extensions/ordered_list_with_checkboxes.unit: -------------------------------------------------------------------------------- 1 | >>> checkbox with space 2 | 1. [ ] one 3 | 2. [ ] two 4 | <<< 5 |
    6 |
  1. one
  2. 7 |
  3. two
  4. 8 |
9 | >>> empty checkbox 10 | 1. [] one 11 | 2. [] two 12 | <<< 13 |
    14 |
  1. [] one
  2. 15 |
  3. [] two
  4. 16 |
17 | >>> checkbox with x 18 | 1. [x] one 19 | 2. [x] two 20 | <<< 21 |
    22 |
  1. one
  2. 23 |
  3. two
  4. 24 |
25 | >>> checkbox with X 26 | 1. [X] one 27 | 2. [X] two 28 | <<< 29 |
    30 |
  1. one
  2. 31 |
  3. two
  4. 32 |
33 | >>> mixed checkboxes 34 | 1. [ ] one 35 | 2. [] two 36 | 3. [x] three 37 | 4. [X] four 38 | 5. five 39 | <<< 40 |
    41 |
  1. one
  2. 42 |
  3. [] two
  4. 43 |
  5. three
  6. 44 |
  7. four
  8. 45 |
  9. five
  10. 46 |
47 | >>> mixed leading spaces 48 | 1. [ ] zero 49 | 2. [ ] one 50 | 3. [ ] two 51 | 4. [ ] three 52 | 5. [ ] four 53 | <<< 54 |
    55 |
  1. zero
  2. 56 |
  3. one
  4. 57 |
  5. two
  6. 58 |
  7. three
  8. 59 |
  9. 60 |
    [ ] four
    61 | 
    62 |
  10. 63 |
64 | >>> checkbox with empty content 65 | 1. [ ] one 66 | 2. 67 | 3. 68 | 4. four 69 | 5. [ ] five 70 | 6. 71 | <<< 72 |
    73 |
  1. one
  2. 74 |
  3. 75 |
  4. 76 |
  5. four
  6. 77 |
  7. five
  8. 78 |
  9. 79 |
-------------------------------------------------------------------------------- /test/extensions/setext_headers_with_ids.unit: -------------------------------------------------------------------------------- 1 | >>> h1 2 | text 3 | === 4 | 5 | <<< 6 |

text

7 | >>> h2 8 | text 9 | --- 10 | 11 | <<< 12 |

text

13 | >>> header with inline syntax 14 | header *emphasised* 15 | === 16 | 17 | <<< 18 |

header emphasised

19 | -------------------------------------------------------------------------------- /test/extensions/strikethrough.unit: -------------------------------------------------------------------------------- 1 | >>> Missing leading whitespace 2 | word pas~~t~~ word 3 | <<< 4 |

word past word

5 | >>> Missing trailing whitespace 6 | word ~~p~~ast word 7 | <<< 8 |

word past word

9 | >>> Middle of word 10 | word p~~as~~t word 11 | <<< 12 |

word past word

13 | >>> Whitespace after opening 14 | word~~ past~~ word 15 | <<< 16 |

word~~ past~~ word

17 | >>> Whitespace before closing 18 | word ~~past ~~word 19 | <<< 20 |

word ~~past ~~word

21 | >>> mixed with emphasis and order changes 22 | **~~first~~** ~~**second**~~ 23 | <<< 24 |

first second

25 | -------------------------------------------------------------------------------- /test/extensions/unordered_list_with_checkboxes.unit: -------------------------------------------------------------------------------- 1 | >>> checkbox with space 2 | * [ ] one 3 | * [ ] two 4 | <<< 5 |
    6 |
  • one
  • 7 |
  • two
  • 8 |
9 | >>> empty checkbox 10 | * [] one 11 | * [] two 12 | <<< 13 |
    14 |
  • [] one
  • 15 |
  • [] two
  • 16 |
17 | >>> checkbox with x 18 | * [x] one 19 | * [x] two 20 | <<< 21 |
    22 |
  • one
  • 23 |
  • two
  • 24 |
25 | >>> checkbox with X 26 | * [X] one 27 | * [X] two 28 | <<< 29 |
    30 |
  • one
  • 31 |
  • two
  • 32 |
33 | >>> mixed checkboxes 34 | * [ ] one 35 | * [] two 36 | * [x] three 37 | * [X] four 38 | * five 39 | <<< 40 |
    41 |
  • one
  • 42 |
  • [] two
  • 43 |
  • three
  • 44 |
  • four
  • 45 |
  • five
  • 46 |
47 | >>> mixed leading spaces 48 | *[ ] zero 49 | * [ ] one 50 | * [ ] two 51 | * [ ] three 52 | * [ ] four 53 | * [ ] five 54 | <<< 55 |

*[ ] zero

56 |
    57 |
  • one
  • 58 |
  • two
  • 59 |
  • three
  • 60 |
  • four
  • 61 |
  • 62 |
    [ ] five
    63 | 
    64 |
  • 65 |
66 | >>> checkbox list separated with blank lines 67 | - [ ] A 68 | 69 | - [ ] B 70 | 71 | - [ ] 72 | <<< 73 |
    74 |
  • 75 |

    A

    76 |
  • 77 |
  • 78 |

    B

    79 |
  • 80 |
  • 81 |

    [ ]

    82 |
  • 83 |
-------------------------------------------------------------------------------- /test/gfm/atx_headings.unit: -------------------------------------------------------------------------------- 1 | >>> ATX headings - 32 2 | # foo 3 | ## foo 4 | ### foo 5 | #### foo 6 | ##### foo 7 | ###### foo 8 | <<< 9 |

foo

10 |

foo

11 |

foo

12 |

foo

13 |
foo
14 |
foo
15 | >>> ATX headings - 33 16 | ####### foo 17 | <<< 18 |

####### foo

19 | >>> ATX headings - 34 20 | #5 bolt 21 | 22 | #hashtag 23 | <<< 24 |

#5 bolt

25 |

#hashtag

26 | >>> ATX headings - 35 27 | \## foo 28 | <<< 29 |

## foo

30 | >>> ATX headings - 36 31 | # foo *bar* \*baz\* 32 | <<< 33 |

foo bar *baz*

34 | >>> ATX headings - 37 35 | # foo 36 | <<< 37 |

foo

38 | >>> ATX headings - 38 39 | ### foo 40 | ## foo 41 | # foo 42 | <<< 43 |

foo

44 |

foo

45 |

foo

46 | >>> ATX headings - 39 47 | # foo 48 | <<< 49 |
# foo
 50 | 
51 | >>> ATX headings - 40 52 | foo 53 | # bar 54 | <<< 55 |

foo 56 | # bar

57 | >>> ATX headings - 41 58 | ## foo ## 59 | ### bar ### 60 | <<< 61 |

foo

62 |

bar

63 | >>> ATX headings - 42 64 | # foo ################################## 65 | ##### foo ## 66 | <<< 67 |

foo

68 |
foo
69 | >>> ATX headings - 43 70 | ### foo ### 71 | <<< 72 |

foo

73 | >>> ATX headings - 44 74 | ### foo ### b 75 | <<< 76 |

foo ### b

77 | >>> ATX headings - 45 78 | # foo# 79 | <<< 80 |

foo#

81 | >>> ATX headings - 46 82 | ### foo \### 83 | ## foo #\## 84 | # foo \# 85 | <<< 86 |

foo ###

87 |

foo ###

88 |

foo #

89 | >>> ATX headings - 47 90 | **** 91 | ## foo 92 | **** 93 | <<< 94 |
95 |

foo

96 |
97 | >>> ATX headings - 48 98 | Foo bar 99 | # baz 100 | Bar foo 101 | <<< 102 |

Foo bar

103 |

baz

104 |

Bar foo

105 | >>> ATX headings - 49 106 | ## 107 | # 108 | ### ### 109 | <<< 110 |

111 |

112 |

113 | -------------------------------------------------------------------------------- /test/gfm/autolinks.unit: -------------------------------------------------------------------------------- 1 | >>> Autolinks - 602 2 | 3 | <<< 4 |

http://foo.bar.baz

5 | >>> Autolinks - 603 6 | 7 | <<< 8 |

http://foo.bar.baz/test?q=hello&id=22&boolean

9 | >>> Autolinks - 604 10 | 11 | <<< 12 |

irc://foo.bar:2233/baz

13 | >>> Autolinks - 605 14 | 15 | <<< 16 |

MAILTO:FOO@BAR.BAZ

17 | >>> Autolinks - 606 18 | 19 | <<< 20 |

a+b+c:d

21 | >>> Autolinks - 607 22 | 23 | <<< 24 |

made-up-scheme://foo,bar

25 | >>> Autolinks - 608 26 | 27 | <<< 28 |

http://../

29 | >>> Autolinks - 609 30 | 31 | <<< 32 |

localhost:5001/foo

33 | >>> Autolinks - 610 34 | 35 | <<< 36 |

<http://foo.bar/baz bim>

37 | >>> Autolinks - 611 38 | 39 | <<< 40 |

http://example.com/\[\

41 | >>> Autolinks - 612 42 | 43 | <<< 44 |

foo@bar.example.com

45 | >>> Autolinks - 613 46 | 47 | <<< 48 |

foo+special@Bar.baz-bar0.com

49 | >>> Autolinks - 614 50 | 51 | <<< 52 |

<foo+@bar.example.com>

53 | >>> Autolinks - 615 54 | <> 55 | <<< 56 |

<>

57 | >>> Autolinks - 616 58 | < http://foo.bar > 59 | <<< 60 |

< http://foo.bar >

61 | >>> Autolinks - 617 62 | 63 | <<< 64 |

<m:abc>

65 | >>> Autolinks - 618 66 | 67 | <<< 68 |

<foo.bar.baz>

69 | >>> Autolinks - 619 70 | http://example.com 71 | <<< 72 |

http://example.com

73 | >>> Autolinks - 620 74 | foo@bar.example.com 75 | <<< 76 |

foo@bar.example.com

77 | -------------------------------------------------------------------------------- /test/gfm/autolinks_extension.unit: -------------------------------------------------------------------------------- 1 | >>> Autolinks (extension) - 621 2 | www.commonmark.org 3 | <<< 4 |

www.commonmark.org

5 | >>> Autolinks (extension) - 622 6 | Visit www.commonmark.org/help for more information. 7 | <<< 8 |

Visit www.commonmark.org/help for more information.

9 | >>> Autolinks (extension) - 623 10 | Visit www.commonmark.org. 11 | 12 | Visit www.commonmark.org/a.b. 13 | <<< 14 |

Visit www.commonmark.org.

15 |

Visit www.commonmark.org/a.b.

16 | >>> Autolinks (extension) - 624 17 | www.google.com/search?q=Markup+(business) 18 | 19 | www.google.com/search?q=Markup+(business))) 20 | 21 | (www.google.com/search?q=Markup+(business)) 22 | 23 | (www.google.com/search?q=Markup+(business) 24 | <<< 25 |

www.google.com/search?q=Markup+(business)

26 |

www.google.com/search?q=Markup+(business)))

27 |

(www.google.com/search?q=Markup+(business))

28 |

(www.google.com/search?q=Markup+(business)

29 | >>> Autolinks (extension) - 625 30 | www.google.com/search?q=(business))+ok 31 | <<< 32 |

www.google.com/search?q=(business))+ok

33 | >>> Autolinks (extension) - 626 34 | www.google.com/search?q=commonmark&hl=en 35 | 36 | www.google.com/search?q=commonmark&hl; 37 | <<< 38 |

www.google.com/search?q=commonmark&hl=en

39 |

www.google.com/search?q=commonmark&hl;

40 | >>> Autolinks (extension) - 627 41 | www.commonmark.org/hewww.commonmark.org/he<lp

44 | >>> Autolinks (extension) - 628 45 | http://commonmark.org 46 | 47 | (Visit https://encrypted.google.com/search?q=Markup+(business)) 48 | 49 | Anonymous FTP is available at ftp://foo.bar.baz. 50 | <<< 51 |

http://commonmark.org

52 |

(Visit https://encrypted.google.com/search?q=Markup+(business))

53 |

Anonymous FTP is available at ftp://foo.bar.baz.

54 | >>> Autolinks (extension) - 629 55 | foo@bar.baz 56 | <<< 57 |

foo@bar.baz

58 | >>> Autolinks (extension) - 630 59 | hello@mail+xyz.example isn't valid, but hello+xyz@mail.example is. 60 | <<< 61 |

hello@mail+xyz.example isn't valid, but hello+xyz@mail.example is.

62 | >>> Autolinks (extension) - 631 63 | a.b-c_d@a.b 64 | 65 | a.b-c_d@a.b. 66 | 67 | a.b-c_d@a.b- 68 | 69 | a.b-c_d@a.b_ 70 | <<< 71 |

a.b-c_d@a.b

72 |

a.b-c_d@a.b.

73 |

a.b-c_d@a.b-

74 |

a.b-c_d@a.b_

75 | -------------------------------------------------------------------------------- /test/gfm/backslash_escapes.unit: -------------------------------------------------------------------------------- 1 | >>> Backslash escapes - 308 2 | \!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~ 3 | <<< 4 |

!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

5 | >>> Backslash escapes - 309 6 | \ \A\a\ \3\φ\« 7 | <<< 8 |

\ \A\a\ \3\φ\«

9 | >>> Backslash escapes - 310 10 | \*not emphasized* 11 | \
not a tag 12 | \[not a link](/foo) 13 | \`not code` 14 | 1\. not a list 15 | \* not a list 16 | \# not a heading 17 | \[foo]: /url "not a reference" 18 | \ö not a character entity 19 | <<< 20 |

*not emphasized* 21 | <br/> not a tag 22 | [not a link](/foo) 23 | `not code` 24 | 1. not a list 25 | * not a list 26 | # not a heading 27 | [foo]: /url "not a reference" 28 | &ouml; not a character entity

29 | >>> Backslash escapes - 311 30 | \\*emphasis* 31 | <<< 32 |

\emphasis

33 | >>> Backslash escapes - 312 34 | foo\ 35 | bar 36 | <<< 37 |

foo
38 | bar

39 | >>> Backslash escapes - 313 40 | `` \[\` `` 41 | <<< 42 |

\[\`

43 | >>> Backslash escapes - 314 44 | \[\] 45 | <<< 46 |
\[\]
47 | 
48 | >>> Backslash escapes - 315 49 | ~~~ 50 | \[\] 51 | ~~~ 52 | <<< 53 |
\[\]
54 | 
55 | >>> Backslash escapes - 316 56 | 57 | <<< 58 |

http://example.com?find=\*

59 | >>> Backslash escapes - 317 60 | 61 | <<< 62 | 63 | >>> Backslash escapes - 318 64 | [foo](/bar\* "ti\*tle") 65 | <<< 66 |

foo

67 | >>> Backslash escapes - 319 68 | [foo] 69 | 70 | [foo]: /bar\* "ti\*tle" 71 | <<< 72 |

foo

73 | >>> Backslash escapes - 320 74 | ``` foo\+bar 75 | foo 76 | ``` 77 | <<< 78 |
foo
79 | 
80 | -------------------------------------------------------------------------------- /test/gfm/blank_lines.unit: -------------------------------------------------------------------------------- 1 | >>> Blank lines - 197 2 | 3 | 4 | aaa 5 | 6 | 7 | # aaa 8 | 9 | 10 | <<< 11 |

aaa

12 |

aaa

13 | -------------------------------------------------------------------------------- /test/gfm/block_quotes.unit: -------------------------------------------------------------------------------- 1 | >>> Block quotes - 206 2 | > # Foo 3 | > bar 4 | > baz 5 | <<< 6 |
7 |

Foo

8 |

bar 9 | baz

10 |
11 | >>> Block quotes - 207 12 | ># Foo 13 | >bar 14 | > baz 15 | <<< 16 |
17 |

Foo

18 |

bar 19 | baz

20 |
21 | >>> Block quotes - 208 22 | > # Foo 23 | > bar 24 | > baz 25 | <<< 26 |
27 |

Foo

28 |

bar 29 | baz

30 |
31 | >>> Block quotes - 209 32 | > # Foo 33 | > bar 34 | > baz 35 | <<< 36 |
> # Foo
 37 | > bar
 38 | > baz
 39 | 
40 | >>> Block quotes - 210 41 | > # Foo 42 | > bar 43 | baz 44 | <<< 45 |
46 |

Foo

47 |

bar 48 | baz

49 |
50 | >>> Block quotes - 211 51 | > bar 52 | baz 53 | > foo 54 | <<< 55 |
56 |

bar 57 | baz 58 | foo

59 |
60 | >>> Block quotes - 212 61 | > foo 62 | --- 63 | <<< 64 |
65 |

foo

66 |
67 |
68 | >>> Block quotes - 213 69 | > - foo 70 | - bar 71 | <<< 72 |
73 |
    74 |
  • foo
  • 75 |
76 |
77 |
    78 |
  • bar
  • 79 |
80 | >>> Block quotes - 214 81 | > foo 82 | bar 83 | <<< 84 |
85 |
foo
 86 | 
87 |
88 |
bar
 89 | 
90 | >>> Block quotes - 215 91 | > ``` 92 | foo 93 | ``` 94 | <<< 95 |
96 |
97 |
98 |

foo

99 |
100 | >>> Block quotes - 216 101 | > foo 102 | - bar 103 | <<< 104 |
105 |

foo 106 | - bar

107 |
108 | >>> Block quotes - 217 109 | > 110 | <<< 111 |
112 |
113 | >>> Block quotes - 218 114 | > 115 | > 116 | > 117 | <<< 118 |
119 |
120 | >>> Block quotes - 219 121 | > 122 | > foo 123 | > 124 | <<< 125 |
126 |

foo

127 |
128 | >>> Block quotes - 220 129 | > foo 130 | 131 | > bar 132 | <<< 133 |
134 |

foo

135 |
136 |
137 |

bar

138 |
139 | >>> Block quotes - 221 140 | > foo 141 | > bar 142 | <<< 143 |
144 |

foo 145 | bar

146 |
147 | >>> Block quotes - 222 148 | > foo 149 | > 150 | > bar 151 | <<< 152 |
153 |

foo

154 |

bar

155 |
156 | >>> Block quotes - 223 157 | foo 158 | > bar 159 | <<< 160 |

foo

161 |
162 |

bar

163 |
164 | >>> Block quotes - 224 165 | > aaa 166 | *** 167 | > bbb 168 | <<< 169 |
170 |

aaa

171 |
172 |
173 |
174 |

bbb

175 |
176 | >>> Block quotes - 225 177 | > bar 178 | baz 179 | <<< 180 |
181 |

bar 182 | baz

183 |
184 | >>> Block quotes - 226 185 | > bar 186 | 187 | baz 188 | <<< 189 |
190 |

bar

191 |
192 |

baz

193 | >>> Block quotes - 227 194 | > bar 195 | > 196 | baz 197 | <<< 198 |
199 |

bar

200 |
201 |

baz

202 | >>> Block quotes - 228 203 | > > > foo 204 | bar 205 | <<< 206 |
207 |
208 |
209 |

foo 210 | bar

211 |
212 |
213 |
214 | >>> Block quotes - 229 215 | >>> foo 216 | > bar 217 | >>baz 218 | <<< 219 |
220 |
221 |
222 |

foo 223 | bar 224 | baz

225 |
226 |
227 |
228 | >>> Block quotes - 230 229 | > code 230 | 231 | > not code 232 | <<< 233 |
234 |
code
235 | 
236 |
237 |
238 |

not code

239 |
240 | -------------------------------------------------------------------------------- /test/gfm/code_spans.unit: -------------------------------------------------------------------------------- 1 | >>> Code spans - 338 2 | `foo` 3 | <<< 4 |

foo

5 | >>> Code spans - 339 6 | `` foo ` bar `` 7 | <<< 8 |

foo ` bar

9 | >>> Code spans - 340 10 | ` `` ` 11 | <<< 12 |

``

13 | >>> Code spans - 341 14 | ` `` ` 15 | <<< 16 |

``

17 | >>> Code spans - 342 18 | ` a` 19 | <<< 20 |

a

21 | >>> Code spans - 343 22 | ` b ` 23 | <<< 24 |

 b 

25 | >>> Code spans - 344 26 | ` ` 27 | ` ` 28 | <<< 29 |

  30 |

31 | >>> Code spans - 345 32 | `` 33 | foo 34 | bar 35 | baz 36 | `` 37 | <<< 38 |

foo bar baz

39 | >>> Code spans - 346 40 | `` 41 | foo 42 | `` 43 | <<< 44 |

foo

45 | >>> Code spans - 347 46 | `foo bar 47 | baz` 48 | <<< 49 |

foo bar baz

50 | >>> Code spans - 348 51 | `foo\`bar` 52 | <<< 53 |

foo\bar`

54 | >>> Code spans - 349 55 | ``foo`bar`` 56 | <<< 57 |

foo`bar

58 | >>> Code spans - 350 59 | ` foo `` bar ` 60 | <<< 61 |

foo `` bar

62 | >>> Code spans - 351 63 | *foo`*` 64 | <<< 65 |

*foo*

66 | >>> Code spans - 352 67 | [not a `link](/foo`) 68 | <<< 69 |

[not a link](/foo)

70 | >>> Code spans - 353 71 | `` 72 | <<< 73 |

<a href="">`

74 | >>> Code spans - 354 75 |
` 76 | <<< 77 |

`

78 | >>> Code spans - 355 79 | `` 80 | <<< 81 |

<http://foo.bar.baz>`

82 | >>> Code spans - 356 83 | ` 84 | <<< 85 |

http://foo.bar.`baz`

86 | >>> Code spans - 357 87 | ```foo`` 88 | <<< 89 |

```foo``

90 | >>> Code spans - 358 91 | `foo 92 | <<< 93 |

`foo

94 | >>> Code spans - 359 95 | `foo``bar`` 96 | <<< 97 |

`foobar

98 | -------------------------------------------------------------------------------- /test/gfm/disallowed_raw_html_extension.unit: -------------------------------------------------------------------------------- 1 | >>> Disallowed Raw HTML (extension) - 652 2 | <style> <em> 3 | 4 | <blockquote> 5 | <xmp> is disallowed. <XMP> is also disallowed. 6 | </blockquote> 7 | <<< 8 | <p><strong> <title> <style> <em></p> 9 | <blockquote> 10 | <xmp> is disallowed. <XMP> is also disallowed. 11 | </blockquote> 12 | -------------------------------------------------------------------------------- /test/gfm/entity_and_numeric_character_references.unit: -------------------------------------------------------------------------------- 1 | >>> Entity and numeric character references - 321 2 |   & © Æ Ď 3 | ¾ ℋ ⅆ 4 | ∲ ≧̸ 5 | <<< 6 | <p>& © Æ Ď 7 | ¾ ℋ ⅆ 8 | ∲ ≧̸</p> 9 | >>> Entity and numeric character references - 322 10 | # Ӓ Ϡ � 11 | <<< 12 | <p># Ӓ Ϡ �</p> 13 | >>> Entity and numeric character references - 323 14 | " ആ ಫ 15 | <<< 16 | <p>" ആ ಫ</p> 17 | >>> Entity and numeric character references - 324 18 |   &x; &#; &#x; 19 | � 20 | &#abcdef0; 21 | &ThisIsNotDefined; &hi?; 22 | <<< 23 | <p>&nbsp &x; &#; &#x; 24 | &#987654321; 25 | &#abcdef0; 26 | &ThisIsNotDefined; &hi?;</p> 27 | >>> Entity and numeric character references - 325 28 | © 29 | <<< 30 | <p>&copy</p> 31 | >>> Entity and numeric character references - 326 32 | &MadeUpEntity; 33 | <<< 34 | <p>&MadeUpEntity;</p> 35 | >>> Entity and numeric character references - 327 36 | <a href="öö.html"> 37 | <<< 38 | <a href="öö.html"> 39 | >>> Entity and numeric character references - 328 40 | [foo](/föö "föö") 41 | <<< 42 | <p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p> 43 | >>> Entity and numeric character references - 329 44 | [foo] 45 | 46 | [foo]: /föö "föö" 47 | <<< 48 | <p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p> 49 | >>> Entity and numeric character references - 330 50 | ``` föö 51 | foo 52 | ``` 53 | <<< 54 | <pre><code class="language-föö">foo 55 | </code></pre> 56 | >>> Entity and numeric character references - 331 57 | `föö` 58 | <<< 59 | <p><code>f&ouml;&ouml;</code></p> 60 | >>> Entity and numeric character references - 332 61 | föfö 62 | <<< 63 | <pre><code>f&ouml;f&ouml; 64 | </code></pre> 65 | >>> Entity and numeric character references - 333 66 | *foo* 67 | *foo* 68 | <<< 69 | <p>*foo* 70 | <em>foo</em></p> 71 | >>> Entity and numeric character references - 334 72 | * foo 73 | 74 | * foo 75 | <<< 76 | <p>* foo</p> 77 | <ul> 78 | <li>foo</li> 79 | </ul> 80 | >>> Entity and numeric character references - 335 81 | foo bar 82 | <<< 83 | <p>foo 84 | 85 | bar</p> 86 | >>> Entity and numeric character references - 336 87 | foo 88 | <<< 89 | <p>foo</p> 90 | >>> Entity and numeric character references - 337 91 | [a](url "tit") 92 | <<< 93 | <p>[a](url "tit")</p> 94 | -------------------------------------------------------------------------------- /test/gfm/fenced_code_blocks.unit: -------------------------------------------------------------------------------- 1 | >>> Fenced code blocks - 89 2 | ``` 3 | < 4 | > 5 | ``` 6 | <<< 7 | <pre><code>< 8 | > 9 | </code></pre> 10 | >>> Fenced code blocks - 90 11 | ~~~ 12 | < 13 | > 14 | ~~~ 15 | <<< 16 | <pre><code>< 17 | > 18 | </code></pre> 19 | >>> Fenced code blocks - 91 20 | `` 21 | foo 22 | `` 23 | <<< 24 | <p><code>foo</code></p> 25 | >>> Fenced code blocks - 92 26 | ``` 27 | aaa 28 | ~~~ 29 | ``` 30 | <<< 31 | <pre><code>aaa 32 | ~~~ 33 | </code></pre> 34 | >>> Fenced code blocks - 93 35 | ~~~ 36 | aaa 37 | ``` 38 | ~~~ 39 | <<< 40 | <pre><code>aaa 41 | ``` 42 | </code></pre> 43 | >>> Fenced code blocks - 94 44 | ```` 45 | aaa 46 | ``` 47 | `````` 48 | <<< 49 | <pre><code>aaa 50 | ``` 51 | </code></pre> 52 | >>> Fenced code blocks - 95 53 | ~~~~ 54 | aaa 55 | ~~~ 56 | ~~~~ 57 | <<< 58 | <pre><code>aaa 59 | ~~~ 60 | </code></pre> 61 | >>> Fenced code blocks - 96 62 | ``` 63 | <<< 64 | <pre><code></code></pre> 65 | >>> Fenced code blocks - 97 66 | ````` 67 | 68 | ``` 69 | aaa 70 | <<< 71 | <pre><code> 72 | ``` 73 | aaa 74 | </code></pre> 75 | >>> Fenced code blocks - 98 76 | > ``` 77 | > aaa 78 | 79 | bbb 80 | <<< 81 | <blockquote> 82 | <pre><code>aaa 83 | </code></pre> 84 | </blockquote> 85 | <p>bbb</p> 86 | >>> Fenced code blocks - 99 87 | ``` 88 | 89 | 90 | ``` 91 | <<< 92 | <pre><code> 93 | 94 | </code></pre> 95 | >>> Fenced code blocks - 100 96 | ``` 97 | ``` 98 | <<< 99 | <pre><code></code></pre> 100 | >>> Fenced code blocks - 101 101 | ``` 102 | aaa 103 | aaa 104 | ``` 105 | <<< 106 | <pre><code>aaa 107 | aaa 108 | </code></pre> 109 | >>> Fenced code blocks - 102 110 | ``` 111 | aaa 112 | aaa 113 | aaa 114 | ``` 115 | <<< 116 | <pre><code>aaa 117 | aaa 118 | aaa 119 | </code></pre> 120 | >>> Fenced code blocks - 103 121 | ``` 122 | aaa 123 | aaa 124 | aaa 125 | ``` 126 | <<< 127 | <pre><code>aaa 128 | aaa 129 | aaa 130 | </code></pre> 131 | >>> Fenced code blocks - 104 132 | ``` 133 | aaa 134 | ``` 135 | <<< 136 | <pre><code>``` 137 | aaa 138 | ``` 139 | </code></pre> 140 | >>> Fenced code blocks - 105 141 | ``` 142 | aaa 143 | ``` 144 | <<< 145 | <pre><code>aaa 146 | </code></pre> 147 | >>> Fenced code blocks - 106 148 | ``` 149 | aaa 150 | ``` 151 | <<< 152 | <pre><code>aaa 153 | </code></pre> 154 | >>> Fenced code blocks - 107 155 | ``` 156 | aaa 157 | ``` 158 | <<< 159 | <pre><code>aaa 160 | ``` 161 | </code></pre> 162 | >>> Fenced code blocks - 108 163 | ``` ``` 164 | aaa 165 | <<< 166 | <p><code> </code> 167 | aaa</p> 168 | >>> Fenced code blocks - 109 169 | ~~~~~~ 170 | aaa 171 | ~~~ ~~ 172 | <<< 173 | <pre><code>aaa 174 | ~~~ ~~ 175 | </code></pre> 176 | >>> Fenced code blocks - 110 177 | foo 178 | ``` 179 | bar 180 | ``` 181 | baz 182 | <<< 183 | <p>foo</p> 184 | <pre><code>bar 185 | </code></pre> 186 | <p>baz</p> 187 | >>> Fenced code blocks - 111 188 | foo 189 | --- 190 | ~~~ 191 | bar 192 | ~~~ 193 | # baz 194 | <<< 195 | <h2>foo</h2> 196 | <pre><code>bar 197 | </code></pre> 198 | <h1>baz</h1> 199 | >>> Fenced code blocks - 112 200 | ```ruby 201 | def foo(x) 202 | return 3 203 | end 204 | ``` 205 | <<< 206 | <pre><code class="language-ruby">def foo(x) 207 | return 3 208 | end 209 | </code></pre> 210 | >>> Fenced code blocks - 113 211 | ~~~~ ruby startline=3 $%@#$ 212 | def foo(x) 213 | return 3 214 | end 215 | ~~~~~~~ 216 | <<< 217 | <pre><code class="language-ruby">def foo(x) 218 | return 3 219 | end 220 | </code></pre> 221 | >>> Fenced code blocks - 114 222 | ````; 223 | ```` 224 | <<< 225 | <pre><code class="language-;"></code></pre> 226 | >>> Fenced code blocks - 115 227 | ``` aa ``` 228 | foo 229 | <<< 230 | <p><code>aa</code> 231 | foo</p> 232 | >>> Fenced code blocks - 116 233 | ~~~ aa ``` ~~~ 234 | foo 235 | ~~~ 236 | <<< 237 | <pre><code class="language-aa">foo 238 | </code></pre> 239 | >>> Fenced code blocks - 117 240 | ``` 241 | ``` aaa 242 | ``` 243 | <<< 244 | <pre><code>``` aaa 245 | </code></pre> 246 | -------------------------------------------------------------------------------- /test/gfm/hard_line_breaks.unit: -------------------------------------------------------------------------------- 1 | >>> Hard line breaks - 653 2 | foo 3 | baz 4 | <<< 5 | <p>foo<br /> 6 | baz</p> 7 | >>> Hard line breaks - 654 8 | foo\ 9 | baz 10 | <<< 11 | <p>foo<br /> 12 | baz</p> 13 | >>> Hard line breaks - 655 14 | foo 15 | baz 16 | <<< 17 | <p>foo<br /> 18 | baz</p> 19 | >>> Hard line breaks - 656 20 | foo 21 | bar 22 | <<< 23 | <p>foo<br /> 24 | bar</p> 25 | >>> Hard line breaks - 657 26 | foo\ 27 | bar 28 | <<< 29 | <p>foo<br /> 30 | bar</p> 31 | >>> Hard line breaks - 658 32 | *foo 33 | bar* 34 | <<< 35 | <p><em>foo<br /> 36 | bar</em></p> 37 | >>> Hard line breaks - 659 38 | *foo\ 39 | bar* 40 | <<< 41 | <p><em>foo<br /> 42 | bar</em></p> 43 | >>> Hard line breaks - 660 44 | `code 45 | span` 46 | <<< 47 | <p><code>code span</code></p> 48 | >>> Hard line breaks - 661 49 | `code\ 50 | span` 51 | <<< 52 | <p><code>code\ span</code></p> 53 | >>> Hard line breaks - 662 54 | <a href="foo 55 | bar"> 56 | <<< 57 | <p><a href="foo 58 | bar"></p> 59 | >>> Hard line breaks - 663 60 | <a href="foo\ 61 | bar"> 62 | <<< 63 | <p><a href="foo\ 64 | bar"></p> 65 | >>> Hard line breaks - 664 66 | foo\ 67 | <<< 68 | <p>foo\</p> 69 | >>> Hard line breaks - 665 70 | foo 71 | <<< 72 | <p>foo</p> 73 | >>> Hard line breaks - 666 74 | ### foo\ 75 | <<< 76 | <h3>foo\</h3> 77 | >>> Hard line breaks - 667 78 | ### foo 79 | <<< 80 | <h3>foo</h3> 81 | -------------------------------------------------------------------------------- /test/gfm/images.unit: -------------------------------------------------------------------------------- 1 | >>> Images - 580 2 | ![foo](/url "title") 3 | <<< 4 | <p><img src="/url" alt="foo" title="title" /></p> 5 | >>> Images - 581 6 | ![foo *bar*] 7 | 8 | [foo *bar*]: train.jpg "train & tracks" 9 | <<< 10 | <p><img src="train.jpg" alt="foo bar" title="train & tracks" /></p> 11 | >>> Images - 582 12 | ![foo ![bar](/url)](/url2) 13 | <<< 14 | <p><img src="/url2" alt="foo bar" /></p> 15 | >>> Images - 583 16 | ![foo [bar](/url)](/url2) 17 | <<< 18 | <p><img src="/url2" alt="foo bar" /></p> 19 | >>> Images - 584 20 | ![foo *bar*][] 21 | 22 | [foo *bar*]: train.jpg "train & tracks" 23 | <<< 24 | <p><img src="train.jpg" alt="foo bar" title="train & tracks" /></p> 25 | >>> Images - 585 26 | ![foo *bar*][foobar] 27 | 28 | [FOOBAR]: train.jpg "train & tracks" 29 | <<< 30 | <p><img src="train.jpg" alt="foo bar" title="train & tracks" /></p> 31 | >>> Images - 586 32 | ![foo](train.jpg) 33 | <<< 34 | <p><img src="train.jpg" alt="foo" /></p> 35 | >>> Images - 587 36 | My ![foo bar](/path/to/train.jpg "title" ) 37 | <<< 38 | <p>My <img src="/path/to/train.jpg" alt="foo bar" title="title" /></p> 39 | >>> Images - 588 40 | ![foo](<url>) 41 | <<< 42 | <p><img src="url" alt="foo" /></p> 43 | >>> Images - 589 44 | ![](/url) 45 | <<< 46 | <p><img src="/url" alt="" /></p> 47 | >>> Images - 590 48 | ![foo][bar] 49 | 50 | [bar]: /url 51 | <<< 52 | <p><img src="/url" alt="foo" /></p> 53 | >>> Images - 591 54 | ![foo][bar] 55 | 56 | [BAR]: /url 57 | <<< 58 | <p><img src="/url" alt="foo" /></p> 59 | >>> Images - 592 60 | ![foo][] 61 | 62 | [foo]: /url "title" 63 | <<< 64 | <p><img src="/url" alt="foo" title="title" /></p> 65 | >>> Images - 593 66 | ![*foo* bar][] 67 | 68 | [*foo* bar]: /url "title" 69 | <<< 70 | <p><img src="/url" alt="foo bar" title="title" /></p> 71 | >>> Images - 594 72 | ![Foo][] 73 | 74 | [foo]: /url "title" 75 | <<< 76 | <p><img src="/url" alt="Foo" title="title" /></p> 77 | >>> Images - 595 78 | ![foo] 79 | [] 80 | 81 | [foo]: /url "title" 82 | <<< 83 | <p><img src="/url" alt="foo" title="title" /> 84 | []</p> 85 | >>> Images - 596 86 | ![foo] 87 | 88 | [foo]: /url "title" 89 | <<< 90 | <p><img src="/url" alt="foo" title="title" /></p> 91 | >>> Images - 597 92 | ![*foo* bar] 93 | 94 | [*foo* bar]: /url "title" 95 | <<< 96 | <p><img src="/url" alt="foo bar" title="title" /></p> 97 | >>> Images - 598 98 | ![[foo]] 99 | 100 | [[foo]]: /url "title" 101 | <<< 102 | <p>![[foo]]</p> 103 | <p>[[foo]]: /url "title"</p> 104 | >>> Images - 599 105 | ![Foo] 106 | 107 | [foo]: /url "title" 108 | <<< 109 | <p><img src="/url" alt="Foo" title="title" /></p> 110 | >>> Images - 600 111 | !\[foo] 112 | 113 | [foo]: /url "title" 114 | <<< 115 | <p>![foo]</p> 116 | >>> Images - 601 117 | \![foo] 118 | 119 | [foo]: /url "title" 120 | <<< 121 | <p>!<a href="/url" title="title">foo</a></p> 122 | -------------------------------------------------------------------------------- /test/gfm/indented_code_blocks.unit: -------------------------------------------------------------------------------- 1 | >>> Indented code blocks - 77 2 | a simple 3 | indented code block 4 | <<< 5 | <pre><code>a simple 6 | indented code block 7 | </code></pre> 8 | >>> Indented code blocks - 78 9 | - foo 10 | 11 | bar 12 | <<< 13 | <ul> 14 | <li> 15 | <p>foo</p> 16 | <p>bar</p> 17 | </li> 18 | </ul> 19 | >>> Indented code blocks - 79 20 | 1. foo 21 | 22 | - bar 23 | <<< 24 | <ol> 25 | <li> 26 | <p>foo</p> 27 | <ul> 28 | <li>bar</li> 29 | </ul> 30 | </li> 31 | </ol> 32 | >>> Indented code blocks - 80 33 | <a/> 34 | *hi* 35 | 36 | - one 37 | <<< 38 | <pre><code><a/> 39 | *hi* 40 | 41 | - one 42 | </code></pre> 43 | >>> Indented code blocks - 81 44 | chunk1 45 | 46 | chunk2 47 | 48 | 49 | 50 | chunk3 51 | <<< 52 | <pre><code>chunk1 53 | 54 | chunk2 55 | 56 | 57 | 58 | chunk3 59 | </code></pre> 60 | >>> Indented code blocks - 82 61 | chunk1 62 | 63 | chunk2 64 | <<< 65 | <pre><code>chunk1 66 | 67 | chunk2 68 | </code></pre> 69 | >>> Indented code blocks - 83 70 | Foo 71 | bar 72 | 73 | <<< 74 | <p>Foo 75 | bar</p> 76 | >>> Indented code blocks - 84 77 | foo 78 | bar 79 | <<< 80 | <pre><code>foo 81 | </code></pre> 82 | <p>bar</p> 83 | >>> Indented code blocks - 85 84 | # Heading 85 | foo 86 | Heading 87 | ------ 88 | foo 89 | ---- 90 | <<< 91 | <h1>Heading</h1> 92 | <pre><code>foo 93 | </code></pre> 94 | <h2>Heading</h2> 95 | <pre><code>foo 96 | </code></pre> 97 | <hr /> 98 | >>> Indented code blocks - 86 99 | foo 100 | bar 101 | <<< 102 | <pre><code> foo 103 | bar 104 | </code></pre> 105 | >>> Indented code blocks - 87 106 | 107 | 108 | foo 109 | 110 | 111 | <<< 112 | <pre><code>foo 113 | </code></pre> 114 | >>> Indented code blocks - 88 115 | foo 116 | <<< 117 | <pre><code>foo 118 | </code></pre> 119 | -------------------------------------------------------------------------------- /test/gfm/inlines.unit: -------------------------------------------------------------------------------- 1 | >>> Inlines - 307 2 | `hi`lo` 3 | <<< 4 | <p><code>hi</code>lo`</p> 5 | -------------------------------------------------------------------------------- /test/gfm/paragraphs.unit: -------------------------------------------------------------------------------- 1 | >>> Paragraphs - 189 2 | aaa 3 | 4 | bbb 5 | <<< 6 | <p>aaa</p> 7 | <p>bbb</p> 8 | >>> Paragraphs - 190 9 | aaa 10 | bbb 11 | 12 | ccc 13 | ddd 14 | <<< 15 | <p>aaa 16 | bbb</p> 17 | <p>ccc 18 | ddd</p> 19 | >>> Paragraphs - 191 20 | aaa 21 | 22 | 23 | bbb 24 | <<< 25 | <p>aaa</p> 26 | <p>bbb</p> 27 | >>> Paragraphs - 192 28 | aaa 29 | bbb 30 | <<< 31 | <p>aaa 32 | bbb</p> 33 | >>> Paragraphs - 193 34 | aaa 35 | bbb 36 | ccc 37 | <<< 38 | <p>aaa 39 | bbb 40 | ccc</p> 41 | >>> Paragraphs - 194 42 | aaa 43 | bbb 44 | <<< 45 | <p>aaa 46 | bbb</p> 47 | >>> Paragraphs - 195 48 | aaa 49 | bbb 50 | <<< 51 | <pre><code>aaa 52 | </code></pre> 53 | <p>bbb</p> 54 | >>> Paragraphs - 196 55 | aaa 56 | bbb 57 | <<< 58 | <p>aaa<br /> 59 | bbb</p> 60 | -------------------------------------------------------------------------------- /test/gfm/precedence.unit: -------------------------------------------------------------------------------- 1 | >>> Precedence - 12 2 | - `one 3 | - two` 4 | <<< 5 | <ul> 6 | <li>`one</li> 7 | <li>two`</li> 8 | </ul> 9 | -------------------------------------------------------------------------------- /test/gfm/raw_html.unit: -------------------------------------------------------------------------------- 1 | >>> Raw HTML - 632 2 | <a><bab><c2c> 3 | <<< 4 | <p><a><bab><c2c></p> 5 | >>> Raw HTML - 633 6 | <a/><b2/> 7 | <<< 8 | <p><a/><b2/></p> 9 | >>> Raw HTML - 634 10 | <a /><b2 11 | data="foo" > 12 | <<< 13 | <p><a /><b2 14 | data="foo" ></p> 15 | >>> Raw HTML - 635 16 | <a foo="bar" bam = 'baz <em>"</em>' 17 | _boolean zoop:33=zoop:33 /> 18 | <<< 19 | <p><a foo="bar" bam = 'baz <em>"</em>' 20 | _boolean zoop:33=zoop:33 /></p> 21 | >>> Raw HTML - 636 22 | Foo <responsive-image src="foo.jpg" /> 23 | <<< 24 | <p>Foo <responsive-image src="foo.jpg" /></p> 25 | >>> Raw HTML - 637 26 | <33> <__> 27 | <<< 28 | <p><33> <__></p> 29 | >>> Raw HTML - 638 30 | <a h*#ref="hi"> 31 | <<< 32 | <p><a h*#ref="hi"></p> 33 | >>> Raw HTML - 639 34 | <a href="hi'> <a href=hi'> 35 | <<< 36 | <p><a href="hi'> <a href=hi'></p> 37 | >>> Raw HTML - 640 38 | < a>< 39 | foo><bar/ > 40 | <foo bar=baz 41 | bim!bop /> 42 | <<< 43 | <p>< a>< 44 | foo><bar/ > 45 | <foo bar=baz 46 | bim!bop /></p> 47 | >>> Raw HTML - 641 48 | <a href='bar'title=title> 49 | <<< 50 | <p><a href='bar'title=title></p> 51 | >>> Raw HTML - 642 52 | </a></foo > 53 | <<< 54 | <p></a></foo ></p> 55 | >>> Raw HTML - 643 56 | </a href="foo"> 57 | <<< 58 | <p></a href="foo"></p> 59 | >>> Raw HTML - 644 60 | foo <!-- this is a -- 61 | comment - with hyphens --> 62 | <<< 63 | <p>foo <!-- this is a -- 64 | comment - with hyphens --></p> 65 | >>> Raw HTML - 645 66 | foo <!--> foo --> 67 | 68 | foo <!---> foo --> 69 | <<< 70 | <p>foo <!--> foo --></p> 71 | <p>foo <!---> foo --></p> 72 | >>> Raw HTML - 646 73 | foo <?php echo $a; ?> 74 | <<< 75 | <p>foo <?php echo $a; ?></p> 76 | >>> Raw HTML - 647 77 | foo <!ELEMENT br EMPTY> 78 | <<< 79 | <p>foo <!ELEMENT br EMPTY></p> 80 | >>> Raw HTML - 648 81 | foo <![CDATA[>&<]]> 82 | <<< 83 | <p>foo <![CDATA[>&<]]></p> 84 | >>> Raw HTML - 649 85 | foo <a href="ö"> 86 | <<< 87 | <p>foo <a href="ö"></p> 88 | >>> Raw HTML - 650 89 | foo <a href="\*"> 90 | <<< 91 | <p>foo <a href="\*"></p> 92 | >>> Raw HTML - 651 93 | <a href="\""> 94 | <<< 95 | <p><a href="""></p> 96 | -------------------------------------------------------------------------------- /test/gfm/setext_headings.unit: -------------------------------------------------------------------------------- 1 | >>> Setext headings - 50 2 | Foo *bar* 3 | ========= 4 | 5 | Foo *bar* 6 | --------- 7 | <<< 8 | <h1>Foo <em>bar</em></h1> 9 | <h2>Foo <em>bar</em></h2> 10 | >>> Setext headings - 51 11 | Foo *bar 12 | baz* 13 | ==== 14 | <<< 15 | <h1>Foo <em>bar 16 | baz</em></h1> 17 | >>> Setext headings - 52 18 | Foo *bar 19 | baz* 20 | ==== 21 | <<< 22 | <h1> Foo <em>bar 23 | baz</em></h1> 24 | >>> Setext headings - 53 25 | Foo 26 | ------------------------- 27 | 28 | Foo 29 | = 30 | <<< 31 | <h2>Foo</h2> 32 | <h1>Foo</h1> 33 | >>> Setext headings - 54 34 | Foo 35 | --- 36 | 37 | Foo 38 | ----- 39 | 40 | Foo 41 | === 42 | <<< 43 | <h2> Foo</h2> 44 | <h2> Foo</h2> 45 | <h1> Foo</h1> 46 | >>> Setext headings - 55 47 | Foo 48 | --- 49 | 50 | Foo 51 | --- 52 | <<< 53 | <pre><code>Foo 54 | --- 55 | 56 | Foo 57 | </code></pre> 58 | <hr /> 59 | >>> Setext headings - 56 60 | Foo 61 | ---- 62 | <<< 63 | <h2>Foo</h2> 64 | >>> Setext headings - 57 65 | Foo 66 | --- 67 | <<< 68 | <p>Foo 69 | ---</p> 70 | >>> Setext headings - 58 71 | Foo 72 | = = 73 | 74 | Foo 75 | --- - 76 | <<< 77 | <p>Foo 78 | = =</p> 79 | <p>Foo</p> 80 | <hr /> 81 | >>> Setext headings - 59 82 | Foo 83 | ----- 84 | <<< 85 | <h2>Foo</h2> 86 | >>> Setext headings - 60 87 | Foo\ 88 | ---- 89 | <<< 90 | <h2>Foo\</h2> 91 | >>> Setext headings - 61 92 | `Foo 93 | ---- 94 | ` 95 | 96 | <a title="a lot 97 | --- 98 | of dashes"/> 99 | <<< 100 | <h2>`Foo</h2> 101 | <p>`</p> 102 | <h2><a title="a lot</h2> 103 | <p>of dashes"/></p> 104 | >>> Setext headings - 62 105 | > Foo 106 | --- 107 | <<< 108 | <blockquote> 109 | <p>Foo</p> 110 | </blockquote> 111 | <hr /> 112 | >>> Setext headings - 63 113 | > foo 114 | bar 115 | === 116 | <<< 117 | <blockquote> 118 | <p>foo 119 | bar 120 | ===</p> 121 | </blockquote> 122 | >>> Setext headings - 64 123 | - Foo 124 | --- 125 | <<< 126 | <ul> 127 | <li>Foo</li> 128 | </ul> 129 | <hr /> 130 | >>> Setext headings - 65 131 | Foo 132 | Bar 133 | --- 134 | <<< 135 | <h2>Foo 136 | Bar</h2> 137 | >>> Setext headings - 66 138 | --- 139 | Foo 140 | --- 141 | Bar 142 | --- 143 | Baz 144 | <<< 145 | <hr /> 146 | <h2>Foo</h2> 147 | <h2>Bar</h2> 148 | <p>Baz</p> 149 | >>> Setext headings - 67 150 | 151 | ==== 152 | <<< 153 | <p>====</p> 154 | >>> Setext headings - 68 155 | --- 156 | --- 157 | <<< 158 | <hr /> 159 | <hr /> 160 | >>> Setext headings - 69 161 | - foo 162 | ----- 163 | <<< 164 | <ul> 165 | <li>foo</li> 166 | </ul> 167 | <hr /> 168 | >>> Setext headings - 70 169 | foo 170 | --- 171 | <<< 172 | <pre><code>foo 173 | </code></pre> 174 | <hr /> 175 | >>> Setext headings - 71 176 | > foo 177 | ----- 178 | <<< 179 | <blockquote> 180 | <p>foo</p> 181 | </blockquote> 182 | <hr /> 183 | >>> Setext headings - 72 184 | \> foo 185 | ------ 186 | <<< 187 | <h2>> foo</h2> 188 | >>> Setext headings - 73 189 | Foo 190 | 191 | bar 192 | --- 193 | baz 194 | <<< 195 | <p>Foo</p> 196 | <h2>bar</h2> 197 | <p>baz</p> 198 | >>> Setext headings - 74 199 | Foo 200 | bar 201 | 202 | --- 203 | 204 | baz 205 | <<< 206 | <p>Foo 207 | bar</p> 208 | <hr /> 209 | <p>baz</p> 210 | >>> Setext headings - 75 211 | Foo 212 | bar 213 | * * * 214 | baz 215 | <<< 216 | <p>Foo 217 | bar</p> 218 | <hr /> 219 | <p>baz</p> 220 | >>> Setext headings - 76 221 | Foo 222 | bar 223 | \--- 224 | baz 225 | <<< 226 | <p>Foo 227 | bar 228 | --- 229 | baz</p> 230 | -------------------------------------------------------------------------------- /test/gfm/soft_line_breaks.unit: -------------------------------------------------------------------------------- 1 | >>> Soft line breaks - 668 2 | foo 3 | baz 4 | <<< 5 | <p>foo 6 | baz</p> 7 | >>> Soft line breaks - 669 8 | foo 9 | baz 10 | <<< 11 | <p>foo 12 | baz</p> 13 | -------------------------------------------------------------------------------- /test/gfm/strikethrough_extension.unit: -------------------------------------------------------------------------------- 1 | >>> Strikethrough (extension) - 491 2 | ~~Hi~~ Hello, world! 3 | <<< 4 | <p><del>Hi</del> Hello, world!</p> 5 | >>> Strikethrough (extension) - 492 6 | This ~~has a 7 | 8 | new paragraph~~. 9 | <<< 10 | <p>This ~~has a</p> 11 | <p>new paragraph~~.</p> 12 | >>> single tilde 13 | ~Hi~ there. 14 | <<< 15 | <p><del>Hi</del> there.</p> 16 | >>> single tilde with double tilde 17 | ~Hi~~ there. 18 | <<< 19 | <p><del>Hi</del>~ there.</p> 20 | -------------------------------------------------------------------------------- /test/gfm/tables_extension.unit: -------------------------------------------------------------------------------- 1 | >>> Tables (extension) - 198 2 | | foo | bar | 3 | | --- | --- | 4 | | baz | bim | 5 | <<< 6 | <table> 7 | <thead> 8 | <tr> 9 | <th>foo</th> 10 | <th>bar</th> 11 | </tr> 12 | </thead> 13 | <tbody> 14 | <tr> 15 | <td>baz</td> 16 | <td>bim</td> 17 | </tr> 18 | </tbody> 19 | </table> 20 | >>> Tables (extension) - 199 21 | | abc | defghi | 22 | :-: | -----------: 23 | bar | baz 24 | <<< 25 | <table> 26 | <thead> 27 | <tr> 28 | <th align="center">abc</th> 29 | <th align="right">defghi</th> 30 | </tr> 31 | </thead> 32 | <tbody> 33 | <tr> 34 | <td align="center">bar</td> 35 | <td align="right">baz</td> 36 | </tr> 37 | </tbody> 38 | </table> 39 | >>> Tables (extension) - 200 40 | | f\|oo | 41 | | ------ | 42 | | b `\|` az | 43 | | b **\|** im | 44 | <<< 45 | <table> 46 | <thead> 47 | <tr> 48 | <th>f|oo</th> 49 | </tr> 50 | </thead> 51 | <tbody> 52 | <tr> 53 | <td>b <code>|</code> az</td> 54 | </tr> 55 | <tr> 56 | <td>b <strong>|</strong> im</td> 57 | </tr> 58 | </tbody> 59 | </table> 60 | >>> Tables (extension) - 201 61 | | abc | def | 62 | | --- | --- | 63 | | bar | baz | 64 | > bar 65 | <<< 66 | <table> 67 | <thead> 68 | <tr> 69 | <th>abc</th> 70 | <th>def</th> 71 | </tr> 72 | </thead> 73 | <tbody> 74 | <tr> 75 | <td>bar</td> 76 | <td>baz</td> 77 | </tr> 78 | </tbody> 79 | </table> 80 | <blockquote> 81 | <p>bar</p> 82 | </blockquote> 83 | >>> Tables (extension) - 202 84 | | abc | def | 85 | | --- | --- | 86 | | bar | baz | 87 | bar 88 | 89 | bar 90 | <<< 91 | <table> 92 | <thead> 93 | <tr> 94 | <th>abc</th> 95 | <th>def</th> 96 | </tr> 97 | </thead> 98 | <tbody> 99 | <tr> 100 | <td>bar</td> 101 | <td>baz</td> 102 | </tr> 103 | <tr> 104 | <td>bar</td> 105 | <td></td> 106 | </tr> 107 | </tbody> 108 | </table> 109 | <p>bar</p> 110 | >>> Tables (extension) - 203 111 | | abc | def | 112 | | --- | 113 | | bar | 114 | <<< 115 | <p>| abc | def | 116 | | --- | 117 | | bar |</p> 118 | >>> Tables (extension) - 204 119 | | abc | def | 120 | | --- | --- | 121 | | bar | 122 | | bar | baz | boo | 123 | <<< 124 | <table> 125 | <thead> 126 | <tr> 127 | <th>abc</th> 128 | <th>def</th> 129 | </tr> 130 | </thead> 131 | <tbody> 132 | <tr> 133 | <td>bar</td> 134 | <td></td> 135 | </tr> 136 | <tr> 137 | <td>bar</td> 138 | <td>baz</td> 139 | </tr> 140 | </tbody> 141 | </table> 142 | >>> Tables (extension) - 205 143 | | abc | def | 144 | | --- | --- | 145 | <<< 146 | <table> 147 | <thead> 148 | <tr> 149 | <th>abc</th> 150 | <th>def</th> 151 | </tr> 152 | </thead> 153 | </table> 154 | -------------------------------------------------------------------------------- /test/gfm/tabs.unit: -------------------------------------------------------------------------------- 1 | >>> Tabs - 1 2 | foo baz bim 3 | <<< 4 | <pre><code>foo baz bim 5 | </code></pre> 6 | >>> Tabs - 2 7 | foo baz bim 8 | <<< 9 | <pre><code>foo baz bim 10 | </code></pre> 11 | >>> Tabs - 3 12 | a a 13 | ὐ a 14 | <<< 15 | <pre><code>a a 16 | ὐ a 17 | </code></pre> 18 | >>> Tabs - 4 19 | - foo 20 | 21 | bar 22 | <<< 23 | <ul> 24 | <li> 25 | <p>foo</p> 26 | <p>bar</p> 27 | </li> 28 | </ul> 29 | >>> Tabs - 5 30 | - foo 31 | 32 | bar 33 | <<< 34 | <ul> 35 | <li> 36 | <p>foo</p> 37 | <pre><code> bar 38 | </code></pre> 39 | </li> 40 | </ul> 41 | >>> Tabs - 6 42 | > foo 43 | <<< 44 | <blockquote> 45 | <pre><code>foo 46 | </code></pre> 47 | </blockquote> 48 | >>> Tabs - 7 49 | - foo 50 | <<< 51 | <ul> 52 | <li> 53 | <pre><code> foo 54 | </code></pre> 55 | </li> 56 | </ul> 57 | >>> Tabs - 8 58 | foo 59 | bar 60 | <<< 61 | <pre><code>foo 62 | bar 63 | </code></pre> 64 | >>> Tabs - 9 65 | - foo 66 | - bar 67 | - baz 68 | <<< 69 | <ul> 70 | <li>foo 71 | <ul> 72 | <li>bar 73 | <ul> 74 | <li>baz</li> 75 | </ul> 76 | </li> 77 | </ul> 78 | </li> 79 | </ul> 80 | >>> Tabs - 10 81 | # Foo 82 | <<< 83 | <h1>Foo</h1> 84 | >>> Tabs - 11 85 | * * * 86 | <<< 87 | <hr /> 88 | -------------------------------------------------------------------------------- /test/gfm/textual_content.unit: -------------------------------------------------------------------------------- 1 | >>> Textual content - 670 2 | hello $.;'there 3 | <<< 4 | <p>hello $.;'there</p> 5 | >>> Textual content - 671 6 | Foo χρῆν 7 | <<< 8 | <p>Foo χρῆν</p> 9 | >>> Textual content - 672 10 | Multiple spaces 11 | <<< 12 | <p>Multiple spaces</p> 13 | -------------------------------------------------------------------------------- /test/gfm/thematic_breaks.unit: -------------------------------------------------------------------------------- 1 | >>> Thematic breaks - 13 2 | *** 3 | --- 4 | ___ 5 | <<< 6 | <hr /> 7 | <hr /> 8 | <hr /> 9 | >>> Thematic breaks - 14 10 | +++ 11 | <<< 12 | <p>+++</p> 13 | >>> Thematic breaks - 15 14 | === 15 | <<< 16 | <p>===</p> 17 | >>> Thematic breaks - 16 18 | -- 19 | ** 20 | __ 21 | <<< 22 | <p>-- 23 | ** 24 | __</p> 25 | >>> Thematic breaks - 17 26 | *** 27 | *** 28 | *** 29 | <<< 30 | <hr /> 31 | <hr /> 32 | <hr /> 33 | >>> Thematic breaks - 18 34 | *** 35 | <<< 36 | <pre><code>*** 37 | </code></pre> 38 | >>> Thematic breaks - 19 39 | Foo 40 | *** 41 | <<< 42 | <p>Foo 43 | ***</p> 44 | >>> Thematic breaks - 20 45 | _____________________________________ 46 | <<< 47 | <hr /> 48 | >>> Thematic breaks - 21 49 | - - - 50 | <<< 51 | <hr /> 52 | >>> Thematic breaks - 22 53 | ** * ** * ** * ** 54 | <<< 55 | <hr /> 56 | >>> Thematic breaks - 23 57 | - - - - 58 | <<< 59 | <hr /> 60 | >>> Thematic breaks - 24 61 | - - - - 62 | <<< 63 | <hr /> 64 | >>> Thematic breaks - 25 65 | _ _ _ _ a 66 | 67 | a------ 68 | 69 | ---a--- 70 | <<< 71 | <p>_ _ _ _ a</p> 72 | <p>a------</p> 73 | <p>---a---</p> 74 | >>> Thematic breaks - 26 75 | *-* 76 | <<< 77 | <p><em>-</em></p> 78 | >>> Thematic breaks - 27 79 | - foo 80 | *** 81 | - bar 82 | <<< 83 | <ul> 84 | <li>foo</li> 85 | </ul> 86 | <hr /> 87 | <ul> 88 | <li>bar</li> 89 | </ul> 90 | >>> Thematic breaks - 28 91 | Foo 92 | *** 93 | bar 94 | <<< 95 | <p>Foo</p> 96 | <hr /> 97 | <p>bar</p> 98 | >>> Thematic breaks - 29 99 | Foo 100 | --- 101 | bar 102 | <<< 103 | <h2>Foo</h2> 104 | <p>bar</p> 105 | >>> Thematic breaks - 30 106 | * Foo 107 | * * * 108 | * Bar 109 | <<< 110 | <ul> 111 | <li>Foo</li> 112 | </ul> 113 | <hr /> 114 | <ul> 115 | <li>Bar</li> 116 | </ul> 117 | >>> Thematic breaks - 31 118 | - Foo 119 | - * * * 120 | <<< 121 | <ul> 122 | <li>Foo</li> 123 | <li> 124 | <hr /> 125 | </li> 126 | </ul> 127 | -------------------------------------------------------------------------------- /test/html_renderer_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import 'package:markdown/markdown.dart'; 6 | import 'package:test/test.dart'; 7 | 8 | void main() { 9 | group('markdownToHtml', () { 10 | const text = '# Hello **Markdown<em>!</em>**\n***'; 11 | 12 | test('with no syntaxes', () { 13 | final result = markdownToHtml( 14 | text, 15 | withDefaultBlockSyntaxes: false, 16 | withDefaultInlineSyntaxes: false, 17 | encodeHtml: false, 18 | ); 19 | expect(result, equals('# Hello **Markdown<em>!</em>**\n***\n')); 20 | }); 21 | 22 | test('with no default syntaxes but with custom syntaxes', () { 23 | final result = markdownToHtml( 24 | text, 25 | withDefaultBlockSyntaxes: false, 26 | withDefaultInlineSyntaxes: false, 27 | encodeHtml: false, 28 | blockSyntaxes: [const HorizontalRuleSyntax()], 29 | inlineSyntaxes: [ 30 | EmphasisSyntax.asterisk(), 31 | ], 32 | ); 33 | 34 | expect( 35 | result, 36 | equals('# Hello <strong>Markdown<em>!</em></strong>\n<hr />\n'), 37 | ); 38 | }); 39 | 40 | test('with only default block syntaxes', () { 41 | final result = markdownToHtml( 42 | text, 43 | withDefaultInlineSyntaxes: false, 44 | encodeHtml: false, 45 | ); 46 | 47 | expect( 48 | result, 49 | equals('<h1>Hello **Markdown<em>!</em>**</h1>\n<hr />\n'), 50 | ); 51 | }); 52 | 53 | test('with only default inline syntaxes', () { 54 | final result = markdownToHtml( 55 | text, 56 | withDefaultBlockSyntaxes: false, 57 | encodeHtml: false, 58 | ); 59 | 60 | expect( 61 | result, 62 | equals('# Hello <strong>Markdown<em>!</em></strong>\n***\n'), 63 | ); 64 | }); 65 | 66 | test('with no default syntaxes but with encodeHtml enabled', () { 67 | final result = markdownToHtml( 68 | text, 69 | withDefaultBlockSyntaxes: false, 70 | withDefaultInlineSyntaxes: false, 71 | ); 72 | 73 | expect( 74 | result, 75 | equals('# Hello **Markdown<em>!</em>**\n***\n'), 76 | ); 77 | }); 78 | }); 79 | 80 | group('test InlineSyntax caseSensitive parameter', () { 81 | const text = 'one BREAK two'; 82 | 83 | test('with caseSensitive enabled', () { 84 | final result = markdownToHtml( 85 | text, 86 | inlineOnly: true, 87 | inlineSyntaxes: [_BreakSyntax(true)], 88 | ); 89 | 90 | expect(result, equals('one BREAK two')); 91 | }); 92 | 93 | test('with caseSensitive disabled', () { 94 | final result = markdownToHtml( 95 | text, 96 | inlineOnly: true, 97 | inlineSyntaxes: [_BreakSyntax(false)], 98 | ); 99 | 100 | expect(result, equals('one <break /> two')); 101 | }); 102 | }); 103 | } 104 | 105 | class _BreakSyntax extends InlineSyntax { 106 | _BreakSyntax(bool caseSensitive) 107 | : super('break', caseSensitive: caseSensitive); 108 | 109 | @override 110 | bool onMatch(InlineParser parser, Match match) { 111 | parser.addNode(Element.empty('break')); 112 | return true; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /test/original/autolinks.unit: -------------------------------------------------------------------------------- 1 | >>> basic link 2 | before <http://foo.com/> after 3 | 4 | <<< 5 | <p>before <a href="http://foo.com/">http://foo.com/</a> after</p> 6 | >>> handles ampersand in url 7 | <http://foo.com/?a=1&b=2> 8 | 9 | <<< 10 | <p><a href="http://foo.com/?a=1&b=2">http://foo.com/?a=1&b=2</a></p> 11 | -------------------------------------------------------------------------------- /test/original/backslash_escapes.unit: -------------------------------------------------------------------------------- 1 | >>> Escaped punctuation is indeed escaped. 2 | Punctuations like \! and \" and \# and \$ and \% and \& and \' and \( and \) 3 | and \* and \+ and \, and \- and \. and \/ and \: and \; and \< and \= and \> 4 | and \? and \@ and \[ and \\ and \] and \^ and \_ and \` and \{ and \| and \} 5 | and \~. 6 | 7 | <<< 8 | <p>Punctuations like ! and " and # and $ and % and & and ' and ( and ) 9 | and * and + and , and - and . and / and : and ; and < and = and > 10 | and ? and @ and [ and \ and ] and ^ and _ and ` and { and | and } 11 | and ~.</p> 12 | >>> Inline code blocks can be escaped. 13 | Not \`code`. 14 | 15 | <<< 16 | <p>Not `code`.</p> 17 | >>> Emphasis can be escaped. 18 | \*Both* \_kinds_. 19 | 20 | <<< 21 | <p>*Both* _kinds_.</p> 22 | >>> Links can be escaped. 23 | Escaped brackets: \[foo](bar), and parens: [foo]\(bar). 24 | 25 | <<< 26 | <p>Escaped brackets: [foo](bar), and parens: [foo](bar).</p> 27 | >>> Reference links can be escaped. 28 | Front: \[foo][bar] and back: [foo]\[bar]. 29 | 30 | <<< 31 | <p>Front: [foo][bar] and back: [foo][bar].</p> 32 | >>> Images can be escaped. 33 | Escapes the bang: \![img](img.png), 34 | and escapes the image: !\[img](img.png). 35 | 36 | <<< 37 | <p>Escapes the bang: !<a href="img.png">img</a>, 38 | and escapes the image: ![img](img.png).</p> 39 | -------------------------------------------------------------------------------- /test/original/block_level_html.unit: -------------------------------------------------------------------------------- 1 | >>> single line 2 | <table></table> 3 | 4 | <<< 5 | <table></table> 6 | >>> multi-line 7 | <table> 8 | blah 9 | </table> 10 | 11 | <<< 12 | <table> 13 | blah 14 | </table> 15 | >>> blank line ends block 16 | <table> 17 | blah 18 | </table> 19 | 20 | para 21 | 22 | <<< 23 | <table> 24 | blah 25 | </table> 26 | <p>para</p> 27 | >>> HTML can be bogus 28 | <bogus> 29 | blah 30 | </weird> 31 | 32 | para 33 | 34 | <<< 35 | <bogus> 36 | blah 37 | </weird> 38 | <p>para</p> 39 | -------------------------------------------------------------------------------- /test/original/block_quotes.unit: -------------------------------------------------------------------------------- 1 | >>> single line 2 | > blah 3 | 4 | <<< 5 | <blockquote> 6 | <p>blah</p> 7 | </blockquote> 8 | >>> with two paragraphs 9 | > first 10 | > 11 | > second 12 | 13 | <<< 14 | <blockquote> 15 | <p>first</p> 16 | <p>second</p> 17 | </blockquote> 18 | >>> nested 19 | > one 20 | >> two 21 | > > > three 22 | 23 | <<< 24 | <blockquote> 25 | <p>one</p> 26 | <blockquote> 27 | <p>two</p> 28 | <blockquote> 29 | <p>three</p> 30 | </blockquote> 31 | </blockquote> 32 | </blockquote> 33 | >>> qoute with lazy continuation 34 | > quote 35 | text 36 | <<< 37 | <blockquote> 38 | <p>quote 39 | text</p> 40 | </blockquote> 41 | >>> quote turns what might be an h2 into an hr 42 | > quote 43 | --- 44 | 45 | <<< 46 | <blockquote> 47 | <p>quote</p> 48 | </blockquote> 49 | <hr /> 50 | >>> issue #495 51 | > 52 | <<< 53 | <blockquote> 54 | </blockquote> 55 | -------------------------------------------------------------------------------- /test/original/code_blocks.unit: -------------------------------------------------------------------------------- 1 | >>> single line 2 | code 3 | 4 | <<< 5 | <pre><code>code 6 | </code></pre> 7 | >>> include leading whitespace after indentation 8 | zero 9 | one 10 | two 11 | three 12 | 13 | <<< 14 | <pre><code>zero 15 | one 16 | two 17 | three 18 | </code></pre> 19 | >>> code blocks separated by newlines form one block 20 | zero 21 | one 22 | 23 | two 24 | 25 | three 26 | 27 | <<< 28 | <pre><code>zero 29 | one 30 | 31 | two 32 | 33 | three 34 | </code></pre> 35 | >>> code blocks separated by two newlines form multiple blocks 36 | zero 37 | one 38 | 39 | 40 | two 41 | 42 | 43 | three 44 | 45 | <<< 46 | <pre><code>zero 47 | one 48 | 49 | 50 | two 51 | 52 | 53 | three 54 | </code></pre> 55 | >>> escape HTML characters 56 | <&> 57 | 58 | <<< 59 | <pre><code><&> 60 | </code></pre> 61 | >>> issue #497 62 | 'foo' 63 | <<< 64 | <pre><code>'foo' 65 | </code></pre> 66 | -------------------------------------------------------------------------------- /test/original/emphasis_and_strong.unit: -------------------------------------------------------------------------------- 1 | >>> single asterisks 2 | before *em* after 3 | 4 | <<< 5 | <p>before <em>em</em> after</p> 6 | >>> single underscores 7 | before _em_ after 8 | 9 | <<< 10 | <p>before <em>em</em> after</p> 11 | >>> double asterisks 12 | before **strong** after 13 | 14 | <<< 15 | <p>before <strong>strong</strong> after</p> 16 | >>> double underscores 17 | before __strong__ after 18 | 19 | <<< 20 | <p>before <strong>strong</strong> after</p> 21 | >>> unmatched asterisk 22 | before *after 23 | 24 | <<< 25 | <p>before *after</p> 26 | >>> unmatched underscore 27 | before _after 28 | 29 | <<< 30 | <p>before _after</p> 31 | >>> multiple spans in one text 32 | a *one* b _two_ c 33 | 34 | <<< 35 | <p>a <em>one</em> b <em>two</em> c</p> 36 | >>> multi-line 37 | before *first 38 | second* after 39 | 40 | <<< 41 | <p>before <em>first 42 | second</em> after</p> 43 | >>> not processed when surrounded by spaces 44 | a * b * c _ d _ e 45 | 46 | <<< 47 | <p>a * b * c _ d _ e</p> 48 | >>> strong then emphasis 49 | **strong***em* 50 | 51 | <<< 52 | <p><strong>strong</strong><em>em</em></p> 53 | >>> emphasis then strong 54 | *em***strong** 55 | 56 | <<< 57 | <p><em>em</em><strong>strong</strong></p> 58 | >>> emphasis inside strong 59 | **strong *em*** 60 | 61 | <<< 62 | <p><strong>strong <em>em</em></strong></p> 63 | >>> mismatched in nested 64 | *a _b* c_ 65 | 66 | <<< 67 | <p><em>a _b</em> c_</p> 68 | >>> in the middle of a word 69 | a_b_c a__b__c a*b*c a**b**c 70 | <<< 71 | <p>a_b_c a__b__c a<em>b</em>c a<strong>b</strong>c</p> 72 | >>> prefixing a word 73 | _a_b __a__b *a*b **a**b 74 | <<< 75 | <p>_a_b __a__b <em>a</em>b <strong>a</strong>b</p> 76 | >>> suffixing a word 77 | a_b_ a__b__ a*b* a**b** 78 | <<< 79 | <p>a_b_ a__b__ a<em>b</em> a<strong>b</strong></p> 80 | >>> spanning words 81 | _a_b c_d_ __a__b c__d__ *a*b c*d* **a**b c**d** 82 | <<< 83 | <p><em>a_b c_d</em> <strong>a__b c__d</strong> <em>a</em>b c<em>d</em> <strong>a</strong>b c<strong>d</strong></p> 84 | -------------------------------------------------------------------------------- /test/original/fenced_code_block.unit: -------------------------------------------------------------------------------- 1 | >>> issue #497 2 | ``` 3 | 'foo' 4 | ``` 5 | <<< 6 | <pre><code>'foo' 7 | </code></pre> 8 | -------------------------------------------------------------------------------- /test/original/hard_line_breaks.unit: -------------------------------------------------------------------------------- 1 | >>> hard line break in a paragraph, using backslash 2 | First line.\ 3 | Second line. 4 | 5 | <<< 6 | <p>First line.<br /> 7 | Second line.</p> 8 | >>> within emphasis, using backslash 9 | *Emphasised\ 10 | text.* 11 | 12 | <<< 13 | <p><em>Emphasised<br /> 14 | text.</em></p> 15 | >>> no escape within code, using backslash 16 | `Some\ 17 | code`. 18 | 19 | <<< 20 | <p><code>Some\ code</code>.</p> 21 | >>> hard line break in a paragraph, using trailing spaces 22 | First line. 23 | Second line. 24 | 25 | <<< 26 | <p>First line. 27 | Second line.</p> 28 | >>> within emphasis, using trailing spaces 29 | *Emphasised 30 | text.* 31 | 32 | <<< 33 | <p><em>Emphasised 34 | text.</em></p> 35 | >>> no escape within code, using trailing spaces 36 | `Some 37 | code`. 38 | 39 | <<< 40 | <p><code>Some code</code>.</p> 41 | -------------------------------------------------------------------------------- /test/original/headers.unit: -------------------------------------------------------------------------------- 1 | >>> h1 2 | # header 3 | 4 | <<< 5 | <h1>header</h1> 6 | >>> h2 7 | ## header 8 | 9 | <<< 10 | <h2>header</h2> 11 | >>> h3 12 | ### header 13 | 14 | <<< 15 | <h3>header</h3> 16 | >>> h4 17 | #### header 18 | 19 | <<< 20 | <h4>header</h4> 21 | >>> h5 22 | ##### header 23 | 24 | <<< 25 | <h5>header</h5> 26 | >>> h6 27 | ###### header 28 | 29 | <<< 30 | <h6>header</h6> 31 | >>> trailing "#" are removed 32 | # header ###### 33 | 34 | <<< 35 | <h1>header</h1> 36 | -------------------------------------------------------------------------------- /test/original/horizontal_rules.unit: -------------------------------------------------------------------------------- 1 | >>> from dashes 2 | --- 3 | 4 | <<< 5 | <hr /> 6 | >>> from asterisks 7 | *** 8 | 9 | <<< 10 | <hr /> 11 | >>> from underscores 12 | ___ 13 | 14 | <<< 15 | <hr /> 16 | >>> can include up to two spaces 17 | _ _ _ 18 | 19 | <<< 20 | <hr /> 21 | -------------------------------------------------------------------------------- /test/original/html_block.unit: -------------------------------------------------------------------------------- 1 | >>> issue https://github.com/dart-lang/markdown/issues/547 2 | <?code-excerpt ?> 3 | ```xml 4 | <q> 5 | </q> 6 | ``` 7 | <<< 8 | <?code-excerpt ?> 9 | <pre><code class="language-xml"><q> 10 | </q> 11 | </code></pre> -------------------------------------------------------------------------------- /test/original/html_encoding.unit: -------------------------------------------------------------------------------- 1 | >>> less than and ampersand are escaped 2 | < & 3 | 4 | <<< 5 | <p>< &</p> 6 | >>> greater than is escaped 7 | not you > 8 | 9 | <<< 10 | <p>not you ></p> 11 | >>> existing entities are untouched 12 | & 13 | 14 | <<< 15 | <p>&</p> 16 | -------------------------------------------------------------------------------- /test/original/inline_code.unit: -------------------------------------------------------------------------------- 1 | >>> simple case 2 | before `source` after 3 | 4 | <<< 5 | <p>before <code>source</code> after</p> 6 | >>> single characters 7 | before `x` and `_` after 8 | 9 | <<< 10 | <p>before <code>x</code> and <code>_</code> after</p> 11 | >>> unmatched backtick 12 | before ` after 13 | 14 | <<< 15 | <p>before ` after</p> 16 | >>> multiple spans in one text 17 | a `one` b `two` c 18 | 19 | <<< 20 | <p>a <code>one</code> b <code>two</code> c</p> 21 | >>> multi-line 22 | before `first 23 | second` after 24 | 25 | <<< 26 | <p>before <code>first second</code> after</p> 27 | >>> simple double backticks 28 | before ``source`` after 29 | 30 | <<< 31 | <p>before <code>source</code> after</p> 32 | >>> even more backticks 33 | before ````source with ``` and```` after 34 | 35 | <<< 36 | <p>before <code>source with ``` and</code> after</p> 37 | >>> double backticks 38 | before ``can `contain` backticks`` after 39 | 40 | <<< 41 | <p>before <code>can `contain` backticks</code> after</p> 42 | >>> double backticks with spaces 43 | before `` `tick` `` after 44 | 45 | <<< 46 | <p>before <code>`tick`</code> after</p> 47 | >>> multiline single backticks with spaces 48 | before `in tick 49 | another` after 50 | 51 | <<< 52 | <p>before <code>in tick another</code> after</p> 53 | >>> multiline double backticks with spaces 54 | before ``in `tick` 55 | another`` after 56 | 57 | <<< 58 | <p>before <code>in `tick` another</code> after</p> 59 | >>> ignore markup inside code 60 | before `*b* _c_` after 61 | 62 | <<< 63 | <p>before <code>*b* _c_</code> after</p> 64 | >>> escape HTML characters 65 | `<&>` 66 | 67 | <<< 68 | <p><code><&></code></p> 69 | >>> escape HTML tags 70 | '*' `<em>` 71 | 72 | <<< 73 | <p>'*' <code><em></code></p> 74 | >>> leave unmatched backticks when first are too long 75 | before ``` tick `` after 76 | 77 | <<< 78 | <p>before ``` tick `` after</p> 79 | >>> leave unmatched backticks when first are too short 80 | before `` tick ``` after 81 | 82 | <<< 83 | <p>before `` tick ``` after</p> 84 | >>> issue #497 85 | `'foo'` 86 | <<< 87 | <p><code>'foo'</code></p> 88 | -------------------------------------------------------------------------------- /test/original/inline_images.unit: -------------------------------------------------------------------------------- 1 | >>> image 2 | ![](http://foo.com/foo.png) 3 | 4 | <<< 5 | <p><img src="http://foo.com/foo.png" alt="" /></p> 6 | >>> alternate text 7 | ![alternate text](http://foo.com/foo.png) 8 | 9 | <<< 10 | <p><img src="http://foo.com/foo.png" alt="alternate text" /></p> 11 | >>> title 12 | ![](http://foo.com/foo.png "optional title") 13 | 14 | <<< 15 | <p><img src="http://foo.com/foo.png" alt="" title="optional title" /></p> 16 | >>> invalid alt text 17 | ![`alt`](http://foo.com/foo.png) 18 | 19 | <<< 20 | <p><img src="http://foo.com/foo.png" alt="alt" /></p> 21 | >>> XSS 22 | ![Uh oh...]("onerror="alert('XSS')) 23 | 24 | <<< 25 | <p><img src="%22onerror=%22alert('XSS')" alt="Uh oh..." /></p> 26 | >>> URL-escaping should be left alone inside the destination 27 | ![](https://example/foo%2Fvar) 28 | <<< 29 | <p><img src="https://example/foo%2Fvar" alt="" /></p> -------------------------------------------------------------------------------- /test/original/inline_links.unit: -------------------------------------------------------------------------------- 1 | >>> double quotes for title 2 | links [are](http://foo.com "woo") awesome 3 | 4 | <<< 5 | <p>links <a href="http://foo.com" title="woo">are</a> awesome</p> 6 | >>> no title 7 | links [are](http://foo.com) awesome 8 | 9 | <<< 10 | <p>links <a href="http://foo.com">are</a> awesome</p> 11 | >>> can style link contents 12 | links [*are*](http://foo.com) awesome 13 | 14 | <<< 15 | <p>links <a href="http://foo.com"><em>are</em></a> awesome</p> 16 | >>> image inside link 17 | links [![](/are.png)](http://foo.com) awesome 18 | 19 | <<< 20 | <p>links <a href="http://foo.com"><img src="/are.png" alt="" /></a> awesome</p> 21 | >>> image with alt inside link 22 | links [![my alt](/are.png)](http://foo.com) awesome 23 | 24 | <<< 25 | <p>links <a href="http://foo.com"><img src="/are.png" alt="my alt" /></a> awesome</p> 26 | >>> image with title inside link 27 | links [![](/are.png "my title")](http://foo.com) awesome 28 | 29 | <<< 30 | <p>links <a href="http://foo.com"><img src="/are.png" alt="" title="my title" /></a> awesome</p> 31 | >>> no URL 32 | links [are]() awesome 33 | 34 | <<< 35 | <p>links <a href="">are</a> awesome</p> 36 | >>> URL wrapped in angle brackets 37 | links [are](<http://example.com>) awesome 38 | 39 | <<< 40 | <p>links <a href="http://example.com">are</a> awesome</p> 41 | >>> URL wrapped in angle brackets with a title; https://github.com/commonmark/CommonMark/issues/521 42 | links [are](<http://example.com> "title") awesome 43 | 44 | <<< 45 | <p>links <a href="http://example.com" title="title">are</a> awesome</p> 46 | >>> multi-line link 47 | links [are 48 | awesome](<http://example.com>). 49 | 50 | <<< 51 | <p>links <a href="http://example.com">are 52 | awesome</a>.</p> 53 | >>> multi-line link with a title 54 | links [are](http://foo.com 55 | "woo") awesome 56 | 57 | <<< 58 | <p>links <a href="http://foo.com" title="woo">are</a> awesome</p> 59 | >>> not a real link 60 | links [are] (http://foo.com) awesome 61 | 62 | <<< 63 | <p>links [are] (http://foo.com) awesome</p> 64 | >>> resolver link without a resolver 65 | links [are *awesome*] 66 | 67 | <<< 68 | <p>links [are <em>awesome</em>]</p> 69 | >>> links with escaped parens 70 | [a](\(yes-a-link) 71 | [a](\(yes-a-link\)) 72 | [a](\\(not-a-link\)) 73 | [a](\\(yes-a-link\))) 74 | <<< 75 | <p><a href="(yes-a-link">a</a> 76 | <a href="(yes-a-link)">a</a> 77 | [a](\(not-a-link)) 78 | <a href="(yes-a-link))">a</a></p> 79 | >>> links with unbalanced parentheses 80 | [foo](link(1.png) (what?) 81 | <<< 82 | <p>[foo](link(1.png) (what?)</p> 83 | >>> not an inline link: the title's ending quote is escaped 84 | links [are](<http://example.com> "title\") awesome 85 | 86 | <<< 87 | <p>links [are](<a href="http://example.com">http://example.com</a> "title") awesome</p> -------------------------------------------------------------------------------- /test/original/ordered_lists.unit: -------------------------------------------------------------------------------- 1 | >>> ordered list with multiple items 2 | 1. one 3 | 2. two 4 | 10. ten 5 | <<< 6 | <ol> 7 | <li>one</li> 8 | <li>two</li> 9 | <li>ten</li> 10 | </ol> 11 | >>> ordered list with almost nested item 12 | 1. one 13 | 45. two 14 | 12345. three 15 | 16 | <<< 17 | <ol> 18 | <li>one</li> 19 | <li>two</li> 20 | <li>three</li> 21 | </ol> 22 | >>> nested ordered lists 23 | 1. one 24 | 2. two 25 | 3. three 26 | 4. four 27 | 5. five 28 | <<< 29 | <ol> 30 | <li>one</li> 31 | <li>two 32 | <ol start="3"> 33 | <li>three</li> 34 | <li>four</li> 35 | </ol> 36 | </li> 37 | <li>five</li> 38 | </ol> 39 | >>> new list markers start new lists 40 | 1. a 41 | * b 42 | 43 | <<< 44 | <ol> 45 | <li>a</li> 46 | </ol> 47 | <ul> 48 | <li>b</li> 49 | </ul> 50 | -------------------------------------------------------------------------------- /test/original/paragraphs.unit: -------------------------------------------------------------------------------- 1 | >>> consecutive lines form a single paragraph 2 | This is the first line. 3 | This is the second line. 4 | 5 | <<< 6 | <p>This is the first line. 7 | This is the second line.</p> 8 | >>> are terminated by a header 9 | para 10 | # header 11 | 12 | <<< 13 | <p>para</p> 14 | <h1>header</h1> 15 | >>> are terminated by a hr 16 | para 17 | ___ 18 | 19 | <<< 20 | <p>para</p> 21 | <hr /> 22 | >>> are terminated by an unordered list 23 | para 24 | * list 25 | 26 | <<< 27 | <p>para</p> 28 | <ul> 29 | <li>list</li> 30 | </ul> 31 | >>> are terminated by an ordered list 32 | para 33 | 1. list 34 | 35 | <<< 36 | <p>para</p> 37 | <ol> 38 | <li>list</li> 39 | </ol> 40 | >>> take account of windows line endings 41 | line1 42 | 43 | line2 44 | 45 | 46 | <<< 47 | <p>line1</p> 48 | <p>line2</p> 49 | >>> cannot be terminated by indented code blocks 50 | para 51 | not code 52 | 53 | <<< 54 | <p>para 55 | not code</p> 56 | -------------------------------------------------------------------------------- /test/original/reference_images.unit: -------------------------------------------------------------------------------- 1 | >>> image 2 | ![][foo] 3 | 4 | [foo]: http://foo.com/foo.png 5 | 6 | <<< 7 | <p><img src="http://foo.com/foo.png" alt="" /></p> 8 | >>> alternate text 9 | ![alternate text][foo] 10 | 11 | [foo]: http://foo.com/foo.png 12 | 13 | <<< 14 | <p><img src="http://foo.com/foo.png" alt="alternate text" /></p> 15 | >>> title 16 | ![][foo] 17 | 18 | [foo]: http://foo.com/foo.png "optional title" 19 | 20 | <<< 21 | <p><img src="http://foo.com/foo.png" alt="" title="optional title" /></p> 22 | >>> invalid alt text 23 | ![`alt`][foo] 24 | 25 | [foo]: http://foo.com/foo.png "optional title" 26 | 27 | <<< 28 | <p><img src="http://foo.com/foo.png" alt="alt" title="optional title" /></p> 29 | >>> shortcut reference image 30 | ![foo] 31 | 32 | [foo]: http://foo.com/foo.png 33 | <<< 34 | <p><img src="http://foo.com/foo.png" alt="foo" /></p> 35 | -------------------------------------------------------------------------------- /test/original/reference_links.unit: -------------------------------------------------------------------------------- 1 | >>> double quotes for title 2 | links [are][a] awesome 3 | 4 | [a]: http://foo.com "woo" 5 | 6 | <<< 7 | <p>links <a href="http://foo.com" title="woo">are</a> awesome</p> 8 | >>> single quoted title 9 | links [are][a] awesome 10 | 11 | [a]: http://foo.com 'woo' 12 | 13 | <<< 14 | <p>links <a href="http://foo.com" title="woo">are</a> awesome</p> 15 | >>> parentheses for title 16 | links [are][a] awesome 17 | 18 | [a]: http://foo.com (woo) 19 | 20 | <<< 21 | <p>links <a href="http://foo.com" title="woo">are</a> awesome</p> 22 | >>> no title 23 | links [are][a] awesome 24 | 25 | [a]: http://foo.com 26 | 27 | <<< 28 | <p>links <a href="http://foo.com">are</a> awesome</p> 29 | >>> unknown link becomes plaintext 30 | [not] [known] 31 | 32 | <<< 33 | <p>[not] [known]</p> 34 | >>> can style link contents 35 | links [*are*][a] awesome 36 | 37 | [a]: http://foo.com 38 | 39 | <<< 40 | <p>links <a href="http://foo.com"><em>are</em></a> awesome</p> 41 | >>> inline styles after a bad link are processed 42 | [bad] `code` 43 | 44 | <<< 45 | <p>[bad] <code>code</code></p> 46 | >>> empty reference uses text from link 47 | links [are][] awesome 48 | 49 | [are]: http://foo.com 50 | 51 | <<< 52 | <p>links <a href="http://foo.com">are</a> awesome</p> 53 | >>> references are case-insensitive 54 | links [ARE][] awesome 55 | 56 | [are]: http://foo.com 57 | 58 | <<< 59 | <p>links <a href="http://foo.com">ARE</a> awesome</p> 60 | >>> shortcut reference links 61 | links [are] awesome 62 | 63 | [are]: http://foo.com 64 | <<< 65 | <p>links <a href="http://foo.com">are</a> awesome</p> 66 | >>> reference definitions can span lines 67 | links [are] [awesome] 68 | 69 | [are]: 70 | http://foo.com 71 | [awesome]: 72 | http://bar.com 73 | "Long 74 | Title" 75 | <<< 76 | <p>links <a href="http://foo.com">are</a> <a href="http://bar.com" title="Long 77 | Title">awesome</a></p> 78 | >>> references can be defined in blocks 79 | > links [are] awesome 80 | > 81 | > [are]: http://foo.com 82 | <<< 83 | <blockquote> 84 | <p>links <a href="http://foo.com">are</a> awesome</p> 85 | </blockquote> 86 | >>> reference link regression for github.com/dart-lang/markdown/issues/176 87 | [![Coverage Status][coverage_status]][coverage_page] 88 | 89 | [coverage_page]:https://coveralls.io/github/yeradis/stay_points.dart?branch=master 90 | [coverage_status]: https://coveralls.io/repos/github/yeradis/stay_points.dart/badge.svg?branch=master 91 | <<< 92 | <p><a href="https://coveralls.io/github/yeradis/stay_points.dart?branch=master"><img src="https://coveralls.io/repos/github/yeradis/stay_points.dart/badge.svg?branch=master" alt="Coverage Status" /></a></p> 93 | >>> compressed reference link label is normalized 94 | Text [foo 95 | bar][]. 96 | 97 | [foo bar]: http://bar.com 98 | <<< 99 | <p>Text <a href="http://bar.com">foo 100 | bar</a>.</p> 101 | -------------------------------------------------------------------------------- /test/original/setext_headers.unit: -------------------------------------------------------------------------------- 1 | >>> h1 2 | text 3 | === 4 | 5 | <<< 6 | <h1>text</h1> 7 | >>> h2 8 | text 9 | --- 10 | 11 | <<< 12 | <h2>text</h2> 13 | >>> h1 bar on first line becomes text 14 | === 15 | 16 | <<< 17 | <p>===</p> 18 | >>> h2 bar on first line becomes list 19 | - 20 | 21 | <<< 22 | <ul> 23 | <li></li> 24 | </ul> 25 | >>> can be multiline 26 | header 27 | on two lines 28 | == 29 | 30 | <<< 31 | <h1>header 32 | on two lines</h1> 33 | -------------------------------------------------------------------------------- /test/original/strong.unit: -------------------------------------------------------------------------------- 1 | >>> using asterisks 2 | before **strong** after 3 | 4 | <<< 5 | <p>before <strong>strong</strong> after</p> 6 | >>> using underscores 7 | before __strong__ after 8 | 9 | <<< 10 | <p>before <strong>strong</strong> after</p> 11 | >>> unmatched asterisks 12 | before ** after 13 | 14 | <<< 15 | <p>before ** after</p> 16 | >>> unmatched underscores 17 | before __ after 18 | 19 | <<< 20 | <p>before __ after</p> 21 | >>> multiple spans in one text 22 | a **one** b __two__ c 23 | 24 | <<< 25 | <p>a <strong>one</strong> b <strong>two</strong> c</p> 26 | >>> multi-line 27 | before **first 28 | second** after 29 | 30 | <<< 31 | <p>before <strong>first 32 | second</strong> after</p> 33 | -------------------------------------------------------------------------------- /test/original/unordered_lists.unit: -------------------------------------------------------------------------------- 1 | >>> asterisk, plus and hyphen 2 | * star 3 | - dash 4 | + plus 5 | 6 | <<< 7 | <ul> 8 | <li>star</li> 9 | </ul> 10 | <ul> 11 | <li>dash</li> 12 | </ul> 13 | <ul> 14 | <li>plus</li> 15 | </ul> 16 | >>> new markers begin new lists 17 | * a 18 | 1. b 19 | 20 | <<< 21 | <ul> 22 | <li>a</li> 23 | </ul> 24 | <ol> 25 | <li>b</li> 26 | </ol> 27 | >>> allow a tab after the marker 28 | * a 29 | 1. b 30 | 31 | <<< 32 | <ul> 33 | <li>a</li> 34 | </ul> 35 | <ol> 36 | <li>b</li> 37 | </ol> 38 | >>> wrap items in paragraphs if blank lines separate 39 | * one 40 | 41 | * two 42 | 43 | <<< 44 | <ul> 45 | <li> 46 | <p>one</p> 47 | </li> 48 | <li> 49 | <p>two</p> 50 | </li> 51 | </ul> 52 | >>> force paragraph on item before and after blank lines 53 | * one 54 | * two 55 | 56 | * three 57 | 58 | <<< 59 | <ul> 60 | <li> 61 | <p>one</p> 62 | </li> 63 | <li> 64 | <p>two</p> 65 | </li> 66 | <li> 67 | <p>three</p> 68 | </li> 69 | </ul> 70 | >>> do not force paragraph if item is already block 71 | * > quote 72 | 73 | * # header 74 | 75 | <<< 76 | <ul> 77 | <li> 78 | <blockquote> 79 | <p>quote</p> 80 | </blockquote> 81 | </li> 82 | <li> 83 | <h1>header</h1> 84 | </li> 85 | </ul> 86 | >>> can contain multiple paragraphs 87 | * one 88 | 89 | two 90 | 91 | * three 92 | 93 | <<< 94 | <ul> 95 | <li> 96 | <p>one</p> 97 | <p>two</p> 98 | </li> 99 | <li> 100 | <p>three</p> 101 | </li> 102 | </ul> 103 | >>> can span newlines 104 | * one 105 | two 106 | * three 107 | 108 | <<< 109 | <ul> 110 | <li>one 111 | two</li> 112 | <li>three</li> 113 | </ul> 114 | >>> can nest lists 115 | * one 116 | * nested one 117 | * nested two 118 | 119 | * two 120 | 121 | <<< 122 | <ul> 123 | <li> 124 | <p>one</p> 125 | <ul> 126 | <li>nested one</li> 127 | <li>nested two</li> 128 | </ul> 129 | </li> 130 | <li> 131 | <p>two</p> 132 | </li> 133 | </ul> 134 | >>> list item allows lazy continuations 135 | - list 136 | item 137 | 138 | <<< 139 | <ul> 140 | <li>list 141 | item</li> 142 | </ul> 143 | >>> list item turns what might be an h2 into nothing 144 | - list 145 | --- 146 | 147 | <<< 148 | <ul> 149 | <li>list</li> 150 | </ul> 151 | <hr /> 152 | -------------------------------------------------------------------------------- /test/util_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import 'package:markdown/markdown.dart'; 6 | import 'package:markdown/src/util.dart'; 7 | import 'package:test/test.dart'; 8 | 9 | void main() { 10 | group('String.toLines()', () { 11 | test('a single line without a line ending', () { 12 | const text = 'Foo'; 13 | final lines = text.toLines(); 14 | 15 | expect(lines.map((e) => e.toMap()), [ 16 | { 17 | 'content': 'Foo', 18 | 'isBlankLine': false, 19 | } 20 | ]); 21 | }); 22 | 23 | test('a single line with a line ending', () { 24 | const text = 'Foo\n'; 25 | final lines = text.toLines(); 26 | 27 | expect(lines.map((e) => e.toMap()), [ 28 | { 29 | 'content': 'Foo', 30 | 'isBlankLine': false, 31 | }, 32 | ]); 33 | }); 34 | 35 | test('multiple lines with a blank line in between', () { 36 | const text = 'Foo\r\n\nBar'; 37 | final lines = text.toLines(); 38 | 39 | expect(lines.map((e) => e.toMap()), [ 40 | { 41 | 'content': 'Foo', 42 | 'isBlankLine': false, 43 | }, 44 | { 45 | 'content': '', 46 | 'isBlankLine': true, 47 | }, 48 | { 49 | 'content': 'Bar', 50 | 'isBlankLine': false, 51 | } 52 | ]); 53 | }); 54 | }); 55 | 56 | group('String.indentation()', () { 57 | test('only spaces', () { 58 | expect(' '.indentation(), 3); 59 | expect(' '.indentation(), 4); 60 | expect(' '.indentation(), 5); 61 | }); 62 | 63 | test('spaces and tabs', () { 64 | expect('\t '.indentation(), 6); 65 | expect(' \t '.indentation(), 5); 66 | expect(' \t'.indentation(), 4); 67 | expect('\t\t '.indentation(), 10); 68 | expect(' \t\t '.indentation(), 9); 69 | expect(' \t\t'.indentation(), 8); 70 | }); 71 | 72 | test('spaces, tabs and non whitespace characters', () { 73 | expect('\t foo'.indentation(), 6); 74 | expect(' \t foo'.indentation(), 5); 75 | expect(' \tfoo'.indentation(), 4); 76 | }); 77 | }); 78 | } 79 | 80 | extension on Line { 81 | Map<String, dynamic> toMap() => { 82 | 'content': content, 83 | 'isBlankLine': isBlankLine, 84 | if (tabRemaining != null) 'tabRemaining': tabRemaining, 85 | }; 86 | } 87 | -------------------------------------------------------------------------------- /test/version_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | @TestOn('vm') 6 | library; 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:path/path.dart' as p; 11 | import 'package:test/test.dart'; 12 | import 'package:yaml/yaml.dart'; 13 | 14 | void main() { 15 | test('check versions', () async { 16 | final binary = p.join(p.current, 'bin', 'markdown.dart'); 17 | final dartBin = Platform.executable; 18 | final result = Process.runSync(dartBin, [binary, '--version']); 19 | expect( 20 | result.exitCode, 21 | 0, 22 | reason: 'Exit code expected: 0; actual: ${result.exitCode}\n\n' 23 | 'stdout: ${result.stdout}\n\n' 24 | 'stderr: ${result.stderr}', 25 | ); 26 | 27 | final binVersion = (result.stdout as String).trim(); 28 | 29 | final pubspecFile = p.join(p.current, 'pubspec.yaml'); 30 | 31 | final pubspecContent = 32 | loadYaml(File(pubspecFile).readAsStringSync()) as YamlMap; 33 | 34 | expect( 35 | binVersion, 36 | pubspecContent['version'], 37 | reason: 'The version reported by bin/markdown.dart should match the ' 38 | 'version in pubspec. Run `dart run build_runner build` to update.', 39 | ); 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /tool/README.md: -------------------------------------------------------------------------------- 1 | # Developer Tools 2 | 3 | This directory contains tools for developers of the Dart markdown package. 4 | 5 | ## dartdoc_compare.dart 6 | 7 | When you make a change to the package that might have subtle consequences on 8 | how Markdown is parsed, it would be really great to see how your output compares 9 | to the previous output, on a large collection of Markdown. 10 | 11 | One such collection is the Dartdoc comments of any Dart package, which [dartdoc] 12 | translates into HTML, with the help of this markdown package. You can use the 13 | `dartdoc_compare.dart` script to compare what changes your code will make to 14 | dartdoc's output. Here's how it works: 15 | 16 | 1. Clone the [dartdoc git repository]. 17 | 2. Get a copy of some Dart code that you would like to use for the comparison. 18 | 3. Run the `dartdoc_compare.dart` script like so: 19 | 20 | ``` 21 | $ dart tool/dartdoc_compare.dart \ 22 | --dartdoc-dir=<dartdoc repo> \ 23 | --before=<git SHA of "previous" code> \ 24 | <directory of dart code for comparison> 25 | ``` 26 | 27 | 4. The tool will then walk through the following steps: 28 | 29 | 1. cd into the dartdoc directory, change `pubspec.yaml` to depend on your 30 | "before" version of markdown, and run `pub get`. 31 | 2. cd into the directory of dart code, and run `pub get`. 32 | 3. Run dartdoc. 33 | 4. cd back into the dartdoc directory, change `pubspec.yaml` to depend on 34 | your "after" version of markdown (defaults to HEAD), and run `pub get`. 35 | 5. Repeat steps 2 and 3. 36 | 6. Diff the output of steps 3 and 5, and show you how to diff it yourself. 37 | 38 | [dartdoc]: https://pub.dev/packages/dartdoc 39 | [dartdoc git repository]: https://github.com/dart-lang/dartdoc 40 | 41 | ## stats.dart 42 | 43 | In an effort to make this package CommonMark-compliant, we have a script that 44 | runs the package through the CommonMark specs. To see help: 45 | 46 | ```bash 47 | $ dart tool/stats.dart --help 48 | ``` 49 | -------------------------------------------------------------------------------- /tool/common_mark_stats.txt: -------------------------------------------------------------------------------- 1 | 18 of 18 – 100.0% ATX headings 2 | 19 of 19 – 100.0% Autolinks 3 | 13 of 13 – 100.0% Backslash escapes 4 | 1 of 1 – 100.0% Blank lines 5 | 25 of 25 – 100.0% Block quotes 6 | 22 of 22 – 100.0% Code spans 7 | 131 of 132 – 99.2% Emphasis and strong emphasis 8 | 17 of 17 – 100.0% Entity and numeric character references 9 | 29 of 29 – 100.0% Fenced code blocks 10 | 15 of 15 – 100.0% Hard line breaks 11 | 44 of 44 – 100.0% HTML blocks 12 | 22 of 22 – 100.0% Images 13 | 12 of 12 – 100.0% Indented code blocks 14 | 1 of 1 – 100.0% Inlines 15 | 27 of 27 – 100.0% Link reference definitions 16 | 90 of 90 – 100.0% Links 17 | 48 of 48 – 100.0% List items 18 | 26 of 26 – 100.0% Lists 19 | 8 of 8 – 100.0% Paragraphs 20 | 1 of 1 – 100.0% Precedence 21 | 20 of 20 – 100.0% Raw HTML 22 | 27 of 27 – 100.0% Setext headings 23 | 2 of 2 – 100.0% Soft line breaks 24 | 11 of 11 – 100.0% Tabs 25 | 3 of 3 – 100.0% Textual content 26 | 19 of 19 – 100.0% Thematic breaks 27 | 651 of 652 – 99.8% TOTAL 28 | 643 of 651 – 98.8% TOTAL Strict 29 | -------------------------------------------------------------------------------- /tool/gfm_stats.txt: -------------------------------------------------------------------------------- 1 | 18 of 18 – 100.0% ATX headings 2 | 19 of 19 – 100.0% Autolinks 3 | 11 of 11 – 100.0% Autolinks (extension) 4 | 13 of 13 – 100.0% Backslash escapes 5 | 1 of 1 – 100.0% Blank lines 6 | 25 of 25 – 100.0% Block quotes 7 | 22 of 22 – 100.0% Code spans 8 | 1 of 1 – 100.0% Disallowed Raw HTML (extension) 9 | 131 of 131 – 100.0% Emphasis and strong emphasis 10 | 17 of 17 – 100.0% Entity and numeric character references 11 | 29 of 29 – 100.0% Fenced code blocks 12 | 15 of 15 – 100.0% Hard line breaks 13 | 43 of 43 – 100.0% HTML blocks 14 | 22 of 22 – 100.0% Images 15 | 12 of 12 – 100.0% Indented code blocks 16 | 1 of 1 – 100.0% Inlines 17 | 28 of 28 – 100.0% Link reference definitions 18 | 87 of 87 – 100.0% Links 19 | 48 of 48 – 100.0% List items 20 | 26 of 26 – 100.0% Lists 21 | 8 of 8 – 100.0% Paragraphs 22 | 1 of 1 – 100.0% Precedence 23 | 20 of 20 – 100.0% Raw HTML 24 | 27 of 27 – 100.0% Setext headings 25 | 2 of 2 – 100.0% Soft line breaks 26 | 2 of 2 – 100.0% Strikethrough (extension) 27 | 8 of 8 – 100.0% Tables (extension) 28 | 11 of 11 – 100.0% Tabs 29 | 3 of 3 – 100.0% Textual content 30 | 19 of 19 – 100.0% Thematic breaks 31 | 670 of 670 – 100.0% TOTAL 32 | 660 of 670 – 98.5% TOTAL Strict 33 | -------------------------------------------------------------------------------- /tool/update-gh-pages.sh: -------------------------------------------------------------------------------- 1 | # Echo every command being run. 2 | set +x 3 | 4 | # Fail fast if a command fails. 5 | set -e 6 | 7 | dart pub global activate peanut 8 | 9 | peanut -d example 10 | 11 | echo Now push updated gh-pages branch with: 12 | echo 13 | echo ' git push origin --set-upstream gh-pages' 14 | -------------------------------------------------------------------------------- /tool/update_blns.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | 4 | import 'update_shared.dart'; 5 | 6 | const _blnsJsonRawUrl = 7 | 'https://github.com/minimaxir/big-list-of-naughty-strings/raw/master/blns.json'; 8 | const _blnsFilePath = 'test/blns.dart'; 9 | 10 | Future<void> main() async { 11 | final json = (await downloadJson(_blnsJsonRawUrl) as List).cast<String>(); 12 | final blnsContent = StringBuffer(''' 13 | // GENERATED FILE. DO NOT EDIT. 14 | // 15 | // This file was generated from big-list-of-naughty-strings's JSON file: 16 | // $_blnsJsonRawUrl 17 | // at ${DateTime.now()} by the script, tool/update_blns.dart. 18 | 19 | // ignore_for_file: text_direction_code_point_in_literal, use_raw_strings 20 | // ignore_for_file: lines_longer_than_80_chars 21 | 22 | '''); 23 | blnsContent.writeln('const blns = <String>['); 24 | for (final str in json) { 25 | final escaped = str 26 | .replaceAll(r'\', r'\\') 27 | .replaceAll("'", r"\'") 28 | .replaceAll(r'$', r'\$'); 29 | blnsContent.writeln(" '$escaped',"); 30 | } 31 | blnsContent.writeln('];'); 32 | File(_blnsFilePath).writeAsStringSync(blnsContent.toString()); 33 | } 34 | -------------------------------------------------------------------------------- /tool/update_case_folding.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import 'dart:convert'; 6 | import 'dart:io'; 7 | 8 | import 'package:path/path.dart' as p; 9 | 10 | // Generates and updates unicode case folding map. 11 | // Here only extract status C + F capital letters. 12 | void main() { 13 | // Downloaded from http://www.unicode.org/Public/14.0.0/ucd/CaseFolding.txt 14 | final file = File('${p.current}/tool/case_folding.txt'); 15 | 16 | final result = <String, String>{}; 17 | 18 | for (final line in file.readAsLinesSync()) { 19 | if (line.startsWith('#') || 20 | line.trim().isEmpty || 21 | !line.contains('CAPITAL LETTER')) { 22 | continue; 23 | } 24 | 25 | final content = line.substring(0, line.indexOf('#')); 26 | final match = 27 | RegExp(r'([0-9A-F]{1,6});\s+[CF];\s+(.+);').firstMatch(content); 28 | if (match == null) { 29 | continue; 30 | } 31 | 32 | final key = String.fromCharCode(int.parse(match[1]!, radix: 16)); 33 | final value = match[2]!.split(RegExp('[ ]+')).map((e) { 34 | return String.fromCharCode(int.parse(e, radix: 16)); 35 | }).join(); 36 | result[key] = value; 37 | } 38 | 39 | final outputPath = '${p.current}/lib/src/assets/case_folding.dart'; 40 | final stringMap = const JsonEncoder.withIndent(' ').convert(result); 41 | final output = ''' 42 | // Generated file. do not edit. 43 | // 44 | // Source: tool/case_folding.txt 45 | // Script: tool/update_case_folding.dart 46 | // ignore_for_file: prefer_single_quotes 47 | 48 | const caseFoldingMap = $stringMap; 49 | '''; 50 | File(outputPath).writeAsStringSync(output); 51 | } 52 | -------------------------------------------------------------------------------- /tool/update_emojis.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import 'dart:async'; 6 | import 'dart:io'; 7 | 8 | import 'update_shared.dart'; 9 | 10 | // update_github_emojis.dart now generates the emoji list using the GitHub API 11 | // to retrieve the emoji list. It uses this emoji source as a source to keep 12 | // binary compatibility with the Unicode sequences for each emoji found here. 13 | const _emojisJsonRawUrl = 14 | 'https://raw.githubusercontent.com/muan/emojilib/v2.4.0/emojis.json'; 15 | const _emojisFilePath = 'lib/src/legacy_emojis.dart'; 16 | 17 | Future<void> main() async { 18 | final json = 19 | (await downloadJson(_emojisJsonRawUrl) as Map<String, dynamic>).map( 20 | (String alias, dynamic info) => 21 | MapEntry(alias, info as Map<String, dynamic>), 22 | ); 23 | final emojisContent = StringBuffer(''' 24 | // GENERATED FILE. DO NOT EDIT. 25 | // 26 | // This file was generated from emojilib's emoji data file: 27 | // $_emojisJsonRawUrl 28 | // at ${DateTime.now()} by the script, tool/update_emojis.dart. 29 | 30 | '''); 31 | emojisContent.writeln('const emojis = <String, String>{'); 32 | var emojiCount = 0; 33 | final ignored = <String>[]; 34 | // Dump in sorted order now to facilitate comparison with new GitHub emoji. 35 | final sortedKeys = json.keys.toList()..sort(); 36 | for (final alias in sortedKeys) { 37 | final info = json[alias] as Map<String, dynamic>; 38 | if (info['char'] != null) { 39 | emojisContent.writeln(" '$alias': '${info['char']}',"); 40 | emojiCount++; 41 | } else { 42 | ignored.add(alias); 43 | } 44 | } 45 | emojisContent.writeln('};'); 46 | File(_emojisFilePath).writeAsStringSync(emojisContent.toString()); 47 | print( 48 | 'WARNING: This updates only the LEGACY emoji - to update the active ' 49 | 'emoji recognized by the markdown package, ' 50 | 'execute `update_github_emojis.dart`.', 51 | ); 52 | print( 53 | 'Wrote data to $_emojisFilePath for $emojiCount emoji, ' 54 | 'ignoring ${ignored.length}: ${ignored.join(', ')}.', 55 | ); 56 | } 57 | -------------------------------------------------------------------------------- /tool/update_entities.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import 'dart:convert'; 6 | import 'dart:io'; 7 | import 'package:path/path.dart' as p; 8 | 9 | /// Generates and updates HTML entities. 10 | void main() { 11 | // Original file: https://html.spec.whatwg.org/entities.json 12 | final file = File('${p.current}/tool/entities.json'); 13 | final json = file.readAsStringSync(); 14 | final map = Map<String, Map<String, dynamic>>.from(jsonDecode(json) as Map); 15 | 16 | final result = <String, String>{}; 17 | for (final name in map.keys) { 18 | if (name.endsWith(';')) { 19 | final value = map[name]!['characters'] as String; 20 | result[name] = value; 21 | } 22 | } 23 | 24 | final outputPath = '${p.current}/lib/src/assets/html_entities.dart'; 25 | final stringMap = const JsonEncoder.withIndent(' ') 26 | .convert(result) 27 | .replaceAll(r'"$"', r'r"$"') 28 | .replaceAll(r'"\\"', r'r"\"'); 29 | final output = ''' 30 | // Generated file. do not edit. 31 | // 32 | // Source: tool/entities.json 33 | // Script: tool/update_entities.dart 34 | // ignore_for_file: prefer_single_quotes 35 | 36 | const htmlEntitiesMap = $stringMap; 37 | '''; 38 | File(outputPath).writeAsStringSync(output); 39 | } 40 | -------------------------------------------------------------------------------- /tool/update_shared.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file 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. 4 | 5 | import 'dart:convert'; 6 | import 'dart:io'; 7 | 8 | Future<Object?> downloadJson(String uri) async { 9 | final client = HttpClient(); 10 | try { 11 | final request = await client.getUrl(Uri.parse(uri)); 12 | final response = await request.close(); 13 | 14 | return response 15 | .transform(utf8.decoder) 16 | .transform(const JsonDecoder()) 17 | .single; 18 | } finally { 19 | client.close(); 20 | } 21 | } 22 | --------------------------------------------------------------------------------