diff --git a/.github/ISSUE_TEMPLATE/markdown.md b/.github/ISSUE_TEMPLATE/markdown.md new file mode 100644 index 000000000..24e9f16f2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/markdown.md @@ -0,0 +1,5 @@ +--- +name: "package:markdown" +about: "Create a bug or file a feature request against package:markdown." +labels: "package:markdown" +--- \ No newline at end of file diff --git a/.github/labeler.yml b/.github/labeler.yml index 45c2239b1..e1587374b 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -68,6 +68,10 @@ - changed-files: - any-glob-to-any-file: 'pkgs/json_rpc_2/**' +'package:markdown': + - changed-files: + - any-glob-to-any-file: 'pkgs/markdown/**' + 'package:mime': - changed-files: - any-glob-to-any-file: 'pkgs/mime/**' diff --git a/.github/workflows/clock.yaml b/.github/workflows/clock.yaml index aef089513..a09a6010c 100644 --- a/.github/workflows/clock.yaml +++ b/.github/workflows/clock.yaml @@ -5,12 +5,12 @@ on: push: branches: [ main ] paths: - - '.github/workflows/clock.yml' + - '.github/workflows/clock.yaml' - 'pkgs/clock/**' pull_request: branches: [ main ] paths: - - '.github/workflows/clock.yml' + - '.github/workflows/clock.yaml' - 'pkgs/clock/**' schedule: - cron: "0 0 * * 0" diff --git a/.github/workflows/health.yaml b/.github/workflows/health.yaml index f258f8b69..3ac7e89e2 100644 --- a/.github/workflows/health.yaml +++ b/.github/workflows/health.yaml @@ -9,6 +9,6 @@ jobs: uses: dart-lang/ecosystem/.github/workflows/health.yaml@main with: ignore_coverage: "**.mock.dart,**.g.dart" - ignore_license: "**.mock.dart,**.g.dart,**.mocks.dart" + ignore_license: "**.mock.dart,**.g.dart,**.mocks.dart,pkgs/markdown/**" permissions: pull-requests: write diff --git a/.github/workflows/markdown.yaml b/.github/workflows/markdown.yaml new file mode 100644 index 000000000..59654b79d --- /dev/null +++ b/.github/workflows/markdown.yaml @@ -0,0 +1,93 @@ +name: package:markdown + +on: + # Run on PRs and pushes to the default branch. + push: + branches: [ main ] + paths: + - '.github/workflows/markdown.yaml' + - 'pkgs/markdown/**' + pull_request: + branches: [ main ] + paths: + - '.github/workflows/markdown.yaml' + - 'pkgs/markdown/**' + schedule: + - cron: "0 0 * * 0" + +env: + PUB_ENVIRONMENT: bot.github + + +defaults: + run: + working-directory: pkgs/markdown/ + + +jobs: + # Check code formatting and static analysis on a single OS (linux) + # against Dart dev. + analyze: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + sdk: [dev] + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 + with: + sdk: ${{ matrix.sdk }} + - id: install + name: Install dependencies + run: dart pub get + - name: Check formatting + run: dart format --output=none --set-exit-if-changed . + if: always() && steps.install.outcome == 'success' + - name: Analyze code + run: dart analyze --fatal-infos + if: always() && steps.install.outcome == 'success' + + # Run tests on a matrix consisting of two dimensions: + # 1. OS: ubuntu-latest, (macos-latest, windows-latest) + # 2. release channel: dev + test: + needs: analyze + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + # Add macos-latest and/or windows-latest if relevant for this package. + os: [ubuntu-latest] + sdk: [3.2, dev] + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 + with: + sdk: ${{ matrix.sdk }} + - id: install + name: Install dependencies + run: dart pub get + - name: Run VM tests + run: dart test --platform vm + if: always() && steps.install.outcome == 'success' + + coverage: + needs: test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 + with: + sdk: dev + - name: Install dependencies + run: dart pub get + - name: Install coverage + run: dart pub global activate coverage + - name: Collect and report coverage + run: dart pub global run coverage:test_with_coverage + - name: Upload coverage + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + path-to-lcov: pkgs/markdown/coverage/lcov.info diff --git a/.github/workflows/markdown_crash_test.yaml b/.github/workflows/markdown_crash_test.yaml new file mode 100644 index 000000000..ceacd7758 --- /dev/null +++ b/.github/workflows/markdown_crash_test.yaml @@ -0,0 +1,27 @@ +# Run against all markdown files in latest version of packages on pub.dev to +# see if any can provoke a crash + +name: package:markdown: crash tests + +on: + schedule: + # “At 00:00 (UTC) on Sunday.” + - cron: '0 0 * * 0' + +defaults: + run: + working-directory: pkgs/markdown/ + +jobs: + crash-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + + - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 + + - name: Install dependencies + run: dart pub get + + - name: Run crash_test.dart + run: dart test -P crash_test test/crash_test.dart diff --git a/.github/workflows/markdown_flutter.yaml b/.github/workflows/markdown_flutter.yaml new file mode 100644 index 000000000..1a6ad5d42 --- /dev/null +++ b/.github/workflows/markdown_flutter.yaml @@ -0,0 +1,66 @@ +# Run a smoke test against package:flutter_markdown. + +name: package:markdown: flutter + +on: + # Run on PRs and pushes to the default branch. + push: + branches: [ main ] + paths: + - '.github/workflows/markdown_flutter.yaml' + - 'pkgs/markdown/**' + pull_request: + branches: [ main ] + paths: + - '.github/workflows/markdown_flutter.yaml' + - 'pkgs/markdown/**' + schedule: + - cron: "0 0 * * 0" + +env: + PUB_ENVIRONMENT: bot.github + +jobs: + smoke-test: + runs-on: ubuntu-latest + + steps: + - name: clone dart-lang/tools + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: dart-lang/tools + path: tools_repo + + - name: clone flutter/packages + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: flutter/packages + path: flutter_packages + + # Install the Flutter SDK using the subosito/flutter-action GitHub action. + - name: install the flutter sdk + uses: subosito/flutter-action@74af56c5ed2697ba4621264652728e8d217e53d3 + with: + channel: beta + + - name: flutter --version + run: flutter --version + + - name: create pubspec_overrides.yaml + working-directory: flutter_packages/packages/flutter_markdown + run: | + echo "dependency_overrides:" > pubspec_overrides.yaml + echo " markdown:" >> pubspec_overrides.yaml + echo " path: ../../../tools_repo/pkgs/markdown" >> pubspec_overrides.yaml + + - name: flutter pub get + working-directory: flutter_packages/packages/flutter_markdown + run: flutter pub get + + - name: flutter analyze package:flutter_markdown + working-directory: flutter_packages/packages/flutter_markdown + run: flutter analyze + + - name: flutter test package:flutter_markdown + working-directory: flutter_packages/packages/flutter_markdown + run: flutter test diff --git a/README.md b/README.md index ed90416dd..91c85e5c2 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ don't naturally belong to other topic monorepos (like | [graphs](pkgs/graphs/) | Graph algorithms that operate on graphs in any representation. | [![package issues](https://img.shields.io/badge/package:graphs-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Agraphs) | [![pub package](https://img.shields.io/pub/v/graphs.svg)](https://pub.dev/packages/graphs) | | [html](pkgs/html/) | APIs for parsing and manipulating HTML content outside the browser. | [![package issues](https://img.shields.io/badge/package:html-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Ahtml) | [![pub package](https://img.shields.io/pub/v/html.svg)](https://pub.dev/packages/html) | | [json_rpc_2](pkgs/json_rpc_2/) | Utilities to write a client or server using the JSON-RPC 2.0 spec. | [![package issues](https://img.shields.io/badge/package:json_rpc_2-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Ajson_rpc_2) | [![pub package](https://img.shields.io/pub/v/json_rpc_2.svg)](https://pub.dev/packages/json_rpc_2) | +| [markdown](pkgs/markdown/) | A portable Markdown library written in Dart that can parse Markdown into HTML. | [![pub package](https://img.shields.io/pub/v/markdown.svg)](https://pub.dev/packages/markdown) | | [mime](pkgs/mime/) | Utilities for handling media (MIME) types, including determining a type from a file extension and file contents. | [![package issues](https://img.shields.io/badge/package:mime-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Amime) | [![pub package](https://img.shields.io/pub/v/mime.svg)](https://pub.dev/packages/mime) | | [oauth2](pkgs/oauth2/) | A client library for authenticating with a remote service via OAuth2 on behalf of a user, and making authorized HTTP requests with the user's OAuth2 credentials. | [![package issues](https://img.shields.io/badge/package:oauth2-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aoauth2) | [![pub package](https://img.shields.io/pub/v/oauth2.svg)](https://pub.dev/packages/oauth2) | | [source_map_stack_trace](pkgs/source_map_stack_trace/) | A package for applying source maps to stack traces. | [![package issues](https://img.shields.io/badge/package:source_map_stack_trace-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Asource_map_stack_trace) | [![pub package](https://img.shields.io/pub/v/source_map_stack_trace.svg)](https://pub.dev/packages/source_map_stack_trace) | diff --git a/pkgs/markdown/.gitignore b/pkgs/markdown/.gitignore new file mode 100644 index 000000000..6ff0be3dc --- /dev/null +++ b/pkgs/markdown/.gitignore @@ -0,0 +1,5 @@ +.dart_tool +.packages +.pub +pubspec.lock +doc/ diff --git a/pkgs/markdown/AUTHORS b/pkgs/markdown/AUTHORS new file mode 100644 index 000000000..ca5b46bfe --- /dev/null +++ b/pkgs/markdown/AUTHORS @@ -0,0 +1,13 @@ +# Below is a list of people and organizations that have contributed +# to the Dart project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. + +David Peek +Daniel Schubert +Jirka Daněk +Seth Westphal +Tim Maffett +Alex Li diff --git a/pkgs/markdown/CHANGELOG.md b/pkgs/markdown/CHANGELOG.md new file mode 100644 index 000000000..5f9f48af8 --- /dev/null +++ b/pkgs/markdown/CHANGELOG.md @@ -0,0 +1,409 @@ +## 7.3.0 + +* Move to `dart-lang/tools` monorepo. +* Fix an issue with checkbox list items separated with blank lines (#602). +* Require package `web: '>=0.4.2 <2.0.0'`. +* Fix several `RangeError` hazards in links (#623). +* Export `LinkReferenceDefinitionSyntax` publicly (#626). + +## 7.2.2 + +* Fix a crash parsing alert block syntax (#584). +* Have alert block syntax support multiple paragraphs (#577). +* Require Dart `^3.2.0`. + +## 7.2.1 + +* Address a termination issue with GitHub alert syntax parsing. + +## 7.2.0 + +* Require Dart `^3.1.0`. +* Update all CommonMark specification links to 0.30. +* Fix beginning of line detection in `AutolinkExtensionSyntax`. +* Add a new syntax `AlertBlockSyntax` to parse GitHub Alerts. + +## 7.1.1 + +* Fix delimiter row matching pattern for tables. +* Tables are now able to interrupt other blocks. +* Fix an obscure issue with HtmlBlockSyntax. + +## 7.1.0 + +* Support for [footnotes](https://pandoc.org/MANUAL.html#footnotes). +* Fixed bug causing infinite loop for links inside tables. + +## 7.0.2 + +* Require Dart 2.19 +* Fix an issue in `HeaderWithIdSyntax`, do not generate heading IDs for headings + with no content. + +## 7.0.1 + +* Remove RegExp lookarounds from autolink extension patterns. (Fixes issues when + running on Safari.) + +## 7.0.0 + +* **Breaking change**: `close()` of `DelimiterSyntax` and `LinkSyntax` + returns multiple nodes instead of single one. +* **Breaking change**: Remove deprecated APIs, including `TagSyntax`, + `indicatorForCheckedCheckBox`, and `indicatorForUncheckedCheckBox`. +* **Breaking change**: Removed `BlockHtmlSyntax`, `BlockTagBlockHtmlSyntax`, + `LongBlockHtmlSyntax`, and `OtherTagBlockHtmlSyntax`. +* **Breaking change**: Change the `line` properties of type `String` to `Line`. +* **Breaking change**: Change the `lines` properties of type `List` to + `List`. +* Add a new syntax `HtmlBlockSyntax` to parse HTML blocks. +* Add an `enableTagfilter` option to `HtmlRenderer` to eanble GFM `tagfilter` + extension. +* Add a new syntax `DecodeHtmlSyntax` to decode HTML entity and numeric + character references. +* Add a new syntax `SoftLineBreakSyntax` to remove the single space before the + line ending. +* Add a new syntax `EscapeHtmlSyntax` to encode (`"`), (`<`), (`>`) and (`&`). +* Add an option `caseSensitive` to `TextSyntax`. +* Add a new public method `parse(String text)` for `Document`. +* Add a new public method `parseLineList(List text)` for `Document`. +* Add a new type: `Line`. +* Add a new optional parameter `parentSyntax` for `parseLines()` of + `BlockParser`, which can be used when parsing nested blocks. +* Add a new optional parameter `disabledSetextHeading` for `parseLines()` of + `BlockParser`, which is used to disable the `SetextHeaderSyntax`. +* Add a new public property `previousSyntax` for `BlockParser`. + +## 6.0.1 + +* Fix a crash in checkbox lists when mixing checkbox items with + non-checkbox items. + +## 6.0.0 + +* Require Dart 2.17 +* Add support to GFM extension for GitHub task lists (aka checkboxes). These + are only active in the `gitHubFlavored` and `gitHubWeb` extension sets. +* Add support for `#ff0000` color swatches. +* Change emoji list do be derived from the GitHub API. The only two emoji that + visually change are `:cricket:` and `:beetle:`. There are alternate emoji + `:cricket_game:` and `:lady_beetle:` which can be used to access the previous + emoji. `update_github_emoji.dart` now pulls all emoji info directly from + GitHub API and as a result we have now support the entire GitHub emoji set + (excluding the 19 custom GitHub specific emoji which have no Unicode support). +* **Breaking change**: The `TagSyntax` is _deprecated_. +* Add new syntax `DelimiterSyntax`. +* **Breaking change**: `StrikethroughSyntax` now extends `DelimiterSyntax` + instead of `TagSyntax`. +* **Breaking change**: `LinkSyntax` now extends `DelimiterSyntax` + instead of `TagSyntax`. +* Add two new emphasis syntaxes `EmphasisSyntax.underscore` and + `EmphasisSyntax.asterisk`. + +## 5.0.0 + +* Breaking change: Change the type of `parseInline`'s parameter from `String?` + to `String`. +* Fix table-rendering bug when table rows have trailing whitespace. + [#368](https://github.com/dart-lang/markdown/issues/368). +* Do not allow reference link labels to contain left brackets. Thanks + @chenzhiguang. + [#335](https://github.com/dart-lang/markdown/issues/335). +* Treat lines matching a code block syntax as continuations of paragraphs, + inside blockquotes. Thanks @chenzhiguang. + [#358](https://github.com/dart-lang/markdown/issues/358). +* Add a syntax for GitLab-flavored fenced blockquotes. GitLab-flavored Markdown + will be evaluated into an ExtensionSet, in a future release. Thanks + @chenzhiguang. + [#359](https://github.com/dart-lang/markdown/issues/359). +* Add `bool withDefaultInlineSyntaxes` and `bool withDefaultBlockSyntaxes` + parameters to `markdownToHtml` and `Document` to support the case of + specifying exactly the list of desired syntaxes. Thanks @chenzhiguang. + [#393](https://github.com/dart-lang/markdown/issues/393). + +## 4.0.1 + +* Export `src/emojis.dart` in public API. +* Update version of example page. +* Internal: enforce lint rules found in the lints package. +* Bump io dependency to `^1.0.0`. + +## 4.0.0 + +* Stable null safety release. +* Require the latest `args`, update the markdown executable to be opted in. + +## 4.0.0-nullsafety.0 + +* Migrate package to Dart's null safety language feature, requiring Dart + 2.12 or higher. +* **Breaking change:** The TagSyntax constructor no longer takes an `end` + parameter. TagSyntax no longer implements `onMatchEnd`. Instead, TagSyntax + implements a method called `close` which creates and returns a Node, if a + Node can be created and closed at the current position. If the TagSyntax + instance cannot create a Node at the current position, the method should + return `null`. Some TagSyntax subclasses will unconditionally create a tag in + `close`, while others may be unable to, such as LinkSyntax, if an inline or + reference link could not be resolved. +* Improved parsing of nested links, images, and emphasis. CommonMark compliance + of emphasis-parsing improves to 99%, and link-parsing compliance rises to + 93%. Overall compliance improves to 94% and overall GitHub-flavored Markdown + improves to 93%. + +## 3.0.0 + +* **Breaking change:** Remove `ListSyntax.removeLeadingEmptyLine`, + `ListSyntax.removeTrailingEmptyLines`, `TableSyntax.parseAlignments`, + `TableSyntax.parseRow`. +* Allow intra-word strikethrough in GFM + ([#300](https://github.com/dart-lang/markdown/issues/300)). +* **Breaking change:** Change `BlockSyntax.canEndBlock` from a getter to a + method accepting a BlockParser. + +## 2.1.8 + +* Deprecate the _public_ methods `ListSyntax.removeLeadingEmptyLine`, + `ListSyntax.removeTrailingEmptyLines`, `TableSyntax.parseAlignments`, + `TableSyntax.parseRow`. These will be made private in a major version bump as + early as 3.0.0. + +## 2.1.7 + +* Add dependency on the meta package + +## 2.1.6 + +* Fix for custom link resolvers + ([#295](https://github.com/dart-lang/markdown/issues/295)). +* Add missing HTML 5 block-level items + ([#294](https://github.com/dart-lang/markdown/pull/294)). + +## 2.1.5 + +* Overhaul table row parsing. This does not have many consequences, except that + whitespace around escaped pipes is handled better. + ([#287](https://github.com/dart-lang/markdown/issues/287)). + +## 2.1.4 + +* Correctly parse a reference link with a newline in the link reference part + ([#281](https://github.com/dart-lang/markdown/issues/281)). + +## 2.1.3 + +* Do not encode HTML in link URLs. Also do not encode HTML in link text when + `encodeHtml` is false (e.g. when used in Flutter). + +## 2.1.2 + +* Drop support for Dart 2.0.0 through 2.1.0. +* Recognize Unicode ellipsis (…) and other Unicode punctuation as punctuation + when parsing potential emphasis. +* Reduce time to parse a large HTML-block-free Markdown document (such as that + in #271) by more than half. +* Add a new optional parameter for InlineSyntax(), `startCharacter`, where a + subclass can specify a single character to try to match, before matching with + more expensive regular expressions. + +## 2.1.1 + +* Fix for encoding HTML for text string that contains `
`
+  ([#263](https://github.com/dart-lang/markdown/issues/263)).
+
+## 2.1.0
+
+* Improve strict spec compliance of `>` handling by always encoding as `>`
+  – unless preceded by `/`.
+* Improve strict spec compliance for `blockquote` by always putting the closing
+  tag on a new line.
+* Improve strict spec compliance for `code` elements defined with "\`".
+* Properly encode `<`, `>`, and `"` as their respective HTML entities when
+  interpreted as text.
+* Improve inline code parsing when using multiple backticks.
+* Do not encode HTML in indented code blocks when `encodeHtml` is false (e.g.
+  when used in Flutter).
+
+## 2.0.3
+
+* Render element attributes in the order they were defined.
+  Aligns more closely with the strict spec definition.
+* Correctly render `&` within inline image titles.
+* Add 68 new GitHub emoji.
+* Escape HTML attribute for fenced code blocks, in the info string.
+
+## 2.0.2
+
+* Set max SDK version to `<3.0.0`, and adjust other dependencies.
+
+## 2.0.1
+
+* Require Dart 2.0.0-dev.
+
+## 2.0.0
+
+* **Breaking change:** The `Link` class has been renamed `LinkReference`, and
+  the `Document` field, `refLinks`, has been renamed `linkReferences`.
+* **Breaking change:** Remove the deprecated `ExtensionSet.gitHub` field.
+  Use `ExtensionSet.gitHubFlavored` instead.
+* **Breaking change:** Make all of the fields on `Document` read-only.
+* Overhaul support for emphasis (`*foo*` and `_foo_`) and strong emphasis
+  (`**foo**` and `__foo__`), dramatically improving CommonMark compliance.
+* Overhaul support for links and images, again dramatically improving CommonMark
+  compliance.
+* Improve support for tab characters, and horizontal rules.
+* Add support for GitHub Flavored Markdown's Strikethrough extension. See the
+  [GFM spec][strikethrough].
+* The above fixes raise compliance with the CommonMark specs to 93%, and
+  compliance with the GFM specs to 92%.
+* Add an `encodeHtml` parameter to `Document`, which defaults to true. When
+  false, HTML entities (such as `©` and the `<` character) will not be
+  escaped, useful when rendering Markdown in some output format other than HTML.
+* Allow the binary script to take a `--extension-set` option.
+
+  A reminder: You can [run `bin/markdown.dart` from anywhere][pub-global] via:
+
+  ```shell
+  $ pub global activate markdown
+  $ markdown
+  ```
+
+[strikethrough]: https://github.github.com/gfm/#strikethrough-extension-
+[pub-global]: https://dart.dev/tools/pub/cmd/pub-global#running-a-script-from-your-path
+
+## 1.1.1
+
+* Add support for GitHub's colon-based Emoji syntax. :tada:! This is available
+  in the `gitHubWeb` extension set.
+
+## 1.1.0
+
+* Make the constructor for ExtensionSet public, for tools like dartdoc.
+* Split the `gitHub` ExtensionSet into two sets: `gitHubFlavored`, which
+  represents the GitHub Flavored Markdown spec, and `gitHubWeb`, which
+  represents what GitHub actually renders Markdown.
+
+## 1.0.0
+
+* Fix issue where `accept` could cause an exception.
+* Remove deprecated `escapeHtml` function.
+* Fix compliance with auto-links, including support for email addresses.
+* Updated `ExtensionSet.gitHub` to more closely align with GitHub markdown.
+
+## 0.11.4
+
+* Fix bug with lazy blockquote continuations (#162)
+* Fix bug with list item continuations (#156)
+
+## 0.11.3
+
+* Deprecate `escapeHtml`. This code exists in `dart:convert`.
+
+## 0.11.2
+
+* Fix reference code links inside blockquotes.
+* Add src/util.dart to exports.
+
+## 0.11.1
+
+* Add version information:
+  * `dart bin/markdown.dart --version` now shows the package version number.
+  * The playground app now shows the version number.
+* Improve autolink parsing.
+* Add new table syntax: `TableSyntax`.
+* Add new ExtensionSet that includes the table syntax: `ExtensionSet.gitHub`.
+* For development: added `tool/travis.sh`.
+* Support multiline Setext headers.
+* Handle loose-vs-strict list items better.
+* Support ordered lists that start with a number other than 1.
+
+## 0.11.0+1
+
+* Add playground app at https://dart-lang.github.io/markdown.
+
+## 0.11.0
+
+* Parse HTML blocks more accurately, according to
+  [CommonMark](https://spec.commonmark.org/0.24/#html-blocks).
+* Support [shortcut reference
+  links](https://spec.commonmark.org/0.24/#reference-link).
+* Don't allow an indented code block to interrupt a paragraph.
+* Change definition of "loose" and "strict" lists (items wrapped in
+  paragraph tags vs not) to CommonMark's. The primary difference is that any
+  single list item can trigger the entire list to be marked as "loose", rather
+  than defining "looseness" on each specific item.
+* Fix paragraph continuations in blockquotes and list items.
+* Fix silly typing bug with `tool/common_mark_stats.dart`, which resulted in
+  a dramatic overestimate of our CommonMark compliance.
+* There are now 427/613 (69%) passing CommonMark v0.25 specs.
+
+## 0.10.1
+
+* Parse [hard line breaks](https://spec.commonmark.org/0.24/#hard-line-breaks)
+  properly (#86). Thanks @mehaase!
+* Fix processing of `[ ... ]` syntax when no resolver is specified (#92).
+* There are now 401/613 (65%) passing CommonMark v0.24 specs.
+  (_Actually: after 0f64c8f the actual number of passing tests was 352/613
+  (57%)._)
+
+## 0.10.0
+
+* BREAKING: Now following the CommonMark spec for fenced code blocks.
+  If a language (info string) is provided, it is added as a class to the `code`
+  element with a `language-` prefix.
+* BREAKING: Now following the CommonMark spec for images. Previously,
+  `![text](img.png)` would compile too
+  `text`. That same code
+  will now compile to `text`.
+* Fix all [strong mode][] errors.
+
+[strong mode]: https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md
+
+## 0.9.0
+
+* BREAKING: The text `[foo] (bar)` no longer renders as an inline link (#53).
+* BREAKING: Change list parsing to allow lists to begin immediately after a
+  preceding block element, without a blank line in between.
+* Formalize an API for Markdown extensions (#43).
+* Introduce ExtensionSets. FencedCodeBlock is considered an extension, but
+  existing usage of `markdownToHtml()` and `new Document()` will use the
+  default extension set, which is `ExtensionSet.commonMark`, which includes
+  FencedCodeBlock.
+* Inline HTML syntax support; This is also considered an extension (#18).
+* The text `[foo]()` now renders as an inline link.
+* Whitespace now allowed between a link's destination and title (#65).
+* Header identifier support in the HeaderWithIdSyntax and
+  SetextHeaderWithIdSyntax extensions.
+* Implement backslash-escaping so that Markdown syntax can be escaped, such as
+  `[foo]\(bar) ==> 

[foo](bar)

`. +* Support for hard line breaks with either `\\\n` or \n (#30, + #60). +* New public method for BlockParser: `peek(int linesAhead)`, meant for use in + subclasses. +* New public members for ListSyntax: `blocksInList` and `determineBlockItems()`, + meant for use in subclasses. +* Improve public docs (better, and more of them). + +## 0.8.0 + +* **Breaking:** Remove (probably unused) fields: `LinkSyntax.resolved`, + `InlineParser.currentSource`. +* Switch tests to use [test][] instead of [unittest][]. +* Fix a few bugs in inline code syntax. +* Ignore underscores inside words (#41). + +[test]: https://pub.dev/packages/test +[unittest]: https://pub.dev/packages/unittest + +## 0.7.2 + +* Allow resolving links that contain inline syntax (#42). + +## 0.7.1+3 + +* Updated homepage. + +## 0.7.1+2 + +* Formatted code. + +* Updated readme. diff --git a/pkgs/markdown/LICENSE b/pkgs/markdown/LICENSE new file mode 100644 index 000000000..c2730c930 --- /dev/null +++ b/pkgs/markdown/LICENSE @@ -0,0 +1,27 @@ +Copyright 2012, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/pkgs/markdown/README.md b/pkgs/markdown/README.md new file mode 100644 index 000000000..3b87484d1 --- /dev/null +++ b/pkgs/markdown/README.md @@ -0,0 +1,173 @@ +[![Build Status](https://github.com/dart-lang/tools/actions/workflows/markdown.yaml/badge.svg)](https://github.com/dart-lang/tools/actions/workflows/markdown.yaml) +[![pub package](https://img.shields.io/pub/v/markdown.svg)](https://pub.dev/packages/markdown) +[![package publisher](https://img.shields.io/pub/publisher/markdown.svg)](https://pub.dev/packages/markdown/publisher) + +A portable Markdown library written in Dart. It can parse Markdown into +HTML on both the client and server. + +Play with it at +[dart-lang.github.io/markdown](https://dart-lang.github.io/markdown). + +### Usage + +```dart +import 'package:markdown/markdown.dart'; + +void main() { + print(markdownToHtml('Hello *Markdown*')); + //=>

Hello Markdown

+} +``` + +### Syntax extensions + +A few Markdown extensions, beyond what was specified in the original +[Perl Markdown][] implementation, are supported. By default, the ones supported +in [CommonMark] are enabled. Any individual extension can be enabled by +specifying an Array of extension syntaxes in the `blockSyntaxes` or +`inlineSyntaxes` argument of `markdownToHtml`. + +The currently supported inline extension syntaxes are: + +* `InlineHtmlSyntax()` - approximately CommonMark's + [definition][commonmark-raw-html] of "Raw HTML". + +The currently supported block extension syntaxes are: + +* `const FencedCodeBlockSyntax()` - Code blocks familiar to Pandoc and PHP + Markdown Extra users. +* `const HeaderWithIdSyntax()` - ATX-style headers have generated IDs, for link + anchors (akin to Pandoc's [`auto_identifiers`][pandoc-auto_identifiers]). +* `const SetextHeaderWithIdSyntax()` - Setext-style headers have generated IDs + for link anchors (akin to Pandoc's + [`auto_identifiers`][pandoc-auto_identifiers]). +* `const TableSyntax()` - Table syntax familiar to GitHub, PHP Markdown Extra, + and Pandoc users. + +For example: + +```dart +import 'package:markdown/markdown.dart'; + +void main() { + print(markdownToHtml('Hello Markdown', + inlineSyntaxes: [InlineHtmlSyntax()])); + //=>

Hello Markdown

+} +``` + +### Extension sets + +To make extension management easy, you can also just specify an extension set. +Both `markdownToHtml()` and `Document()` accept an `extensionSet` named +parameter. Currently, there are four pre-defined extension sets: + +* `ExtensionSet.none` includes no extensions. With no extensions, Markdown + documents will be parsed with a default set of block and inline syntax + parsers that closely match how the document might be parsed by the original + [Perl Markdown][] implementation. + +* `ExtensionSet.commonMark` includes two extensions in addition to the default + parsers to bring the parsed output closer to the [CommonMark] specification: + + * Block Syntax Parser + * `const FencedCodeBlockSyntax()` + + * Inline Syntax Parser + * `InlineHtmlSyntax()` + +* `ExtensionSet.gitHubFlavored` includes five extensions in addition to the default + parsers to bring the parsed output close to the [GitHub Flavored] Markdown + specification: + + * Block Syntax Parser + * `const FencedCodeBlockSyntax()` + * `const TableSyntax()` + + * Inline Syntax Parser + * `InlineHtmlSyntax()` + * `StrikethroughSyntax()` + * `AutolinkExtensionSyntax()` + +* `ExtensionSet.gitHubWeb` includes eight extensions. The same set of parsers use + in the `gitHubFlavored` extension set with the addition of the block syntax parsers, + HeaderWithIdSyntax and SetextHeaderWithIdSyntax, which add `id` attributes to + headers and inline syntax parser, EmojiSyntax, for parsing GitHub style emoji + characters: + + * Block Syntax Parser + * `const FencedCodeBlockSyntax()` + * `const HeaderWithIdSyntax()`, which adds `id` attributes to ATX-style + headers, for easy intra-document linking. + * `const SetextHeaderWithIdSyntax()`, which adds `id` attributes to + Setext-style headers, for easy intra-document linking. + * `const TableSyntax()` + + * Inline Syntax Parser + * `InlineHtmlSyntax()` + * `StrikethroughSyntax()` + * `EmojiSyntax()` + * `AutolinkExtensionSyntax()` + +### Custom syntax extensions + +You can create and use your own syntaxes. + +```dart +import 'package:markdown/markdown.dart'; + +void main() { + var syntaxes = [TextSyntax('nyan', sub: '~=[,,_,,]:3')]; + print(markdownToHtml('nyan', inlineSyntaxes: syntaxes)); + //=>

~=[,,_,,]:3

+} +``` + +### HTML sanitization + +This package offers no features in the way of HTML sanitization. Read Estevão +Soares dos Santos's great article, ["Markdown's XSS Vulnerability (and how to +mitigate it)"], to learn more. + +The authors recommend that you perform any necessary sanitization on the +resulting HTML, for example via `dart:html`'s [NodeValidator]. + +### CommonMark compliance + +This package contains a number of files in the `tool` directory for tracking +compliance with [CommonMark]. + +#### Updating CommonMark stats when changing the implementation + + 1. Update the library and test code, making sure that tests still pass. + 2. Run `dart run tool/stats.dart --update-files` to update the + per-test results `tool/common_mark_stats.json` and the test summary + `tool/common_mark_stats.txt`. + 3. Verify that more tests now pass – or at least, no more tests fail. + 4. Make sure you include the updated stats files in your commit. + +#### Updating the CommonMark test file for a spec update + + 1. Check out the [CommonMark source]. Make sure you checkout a *major* release. + 2. Dump the test output overwriting the existing tests file. + + ```console + > cd /path/to/common_mark_dir + > python3 test/spec_tests.py --dump-tests > \ + /path/to/markdown.dart/tool/common_mark_tests.json + ``` + + 3. Update the stats files as described above. Note any changes in the results. + 4. Update any references to the existing spec by search for + `https://spec.commonmark.org/0.30/` in the repository. (Including this one.) + Verify the updated links are still valid. + 5. Commit changes, including a corresponding note in `CHANGELOG.md`. + +[Perl Markdown]: https://daringfireball.net/projects/markdown/ +[CommonMark]: https://commonmark.org/ +[commonMark-raw-html]: https://spec.commonmark.org/0.30/#raw-html +[CommonMark source]: https://github.com/commonmark/commonmark-spec +[GitHub Flavored]: https://github.github.io/gfm/ +[pandoc-auto_identifiers]: https://pandoc.org/MANUAL.html#extension-auto_identifiers +["Markdown's XSS Vulnerability (and how to mitigate it)"]: https://github.com/showdownjs/showdown/wiki/Markdown%27s-XSS-Vulnerability-(and-how-to-mitigate-it) +[NodeValidator]: https://api.dart.dev/stable/dart-html/NodeValidator-class.html diff --git a/pkgs/markdown/analysis_options.yaml b/pkgs/markdown/analysis_options.yaml new file mode 100644 index 000000000..e7748f55a --- /dev/null +++ b/pkgs/markdown/analysis_options.yaml @@ -0,0 +1,36 @@ +# https://dart.dev/tools/analysis +include: package:dart_flutter_team_lints/analysis_options.yaml + +analyzer: + language: + strict-casts: true + strict-inference: true + strict-raw-types: true + + errors: + # The example app explicitly takes a String of user-generated HTML and + # inserts it straight into a
using innerHtml. + unsafe_html: ignore + # Waiting on a couple of bug fixes and new features before this should be enabled + comment_references: ignore + +linter: + rules: + # https://github.com/dart-lang/linter/issues/574 + #- comment_references + - avoid_private_typedef_functions + - avoid_redundant_argument_values + - avoid_unused_constructor_parameters + - avoid_void_async + - cancel_subscriptions + - literal_only_boolean_expressions + - missing_whitespace_between_adjacent_strings + - no_adjacent_strings_in_list + - prefer_const_declarations + - prefer_final_locals + - prefer_final_in_for_each + - unnecessary_await_in_return + - unnecessary_raw_strings + - use_if_null_to_convert_nulls_to_bools + - use_raw_strings + - use_string_buffers diff --git a/pkgs/markdown/benchmark/benchmark.dart b/pkgs/markdown/benchmark/benchmark.dart new file mode 100644 index 000000000..aaf8112d8 --- /dev/null +++ b/pkgs/markdown/benchmark/benchmark.dart @@ -0,0 +1,64 @@ +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:io'; + +import 'package:markdown/markdown.dart'; +import 'package:path/path.dart' as p; + +const numTrials = 100; +const runsPerTrial = 50; + +final source = _loadFile('input.md'); +final expected = _loadFile('output.html'); + +void main() { + var best = double.infinity; + + // Run the benchmark several times. This ensures the VM is warmed up and lets + // us see how much variance there is. + for (var i = 0; i <= numTrials; i++) { + final stopwatch = Stopwatch()..start(); + + // For a single benchmark, convert the source multiple times. + late String result; + for (var j = 0; j < runsPerTrial; j++) { + result = markdownToHtml(source); + } + + stopwatch.stop(); + final elapsed = stopwatch.elapsedMilliseconds / runsPerTrial; + + // Keep track of the best run so far. + if (elapsed >= best) continue; + best = elapsed; + + // Sanity check to make sure the output is what we expect and to make sure + // the VM doesn't optimize "dead" code away. + if (result != expected) { + print('Incorrect output:\n$result'); + exitCode = 1; + return; + } + + // Don't print the first run. It's always terrible since the VM hasn't + // warmed up yet. + if (i == 0) continue; + _printResult("Run ${'#$i'.padLeft(3)}", elapsed); + } + + _printResult('Best ', best); +} + +String _loadFile(String name) { + final path = p.join(p.dirname(p.fromUri(Platform.script)), name); + return File(path).readAsStringSync(); +} + +void _printResult(String label, double time) { + print( + '$label: ${time.toStringAsFixed(2).padLeft(4)}ms ' + "${'=' * ((time * 20).toInt())}", + ); +} diff --git a/pkgs/markdown/benchmark/input.md b/pkgs/markdown/benchmark/input.md new file mode 100644 index 000000000..2dd9df52a --- /dev/null +++ b/pkgs/markdown/benchmark/input.md @@ -0,0 +1,421 @@ +**TODO: Add more examples to cover all of the syntax.** + +# Regressions + +Bad backtracking in the HR parser: + +-------------------------- | ------------------------------------------------- + +# Real-world sample + +This input was taken from the test package's README to get a representative +sample of real-world markdown: + +Tests are specified using the top-level [`test()`][test] function, and test +assertions are made using [`expect()`][expect]: + +[test]: https://pub.dev/documentation/test_core/latest/test_core/test.html +[expect]: https://pub.dev/documentation/test_api/latest/test_api/expect.html + +```dart +import "package:test/test.dart"; + +void main() { + test("String.split() splits the string on the delimiter", () { + var string = "foo,bar,baz"; + expect(string.split(","), equals(["foo", "bar", "baz"])); + }); + + test("String.trim() removes surrounding whitespace", () { + var string = " foo "; + expect(string.trim(), equals("foo")); + }); +} +``` + +Tests can be grouped together using the [`group()`] function. Each group's +description is added to the beginning of its test's descriptions. + +```dart +import "package:test/test.dart"; + +void main() { + group("String", () { + test(".split() splits the string on the delimiter", () { + var string = "foo,bar,baz"; + expect(string.split(","), equals(["foo", "bar", "baz"])); + }); + + test(".trim() removes surrounding whitespace", () { + var string = " foo "; + expect(string.trim(), equals("foo")); + }); + }); + + group("int", () { + test(".remainder() returns the remainder of division", () { + expect(11.remainder(3), equals(2)); + }); + + test(".toRadixString() returns a hex string", () { + expect(11.toRadixString(16), equals("b")); + }); + }); +} +``` + +Any matchers from the [`matcher`][matcher] package can be used with `expect()` +to do complex validations: + +[matcher]: https://pub.dev/documentation/matcher/latest/matcher/matcher-library.html + +```dart +import "package:test/test.dart"; + +void main() { + test(".split() splits the string on the delimiter", () { + expect("foo,bar,baz", allOf([ + contains("foo"), + isNot(startsWith("bar")), + endsWith("baz") + ])); + }); +} +``` + +## Running Tests + +A single test file can be run just using `dart run test path/to/test.dart`. + +Many tests can be run at a time using `dart run test path/to/dir`. + +It's also possible to run a test on the Dart VM only by invoking it using `dart +path/to/test.dart`, but this doesn't load the full test runner and will be +missing some features. + +The test runner considers any file that ends with `_test.dart` to be a test +file. If you don't pass any paths, it will run all the test files in your +`test/` directory, making it easy to test your entire application at once. + +By default, tests are run in the Dart VM, but you can run them in the browser as +well by passing `dart run test -p chrome path/to/test.dart`. +`test` will take care of starting the browser and loading the tests, and all +the results will be reported on the command line just like for VM tests. In +fact, you can even run tests on both platforms with a single command: `dart run +test -p chrome,vm path/to/test.dart`. + +### Restricting Tests to Certain Platforms + +Some test files only make sense to run on particular platforms. They may use +`dart:html` or `dart:io`, they might test Windows' particular filesystem +behavior, or they might use a feature that's only available in Chrome. The +[`@TestOn`][TestOn] annotation makes it easy to declare exactly which platforms +a test file should run on. Just put it at the top of your file, before any +`library` or `import` declarations: + +```dart +@TestOn("vm") + +import "dart:io"; + +import "package:test/test.dart"; + +void main() { + // ... +} +``` + +[TestOn]: https://pub.dev/documentation/test_api/latest/test_api/TestOn-class.html + +The string you pass to `@TestOn` is what's called a "platform selector", and it +specifies exactly which platforms a test can run on. It can be as simple as the +name of a platform, or a more complex Dart-like boolean expression involving +these platform names. + +### Platform Selector Syntax + +Platform selectors can contain identifiers, parentheses, and operators. When +loading a test, each identifier is set to `true` or `false` based on the current +platform, and the test is only loaded if the platform selector returns `true`. +The operators `||`, `&&`, `!`, and `? :` all work just like they do in Dart. The +valid identifiers are: + +* `vm`: Whether the test is running on the command-line Dart VM. + +* `dartium`: Whether the test is running on Dartium. + +* `content-shell`: Whether the test is running on the headless Dartium content + shell. + +* `chrome`: Whether the test is running on Google Chrome. + +* `phantomjs`: Whether the test is running on + [PhantomJS](http://phantomjs.org/). + +* `firefox`: Whether the test is running on Mozilla Firefox. + +* `safari`: Whether the test is running on Apple Safari. + +* `ie`: Whether the test is running on Microsoft Internet Explorer. + +* `dart-vm`: Whether the test is running on the Dart VM in any context, + including Dartium. It's identical to `!js`. + +* `browser`: Whether the test is running in any browser. + +* `js`: Whether the test has been compiled to JS. This is identical to + `!dart-vm`. + +* `blink`: Whether the test is running in a browser that uses the Blink + rendering engine. + +* `windows`: Whether the test is running on Windows. If `vm` is false, this will + be `false` as well. + +* `mac-os`: Whether the test is running on Mac OS. If `vm` is false, this will + be `false` as well. + +* `linux`: Whether the test is running on Linux. If `vm` is false, this will be + `false` as well. + +* `android`: Whether the test is running on Android. If `vm` is false, this will + be `false` as well, which means that this *won't* be true if the test is + running on an Android browser. + +* `posix`: Whether the test is running on a POSIX operating system. This is + equivalent to `!windows`. + +For example, if you wanted to run a test on every browser but Chrome, you would +write `@TestOn("browser && !chrome")`. + +## Asynchronous Tests + +Tests written with `async`/`await` will work automatically. The test runner +won't consider the test finished until the returned `Future` completes. + +```dart +import "dart:async"; + +import "package:test/test.dart"; + +void main() { + test("new Future.value() returns the value", () async { + var value = await new Future.value(10); + expect(value, equals(10)); + }); +} +``` + +There are also a number of useful functions and matchers for more advanced +asynchrony. The [`completion()`][completion] matcher can be used to test +`Futures`; it ensures that the test doesn't finish until the `Future` completes, +and runs a matcher against that `Future`'s value. + +[completion]: https://pub.dev/documentation/test_api/latest/test_api/completion.html + +```dart +import "dart:async"; + +import "package:test/test.dart"; + +void main() { + test("new Future.value() returns the value", () { + expect(new Future.value(10), completion(equals(10))); + }); +} +``` + +The [`throwsA()`][throwsA] matcher and the various `throwsExceptionType` +matchers work with both synchronous callbacks and asynchronous `Future`s. They +ensure that a particular type of exception is thrown: + +[throwsA]: https://pub.dev/documentation/test_api/latest/test_api/throwsA.html + +```dart +import "dart:async"; + +import "package:test/test.dart"; + +void main() { + test("new Future.error() throws the error", () { + expect(new Future.error("oh no"), throwsA(equals("oh no"))); + expect(new Future.error(new StateError("bad state")), throwsStateError); + }); +} +``` + +The [`expectAsync()`][expectAsync] function wraps another function and has two +jobs. First, it asserts that the wrapped function is called a certain number of +times, and will cause the test to fail if it's called too often; second, it +keeps the test from finishing until the function is called the requisite number +of times. + +```dart +import "dart:async"; + +import "package:test/test.dart"; + +void main() { + test("Stream.fromIterable() emits the values in the iterable", () { + var stream = new Stream.fromIterable([1, 2, 3]); + + stream.listen(expectAsync((number) { + expect(number, inInclusiveRange(1, 3)); + }, count: 3)); + }); +} +``` + +[expectAsync]: https://pub.dev/documentation/test_api/latest/test_api/expectAsync.html + +## Running Tests with Custom HTML + +By default, the test runner will generate its own empty HTML file for browser +tests. However, tests that need custom HTML can create their own files. These +files have three requirements: + +* They must have the same name as the test, with `.dart` replaced by `.html`. + +* They must contain a `link` tag with `rel="x-dart-test"` and an `href` + attribute pointing to the test script. + +* They must contain ``. + +For example, if you had a test called `custom_html_test.dart`, you might write +the following HTML file: + +```html + + + + + Custom HTML Test + + + + + // ... + + +``` + +## Configuring Tests + +### Skipping Tests + +If a test, group, or entire suite isn't working yet and you just want it to stop +complaining, you can mark it as "skipped". The test or tests won't be run, and, +if you supply a reason why, that reason will be printed. In general, skipping +tests indicates that they should run but is temporarily not working. If they're +is fundamentally incompatible with a platform, [`@TestOn`/`testOn`][TestOn] +should be used instead. + +[TestOn]: #restricting-tests-to-certain-platforms + +To skip a test suite, put a `@Skip` annotation at the top of the file: + +```dart +@Skip("currently failing (see issue 1234)") + +import "package:test/test.dart"; + +void main() { + // ... +} +``` + +The string you pass should describe why the test is skipped. You don't have to +include it, but it's a good idea to document why the test isn't running. + +Groups and individual tests can be skipped by passing the `skip` parameter. This +can be either `true` or a String describing why the test is skipped. For example: + +```dart +import "package:test/test.dart"; + +void main() { + group("complicated algorithm tests", () { + // ... + }, skip: "the algorithm isn't quite right"); + + test("error-checking test", () { + // ... + }, skip: "TODO: add error-checking."); +} +``` + +### Timeouts + +By default, tests will time out after 30 seconds of inactivity. However, this +can be configured on a per-test, -group, or -suite basis. To change the timeout +for a test suite, put a `@Timeout` annotation at the top of the file: + +```dart +@Timeout(const Duration(seconds: 45)) + +import "package:test/test.dart"; + +void main() { + // ... +} +``` + +In addition to setting an absolute timeout, you can set the timeout relative to +the default using `@Timeout.factor`. For example, `@Timeout.factor(1.5)` will +set the timeout to one and a half times as long as the default—45 seconds. + +Timeouts can be set for tests and groups using the `timeout` parameter. This +parameter takes a `Timeout` object just like the annotation. For example: + +```dart +import "package:test/test.dart"; + +void main() { + group("slow tests", () { + // ... + + test("even slower test", () { + // ... + }, timeout: new Timeout.factor(2)) + }, timeout: new Timeout(new Duration(minutes: 1))); +} +``` + +Nested timeouts apply in order from outermost to innermost. That means that +"even slower test" will take two minutes to time out, since it multiplies the +group's timeout by 2. + +### Platform-Specific Configuration + +Sometimes a test may need to be configured differently for different platforms. +Windows might run your code slower than other platforms, or your DOM +manipulation might not work right on Safari yet. For these cases, you can use +the `@OnPlatform` annotation and the `onPlatform` named parameter to `test()` +and `group()`. For example: + +```dart +@OnPlatform(const { + // Give Windows some extra wiggle-room before timing out. + "windows": const Timeout.factor(2) +}) + +import "package:test/test.dart"; + +void main() { + test("do a thing", () { + // ... + }, onPlatform: { + "safari": new Skip("Safari is currently broken (see #1234)") + }); +} +``` + +Both the annotation and the parameter take a map. The map's keys are [platform +selectors](#platform-selector-syntax) which describe the platforms for which the +specialized configuration applies. Its values are instances of some of the same +annotation classes that can be used for a suite: `Skip` and `Timeout`. A value +can also be a list of these values. + +If multiple platforms match, the configuration is applied in order from first to +last, just as they would in nested groups. This means that for configuration +like duration-based timeouts, the last matching value wins. diff --git a/pkgs/markdown/benchmark/output.html b/pkgs/markdown/benchmark/output.html new file mode 100644 index 000000000..200e4bd22 --- /dev/null +++ b/pkgs/markdown/benchmark/output.html @@ -0,0 +1,360 @@ +

TODO: Add more examples to cover all of the syntax.

+

Regressions

+

Bad backtracking in the HR parser:

+

-------------------------- | -------------------------------------------------

+

Real-world sample

+

This input was taken from the test package's README to get a representative +sample of real-world markdown:

+

Tests are specified using the top-level test() function, and test +assertions are made using expect():

+
import "package:test/test.dart";
+
+void main() {
+  test("String.split() splits the string on the delimiter", () {
+    var string = "foo,bar,baz";
+    expect(string.split(","), equals(["foo", "bar", "baz"]));
+  });
+
+  test("String.trim() removes surrounding whitespace", () {
+    var string = "  foo ";
+    expect(string.trim(), equals("foo"));
+  });
+}
+
+

Tests can be grouped together using the [group()] function. Each group's +description is added to the beginning of its test's descriptions.

+
import "package:test/test.dart";
+
+void main() {
+  group("String", () {
+    test(".split() splits the string on the delimiter", () {
+      var string = "foo,bar,baz";
+      expect(string.split(","), equals(["foo", "bar", "baz"]));
+    });
+
+    test(".trim() removes surrounding whitespace", () {
+      var string = "  foo ";
+      expect(string.trim(), equals("foo"));
+    });
+  });
+
+  group("int", () {
+    test(".remainder() returns the remainder of division", () {
+      expect(11.remainder(3), equals(2));
+    });
+
+    test(".toRadixString() returns a hex string", () {
+      expect(11.toRadixString(16), equals("b"));
+    });
+  });
+}
+
+

Any matchers from the matcher package can be used with expect() +to do complex validations:

+
import "package:test/test.dart";
+
+void main() {
+  test(".split() splits the string on the delimiter", () {
+    expect("foo,bar,baz", allOf([
+      contains("foo"),
+      isNot(startsWith("bar")),
+      endsWith("baz")
+    ]));
+  });
+}
+
+

Running Tests

+

A single test file can be run just using pub run test:test path/to/test.dart +(on Dart 1.10, this can be shortened to pub run test path/to/test.dart).

+

Single file being run via pub run"

+

Many tests can be run at a time using pub run test:test path/to/dir.

+

Directory being run via "pub run".

+

It's also possible to run a test on the Dart VM only by invoking it using dart path/to/test.dart, but this doesn't load the full test runner and will be +missing some features.

+

The test runner considers any file that ends with _test.dart to be a test +file. If you don't pass any paths, it will run all the test files in your +test/ directory, making it easy to test your entire application at once.

+

By default, tests are run in the Dart VM, but you can run them in the browser as +well by passing pub run test:test -p chrome path/to/test.dart. +test will take care of starting the browser and loading the tests, and all +the results will be reported on the command line just like for VM tests. In +fact, you can even run tests on both platforms with a single command: pub run test:test -p "chrome,vm" path/to/test.dart.

+

Restricting Tests to Certain Platforms

+

Some test files only make sense to run on particular platforms. They may use +dart:html or dart:io, they might test Windows' particular filesystem +behavior, or they might use a feature that's only available in Chrome. The +@TestOn annotation makes it easy to declare exactly which platforms +a test file should run on. Just put it at the top of your file, before any +library or import declarations:

+
@TestOn("vm")
+
+import "dart:io";
+
+import "package:test/test.dart";
+
+void main() {
+  // ...
+}
+
+

The string you pass to @TestOn is what's called a "platform selector", and it +specifies exactly which platforms a test can run on. It can be as simple as the +name of a platform, or a more complex Dart-like boolean expression involving +these platform names.

+

Platform Selector Syntax

+

Platform selectors can contain identifiers, parentheses, and operators. When +loading a test, each identifier is set to true or false based on the current +platform, and the test is only loaded if the platform selector returns true. +The operators ||, &&, !, and ? : all work just like they do in Dart. The +valid identifiers are:

+
    +
  • +

    vm: Whether the test is running on the command-line Dart VM.

    +
  • +
  • +

    dartium: Whether the test is running on Dartium.

    +
  • +
  • +

    content-shell: Whether the test is running on the headless Dartium content +shell.

    +
  • +
  • +

    chrome: Whether the test is running on Google Chrome.

    +
  • +
  • +

    phantomjs: Whether the test is running on +PhantomJS.

    +
  • +
  • +

    firefox: Whether the test is running on Mozilla Firefox.

    +
  • +
  • +

    safari: Whether the test is running on Apple Safari.

    +
  • +
  • +

    ie: Whether the test is running on Microsoft Internet Explorer.

    +
  • +
  • +

    dart-vm: Whether the test is running on the Dart VM in any context, +including Dartium. It's identical to !js.

    +
  • +
  • +

    browser: Whether the test is running in any browser.

    +
  • +
  • +

    js: Whether the test has been compiled to JS. This is identical to +!dart-vm.

    +
  • +
  • +

    blink: Whether the test is running in a browser that uses the Blink +rendering engine.

    +
  • +
  • +

    windows: Whether the test is running on Windows. If vm is false, this will +be false as well.

    +
  • +
  • +

    mac-os: Whether the test is running on Mac OS. If vm is false, this will +be false as well.

    +
  • +
  • +

    linux: Whether the test is running on Linux. If vm is false, this will be +false as well.

    +
  • +
  • +

    android: Whether the test is running on Android. If vm is false, this will +be false as well, which means that this won't be true if the test is +running on an Android browser.

    +
  • +
  • +

    posix: Whether the test is running on a POSIX operating system. This is +equivalent to !windows.

    +
  • +
+

For example, if you wanted to run a test on every browser but Chrome, you would +write @TestOn("browser && !chrome").

+

Asynchronous Tests

+

Tests written with async/await will work automatically. The test runner +won't consider the test finished until the returned Future completes.

+
import "dart:async";
+
+import "package:test/test.dart";
+
+void main() {
+  test("new Future.value() returns the value", () async {
+    var value = await new Future.value(10);
+    expect(value, equals(10));
+  });
+}
+
+

There are also a number of useful functions and matchers for more advanced +asynchrony. The completion() matcher can be used to test +Futures; it ensures that the test doesn't finish until the Future completes, +and runs a matcher against that Future's value.

+
import "dart:async";
+
+import "package:test/test.dart";
+
+void main() {
+  test("new Future.value() returns the value", () {
+    expect(new Future.value(10), completion(equals(10)));
+  });
+}
+
+

The throwsA() matcher and the various throwsExceptionType +matchers work with both synchronous callbacks and asynchronous Futures. They +ensure that a particular type of exception is thrown:

+
import "dart:async";
+
+import "package:test/test.dart";
+
+void main() {
+  test("new Future.error() throws the error", () {
+    expect(new Future.error("oh no"), throwsA(equals("oh no")));
+    expect(new Future.error(new StateError("bad state")), throwsStateError);
+  });
+}
+
+

The expectAsync() function wraps another function and has two +jobs. First, it asserts that the wrapped function is called a certain number of +times, and will cause the test to fail if it's called too often; second, it +keeps the test from finishing until the function is called the requisite number +of times.

+
import "dart:async";
+
+import "package:test/test.dart";
+
+void main() {
+  test("Stream.fromIterable() emits the values in the iterable", () {
+    var stream = new Stream.fromIterable([1, 2, 3]);
+
+    stream.listen(expectAsync((number) {
+      expect(number, inInclusiveRange(1, 3));
+    }, count: 3));
+  });
+}
+
+

Running Tests with Custom HTML

+

By default, the test runner will generate its own empty HTML file for browser +tests. However, tests that need custom HTML can create their own files. These +files have three requirements:

+
    +
  • +

    They must have the same name as the test, with .dart replaced by .html.

    +
  • +
  • +

    They must contain a link tag with rel="x-dart-test" and an href +attribute pointing to the test script.

    +
  • +
  • +

    They must contain <script src="packages/test/dart.js"></script>.

    +
  • +
+

For example, if you had a test called custom_html_test.dart, you might write +the following HTML file:

+
<!doctype html>
+<!-- custom_html_test.html -->
+<html>
+  <head>
+    <title>Custom HTML Test</title>
+    <link rel="x-dart-test" href="custom_html_test.dart">
+    <script src="packages/test/dart.js"></script>
+  </head>
+  <body>
+    // ...
+  </body>
+</html>
+
+

Configuring Tests

+

Skipping Tests

+

If a test, group, or entire suite isn't working yet and you just want it to stop +complaining, you can mark it as "skipped". The test or tests won't be run, and, +if you supply a reason why, that reason will be printed. In general, skipping +tests indicates that they should run but is temporarily not working. If they're +is fundamentally incompatible with a platform, @TestOn/testOn +should be used instead.

+

To skip a test suite, put a @Skip annotation at the top of the file:

+
@Skip("currently failing (see issue 1234)")
+
+import "package:test/test.dart";
+
+void main() {
+  // ...
+}
+
+

The string you pass should describe why the test is skipped. You don't have to +include it, but it's a good idea to document why the test isn't running.

+

Groups and individual tests can be skipped by passing the skip parameter. This +can be either true or a String describing why the test is skipped. For example:

+
import "package:test/test.dart";
+
+void main() {
+  group("complicated algorithm tests", () {
+    // ...
+  }, skip: "the algorithm isn't quite right");
+
+  test("error-checking test", () {
+    // ...
+  }, skip: "TODO: add error-checking.");
+}
+
+

Timeouts

+

By default, tests will time out after 30 seconds of inactivity. However, this +can be configured on a per-test, -group, or -suite basis. To change the timeout +for a test suite, put a @Timeout annotation at the top of the file:

+
@Timeout(const Duration(seconds: 45))
+
+import "package:test/test.dart";
+
+void main() {
+  // ...
+}
+
+

In addition to setting an absolute timeout, you can set the timeout relative to +the default using @Timeout.factor. For example, @Timeout.factor(1.5) will +set the timeout to one and a half times as long as the default—45 seconds.

+

Timeouts can be set for tests and groups using the timeout parameter. This +parameter takes a Timeout object just like the annotation. For example:

+
import "package:test/test.dart";
+
+void main() {
+  group("slow tests", () {
+    // ...
+
+    test("even slower test", () {
+      // ...
+    }, timeout: new Timeout.factor(2))
+  }, timeout: new Timeout(new Duration(minutes: 1)));
+}
+
+

Nested timeouts apply in order from outermost to innermost. That means that +"even slower test" will take two minutes to time out, since it multiplies the +group's timeout by 2.

+

Platform-Specific Configuration

+

Sometimes a test may need to be configured differently for different platforms. +Windows might run your code slower than other platforms, or your DOM +manipulation might not work right on Safari yet. For these cases, you can use +the @OnPlatform annotation and the onPlatform named parameter to test() +and group(). For example:

+
@OnPlatform(const {
+  // Give Windows some extra wiggle-room before timing out.
+  "windows": const Timeout.factor(2)
+})
+
+import "package:test/test.dart";
+
+void main() {
+  test("do a thing", () {
+    // ...
+  }, onPlatform: {
+    "safari": new Skip("Safari is currently broken (see #1234)")
+  });
+}
+
+

Both the annotation and the parameter take a map. The map's keys are platform +selectors which describe the platforms for which the +specialized configuration applies. Its values are instances of some of the same +annotation classes that can be used for a suite: Skip and Timeout. A value +can also be a list of these values.

+

If multiple platforms match, the configuration is applied in order from first to +last, just as they would in nested groups. This means that for configuration +like duration-based timeouts, the last matching value wins.

diff --git a/pkgs/markdown/bin/markdown.dart b/pkgs/markdown/bin/markdown.dart new file mode 100644 index 000000000..76926c622 --- /dev/null +++ b/pkgs/markdown/bin/markdown.dart @@ -0,0 +1,81 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:async'; +import 'dart:io'; + +import 'package:args/args.dart'; +import 'package:markdown/markdown.dart'; + +final extensionSets = { + 'none': ExtensionSet.none, + 'CommonMark': ExtensionSet.commonMark, + 'GitHubFlavored': ExtensionSet.gitHubFlavored, + 'GitHubWeb': ExtensionSet.gitHubWeb, +}; + +Future main(List args) async { + final parser = ArgParser() + ..addFlag('help', negatable: false, help: 'Print help text and exit') + ..addFlag('version', negatable: false, help: 'Print version and exit') + ..addOption( + 'extension-set', + allowed: ['none', 'CommonMark', 'GitHubFlavored', 'GitHubWeb'], + defaultsTo: 'CommonMark', + help: 'Specify a set of extensions', + allowedHelp: { + 'none': 'No extensions; similar to Markdown.pl', + 'CommonMark': 'Parse like CommonMark Markdown (default)', + 'GitHubFlavored': 'Parse like GitHub Flavored Markdown', + 'GitHubWeb': 'Parse like GitHub\'s Markdown-enabled web input fields', + }, + ); + final results = parser.parse(args); + + if (results['help'] as bool) { + printUsage(parser); + return; + } + + if (results['version'] as bool) { + print(version); + return; + } + + final extensionSet = extensionSets[results['extension-set']]; + + if (results.rest.length > 1) { + printUsage(parser); + exitCode = 1; + return; + } + + if (results.rest.length == 1) { + // Read argument as a file path. + final input = File(results.rest.first).readAsStringSync(); + print(markdownToHtml(input, extensionSet: extensionSet)); + return; + } + + // Read from stdin. + final buffer = StringBuffer(); + String? line; + while ((line = stdin.readLineSync()) != null) { + buffer.writeln(line); + } + print(markdownToHtml(buffer.toString(), extensionSet: extensionSet)); +} + +void printUsage(ArgParser parser) { + print('''Usage: markdown.dart [options] [file] + +Parse [file] as Markdown and print resulting HTML. If [file] is omitted, +use stdin as input. + +By default, CommonMark Markdown will be parsed. This can be changed with +the --extensionSet flag. + +${parser.usage} +'''); +} diff --git a/pkgs/markdown/dart_test.yaml b/pkgs/markdown/dart_test.yaml new file mode 100644 index 000000000..588b409a3 --- /dev/null +++ b/pkgs/markdown/dart_test.yaml @@ -0,0 +1,6 @@ +tags: + crash_test: + skip: 'Only run crash_test tests manually with `dart test -P crash_test`' + presets: + crash_test: + skip: false # Don't skip when running in -P crash_test diff --git a/pkgs/markdown/example/app.dart b/pkgs/markdown/example/app.dart new file mode 100644 index 000000000..14b8f1937 --- /dev/null +++ b/pkgs/markdown/example/app.dart @@ -0,0 +1,148 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:async'; +import 'dart:js_interop'; + +import 'package:markdown/markdown.dart' as md; +import 'package:web/web.dart'; + +import 'highlight.dart'; + +final markdownInput = + document.querySelector('#markdown') as HTMLTextAreaElement; +final htmlDiv = document.querySelector('#html') as HTMLDivElement; +final versionSpan = document.querySelector('.version') as HTMLSpanElement; + +const typing = Duration(milliseconds: 150); +const introText = '''Markdown is the **best**! + +* It has lists. +* It has [links](https://dart.dev). +* It has... + ```dart + void sourceCode() {} + ``` +* ...and _so much more_...'''; + +// Flavor support. +final basicRadio = document.querySelector('#basic-radio') as HTMLElement; +final commonmarkRadio = + document.querySelector('#commonmark-radio') as HTMLElement; +final gfmRadio = document.querySelector('#gfm-radio') as HTMLElement; +md.ExtensionSet? extensionSet; + +final extensionSets = { + 'basic-radio': md.ExtensionSet.none, + 'commonmark-radio': md.ExtensionSet.commonMark, + 'gfm-radio': md.ExtensionSet.gitHubWeb, +}; + +void main() { + versionSpan.text = 'v${md.version}'; + markdownInput.onKeyUp.listen(_renderMarkdown); + + final savedMarkdown = window.localStorage['markdown']; + + if (savedMarkdown != null && + savedMarkdown.isNotEmpty && + savedMarkdown != introText) { + markdownInput.value = savedMarkdown; + markdownInput.focus(); + _renderMarkdown(); + } else { + _typeItOut(introText, 82); + } + + // GitHub is the default extension set. + gfmRadio.attributes.getNamedItem('checked')?.value = ''; + gfmRadio.querySelector('.glyph')!.text = 'radio_button_checked'; + extensionSet = extensionSets[gfmRadio.id]; + _renderMarkdown(); + + basicRadio.onClick.listen(_switchFlavor); + commonmarkRadio.onClick.listen(_switchFlavor); + gfmRadio.onClick.listen(_switchFlavor); +} + +void _renderMarkdown([Event? event]) { + final markdown = markdownInput.value; + + htmlDiv.innerHtml = md.markdownToHtml(markdown, extensionSet: extensionSet); + + for (final block in htmlDiv.querySelectorAll('pre code').items) { + try { + highlightElement(block); + } catch (e) { + console.error('Error highlighting markdown:'.toJS); + console.error(e.toString().toJS); + } + } + + if (event != null) { + // Not simulated typing. Store it. + window.localStorage['markdown'] = markdown; + } +} + +void _typeItOut(String msg, int pos) { + late Timer timer; + markdownInput.onKeyUp.listen((_) { + timer.cancel(); + }); + void addCharacter() { + if (pos > msg.length) { + return; + } + markdownInput.value = msg.substring(0, pos); + markdownInput.focus(); + _renderMarkdown(); + pos++; + timer = Timer(typing, addCharacter); + } + + timer = Timer(typing, addCharacter); +} + +void _switchFlavor(Event e) { + final target = e.currentTarget as HTMLElement; + if (target.attributes.getNamedItem('checked') == null) { + if (basicRadio != target) { + basicRadio.attributes.safeRemove('checked'); + basicRadio.querySelector('.glyph')!.text = 'radio_button_unchecked'; + } + if (commonmarkRadio != target) { + commonmarkRadio.attributes.safeRemove('checked'); + commonmarkRadio.querySelector('.glyph')!.text = 'radio_button_unchecked'; + } + if (gfmRadio != target) { + gfmRadio.attributes.safeRemove('checked'); + gfmRadio.querySelector('.glyph')!.text = 'radio_button_unchecked'; + } + + target.attributes.getNamedItem('checked')?.value = ''; + target.querySelector('.glyph')!.text = 'radio_button_checked'; + extensionSet = extensionSets[target.id]; + _renderMarkdown(); + } +} + +extension on NodeList { + List get items => [ + for (var i = 0; i < length; i++) item(i)!, + ]; +} + +extension on NamedNodeMap { + void safeRemove(String qualifiedName) { + if (getNamedItem(qualifiedName) != null) removeNamedItem(qualifiedName); + } +} + +extension on HTMLDivElement { + // The default implementation allows `JSAny` to support trusted types. We only + // use `String`s, so prefer this to avoid manual conversions. + @JS('innerHTML') + external set innerHtml(String value); +} diff --git a/pkgs/markdown/example/favicon.png b/pkgs/markdown/example/favicon.png new file mode 100644 index 000000000..43d2ffa07 Binary files /dev/null and b/pkgs/markdown/example/favicon.png differ diff --git a/pkgs/markdown/example/highlight.dart b/pkgs/markdown/example/highlight.dart new file mode 100644 index 000000000..b54c447d3 --- /dev/null +++ b/pkgs/markdown/example/highlight.dart @@ -0,0 +1,13 @@ +// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@JS('hljs') +library; + +import 'dart:js_interop'; + +import 'package:web/web.dart'; + +@JS() +external void highlightElement(Node block); diff --git a/pkgs/markdown/example/index.html b/pkgs/markdown/example/index.html new file mode 100644 index 000000000..82650a6cd --- /dev/null +++ b/pkgs/markdown/example/index.html @@ -0,0 +1,95 @@ + + + + + + + + + + + + Dart Markdown Live Editor + + + +
+
+
+

Dart Markdown Live Editor

+ + + + + + + +
+
+
+
+
+

Markdown

+
+
+ +
+
+
+
+

HTML

+
+
+
+
+
+ Markdown Flavor: +
+ radio_button_unchecked + Basic Markdown +
+
+ radio_button_unchecked + CommonMark +
+
+ radio_button_unchecked + GitHub Flavored Markdown +
+ + + help + +
+
+ + diff --git a/pkgs/markdown/example/style.css b/pkgs/markdown/example/style.css new file mode 100644 index 000000000..bfacfb0b3 --- /dev/null +++ b/pkgs/markdown/example/style.css @@ -0,0 +1,152 @@ +html, body { + background-color: rgb(250, 250, 250); + font-family: Roboto,"Helvetica Neue",sans-serif; + font-size: 16px; + margin: 0; +} + +.container { + box-sizing: border-box; + display: flex; + flex-direction: column; + height: 100%; + width: 100%; +} + +.main { + align-items: stretch; + box-sizing: border-box; + display: flex; + flex-direction: row; + height: 100%; + margin: 32px; +} + +.version { + color: rgba(0, 0, 0, 0.54); + margin-right: 16px; +} + +.card { + /* Styled like Material Cards. */ + color: rgba(0, 0, 0, 0.87); + background-color: white; + border-radius: 2px; + box-sizing: border-box; + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .2), + 0 1px 1px 0 rgba(0, 0, 0, .14), + 0 2px 1px -1px rgba(0, 0, 0, .12); + margin: 8px; + + /* Positioned next to each other. */ + display: flex; + flex: 1 1 50%; + flex-direction: column; + max-height: 100%; + max-width: 50%; + min-height: 400px; +} + +.toolbar { + /* Styled like Material Toolbar. */ + align-items: center; + background-color: #22d3c5; + box-sizing: border-box; + color: rgba(0, 0, 0, 0.87); + display: flex; + font-size: 20px; + line-height: 1.4; + margin: 0; + min-height: 64px; + padding: 0 16px; + position: relative; + width: 100%; +} + +.toolbar h2 { + font-size: inherit; + font-weight: inherit; + margin: inherit; +} + +.toolbar a:link, +.toolbar a:visited { + color: rgba(0, 0, 0, 0.87); +} + +.toolbar svg { + fill: currentColor; +} + +.card .toolbar { + border-radius: 3px 3px 0 0; +} + +.textarea-container { + display: flex; + height: 100%; + padding: 8px; +} + +textarea { + border-color: rgba(0, 0, 0, 0.12); + border-width: 0 0 1px; + box-sizing: border-box; + color: rgba(0, 0, 0, 0.87); + font-family: "Roboto Mono",monospace; + font-size: 100%; + line-height: 26px; + overflow: auto; + padding: 2px 2px 1px; + width: 100%; +} + +textarea:focus { + border-color: #22d3c5; + border-width: 0 0 2px; + outline: 0; + padding-bottom: 0; +} + +#html { + overflow: auto; + padding: 8px; +} + +footer { + box-sizing: border-box; + display: flex; + font-size: 20px; + height: 64px; + padding: 0 16px; +} + +footer a:link, +footer a:visited { + color: rgba(0, 0, 0, 0.87); +} + +.radio { + cursor: pointer; + display: inline-block; + margin-right: 16px; +} + +i.glyph { + display: inline-block; + font-family: 'Material Icons Extended'; + font-size: 16px; + font-style: normal; + font-weight: normal; + line-height: 1; +} + +.radio[checked] i.glyph { + color: #22d3c5; +} + +i.glyph.big { + font-size: 32px; + height: 32px; + width: 32px; +} diff --git a/pkgs/markdown/lib/markdown.dart b/pkgs/markdown/lib/markdown.dart new file mode 100644 index 000000000..9fac7321d --- /dev/null +++ b/pkgs/markdown/lib/markdown.dart @@ -0,0 +1,94 @@ +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Parses text in a Markdown-like format building an +/// [AST tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree) +/// that can then be rendered to HTML. +/// +/// If you are only interested in rendering Markdown to HTML please refer +/// to the [README](../index.html) which explains the use of [markdownToHtml]. +/// +/// The main entrypoint to the library is the [Document] which +/// encapsulates the parsing process converting a Markdown text into +/// a tree of [Node] (`List`). +/// +/// The two main parsing mechanics used are: +/// +/// - Blocks, representing top-level elements +/// implemented via [BlockSyntax] subclasses, +/// such as headers, paragraphs, blockquotes, and code blocks. +/// - Inlines, representing chunks of text within a block with special meaning, +/// implemented via [InlineSyntax] subclasses, +/// such as links, emphasis, and inlined code. +/// +/// Looking closely at [Document.new] a few other concepts merit a mention: +/// +/// - [ExtensionSet] that provide configurations for common Markdown flavors +/// - [Resolver] which aid in resolving links and images +/// +/// If you are looking at extending the library to support custom formatting +/// what you might want is to: +/// +/// - Implement your own [InlineSyntax] subclasses +/// - Implement your own [BlockSyntax] subclasses +/// - Instruct the library to use those by: +/// - Creating a new [ExtensionSet] from one of the existing flavors +/// and adding your syntaxes. +/// - Passing your syntaxes to [Document] or [markdownToHtml] as parameters. +library; + +import 'src/version.dart'; + +export 'src/ast.dart'; +export 'src/block_parser.dart'; +export 'src/block_syntaxes/alert_block_syntax.dart'; +export 'src/block_syntaxes/block_syntax.dart'; +export 'src/block_syntaxes/blockquote_syntax.dart'; +export 'src/block_syntaxes/code_block_syntax.dart'; +export 'src/block_syntaxes/dummy_block_syntax.dart'; +export 'src/block_syntaxes/empty_block_syntax.dart'; +export 'src/block_syntaxes/fenced_blockquote_syntax.dart'; +export 'src/block_syntaxes/fenced_code_block_syntax.dart'; +export 'src/block_syntaxes/footnote_def_syntax.dart'; +export 'src/block_syntaxes/header_syntax.dart'; +export 'src/block_syntaxes/header_with_id_syntax.dart'; +export 'src/block_syntaxes/horizontal_rule_syntax.dart'; +export 'src/block_syntaxes/html_block_syntax.dart'; +export 'src/block_syntaxes/link_reference_definition_syntax.dart'; +export 'src/block_syntaxes/list_syntax.dart'; +export 'src/block_syntaxes/ordered_list_syntax.dart'; +export 'src/block_syntaxes/ordered_list_with_checkbox_syntax.dart'; +export 'src/block_syntaxes/paragraph_syntax.dart'; +export 'src/block_syntaxes/setext_header_syntax.dart'; +export 'src/block_syntaxes/setext_header_with_id_syntax.dart'; +export 'src/block_syntaxes/table_syntax.dart'; +export 'src/block_syntaxes/unordered_list_syntax.dart'; +export 'src/block_syntaxes/unordered_list_with_checkbox_syntax.dart'; +export 'src/document.dart'; +export 'src/emojis.dart'; +export 'src/extension_set.dart'; +export 'src/html_renderer.dart'; +export 'src/inline_parser.dart'; +export 'src/inline_syntaxes/autolink_extension_syntax.dart'; +export 'src/inline_syntaxes/autolink_syntax.dart'; +export 'src/inline_syntaxes/code_syntax.dart'; +export 'src/inline_syntaxes/color_swatch_syntax.dart'; +export 'src/inline_syntaxes/decode_html_syntax.dart'; +export 'src/inline_syntaxes/delimiter_syntax.dart'; +export 'src/inline_syntaxes/email_autolink_syntax.dart'; +export 'src/inline_syntaxes/emoji_syntax.dart'; +export 'src/inline_syntaxes/emphasis_syntax.dart'; +export 'src/inline_syntaxes/escape_html_syntax.dart'; +export 'src/inline_syntaxes/escape_syntax.dart'; +export 'src/inline_syntaxes/image_syntax.dart'; +export 'src/inline_syntaxes/inline_html_syntax.dart'; +export 'src/inline_syntaxes/inline_syntax.dart'; +export 'src/inline_syntaxes/line_break_syntax.dart'; +export 'src/inline_syntaxes/link_syntax.dart'; +export 'src/inline_syntaxes/soft_line_break_syntax.dart'; +export 'src/inline_syntaxes/strikethrough_syntax.dart'; +export 'src/inline_syntaxes/text_syntax.dart'; +export 'src/line.dart'; + +const version = packageVersion; diff --git a/pkgs/markdown/lib/src/assets/case_folding.dart b/pkgs/markdown/lib/src/assets/case_folding.dart new file mode 100644 index 000000000..09081aa46 --- /dev/null +++ b/pkgs/markdown/lib/src/assets/case_folding.dart @@ -0,0 +1,1316 @@ +// Generated file. do not edit. +// +// Source: tool/case_folding.txt +// Script: tool/update_case_folding.dart +// ignore_for_file: prefer_single_quotes + +const caseFoldingMap = { + "A": "a", + "B": "b", + "C": "c", + "D": "d", + "E": "e", + "F": "f", + "G": "g", + "H": "h", + "I": "i", + "J": "j", + "K": "k", + "L": "l", + "M": "m", + "N": "n", + "O": "o", + "P": "p", + "Q": "q", + "R": "r", + "S": "s", + "T": "t", + "U": "u", + "V": "v", + "W": "w", + "X": "x", + "Y": "y", + "Z": "z", + "À": "à", + "Á": "á", + "Â": "â", + "Ã": "ã", + "Ä": "ä", + "Å": "å", + "Æ": "æ", + "Ç": "ç", + "È": "è", + "É": "é", + "Ê": "ê", + "Ë": "ë", + "Ì": "ì", + "Í": "í", + "Î": "î", + "Ï": "ï", + "Ð": "ð", + "Ñ": "ñ", + "Ò": "ò", + "Ó": "ó", + "Ô": "ô", + "Õ": "õ", + "Ö": "ö", + "Ø": "ø", + "Ù": "ù", + "Ú": "ú", + "Û": "û", + "Ü": "ü", + "Ý": "ý", + "Þ": "þ", + "Ā": "ā", + "Ă": "ă", + "Ą": "ą", + "Ć": "ć", + "Ĉ": "ĉ", + "Ċ": "ċ", + "Č": "č", + "Ď": "ď", + "Đ": "đ", + "Ē": "ē", + "Ĕ": "ĕ", + "Ė": "ė", + "Ę": "ę", + "Ě": "ě", + "Ĝ": "ĝ", + "Ğ": "ğ", + "Ġ": "ġ", + "Ģ": "ģ", + "Ĥ": "ĥ", + "Ħ": "ħ", + "Ĩ": "ĩ", + "Ī": "ī", + "Ĭ": "ĭ", + "Į": "į", + "İ": "i̇", + "Ĵ": "ĵ", + "Ķ": "ķ", + "Ĺ": "ĺ", + "Ļ": "ļ", + "Ľ": "ľ", + "Ŀ": "ŀ", + "Ł": "ł", + "Ń": "ń", + "Ņ": "ņ", + "Ň": "ň", + "Ŋ": "ŋ", + "Ō": "ō", + "Ŏ": "ŏ", + "Ő": "ő", + "Ŕ": "ŕ", + "Ŗ": "ŗ", + "Ř": "ř", + "Ś": "ś", + "Ŝ": "ŝ", + "Ş": "ş", + "Š": "š", + "Ţ": "ţ", + "Ť": "ť", + "Ŧ": "ŧ", + "Ũ": "ũ", + "Ū": "ū", + "Ŭ": "ŭ", + "Ů": "ů", + "Ű": "ű", + "Ų": "ų", + "Ŵ": "ŵ", + "Ŷ": "ŷ", + "Ÿ": "ÿ", + "Ź": "ź", + "Ż": "ż", + "Ž": "ž", + "Ɓ": "ɓ", + "Ƃ": "ƃ", + "Ƅ": "ƅ", + "Ɔ": "ɔ", + "Ƈ": "ƈ", + "Ɖ": "ɖ", + "Ɗ": "ɗ", + "Ƌ": "ƌ", + "Ǝ": "ǝ", + "Ə": "ə", + "Ɛ": "ɛ", + "Ƒ": "ƒ", + "Ɠ": "ɠ", + "Ɣ": "ɣ", + "Ɩ": "ɩ", + "Ɨ": "ɨ", + "Ƙ": "ƙ", + "Ɯ": "ɯ", + "Ɲ": "ɲ", + "Ɵ": "ɵ", + "Ơ": "ơ", + "Ƣ": "ƣ", + "Ƥ": "ƥ", + "Ƨ": "ƨ", + "Ʃ": "ʃ", + "Ƭ": "ƭ", + "Ʈ": "ʈ", + "Ư": "ư", + "Ʊ": "ʊ", + "Ʋ": "ʋ", + "Ƴ": "ƴ", + "Ƶ": "ƶ", + "Ʒ": "ʒ", + "Ƹ": "ƹ", + "Ƽ": "ƽ", + "DŽ": "dž", + "Dž": "dž", + "LJ": "lj", + "Lj": "lj", + "NJ": "nj", + "Nj": "nj", + "Ǎ": "ǎ", + "Ǐ": "ǐ", + "Ǒ": "ǒ", + "Ǔ": "ǔ", + "Ǖ": "ǖ", + "Ǘ": "ǘ", + "Ǚ": "ǚ", + "Ǜ": "ǜ", + "Ǟ": "ǟ", + "Ǡ": "ǡ", + "Ǣ": "ǣ", + "Ǥ": "ǥ", + "Ǧ": "ǧ", + "Ǩ": "ǩ", + "Ǫ": "ǫ", + "Ǭ": "ǭ", + "Ǯ": "ǯ", + "DZ": "dz", + "Dz": "dz", + "Ǵ": "ǵ", + "Ƕ": "ƕ", + "Ƿ": "ƿ", + "Ǹ": "ǹ", + "Ǻ": "ǻ", + "Ǽ": "ǽ", + "Ǿ": "ǿ", + "Ȁ": "ȁ", + "Ȃ": "ȃ", + "Ȅ": "ȅ", + "Ȇ": "ȇ", + "Ȉ": "ȉ", + "Ȋ": "ȋ", + "Ȍ": "ȍ", + "Ȏ": "ȏ", + "Ȑ": "ȑ", + "Ȓ": "ȓ", + "Ȕ": "ȕ", + "Ȗ": "ȗ", + "Ș": "ș", + "Ț": "ț", + "Ȝ": "ȝ", + "Ȟ": "ȟ", + "Ƞ": "ƞ", + "Ȣ": "ȣ", + "Ȥ": "ȥ", + "Ȧ": "ȧ", + "Ȩ": "ȩ", + "Ȫ": "ȫ", + "Ȭ": "ȭ", + "Ȯ": "ȯ", + "Ȱ": "ȱ", + "Ȳ": "ȳ", + "Ⱥ": "ⱥ", + "Ȼ": "ȼ", + "Ƚ": "ƚ", + "Ⱦ": "ⱦ", + "Ɂ": "ɂ", + "Ƀ": "ƀ", + "Ʉ": "ʉ", + "Ʌ": "ʌ", + "Ɇ": "ɇ", + "Ɉ": "ɉ", + "Ɋ": "ɋ", + "Ɍ": "ɍ", + "Ɏ": "ɏ", + "Ͱ": "ͱ", + "Ͳ": "ͳ", + "Ͷ": "ͷ", + "Ϳ": "ϳ", + "Ά": "ά", + "Έ": "έ", + "Ή": "ή", + "Ί": "ί", + "Ό": "ό", + "Ύ": "ύ", + "Ώ": "ώ", + "Α": "α", + "Β": "β", + "Γ": "γ", + "Δ": "δ", + "Ε": "ε", + "Ζ": "ζ", + "Η": "η", + "Θ": "θ", + "Ι": "ι", + "Κ": "κ", + "Λ": "λ", + "Μ": "μ", + "Ν": "ν", + "Ξ": "ξ", + "Ο": "ο", + "Π": "π", + "Ρ": "ρ", + "Σ": "σ", + "Τ": "τ", + "Υ": "υ", + "Φ": "φ", + "Χ": "χ", + "Ψ": "ψ", + "Ω": "ω", + "Ϊ": "ϊ", + "Ϋ": "ϋ", + "Ϣ": "ϣ", + "Ϥ": "ϥ", + "Ϧ": "ϧ", + "Ϩ": "ϩ", + "Ϫ": "ϫ", + "Ϭ": "ϭ", + "Ϯ": "ϯ", + "Ϸ": "ϸ", + "Ϻ": "ϻ", + "Ѐ": "ѐ", + "Ё": "ё", + "Ђ": "ђ", + "Ѓ": "ѓ", + "Є": "є", + "Ѕ": "ѕ", + "І": "і", + "Ї": "ї", + "Ј": "ј", + "Љ": "љ", + "Њ": "њ", + "Ћ": "ћ", + "Ќ": "ќ", + "Ѝ": "ѝ", + "Ў": "ў", + "Џ": "џ", + "А": "а", + "Б": "б", + "В": "в", + "Г": "г", + "Д": "д", + "Е": "е", + "Ж": "ж", + "З": "з", + "И": "и", + "Й": "й", + "К": "к", + "Л": "л", + "М": "м", + "Н": "н", + "О": "о", + "П": "п", + "Р": "р", + "С": "с", + "Т": "т", + "У": "у", + "Ф": "ф", + "Х": "х", + "Ц": "ц", + "Ч": "ч", + "Ш": "ш", + "Щ": "щ", + "Ъ": "ъ", + "Ы": "ы", + "Ь": "ь", + "Э": "э", + "Ю": "ю", + "Я": "я", + "Ѡ": "ѡ", + "Ѣ": "ѣ", + "Ѥ": "ѥ", + "Ѧ": "ѧ", + "Ѩ": "ѩ", + "Ѫ": "ѫ", + "Ѭ": "ѭ", + "Ѯ": "ѯ", + "Ѱ": "ѱ", + "Ѳ": "ѳ", + "Ѵ": "ѵ", + "Ѷ": "ѷ", + "Ѹ": "ѹ", + "Ѻ": "ѻ", + "Ѽ": "ѽ", + "Ѿ": "ѿ", + "Ҁ": "ҁ", + "Ҋ": "ҋ", + "Ҍ": "ҍ", + "Ҏ": "ҏ", + "Ґ": "ґ", + "Ғ": "ғ", + "Ҕ": "ҕ", + "Җ": "җ", + "Ҙ": "ҙ", + "Қ": "қ", + "Ҝ": "ҝ", + "Ҟ": "ҟ", + "Ҡ": "ҡ", + "Ң": "ң", + "Ҧ": "ҧ", + "Ҩ": "ҩ", + "Ҫ": "ҫ", + "Ҭ": "ҭ", + "Ү": "ү", + "Ұ": "ұ", + "Ҳ": "ҳ", + "Ҷ": "ҷ", + "Ҹ": "ҹ", + "Һ": "һ", + "Ҽ": "ҽ", + "Ҿ": "ҿ", + "Ӂ": "ӂ", + "Ӄ": "ӄ", + "Ӆ": "ӆ", + "Ӈ": "ӈ", + "Ӊ": "ӊ", + "Ӌ": "ӌ", + "Ӎ": "ӎ", + "Ӑ": "ӑ", + "Ӓ": "ӓ", + "Ӗ": "ӗ", + "Ә": "ә", + "Ӛ": "ӛ", + "Ӝ": "ӝ", + "Ӟ": "ӟ", + "Ӡ": "ӡ", + "Ӣ": "ӣ", + "Ӥ": "ӥ", + "Ӧ": "ӧ", + "Ө": "ө", + "Ӫ": "ӫ", + "Ӭ": "ӭ", + "Ӯ": "ӯ", + "Ӱ": "ӱ", + "Ӳ": "ӳ", + "Ӵ": "ӵ", + "Ӷ": "ӷ", + "Ӹ": "ӹ", + "Ӻ": "ӻ", + "Ӽ": "ӽ", + "Ӿ": "ӿ", + "Ԁ": "ԁ", + "Ԃ": "ԃ", + "Ԅ": "ԅ", + "Ԇ": "ԇ", + "Ԉ": "ԉ", + "Ԋ": "ԋ", + "Ԍ": "ԍ", + "Ԏ": "ԏ", + "Ԑ": "ԑ", + "Ԓ": "ԓ", + "Ԕ": "ԕ", + "Ԗ": "ԗ", + "Ԙ": "ԙ", + "Ԛ": "ԛ", + "Ԝ": "ԝ", + "Ԟ": "ԟ", + "Ԡ": "ԡ", + "Ԣ": "ԣ", + "Ԥ": "ԥ", + "Ԧ": "ԧ", + "Ԩ": "ԩ", + "Ԫ": "ԫ", + "Ԭ": "ԭ", + "Ԯ": "ԯ", + "Ա": "ա", + "Բ": "բ", + "Գ": "գ", + "Դ": "դ", + "Ե": "ե", + "Զ": "զ", + "Է": "է", + "Ը": "ը", + "Թ": "թ", + "Ժ": "ժ", + "Ի": "ի", + "Լ": "լ", + "Խ": "խ", + "Ծ": "ծ", + "Կ": "կ", + "Հ": "հ", + "Ձ": "ձ", + "Ղ": "ղ", + "Ճ": "ճ", + "Մ": "մ", + "Յ": "յ", + "Ն": "ն", + "Շ": "շ", + "Ո": "ո", + "Չ": "չ", + "Պ": "պ", + "Ջ": "ջ", + "Ռ": "ռ", + "Ս": "ս", + "Վ": "վ", + "Տ": "տ", + "Ր": "ր", + "Ց": "ց", + "Ւ": "ւ", + "Փ": "փ", + "Ք": "ք", + "Օ": "օ", + "Ֆ": "ֆ", + "Ⴀ": "ⴀ", + "Ⴁ": "ⴁ", + "Ⴂ": "ⴂ", + "Ⴃ": "ⴃ", + "Ⴄ": "ⴄ", + "Ⴅ": "ⴅ", + "Ⴆ": "ⴆ", + "Ⴇ": "ⴇ", + "Ⴈ": "ⴈ", + "Ⴉ": "ⴉ", + "Ⴊ": "ⴊ", + "Ⴋ": "ⴋ", + "Ⴌ": "ⴌ", + "Ⴍ": "ⴍ", + "Ⴎ": "ⴎ", + "Ⴏ": "ⴏ", + "Ⴐ": "ⴐ", + "Ⴑ": "ⴑ", + "Ⴒ": "ⴒ", + "Ⴓ": "ⴓ", + "Ⴔ": "ⴔ", + "Ⴕ": "ⴕ", + "Ⴖ": "ⴖ", + "Ⴗ": "ⴗ", + "Ⴘ": "ⴘ", + "Ⴙ": "ⴙ", + "Ⴚ": "ⴚ", + "Ⴛ": "ⴛ", + "Ⴜ": "ⴜ", + "Ⴝ": "ⴝ", + "Ⴞ": "ⴞ", + "Ⴟ": "ⴟ", + "Ⴠ": "ⴠ", + "Ⴡ": "ⴡ", + "Ⴢ": "ⴢ", + "Ⴣ": "ⴣ", + "Ⴤ": "ⴤ", + "Ⴥ": "ⴥ", + "Ⴧ": "ⴧ", + "Ⴭ": "ⴭ", + "Ა": "ა", + "Ბ": "ბ", + "Გ": "გ", + "Დ": "დ", + "Ე": "ე", + "Ვ": "ვ", + "Ზ": "ზ", + "Თ": "თ", + "Ი": "ი", + "Კ": "კ", + "Ლ": "ლ", + "Მ": "მ", + "Ნ": "ნ", + "Ო": "ო", + "Პ": "პ", + "Ჟ": "ჟ", + "Რ": "რ", + "Ს": "ს", + "Ტ": "ტ", + "Უ": "უ", + "Ფ": "ფ", + "Ქ": "ქ", + "Ღ": "ღ", + "Ყ": "ყ", + "Შ": "შ", + "Ჩ": "ჩ", + "Ც": "ც", + "Ძ": "ძ", + "Წ": "წ", + "Ჭ": "ჭ", + "Ხ": "ხ", + "Ჯ": "ჯ", + "Ჰ": "ჰ", + "Ჱ": "ჱ", + "Ჲ": "ჲ", + "Ჳ": "ჳ", + "Ჴ": "ჴ", + "Ჵ": "ჵ", + "Ჶ": "ჶ", + "Ჷ": "ჷ", + "Ჸ": "ჸ", + "Ჹ": "ჹ", + "Ჺ": "ჺ", + "Ჽ": "ჽ", + "Ჾ": "ჾ", + "Ჿ": "ჿ", + "Ḁ": "ḁ", + "Ḃ": "ḃ", + "Ḅ": "ḅ", + "Ḇ": "ḇ", + "Ḉ": "ḉ", + "Ḋ": "ḋ", + "Ḍ": "ḍ", + "Ḏ": "ḏ", + "Ḑ": "ḑ", + "Ḓ": "ḓ", + "Ḕ": "ḕ", + "Ḗ": "ḗ", + "Ḙ": "ḙ", + "Ḛ": "ḛ", + "Ḝ": "ḝ", + "Ḟ": "ḟ", + "Ḡ": "ḡ", + "Ḣ": "ḣ", + "Ḥ": "ḥ", + "Ḧ": "ḧ", + "Ḩ": "ḩ", + "Ḫ": "ḫ", + "Ḭ": "ḭ", + "Ḯ": "ḯ", + "Ḱ": "ḱ", + "Ḳ": "ḳ", + "Ḵ": "ḵ", + "Ḷ": "ḷ", + "Ḹ": "ḹ", + "Ḻ": "ḻ", + "Ḽ": "ḽ", + "Ḿ": "ḿ", + "Ṁ": "ṁ", + "Ṃ": "ṃ", + "Ṅ": "ṅ", + "Ṇ": "ṇ", + "Ṉ": "ṉ", + "Ṋ": "ṋ", + "Ṍ": "ṍ", + "Ṏ": "ṏ", + "Ṑ": "ṑ", + "Ṓ": "ṓ", + "Ṕ": "ṕ", + "Ṗ": "ṗ", + "Ṙ": "ṙ", + "Ṛ": "ṛ", + "Ṝ": "ṝ", + "Ṟ": "ṟ", + "Ṡ": "ṡ", + "Ṣ": "ṣ", + "Ṥ": "ṥ", + "Ṧ": "ṧ", + "Ṩ": "ṩ", + "Ṫ": "ṫ", + "Ṭ": "ṭ", + "Ṯ": "ṯ", + "Ṱ": "ṱ", + "Ṳ": "ṳ", + "Ṵ": "ṵ", + "Ṷ": "ṷ", + "Ṹ": "ṹ", + "Ṻ": "ṻ", + "Ṽ": "ṽ", + "Ṿ": "ṿ", + "Ẁ": "ẁ", + "Ẃ": "ẃ", + "Ẅ": "ẅ", + "Ẇ": "ẇ", + "Ẉ": "ẉ", + "Ẋ": "ẋ", + "Ẍ": "ẍ", + "Ẏ": "ẏ", + "Ẑ": "ẑ", + "Ẓ": "ẓ", + "Ẕ": "ẕ", + "ẞ": "ss", + "Ạ": "ạ", + "Ả": "ả", + "Ấ": "ấ", + "Ầ": "ầ", + "Ẩ": "ẩ", + "Ẫ": "ẫ", + "Ậ": "ậ", + "Ắ": "ắ", + "Ằ": "ằ", + "Ẳ": "ẳ", + "Ẵ": "ẵ", + "Ặ": "ặ", + "Ẹ": "ẹ", + "Ẻ": "ẻ", + "Ẽ": "ẽ", + "Ế": "ế", + "Ề": "ề", + "Ể": "ể", + "Ễ": "ễ", + "Ệ": "ệ", + "Ỉ": "ỉ", + "Ị": "ị", + "Ọ": "ọ", + "Ỏ": "ỏ", + "Ố": "ố", + "Ồ": "ồ", + "Ổ": "ổ", + "Ỗ": "ỗ", + "Ộ": "ộ", + "Ớ": "ớ", + "Ờ": "ờ", + "Ở": "ở", + "Ỡ": "ỡ", + "Ợ": "ợ", + "Ụ": "ụ", + "Ủ": "ủ", + "Ứ": "ứ", + "Ừ": "ừ", + "Ử": "ử", + "Ữ": "ữ", + "Ự": "ự", + "Ỳ": "ỳ", + "Ỵ": "ỵ", + "Ỷ": "ỷ", + "Ỹ": "ỹ", + "Ỻ": "ỻ", + "Ỽ": "ỽ", + "Ỿ": "ỿ", + "Ἀ": "ἀ", + "Ἁ": "ἁ", + "Ἂ": "ἂ", + "Ἃ": "ἃ", + "Ἄ": "ἄ", + "Ἅ": "ἅ", + "Ἆ": "ἆ", + "Ἇ": "ἇ", + "Ἐ": "ἐ", + "Ἑ": "ἑ", + "Ἒ": "ἒ", + "Ἓ": "ἓ", + "Ἔ": "ἔ", + "Ἕ": "ἕ", + "Ἠ": "ἠ", + "Ἡ": "ἡ", + "Ἢ": "ἢ", + "Ἣ": "ἣ", + "Ἤ": "ἤ", + "Ἥ": "ἥ", + "Ἦ": "ἦ", + "Ἧ": "ἧ", + "Ἰ": "ἰ", + "Ἱ": "ἱ", + "Ἲ": "ἲ", + "Ἳ": "ἳ", + "Ἴ": "ἴ", + "Ἵ": "ἵ", + "Ἶ": "ἶ", + "Ἷ": "ἷ", + "Ὀ": "ὀ", + "Ὁ": "ὁ", + "Ὂ": "ὂ", + "Ὃ": "ὃ", + "Ὄ": "ὄ", + "Ὅ": "ὅ", + "Ὑ": "ὑ", + "Ὓ": "ὓ", + "Ὕ": "ὕ", + "Ὗ": "ὗ", + "Ὠ": "ὠ", + "Ὡ": "ὡ", + "Ὢ": "ὢ", + "Ὣ": "ὣ", + "Ὤ": "ὤ", + "Ὥ": "ὥ", + "Ὦ": "ὦ", + "Ὧ": "ὧ", + "ᾈ": "ἀι", + "ᾉ": "ἁι", + "ᾊ": "ἂι", + "ᾋ": "ἃι", + "ᾌ": "ἄι", + "ᾍ": "ἅι", + "ᾎ": "ἆι", + "ᾏ": "ἇι", + "ᾘ": "ἠι", + "ᾙ": "ἡι", + "ᾚ": "ἢι", + "ᾛ": "ἣι", + "ᾜ": "ἤι", + "ᾝ": "ἥι", + "ᾞ": "ἦι", + "ᾟ": "ἧι", + "ᾨ": "ὠι", + "ᾩ": "ὡι", + "ᾪ": "ὢι", + "ᾫ": "ὣι", + "ᾬ": "ὤι", + "ᾭ": "ὥι", + "ᾮ": "ὦι", + "ᾯ": "ὧι", + "Ᾰ": "ᾰ", + "Ᾱ": "ᾱ", + "Ὰ": "ὰ", + "Ά": "ά", + "ᾼ": "αι", + "Ὲ": "ὲ", + "Έ": "έ", + "Ὴ": "ὴ", + "Ή": "ή", + "ῌ": "ηι", + "Ῐ": "ῐ", + "Ῑ": "ῑ", + "Ὶ": "ὶ", + "Ί": "ί", + "Ῠ": "ῠ", + "Ῡ": "ῡ", + "Ὺ": "ὺ", + "Ύ": "ύ", + "Ῥ": "ῥ", + "Ὸ": "ὸ", + "Ό": "ό", + "Ὼ": "ὼ", + "Ώ": "ώ", + "ῼ": "ωι", + "Ⓐ": "ⓐ", + "Ⓑ": "ⓑ", + "Ⓒ": "ⓒ", + "Ⓓ": "ⓓ", + "Ⓔ": "ⓔ", + "Ⓕ": "ⓕ", + "Ⓖ": "ⓖ", + "Ⓗ": "ⓗ", + "Ⓘ": "ⓘ", + "Ⓙ": "ⓙ", + "Ⓚ": "ⓚ", + "Ⓛ": "ⓛ", + "Ⓜ": "ⓜ", + "Ⓝ": "ⓝ", + "Ⓞ": "ⓞ", + "Ⓟ": "ⓟ", + "Ⓠ": "ⓠ", + "Ⓡ": "ⓡ", + "Ⓢ": "ⓢ", + "Ⓣ": "ⓣ", + "Ⓤ": "ⓤ", + "Ⓥ": "ⓥ", + "Ⓦ": "ⓦ", + "Ⓧ": "ⓧ", + "Ⓨ": "ⓨ", + "Ⓩ": "ⓩ", + "Ⰰ": "ⰰ", + "Ⰱ": "ⰱ", + "Ⰲ": "ⰲ", + "Ⰳ": "ⰳ", + "Ⰴ": "ⰴ", + "Ⰵ": "ⰵ", + "Ⰶ": "ⰶ", + "Ⰷ": "ⰷ", + "Ⰸ": "ⰸ", + "Ⰹ": "ⰹ", + "Ⰺ": "ⰺ", + "Ⰻ": "ⰻ", + "Ⰼ": "ⰼ", + "Ⰽ": "ⰽ", + "Ⰾ": "ⰾ", + "Ⰿ": "ⰿ", + "Ⱀ": "ⱀ", + "Ⱁ": "ⱁ", + "Ⱂ": "ⱂ", + "Ⱃ": "ⱃ", + "Ⱄ": "ⱄ", + "Ⱅ": "ⱅ", + "Ⱆ": "ⱆ", + "Ⱇ": "ⱇ", + "Ⱈ": "ⱈ", + "Ⱉ": "ⱉ", + "Ⱊ": "ⱊ", + "Ⱋ": "ⱋ", + "Ⱌ": "ⱌ", + "Ⱍ": "ⱍ", + "Ⱎ": "ⱎ", + "Ⱏ": "ⱏ", + "Ⱐ": "ⱐ", + "Ⱑ": "ⱑ", + "Ⱒ": "ⱒ", + "Ⱓ": "ⱓ", + "Ⱔ": "ⱔ", + "Ⱕ": "ⱕ", + "Ⱖ": "ⱖ", + "Ⱗ": "ⱗ", + "Ⱘ": "ⱘ", + "Ⱙ": "ⱙ", + "Ⱚ": "ⱚ", + "Ⱛ": "ⱛ", + "Ⱜ": "ⱜ", + "Ⱝ": "ⱝ", + "Ⱞ": "ⱞ", + "Ⱟ": "ⱟ", + "Ⱡ": "ⱡ", + "Ɫ": "ɫ", + "Ᵽ": "ᵽ", + "Ɽ": "ɽ", + "Ⱨ": "ⱨ", + "Ⱪ": "ⱪ", + "Ⱬ": "ⱬ", + "Ɑ": "ɑ", + "Ɱ": "ɱ", + "Ɐ": "ɐ", + "Ɒ": "ɒ", + "Ⱳ": "ⱳ", + "Ⱶ": "ⱶ", + "Ȿ": "ȿ", + "Ɀ": "ɀ", + "Ⲁ": "ⲁ", + "Ⲃ": "ⲃ", + "Ⲅ": "ⲅ", + "Ⲇ": "ⲇ", + "Ⲉ": "ⲉ", + "Ⲋ": "ⲋ", + "Ⲍ": "ⲍ", + "Ⲏ": "ⲏ", + "Ⲑ": "ⲑ", + "Ⲓ": "ⲓ", + "Ⲕ": "ⲕ", + "Ⲗ": "ⲗ", + "Ⲙ": "ⲙ", + "Ⲛ": "ⲛ", + "Ⲝ": "ⲝ", + "Ⲟ": "ⲟ", + "Ⲡ": "ⲡ", + "Ⲣ": "ⲣ", + "Ⲥ": "ⲥ", + "Ⲧ": "ⲧ", + "Ⲩ": "ⲩ", + "Ⲫ": "ⲫ", + "Ⲭ": "ⲭ", + "Ⲯ": "ⲯ", + "Ⲱ": "ⲱ", + "Ⲳ": "ⲳ", + "Ⲵ": "ⲵ", + "Ⲷ": "ⲷ", + "Ⲹ": "ⲹ", + "Ⲻ": "ⲻ", + "Ⲽ": "ⲽ", + "Ⲿ": "ⲿ", + "Ⳁ": "ⳁ", + "Ⳃ": "ⳃ", + "Ⳅ": "ⳅ", + "Ⳇ": "ⳇ", + "Ⳉ": "ⳉ", + "Ⳋ": "ⳋ", + "Ⳍ": "ⳍ", + "Ⳏ": "ⳏ", + "Ⳑ": "ⳑ", + "Ⳓ": "ⳓ", + "Ⳕ": "ⳕ", + "Ⳗ": "ⳗ", + "Ⳙ": "ⳙ", + "Ⳛ": "ⳛ", + "Ⳝ": "ⳝ", + "Ⳟ": "ⳟ", + "Ⳡ": "ⳡ", + "Ⳣ": "ⳣ", + "Ⳬ": "ⳬ", + "Ⳮ": "ⳮ", + "Ⳳ": "ⳳ", + "Ꙁ": "ꙁ", + "Ꙃ": "ꙃ", + "Ꙅ": "ꙅ", + "Ꙇ": "ꙇ", + "Ꙉ": "ꙉ", + "Ꙋ": "ꙋ", + "Ꙍ": "ꙍ", + "Ꙏ": "ꙏ", + "Ꙑ": "ꙑ", + "Ꙓ": "ꙓ", + "Ꙕ": "ꙕ", + "Ꙗ": "ꙗ", + "Ꙙ": "ꙙ", + "Ꙛ": "ꙛ", + "Ꙝ": "ꙝ", + "Ꙟ": "ꙟ", + "Ꙡ": "ꙡ", + "Ꙣ": "ꙣ", + "Ꙥ": "ꙥ", + "Ꙧ": "ꙧ", + "Ꙩ": "ꙩ", + "Ꙫ": "ꙫ", + "Ꙭ": "ꙭ", + "Ꚁ": "ꚁ", + "Ꚃ": "ꚃ", + "Ꚅ": "ꚅ", + "Ꚇ": "ꚇ", + "Ꚉ": "ꚉ", + "Ꚋ": "ꚋ", + "Ꚍ": "ꚍ", + "Ꚏ": "ꚏ", + "Ꚑ": "ꚑ", + "Ꚓ": "ꚓ", + "Ꚕ": "ꚕ", + "Ꚗ": "ꚗ", + "Ꚙ": "ꚙ", + "Ꚛ": "ꚛ", + "Ꜣ": "ꜣ", + "Ꜥ": "ꜥ", + "Ꜧ": "ꜧ", + "Ꜩ": "ꜩ", + "Ꜫ": "ꜫ", + "Ꜭ": "ꜭ", + "Ꜯ": "ꜯ", + "Ꜳ": "ꜳ", + "Ꜵ": "ꜵ", + "Ꜷ": "ꜷ", + "Ꜹ": "ꜹ", + "Ꜻ": "ꜻ", + "Ꜽ": "ꜽ", + "Ꜿ": "ꜿ", + "Ꝁ": "ꝁ", + "Ꝃ": "ꝃ", + "Ꝅ": "ꝅ", + "Ꝇ": "ꝇ", + "Ꝉ": "ꝉ", + "Ꝋ": "ꝋ", + "Ꝍ": "ꝍ", + "Ꝏ": "ꝏ", + "Ꝑ": "ꝑ", + "Ꝓ": "ꝓ", + "Ꝕ": "ꝕ", + "Ꝗ": "ꝗ", + "Ꝙ": "ꝙ", + "Ꝛ": "ꝛ", + "Ꝝ": "ꝝ", + "Ꝟ": "ꝟ", + "Ꝡ": "ꝡ", + "Ꝣ": "ꝣ", + "Ꝥ": "ꝥ", + "Ꝧ": "ꝧ", + "Ꝩ": "ꝩ", + "Ꝫ": "ꝫ", + "Ꝭ": "ꝭ", + "Ꝯ": "ꝯ", + "Ꝺ": "ꝺ", + "Ꝼ": "ꝼ", + "Ᵹ": "ᵹ", + "Ꝿ": "ꝿ", + "Ꞁ": "ꞁ", + "Ꞃ": "ꞃ", + "Ꞅ": "ꞅ", + "Ꞇ": "ꞇ", + "Ꞌ": "ꞌ", + "Ɥ": "ɥ", + "Ꞑ": "ꞑ", + "Ꞓ": "ꞓ", + "Ꞗ": "ꞗ", + "Ꞙ": "ꞙ", + "Ꞛ": "ꞛ", + "Ꞝ": "ꞝ", + "Ꞟ": "ꞟ", + "Ꞡ": "ꞡ", + "Ꞣ": "ꞣ", + "Ꞥ": "ꞥ", + "Ꞧ": "ꞧ", + "Ꞩ": "ꞩ", + "Ɦ": "ɦ", + "Ɜ": "ɜ", + "Ɡ": "ɡ", + "Ɬ": "ɬ", + "Ɪ": "ɪ", + "Ʞ": "ʞ", + "Ʇ": "ʇ", + "Ʝ": "ʝ", + "Ꭓ": "ꭓ", + "Ꞵ": "ꞵ", + "Ꞷ": "ꞷ", + "Ꞹ": "ꞹ", + "Ꞻ": "ꞻ", + "Ꞽ": "ꞽ", + "Ꞿ": "ꞿ", + "Ꟁ": "ꟁ", + "Ꟃ": "ꟃ", + "Ꞔ": "ꞔ", + "Ʂ": "ʂ", + "Ᶎ": "ᶎ", + "Ꟈ": "ꟈ", + "Ꟊ": "ꟊ", + "Ꟑ": "ꟑ", + "Ꟗ": "ꟗ", + "Ꟙ": "ꟙ", + "Ꟶ": "ꟶ", + "A": "a", + "B": "b", + "C": "c", + "D": "d", + "E": "e", + "F": "f", + "G": "g", + "H": "h", + "I": "i", + "J": "j", + "K": "k", + "L": "l", + "M": "m", + "N": "n", + "O": "o", + "P": "p", + "Q": "q", + "R": "r", + "S": "s", + "T": "t", + "U": "u", + "V": "v", + "W": "w", + "X": "x", + "Y": "y", + "Z": "z", + "𐐀": "𐐨", + "𐐁": "𐐩", + "𐐂": "𐐪", + "𐐃": "𐐫", + "𐐄": "𐐬", + "𐐅": "𐐭", + "𐐆": "𐐮", + "𐐇": "𐐯", + "𐐈": "𐐰", + "𐐉": "𐐱", + "𐐊": "𐐲", + "𐐋": "𐐳", + "𐐌": "𐐴", + "𐐍": "𐐵", + "𐐎": "𐐶", + "𐐏": "𐐷", + "𐐐": "𐐸", + "𐐑": "𐐹", + "𐐒": "𐐺", + "𐐓": "𐐻", + "𐐔": "𐐼", + "𐐕": "𐐽", + "𐐖": "𐐾", + "𐐗": "𐐿", + "𐐘": "𐑀", + "𐐙": "𐑁", + "𐐚": "𐑂", + "𐐛": "𐑃", + "𐐜": "𐑄", + "𐐝": "𐑅", + "𐐞": "𐑆", + "𐐟": "𐑇", + "𐐠": "𐑈", + "𐐡": "𐑉", + "𐐢": "𐑊", + "𐐣": "𐑋", + "𐐤": "𐑌", + "𐐥": "𐑍", + "𐐦": "𐑎", + "𐐧": "𐑏", + "𐒰": "𐓘", + "𐒱": "𐓙", + "𐒲": "𐓚", + "𐒳": "𐓛", + "𐒴": "𐓜", + "𐒵": "𐓝", + "𐒶": "𐓞", + "𐒷": "𐓟", + "𐒸": "𐓠", + "𐒹": "𐓡", + "𐒺": "𐓢", + "𐒻": "𐓣", + "𐒼": "𐓤", + "𐒽": "𐓥", + "𐒾": "𐓦", + "𐒿": "𐓧", + "𐓀": "𐓨", + "𐓁": "𐓩", + "𐓂": "𐓪", + "𐓃": "𐓫", + "𐓄": "𐓬", + "𐓅": "𐓭", + "𐓆": "𐓮", + "𐓇": "𐓯", + "𐓈": "𐓰", + "𐓉": "𐓱", + "𐓊": "𐓲", + "𐓋": "𐓳", + "𐓌": "𐓴", + "𐓍": "𐓵", + "𐓎": "𐓶", + "𐓏": "𐓷", + "𐓐": "𐓸", + "𐓑": "𐓹", + "𐓒": "𐓺", + "𐓓": "𐓻", + "𐕰": "𐖗", + "𐕱": "𐖘", + "𐕲": "𐖙", + "𐕳": "𐖚", + "𐕴": "𐖛", + "𐕵": "𐖜", + "𐕶": "𐖝", + "𐕷": "𐖞", + "𐕸": "𐖟", + "𐕹": "𐖠", + "𐕺": "𐖡", + "𐕼": "𐖣", + "𐕽": "𐖤", + "𐕾": "𐖥", + "𐕿": "𐖦", + "𐖀": "𐖧", + "𐖁": "𐖨", + "𐖂": "𐖩", + "𐖃": "𐖪", + "𐖄": "𐖫", + "𐖅": "𐖬", + "𐖆": "𐖭", + "𐖇": "𐖮", + "𐖈": "𐖯", + "𐖉": "𐖰", + "𐖊": "𐖱", + "𐖌": "𐖳", + "𐖍": "𐖴", + "𐖎": "𐖵", + "𐖏": "𐖶", + "𐖐": "𐖷", + "𐖑": "𐖸", + "𐖒": "𐖹", + "𐖔": "𐖻", + "𐖕": "𐖼", + "𐲀": "𐳀", + "𐲁": "𐳁", + "𐲂": "𐳂", + "𐲃": "𐳃", + "𐲄": "𐳄", + "𐲅": "𐳅", + "𐲆": "𐳆", + "𐲇": "𐳇", + "𐲈": "𐳈", + "𐲉": "𐳉", + "𐲊": "𐳊", + "𐲋": "𐳋", + "𐲌": "𐳌", + "𐲍": "𐳍", + "𐲎": "𐳎", + "𐲏": "𐳏", + "𐲐": "𐳐", + "𐲑": "𐳑", + "𐲒": "𐳒", + "𐲓": "𐳓", + "𐲔": "𐳔", + "𐲕": "𐳕", + "𐲖": "𐳖", + "𐲗": "𐳗", + "𐲘": "𐳘", + "𐲙": "𐳙", + "𐲚": "𐳚", + "𐲛": "𐳛", + "𐲜": "𐳜", + "𐲝": "𐳝", + "𐲞": "𐳞", + "𐲟": "𐳟", + "𐲠": "𐳠", + "𐲡": "𐳡", + "𐲢": "𐳢", + "𐲣": "𐳣", + "𐲤": "𐳤", + "𐲥": "𐳥", + "𐲦": "𐳦", + "𐲧": "𐳧", + "𐲨": "𐳨", + "𐲩": "𐳩", + "𐲪": "𐳪", + "𐲫": "𐳫", + "𐲬": "𐳬", + "𐲭": "𐳭", + "𐲮": "𐳮", + "𐲯": "𐳯", + "𐲰": "𐳰", + "𐲱": "𐳱", + "𐲲": "𐳲", + "𑢠": "𑣀", + "𑢡": "𑣁", + "𑢢": "𑣂", + "𑢣": "𑣃", + "𑢤": "𑣄", + "𑢥": "𑣅", + "𑢦": "𑣆", + "𑢧": "𑣇", + "𑢨": "𑣈", + "𑢩": "𑣉", + "𑢪": "𑣊", + "𑢫": "𑣋", + "𑢬": "𑣌", + "𑢭": "𑣍", + "𑢮": "𑣎", + "𑢯": "𑣏", + "𑢰": "𑣐", + "𑢱": "𑣑", + "𑢲": "𑣒", + "𑢳": "𑣓", + "𑢴": "𑣔", + "𑢵": "𑣕", + "𑢶": "𑣖", + "𑢷": "𑣗", + "𑢸": "𑣘", + "𑢹": "𑣙", + "𑢺": "𑣚", + "𑢻": "𑣛", + "𑢼": "𑣜", + "𑢽": "𑣝", + "𑢾": "𑣞", + "𑢿": "𑣟", + "𖹀": "𖹠", + "𖹁": "𖹡", + "𖹂": "𖹢", + "𖹃": "𖹣", + "𖹄": "𖹤", + "𖹅": "𖹥", + "𖹆": "𖹦", + "𖹇": "𖹧", + "𖹈": "𖹨", + "𖹉": "𖹩", + "𖹊": "𖹪", + "𖹋": "𖹫", + "𖹌": "𖹬", + "𖹍": "𖹭", + "𖹎": "𖹮", + "𖹏": "𖹯", + "𖹐": "𖹰", + "𖹑": "𖹱", + "𖹒": "𖹲", + "𖹓": "𖹳", + "𖹔": "𖹴", + "𖹕": "𖹵", + "𖹖": "𖹶", + "𖹗": "𖹷", + "𖹘": "𖹸", + "𖹙": "𖹹", + "𖹚": "𖹺", + "𖹛": "𖹻", + "𖹜": "𖹼", + "𖹝": "𖹽", + "𖹞": "𖹾", + "𖹟": "𖹿", + "𞤀": "𞤢", + "𞤁": "𞤣", + "𞤂": "𞤤", + "𞤃": "𞤥", + "𞤄": "𞤦", + "𞤅": "𞤧", + "𞤆": "𞤨", + "𞤇": "𞤩", + "𞤈": "𞤪", + "𞤉": "𞤫", + "𞤊": "𞤬", + "𞤋": "𞤭", + "𞤌": "𞤮", + "𞤍": "𞤯", + "𞤎": "𞤰", + "𞤏": "𞤱", + "𞤐": "𞤲", + "𞤑": "𞤳", + "𞤒": "𞤴", + "𞤓": "𞤵", + "𞤔": "𞤶", + "𞤕": "𞤷", + "𞤖": "𞤸", + "𞤗": "𞤹", + "𞤘": "𞤺", + "𞤙": "𞤻", + "𞤚": "𞤼", + "𞤛": "𞤽", + "𞤜": "𞤾", + "𞤝": "𞤿", + "𞤞": "𞥀", + "𞤟": "𞥁", + "𞤠": "𞥂", + "𞤡": "𞥃" +}; diff --git a/pkgs/markdown/lib/src/assets/html_entities.dart b/pkgs/markdown/lib/src/assets/html_entities.dart new file mode 100644 index 000000000..2599762f7 --- /dev/null +++ b/pkgs/markdown/lib/src/assets/html_entities.dart @@ -0,0 +1,2133 @@ +// Generated file. do not edit. +// +// Source: tool/entities.json +// Script: tool/update_entities.dart +// ignore_for_file: prefer_single_quotes + +const htmlEntitiesMap = { + "Æ": "Æ", + "&": "&", + "Á": "Á", + "Ă": "Ă", + "Â": "Â", + "А": "А", + "𝔄": "𝔄", + "À": "À", + "Α": "Α", + "Ā": "Ā", + "⩓": "⩓", + "Ą": "Ą", + "𝔸": "𝔸", + "⁡": "⁡", + "Å": "Å", + "𝒜": "𝒜", + "≔": "≔", + "Ã": "Ã", + "Ä": "Ä", + "∖": "∖", + "⫧": "⫧", + "⌆": "⌆", + "Б": "Б", + "∵": "∵", + "ℬ": "ℬ", + "Β": "Β", + "𝔅": "𝔅", + "𝔹": "𝔹", + "˘": "˘", + "ℬ": "ℬ", + "≎": "≎", + "Ч": "Ч", + "©": "©", + "Ć": "Ć", + "⋒": "⋒", + "ⅅ": "ⅅ", + "ℭ": "ℭ", + "Č": "Č", + "Ç": "Ç", + "Ĉ": "Ĉ", + "∰": "∰", + "Ċ": "Ċ", + "¸": "¸", + "·": "·", + "ℭ": "ℭ", + "Χ": "Χ", + "⊙": "⊙", + "⊖": "⊖", + "⊕": "⊕", + "⊗": "⊗", + "∲": "∲", + "”": "”", + "’": "’", + "∷": "∷", + "⩴": "⩴", + "≡": "≡", + "∯": "∯", + "∮": "∮", + "ℂ": "ℂ", + "∐": "∐", + "∳": "∳", + "⨯": "⨯", + "𝒞": "𝒞", + "⋓": "⋓", + "≍": "≍", + "ⅅ": "ⅅ", + "⤑": "⤑", + "Ђ": "Ђ", + "Ѕ": "Ѕ", + "Џ": "Џ", + "‡": "‡", + "↡": "↡", + "⫤": "⫤", + "Ď": "Ď", + "Д": "Д", + "∇": "∇", + "Δ": "Δ", + "𝔇": "𝔇", + "´": "´", + "˙": "˙", + "˝": "˝", + "`": "`", + "˜": "˜", + "⋄": "⋄", + "ⅆ": "ⅆ", + "𝔻": "𝔻", + "¨": "¨", + "⃜": "⃜", + "≐": "≐", + "∯": "∯", + "¨": "¨", + "⇓": "⇓", + "⇐": "⇐", + "⇔": "⇔", + "⫤": "⫤", + "⟸": "⟸", + "⟺": "⟺", + "⟹": "⟹", + "⇒": "⇒", + "⊨": "⊨", + "⇑": "⇑", + "⇕": "⇕", + "∥": "∥", + "↓": "↓", + "⤓": "⤓", + "⇵": "⇵", + "̑": "̑", + "⥐": "⥐", + "⥞": "⥞", + "↽": "↽", + "⥖": "⥖", + "⥟": "⥟", + "⇁": "⇁", + "⥗": "⥗", + "⊤": "⊤", + "↧": "↧", + "⇓": "⇓", + "𝒟": "𝒟", + "Đ": "Đ", + "Ŋ": "Ŋ", + "Ð": "Ð", + "É": "É", + "Ě": "Ě", + "Ê": "Ê", + "Э": "Э", + "Ė": "Ė", + "𝔈": "𝔈", + "È": "È", + "∈": "∈", + "Ē": "Ē", + "◻": "◻", + "▫": "▫", + "Ę": "Ę", + "𝔼": "𝔼", + "Ε": "Ε", + "⩵": "⩵", + "≂": "≂", + "⇌": "⇌", + "ℰ": "ℰ", + "⩳": "⩳", + "Η": "Η", + "Ë": "Ë", + "∃": "∃", + "ⅇ": "ⅇ", + "Ф": "Ф", + "𝔉": "𝔉", + "◼": "◼", + "▪": "▪", + "𝔽": "𝔽", + "∀": "∀", + "ℱ": "ℱ", + "ℱ": "ℱ", + "Ѓ": "Ѓ", + ">": ">", + "Γ": "Γ", + "Ϝ": "Ϝ", + "Ğ": "Ğ", + "Ģ": "Ģ", + "Ĝ": "Ĝ", + "Г": "Г", + "Ġ": "Ġ", + "𝔊": "𝔊", + "⋙": "⋙", + "𝔾": "𝔾", + "≥": "≥", + "⋛": "⋛", + "≧": "≧", + "⪢": "⪢", + "≷": "≷", + "⩾": "⩾", + "≳": "≳", + "𝒢": "𝒢", + "≫": "≫", + "Ъ": "Ъ", + "ˇ": "ˇ", + "^": "^", + "Ĥ": "Ĥ", + "ℌ": "ℌ", + "ℋ": "ℋ", + "ℍ": "ℍ", + "─": "─", + "ℋ": "ℋ", + "Ħ": "Ħ", + "≎": "≎", + "≏": "≏", + "Е": "Е", + "IJ": "IJ", + "Ё": "Ё", + "Í": "Í", + "Î": "Î", + "И": "И", + "İ": "İ", + "ℑ": "ℑ", + "Ì": "Ì", + "ℑ": "ℑ", + "Ī": "Ī", + "ⅈ": "ⅈ", + "⇒": "⇒", + "∬": "∬", + "∫": "∫", + "⋂": "⋂", + "⁣": "⁣", + "⁢": "⁢", + "Į": "Į", + "𝕀": "𝕀", + "Ι": "Ι", + "ℐ": "ℐ", + "Ĩ": "Ĩ", + "І": "І", + "Ï": "Ï", + "Ĵ": "Ĵ", + "Й": "Й", + "𝔍": "𝔍", + "𝕁": "𝕁", + "𝒥": "𝒥", + "Ј": "Ј", + "Є": "Є", + "Х": "Х", + "Ќ": "Ќ", + "Κ": "Κ", + "Ķ": "Ķ", + "К": "К", + "𝔎": "𝔎", + "𝕂": "𝕂", + "𝒦": "𝒦", + "Љ": "Љ", + "<": "<", + "Ĺ": "Ĺ", + "Λ": "Λ", + "⟪": "⟪", + "ℒ": "ℒ", + "↞": "↞", + "Ľ": "Ľ", + "Ļ": "Ļ", + "Л": "Л", + "⟨": "⟨", + "←": "←", + "⇤": "⇤", + "⇆": "⇆", + "⌈": "⌈", + "⟦": "⟦", + "⥡": "⥡", + "⇃": "⇃", + "⥙": "⥙", + "⌊": "⌊", + "↔": "↔", + "⥎": "⥎", + "⊣": "⊣", + "↤": "↤", + "⥚": "⥚", + "⊲": "⊲", + "⧏": "⧏", + "⊴": "⊴", + "⥑": "⥑", + "⥠": "⥠", + "↿": "↿", + "⥘": "⥘", + "↼": "↼", + "⥒": "⥒", + "⇐": "⇐", + "⇔": "⇔", + "⋚": "⋚", + "≦": "≦", + "≶": "≶", + "⪡": "⪡", + "⩽": "⩽", + "≲": "≲", + "𝔏": "𝔏", + "⋘": "⋘", + "⇚": "⇚", + "Ŀ": "Ŀ", + "⟵": "⟵", + "⟷": "⟷", + "⟶": "⟶", + "⟸": "⟸", + "⟺": "⟺", + "⟹": "⟹", + "𝕃": "𝕃", + "↙": "↙", + "↘": "↘", + "ℒ": "ℒ", + "↰": "↰", + "Ł": "Ł", + "≪": "≪", + "⤅": "⤅", + "М": "М", + " ": " ", + "ℳ": "ℳ", + "𝔐": "𝔐", + "∓": "∓", + "𝕄": "𝕄", + "ℳ": "ℳ", + "Μ": "Μ", + "Њ": "Њ", + "Ń": "Ń", + "Ň": "Ň", + "Ņ": "Ņ", + "Н": "Н", + "​": "​", + "​": "​", + "​": "​", + "​": "​", + "≫": "≫", + "≪": "≪", + " ": "\n", + "𝔑": "𝔑", + "⁠": "⁠", + " ": " ", + "ℕ": "ℕ", + "⫬": "⫬", + "≢": "≢", + "≭": "≭", + "∦": "∦", + "∉": "∉", + "≠": "≠", + "≂̸": "≂̸", + "∄": "∄", + "≯": "≯", + "≱": "≱", + "≧̸": "≧̸", + "≫̸": "≫̸", + "≹": "≹", + "⩾̸": "⩾̸", + "≵": "≵", + "≎̸": "≎̸", + "≏̸": "≏̸", + "⋪": "⋪", + "⧏̸": "⧏̸", + "⋬": "⋬", + "≮": "≮", + "≰": "≰", + "≸": "≸", + "≪̸": "≪̸", + "⩽̸": "⩽̸", + "≴": "≴", + "⪢̸": "⪢̸", + "⪡̸": "⪡̸", + "⊀": "⊀", + "⪯̸": "⪯̸", + "⋠": "⋠", + "∌": "∌", + "⋫": "⋫", + "⧐̸": "⧐̸", + "⋭": "⋭", + "⊏̸": "⊏̸", + "⋢": "⋢", + "⊐̸": "⊐̸", + "⋣": "⋣", + "⊂⃒": "⊂⃒", + "⊈": "⊈", + "⊁": "⊁", + "⪰̸": "⪰̸", + "⋡": "⋡", + "≿̸": "≿̸", + "⊃⃒": "⊃⃒", + "⊉": "⊉", + "≁": "≁", + "≄": "≄", + "≇": "≇", + "≉": "≉", + "∤": "∤", + "𝒩": "𝒩", + "Ñ": "Ñ", + "Ν": "Ν", + "Œ": "Œ", + "Ó": "Ó", + "Ô": "Ô", + "О": "О", + "Ő": "Ő", + "𝔒": "𝔒", + "Ò": "Ò", + "Ō": "Ō", + "Ω": "Ω", + "Ο": "Ο", + "𝕆": "𝕆", + "“": "“", + "‘": "‘", + "⩔": "⩔", + "𝒪": "𝒪", + "Ø": "Ø", + "Õ": "Õ", + "⨷": "⨷", + "Ö": "Ö", + "‾": "‾", + "⏞": "⏞", + "⎴": "⎴", + "⏜": "⏜", + "∂": "∂", + "П": "П", + "𝔓": "𝔓", + "Φ": "Φ", + "Π": "Π", + "±": "±", + "ℌ": "ℌ", + "ℙ": "ℙ", + "⪻": "⪻", + "≺": "≺", + "⪯": "⪯", + "≼": "≼", + "≾": "≾", + "″": "″", + "∏": "∏", + "∷": "∷", + "∝": "∝", + "𝒫": "𝒫", + "Ψ": "Ψ", + """: "\"", + "𝔔": "𝔔", + "ℚ": "ℚ", + "𝒬": "𝒬", + "⤐": "⤐", + "®": "®", + "Ŕ": "Ŕ", + "⟫": "⟫", + "↠": "↠", + "⤖": "⤖", + "Ř": "Ř", + "Ŗ": "Ŗ", + "Р": "Р", + "ℜ": "ℜ", + "∋": "∋", + "⇋": "⇋", + "⥯": "⥯", + "ℜ": "ℜ", + "Ρ": "Ρ", + "⟩": "⟩", + "→": "→", + "⇥": "⇥", + "⇄": "⇄", + "⌉": "⌉", + "⟧": "⟧", + "⥝": "⥝", + "⇂": "⇂", + "⥕": "⥕", + "⌋": "⌋", + "⊢": "⊢", + "↦": "↦", + "⥛": "⥛", + "⊳": "⊳", + "⧐": "⧐", + "⊵": "⊵", + "⥏": "⥏", + "⥜": "⥜", + "↾": "↾", + "⥔": "⥔", + "⇀": "⇀", + "⥓": "⥓", + "⇒": "⇒", + "ℝ": "ℝ", + "⥰": "⥰", + "⇛": "⇛", + "ℛ": "ℛ", + "↱": "↱", + "⧴": "⧴", + "Щ": "Щ", + "Ш": "Ш", + "Ь": "Ь", + "Ś": "Ś", + "⪼": "⪼", + "Š": "Š", + "Ş": "Ş", + "Ŝ": "Ŝ", + "С": "С", + "𝔖": "𝔖", + "↓": "↓", + "←": "←", + "→": "→", + "↑": "↑", + "Σ": "Σ", + "∘": "∘", + "𝕊": "𝕊", + "√": "√", + "□": "□", + "⊓": "⊓", + "⊏": "⊏", + "⊑": "⊑", + "⊐": "⊐", + "⊒": "⊒", + "⊔": "⊔", + "𝒮": "𝒮", + "⋆": "⋆", + "⋐": "⋐", + "⋐": "⋐", + "⊆": "⊆", + "≻": "≻", + "⪰": "⪰", + "≽": "≽", + "≿": "≿", + "∋": "∋", + "∑": "∑", + "⋑": "⋑", + "⊃": "⊃", + "⊇": "⊇", + "⋑": "⋑", + "Þ": "Þ", + "™": "™", + "Ћ": "Ћ", + "Ц": "Ц", + " ": "\t", + "Τ": "Τ", + "Ť": "Ť", + "Ţ": "Ţ", + "Т": "Т", + "𝔗": "𝔗", + "∴": "∴", + "Θ": "Θ", + "  ": "  ", + " ": " ", + "∼": "∼", + "≃": "≃", + "≅": "≅", + "≈": "≈", + "𝕋": "𝕋", + "⃛": "⃛", + "𝒯": "𝒯", + "Ŧ": "Ŧ", + "Ú": "Ú", + "↟": "↟", + "⥉": "⥉", + "Ў": "Ў", + "Ŭ": "Ŭ", + "Û": "Û", + "У": "У", + "Ű": "Ű", + "𝔘": "𝔘", + "Ù": "Ù", + "Ū": "Ū", + "_": "_", + "⏟": "⏟", + "⎵": "⎵", + "⏝": "⏝", + "⋃": "⋃", + "⊎": "⊎", + "Ų": "Ų", + "𝕌": "𝕌", + "↑": "↑", + "⤒": "⤒", + "⇅": "⇅", + "↕": "↕", + "⥮": "⥮", + "⊥": "⊥", + "↥": "↥", + "⇑": "⇑", + "⇕": "⇕", + "↖": "↖", + "↗": "↗", + "ϒ": "ϒ", + "Υ": "Υ", + "Ů": "Ů", + "𝒰": "𝒰", + "Ũ": "Ũ", + "Ü": "Ü", + "⊫": "⊫", + "⫫": "⫫", + "В": "В", + "⊩": "⊩", + "⫦": "⫦", + "⋁": "⋁", + "‖": "‖", + "‖": "‖", + "∣": "∣", + "|": "|", + "❘": "❘", + "≀": "≀", + " ": " ", + "𝔙": "𝔙", + "𝕍": "𝕍", + "𝒱": "𝒱", + "⊪": "⊪", + "Ŵ": "Ŵ", + "⋀": "⋀", + "𝔚": "𝔚", + "𝕎": "𝕎", + "𝒲": "𝒲", + "𝔛": "𝔛", + "Ξ": "Ξ", + "𝕏": "𝕏", + "𝒳": "𝒳", + "Я": "Я", + "Ї": "Ї", + "Ю": "Ю", + "Ý": "Ý", + "Ŷ": "Ŷ", + "Ы": "Ы", + "𝔜": "𝔜", + "𝕐": "𝕐", + "𝒴": "𝒴", + "Ÿ": "Ÿ", + "Ж": "Ж", + "Ź": "Ź", + "Ž": "Ž", + "З": "З", + "Ż": "Ż", + "​": "​", + "Ζ": "Ζ", + "ℨ": "ℨ", + "ℤ": "ℤ", + "𝒵": "𝒵", + "á": "á", + "ă": "ă", + "∾": "∾", + "∾̳": "∾̳", + "∿": "∿", + "â": "â", + "´": "´", + "а": "а", + "æ": "æ", + "⁡": "⁡", + "𝔞": "𝔞", + "à": "à", + "ℵ": "ℵ", + "ℵ": "ℵ", + "α": "α", + "ā": "ā", + "⨿": "⨿", + "&": "&", + "∧": "∧", + "⩕": "⩕", + "⩜": "⩜", + "⩘": "⩘", + "⩚": "⩚", + "∠": "∠", + "⦤": "⦤", + "∠": "∠", + "∡": "∡", + "⦨": "⦨", + "⦩": "⦩", + "⦪": "⦪", + "⦫": "⦫", + "⦬": "⦬", + "⦭": "⦭", + "⦮": "⦮", + "⦯": "⦯", + "∟": "∟", + "⊾": "⊾", + "⦝": "⦝", + "∢": "∢", + "Å": "Å", + "⍼": "⍼", + "ą": "ą", + "𝕒": "𝕒", + "≈": "≈", + "⩰": "⩰", + "⩯": "⩯", + "≊": "≊", + "≋": "≋", + "'": "'", + "≈": "≈", + "≊": "≊", + "å": "å", + "𝒶": "𝒶", + "*": "*", + "≈": "≈", + "≍": "≍", + "ã": "ã", + "ä": "ä", + "∳": "∳", + "⨑": "⨑", + "⫭": "⫭", + "≌": "≌", + "϶": "϶", + "‵": "‵", + "∽": "∽", + "⋍": "⋍", + "⊽": "⊽", + "⌅": "⌅", + "⌅": "⌅", + "⎵": "⎵", + "⎶": "⎶", + "≌": "≌", + "б": "б", + "„": "„", + "∵": "∵", + "∵": "∵", + "⦰": "⦰", + "϶": "϶", + "ℬ": "ℬ", + "β": "β", + "ℶ": "ℶ", + "≬": "≬", + "𝔟": "𝔟", + "⋂": "⋂", + "◯": "◯", + "⋃": "⋃", + "⨀": "⨀", + "⨁": "⨁", + "⨂": "⨂", + "⨆": "⨆", + "★": "★", + "▽": "▽", + "△": "△", + "⨄": "⨄", + "⋁": "⋁", + "⋀": "⋀", + "⤍": "⤍", + "⧫": "⧫", + "▪": "▪", + "▴": "▴", + "▾": "▾", + "◂": "◂", + "▸": "▸", + "␣": "␣", + "▒": "▒", + "░": "░", + "▓": "▓", + "█": "█", + "=⃥": "=⃥", + "≡⃥": "≡⃥", + "⌐": "⌐", + "𝕓": "𝕓", + "⊥": "⊥", + "⊥": "⊥", + "⋈": "⋈", + "╗": "╗", + "╔": "╔", + "╖": "╖", + "╓": "╓", + "═": "═", + "╦": "╦", + "╩": "╩", + "╤": "╤", + "╧": "╧", + "╝": "╝", + "╚": "╚", + "╜": "╜", + "╙": "╙", + "║": "║", + "╬": "╬", + "╣": "╣", + "╠": "╠", + "╫": "╫", + "╢": "╢", + "╟": "╟", + "⧉": "⧉", + "╕": "╕", + "╒": "╒", + "┐": "┐", + "┌": "┌", + "─": "─", + "╥": "╥", + "╨": "╨", + "┬": "┬", + "┴": "┴", + "⊟": "⊟", + "⊞": "⊞", + "⊠": "⊠", + "╛": "╛", + "╘": "╘", + "┘": "┘", + "└": "└", + "│": "│", + "╪": "╪", + "╡": "╡", + "╞": "╞", + "┼": "┼", + "┤": "┤", + "├": "├", + "‵": "‵", + "˘": "˘", + "¦": "¦", + "𝒷": "𝒷", + "⁏": "⁏", + "∽": "∽", + "⋍": "⋍", + "\": r"\", + "⧅": "⧅", + "⟈": "⟈", + "•": "•", + "•": "•", + "≎": "≎", + "⪮": "⪮", + "≏": "≏", + "≏": "≏", + "ć": "ć", + "∩": "∩", + "⩄": "⩄", + "⩉": "⩉", + "⩋": "⩋", + "⩇": "⩇", + "⩀": "⩀", + "∩︀": "∩︀", + "⁁": "⁁", + "ˇ": "ˇ", + "⩍": "⩍", + "č": "č", + "ç": "ç", + "ĉ": "ĉ", + "⩌": "⩌", + "⩐": "⩐", + "ċ": "ċ", + "¸": "¸", + "⦲": "⦲", + "¢": "¢", + "·": "·", + "𝔠": "𝔠", + "ч": "ч", + "✓": "✓", + "✓": "✓", + "χ": "χ", + "○": "○", + "⧃": "⧃", + "ˆ": "ˆ", + "≗": "≗", + "↺": "↺", + "↻": "↻", + "®": "®", + "Ⓢ": "Ⓢ", + "⊛": "⊛", + "⊚": "⊚", + "⊝": "⊝", + "≗": "≗", + "⨐": "⨐", + "⫯": "⫯", + "⧂": "⧂", + "♣": "♣", + "♣": "♣", + ":": ":", + "≔": "≔", + "≔": "≔", + ",": ",", + "@": "@", + "∁": "∁", + "∘": "∘", + "∁": "∁", + "ℂ": "ℂ", + "≅": "≅", + "⩭": "⩭", + "∮": "∮", + "𝕔": "𝕔", + "∐": "∐", + "©": "©", + "℗": "℗", + "↵": "↵", + "✗": "✗", + "𝒸": "𝒸", + "⫏": "⫏", + "⫑": "⫑", + "⫐": "⫐", + "⫒": "⫒", + "⋯": "⋯", + "⤸": "⤸", + "⤵": "⤵", + "⋞": "⋞", + "⋟": "⋟", + "↶": "↶", + "⤽": "⤽", + "∪": "∪", + "⩈": "⩈", + "⩆": "⩆", + "⩊": "⩊", + "⊍": "⊍", + "⩅": "⩅", + "∪︀": "∪︀", + "↷": "↷", + "⤼": "⤼", + "⋞": "⋞", + "⋟": "⋟", + "⋎": "⋎", + "⋏": "⋏", + "¤": "¤", + "↶": "↶", + "↷": "↷", + "⋎": "⋎", + "⋏": "⋏", + "∲": "∲", + "∱": "∱", + "⌭": "⌭", + "⇓": "⇓", + "⥥": "⥥", + "†": "†", + "ℸ": "ℸ", + "↓": "↓", + "‐": "‐", + "⊣": "⊣", + "⤏": "⤏", + "˝": "˝", + "ď": "ď", + "д": "д", + "ⅆ": "ⅆ", + "‡": "‡", + "⇊": "⇊", + "⩷": "⩷", + "°": "°", + "δ": "δ", + "⦱": "⦱", + "⥿": "⥿", + "𝔡": "𝔡", + "⇃": "⇃", + "⇂": "⇂", + "⋄": "⋄", + "⋄": "⋄", + "♦": "♦", + "♦": "♦", + "¨": "¨", + "ϝ": "ϝ", + "⋲": "⋲", + "÷": "÷", + "÷": "÷", + "⋇": "⋇", + "⋇": "⋇", + "ђ": "ђ", + "⌞": "⌞", + "⌍": "⌍", + "$": r"$", + "𝕕": "𝕕", + "˙": "˙", + "≐": "≐", + "≑": "≑", + "∸": "∸", + "∔": "∔", + "⊡": "⊡", + "⌆": "⌆", + "↓": "↓", + "⇊": "⇊", + "⇃": "⇃", + "⇂": "⇂", + "⤐": "⤐", + "⌟": "⌟", + "⌌": "⌌", + "𝒹": "𝒹", + "ѕ": "ѕ", + "⧶": "⧶", + "đ": "đ", + "⋱": "⋱", + "▿": "▿", + "▾": "▾", + "⇵": "⇵", + "⥯": "⥯", + "⦦": "⦦", + "џ": "џ", + "⟿": "⟿", + "⩷": "⩷", + "≑": "≑", + "é": "é", + "⩮": "⩮", + "ě": "ě", + "≖": "≖", + "ê": "ê", + "≕": "≕", + "э": "э", + "ė": "ė", + "ⅇ": "ⅇ", + "≒": "≒", + "𝔢": "𝔢", + "⪚": "⪚", + "è": "è", + "⪖": "⪖", + "⪘": "⪘", + "⪙": "⪙", + "⏧": "⏧", + "ℓ": "ℓ", + "⪕": "⪕", + "⪗": "⪗", + "ē": "ē", + "∅": "∅", + "∅": "∅", + "∅": "∅", + " ": " ", + " ": " ", + " ": " ", + "ŋ": "ŋ", + " ": " ", + "ę": "ę", + "𝕖": "𝕖", + "⋕": "⋕", + "⧣": "⧣", + "⩱": "⩱", + "ε": "ε", + "ε": "ε", + "ϵ": "ϵ", + "≖": "≖", + "≕": "≕", + "≂": "≂", + "⪖": "⪖", + "⪕": "⪕", + "=": "=", + "≟": "≟", + "≡": "≡", + "⩸": "⩸", + "⧥": "⧥", + "≓": "≓", + "⥱": "⥱", + "ℯ": "ℯ", + "≐": "≐", + "≂": "≂", + "η": "η", + "ð": "ð", + "ë": "ë", + "€": "€", + "!": "!", + "∃": "∃", + "ℰ": "ℰ", + "ⅇ": "ⅇ", + "≒": "≒", + "ф": "ф", + "♀": "♀", + "ffi": "ffi", + "ff": "ff", + "ffl": "ffl", + "𝔣": "𝔣", + "fi": "fi", + "fj": "fj", + "♭": "♭", + "fl": "fl", + "▱": "▱", + "ƒ": "ƒ", + "𝕗": "𝕗", + "∀": "∀", + "⋔": "⋔", + "⫙": "⫙", + "⨍": "⨍", + "½": "½", + "⅓": "⅓", + "¼": "¼", + "⅕": "⅕", + "⅙": "⅙", + "⅛": "⅛", + "⅔": "⅔", + "⅖": "⅖", + "¾": "¾", + "⅗": "⅗", + "⅜": "⅜", + "⅘": "⅘", + "⅚": "⅚", + "⅝": "⅝", + "⅞": "⅞", + "⁄": "⁄", + "⌢": "⌢", + "𝒻": "𝒻", + "≧": "≧", + "⪌": "⪌", + "ǵ": "ǵ", + "γ": "γ", + "ϝ": "ϝ", + "⪆": "⪆", + "ğ": "ğ", + "ĝ": "ĝ", + "г": "г", + "ġ": "ġ", + "≥": "≥", + "⋛": "⋛", + "≥": "≥", + "≧": "≧", + "⩾": "⩾", + "⩾": "⩾", + "⪩": "⪩", + "⪀": "⪀", + "⪂": "⪂", + "⪄": "⪄", + "⋛︀": "⋛︀", + "⪔": "⪔", + "𝔤": "𝔤", + "≫": "≫", + "⋙": "⋙", + "ℷ": "ℷ", + "ѓ": "ѓ", + "≷": "≷", + "⪒": "⪒", + "⪥": "⪥", + "⪤": "⪤", + "≩": "≩", + "⪊": "⪊", + "⪊": "⪊", + "⪈": "⪈", + "⪈": "⪈", + "≩": "≩", + "⋧": "⋧", + "𝕘": "𝕘", + "`": "`", + "ℊ": "ℊ", + "≳": "≳", + "⪎": "⪎", + "⪐": "⪐", + ">": ">", + "⪧": "⪧", + "⩺": "⩺", + "⋗": "⋗", + "⦕": "⦕", + "⩼": "⩼", + "⪆": "⪆", + "⥸": "⥸", + "⋗": "⋗", + "⋛": "⋛", + "⪌": "⪌", + "≷": "≷", + "≳": "≳", + "≩︀": "≩︀", + "≩︀": "≩︀", + "⇔": "⇔", + " ": " ", + "½": "½", + "ℋ": "ℋ", + "ъ": "ъ", + "↔": "↔", + "⥈": "⥈", + "↭": "↭", + "ℏ": "ℏ", + "ĥ": "ĥ", + "♥": "♥", + "♥": "♥", + "…": "…", + "⊹": "⊹", + "𝔥": "𝔥", + "⤥": "⤥", + "⤦": "⤦", + "⇿": "⇿", + "∻": "∻", + "↩": "↩", + "↪": "↪", + "𝕙": "𝕙", + "―": "―", + "𝒽": "𝒽", + "ℏ": "ℏ", + "ħ": "ħ", + "⁃": "⁃", + "‐": "‐", + "í": "í", + "⁣": "⁣", + "î": "î", + "и": "и", + "е": "е", + "¡": "¡", + "⇔": "⇔", + "𝔦": "𝔦", + "ì": "ì", + "ⅈ": "ⅈ", + "⨌": "⨌", + "∭": "∭", + "⧜": "⧜", + "℩": "℩", + "ij": "ij", + "ī": "ī", + "ℑ": "ℑ", + "ℐ": "ℐ", + "ℑ": "ℑ", + "ı": "ı", + "⊷": "⊷", + "Ƶ": "Ƶ", + "∈": "∈", + "℅": "℅", + "∞": "∞", + "⧝": "⧝", + "ı": "ı", + "∫": "∫", + "⊺": "⊺", + "ℤ": "ℤ", + "⊺": "⊺", + "⨗": "⨗", + "⨼": "⨼", + "ё": "ё", + "į": "į", + "𝕚": "𝕚", + "ι": "ι", + "⨼": "⨼", + "¿": "¿", + "𝒾": "𝒾", + "∈": "∈", + "⋹": "⋹", + "⋵": "⋵", + "⋴": "⋴", + "⋳": "⋳", + "∈": "∈", + "⁢": "⁢", + "ĩ": "ĩ", + "і": "і", + "ï": "ï", + "ĵ": "ĵ", + "й": "й", + "𝔧": "𝔧", + "ȷ": "ȷ", + "𝕛": "𝕛", + "𝒿": "𝒿", + "ј": "ј", + "є": "є", + "κ": "κ", + "ϰ": "ϰ", + "ķ": "ķ", + "к": "к", + "𝔨": "𝔨", + "ĸ": "ĸ", + "х": "х", + "ќ": "ќ", + "𝕜": "𝕜", + "𝓀": "𝓀", + "⇚": "⇚", + "⇐": "⇐", + "⤛": "⤛", + "⤎": "⤎", + "≦": "≦", + "⪋": "⪋", + "⥢": "⥢", + "ĺ": "ĺ", + "⦴": "⦴", + "ℒ": "ℒ", + "λ": "λ", + "⟨": "⟨", + "⦑": "⦑", + "⟨": "⟨", + "⪅": "⪅", + "«": "«", + "←": "←", + "⇤": "⇤", + "⤟": "⤟", + "⤝": "⤝", + "↩": "↩", + "↫": "↫", + "⤹": "⤹", + "⥳": "⥳", + "↢": "↢", + "⪫": "⪫", + "⤙": "⤙", + "⪭": "⪭", + "⪭︀": "⪭︀", + "⤌": "⤌", + "❲": "❲", + "{": "{", + "[": "[", + "⦋": "⦋", + "⦏": "⦏", + "⦍": "⦍", + "ľ": "ľ", + "ļ": "ļ", + "⌈": "⌈", + "{": "{", + "л": "л", + "⤶": "⤶", + "“": "“", + "„": "„", + "⥧": "⥧", + "⥋": "⥋", + "↲": "↲", + "≤": "≤", + "←": "←", + "↢": "↢", + "↽": "↽", + "↼": "↼", + "⇇": "⇇", + "↔": "↔", + "⇆": "⇆", + "⇋": "⇋", + "↭": "↭", + "⋋": "⋋", + "⋚": "⋚", + "≤": "≤", + "≦": "≦", + "⩽": "⩽", + "⩽": "⩽", + "⪨": "⪨", + "⩿": "⩿", + "⪁": "⪁", + "⪃": "⪃", + "⋚︀": "⋚︀", + "⪓": "⪓", + "⪅": "⪅", + "⋖": "⋖", + "⋚": "⋚", + "⪋": "⪋", + "≶": "≶", + "≲": "≲", + "⥼": "⥼", + "⌊": "⌊", + "𝔩": "𝔩", + "≶": "≶", + "⪑": "⪑", + "↽": "↽", + "↼": "↼", + "⥪": "⥪", + "▄": "▄", + "љ": "љ", + "≪": "≪", + "⇇": "⇇", + "⌞": "⌞", + "⥫": "⥫", + "◺": "◺", + "ŀ": "ŀ", + "⎰": "⎰", + "⎰": "⎰", + "≨": "≨", + "⪉": "⪉", + "⪉": "⪉", + "⪇": "⪇", + "⪇": "⪇", + "≨": "≨", + "⋦": "⋦", + "⟬": "⟬", + "⇽": "⇽", + "⟦": "⟦", + "⟵": "⟵", + "⟷": "⟷", + "⟼": "⟼", + "⟶": "⟶", + "↫": "↫", + "↬": "↬", + "⦅": "⦅", + "𝕝": "𝕝", + "⨭": "⨭", + "⨴": "⨴", + "∗": "∗", + "_": "_", + "◊": "◊", + "◊": "◊", + "⧫": "⧫", + "(": "(", + "⦓": "⦓", + "⇆": "⇆", + "⌟": "⌟", + "⇋": "⇋", + "⥭": "⥭", + "‎": "‎", + "⊿": "⊿", + "‹": "‹", + "𝓁": "𝓁", + "↰": "↰", + "≲": "≲", + "⪍": "⪍", + "⪏": "⪏", + "[": "[", + "‘": "‘", + "‚": "‚", + "ł": "ł", + "<": "<", + "⪦": "⪦", + "⩹": "⩹", + "⋖": "⋖", + "⋋": "⋋", + "⋉": "⋉", + "⥶": "⥶", + "⩻": "⩻", + "⦖": "⦖", + "◃": "◃", + "⊴": "⊴", + "◂": "◂", + "⥊": "⥊", + "⥦": "⥦", + "≨︀": "≨︀", + "≨︀": "≨︀", + "∺": "∺", + "¯": "¯", + "♂": "♂", + "✠": "✠", + "✠": "✠", + "↦": "↦", + "↦": "↦", + "↧": "↧", + "↤": "↤", + "↥": "↥", + "▮": "▮", + "⨩": "⨩", + "м": "м", + "—": "—", + "∡": "∡", + "𝔪": "𝔪", + "℧": "℧", + "µ": "µ", + "∣": "∣", + "*": "*", + "⫰": "⫰", + "·": "·", + "−": "−", + "⊟": "⊟", + "∸": "∸", + "⨪": "⨪", + "⫛": "⫛", + "…": "…", + "∓": "∓", + "⊧": "⊧", + "𝕞": "𝕞", + "∓": "∓", + "𝓂": "𝓂", + "∾": "∾", + "μ": "μ", + "⊸": "⊸", + "⊸": "⊸", + "⋙̸": "⋙̸", + "≫⃒": "≫⃒", + "≫̸": "≫̸", + "⇍": "⇍", + "⇎": "⇎", + "⋘̸": "⋘̸", + "≪⃒": "≪⃒", + "≪̸": "≪̸", + "⇏": "⇏", + "⊯": "⊯", + "⊮": "⊮", + "∇": "∇", + "ń": "ń", + "∠⃒": "∠⃒", + "≉": "≉", + "⩰̸": "⩰̸", + "≋̸": "≋̸", + "ʼn": "ʼn", + "≉": "≉", + "♮": "♮", + "♮": "♮", + "ℕ": "ℕ", + " ": " ", + "≎̸": "≎̸", + "≏̸": "≏̸", + "⩃": "⩃", + "ň": "ň", + "ņ": "ņ", + "≇": "≇", + "⩭̸": "⩭̸", + "⩂": "⩂", + "н": "н", + "–": "–", + "≠": "≠", + "⇗": "⇗", + "⤤": "⤤", + "↗": "↗", + "↗": "↗", + "≐̸": "≐̸", + "≢": "≢", + "⤨": "⤨", + "≂̸": "≂̸", + "∄": "∄", + "∄": "∄", + "𝔫": "𝔫", + "≧̸": "≧̸", + "≱": "≱", + "≱": "≱", + "≧̸": "≧̸", + "⩾̸": "⩾̸", + "⩾̸": "⩾̸", + "≵": "≵", + "≯": "≯", + "≯": "≯", + "⇎": "⇎", + "↮": "↮", + "⫲": "⫲", + "∋": "∋", + "⋼": "⋼", + "⋺": "⋺", + "∋": "∋", + "њ": "њ", + "⇍": "⇍", + "≦̸": "≦̸", + "↚": "↚", + "‥": "‥", + "≰": "≰", + "↚": "↚", + "↮": "↮", + "≰": "≰", + "≦̸": "≦̸", + "⩽̸": "⩽̸", + "⩽̸": "⩽̸", + "≮": "≮", + "≴": "≴", + "≮": "≮", + "⋪": "⋪", + "⋬": "⋬", + "∤": "∤", + "𝕟": "𝕟", + "¬": "¬", + "∉": "∉", + "⋹̸": "⋹̸", + "⋵̸": "⋵̸", + "∉": "∉", + "⋷": "⋷", + "⋶": "⋶", + "∌": "∌", + "∌": "∌", + "⋾": "⋾", + "⋽": "⋽", + "∦": "∦", + "∦": "∦", + "⫽⃥": "⫽⃥", + "∂̸": "∂̸", + "⨔": "⨔", + "⊀": "⊀", + "⋠": "⋠", + "⪯̸": "⪯̸", + "⊀": "⊀", + "⪯̸": "⪯̸", + "⇏": "⇏", + "↛": "↛", + "⤳̸": "⤳̸", + "↝̸": "↝̸", + "↛": "↛", + "⋫": "⋫", + "⋭": "⋭", + "⊁": "⊁", + "⋡": "⋡", + "⪰̸": "⪰̸", + "𝓃": "𝓃", + "∤": "∤", + "∦": "∦", + "≁": "≁", + "≄": "≄", + "≄": "≄", + "∤": "∤", + "∦": "∦", + "⋢": "⋢", + "⋣": "⋣", + "⊄": "⊄", + "⫅̸": "⫅̸", + "⊈": "⊈", + "⊂⃒": "⊂⃒", + "⊈": "⊈", + "⫅̸": "⫅̸", + "⊁": "⊁", + "⪰̸": "⪰̸", + "⊅": "⊅", + "⫆̸": "⫆̸", + "⊉": "⊉", + "⊃⃒": "⊃⃒", + "⊉": "⊉", + "⫆̸": "⫆̸", + "≹": "≹", + "ñ": "ñ", + "≸": "≸", + "⋪": "⋪", + "⋬": "⋬", + "⋫": "⋫", + "⋭": "⋭", + "ν": "ν", + "#": "#", + "№": "№", + " ": " ", + "⊭": "⊭", + "⤄": "⤄", + "≍⃒": "≍⃒", + "⊬": "⊬", + "≥⃒": "≥⃒", + ">⃒": ">⃒", + "⧞": "⧞", + "⤂": "⤂", + "≤⃒": "≤⃒", + "<⃒": "<⃒", + "⊴⃒": "⊴⃒", + "⤃": "⤃", + "⊵⃒": "⊵⃒", + "∼⃒": "∼⃒", + "⇖": "⇖", + "⤣": "⤣", + "↖": "↖", + "↖": "↖", + "⤧": "⤧", + "Ⓢ": "Ⓢ", + "ó": "ó", + "⊛": "⊛", + "⊚": "⊚", + "ô": "ô", + "о": "о", + "⊝": "⊝", + "ő": "ő", + "⨸": "⨸", + "⊙": "⊙", + "⦼": "⦼", + "œ": "œ", + "⦿": "⦿", + "𝔬": "𝔬", + "˛": "˛", + "ò": "ò", + "⧁": "⧁", + "⦵": "⦵", + "Ω": "Ω", + "∮": "∮", + "↺": "↺", + "⦾": "⦾", + "⦻": "⦻", + "‾": "‾", + "⧀": "⧀", + "ō": "ō", + "ω": "ω", + "ο": "ο", + "⦶": "⦶", + "⊖": "⊖", + "𝕠": "𝕠", + "⦷": "⦷", + "⦹": "⦹", + "⊕": "⊕", + "∨": "∨", + "↻": "↻", + "⩝": "⩝", + "ℴ": "ℴ", + "ℴ": "ℴ", + "ª": "ª", + "º": "º", + "⊶": "⊶", + "⩖": "⩖", + "⩗": "⩗", + "⩛": "⩛", + "ℴ": "ℴ", + "ø": "ø", + "⊘": "⊘", + "õ": "õ", + "⊗": "⊗", + "⨶": "⨶", + "ö": "ö", + "⌽": "⌽", + "∥": "∥", + "¶": "¶", + "∥": "∥", + "⫳": "⫳", + "⫽": "⫽", + "∂": "∂", + "п": "п", + "%": "%", + ".": ".", + "‰": "‰", + "⊥": "⊥", + "‱": "‱", + "𝔭": "𝔭", + "φ": "φ", + "ϕ": "ϕ", + "ℳ": "ℳ", + "☎": "☎", + "π": "π", + "⋔": "⋔", + "ϖ": "ϖ", + "ℏ": "ℏ", + "ℎ": "ℎ", + "ℏ": "ℏ", + "+": "+", + "⨣": "⨣", + "⊞": "⊞", + "⨢": "⨢", + "∔": "∔", + "⨥": "⨥", + "⩲": "⩲", + "±": "±", + "⨦": "⨦", + "⨧": "⨧", + "±": "±", + "⨕": "⨕", + "𝕡": "𝕡", + "£": "£", + "≺": "≺", + "⪳": "⪳", + "⪷": "⪷", + "≼": "≼", + "⪯": "⪯", + "≺": "≺", + "⪷": "⪷", + "≼": "≼", + "⪯": "⪯", + "⪹": "⪹", + "⪵": "⪵", + "⋨": "⋨", + "≾": "≾", + "′": "′", + "ℙ": "ℙ", + "⪵": "⪵", + "⪹": "⪹", + "⋨": "⋨", + "∏": "∏", + "⌮": "⌮", + "⌒": "⌒", + "⌓": "⌓", + "∝": "∝", + "∝": "∝", + "≾": "≾", + "⊰": "⊰", + "𝓅": "𝓅", + "ψ": "ψ", + " ": " ", + "𝔮": "𝔮", + "⨌": "⨌", + "𝕢": "𝕢", + "⁗": "⁗", + "𝓆": "𝓆", + "ℍ": "ℍ", + "⨖": "⨖", + "?": "?", + "≟": "≟", + """: "\"", + "⇛": "⇛", + "⇒": "⇒", + "⤜": "⤜", + "⤏": "⤏", + "⥤": "⥤", + "∽̱": "∽̱", + "ŕ": "ŕ", + "√": "√", + "⦳": "⦳", + "⟩": "⟩", + "⦒": "⦒", + "⦥": "⦥", + "⟩": "⟩", + "»": "»", + "→": "→", + "⥵": "⥵", + "⇥": "⇥", + "⤠": "⤠", + "⤳": "⤳", + "⤞": "⤞", + "↪": "↪", + "↬": "↬", + "⥅": "⥅", + "⥴": "⥴", + "↣": "↣", + "↝": "↝", + "⤚": "⤚", + "∶": "∶", + "ℚ": "ℚ", + "⤍": "⤍", + "❳": "❳", + "}": "}", + "]": "]", + "⦌": "⦌", + "⦎": "⦎", + "⦐": "⦐", + "ř": "ř", + "ŗ": "ŗ", + "⌉": "⌉", + "}": "}", + "р": "р", + "⤷": "⤷", + "⥩": "⥩", + "”": "”", + "”": "”", + "↳": "↳", + "ℜ": "ℜ", + "ℛ": "ℛ", + "ℜ": "ℜ", + "ℝ": "ℝ", + "▭": "▭", + "®": "®", + "⥽": "⥽", + "⌋": "⌋", + "𝔯": "𝔯", + "⇁": "⇁", + "⇀": "⇀", + "⥬": "⥬", + "ρ": "ρ", + "ϱ": "ϱ", + "→": "→", + "↣": "↣", + "⇁": "⇁", + "⇀": "⇀", + "⇄": "⇄", + "⇌": "⇌", + "⇉": "⇉", + "↝": "↝", + "⋌": "⋌", + "˚": "˚", + "≓": "≓", + "⇄": "⇄", + "⇌": "⇌", + "‏": "‏", + "⎱": "⎱", + "⎱": "⎱", + "⫮": "⫮", + "⟭": "⟭", + "⇾": "⇾", + "⟧": "⟧", + "⦆": "⦆", + "𝕣": "𝕣", + "⨮": "⨮", + "⨵": "⨵", + ")": ")", + "⦔": "⦔", + "⨒": "⨒", + "⇉": "⇉", + "›": "›", + "𝓇": "𝓇", + "↱": "↱", + "]": "]", + "’": "’", + "’": "’", + "⋌": "⋌", + "⋊": "⋊", + "▹": "▹", + "⊵": "⊵", + "▸": "▸", + "⧎": "⧎", + "⥨": "⥨", + "℞": "℞", + "ś": "ś", + "‚": "‚", + "≻": "≻", + "⪴": "⪴", + "⪸": "⪸", + "š": "š", + "≽": "≽", + "⪰": "⪰", + "ş": "ş", + "ŝ": "ŝ", + "⪶": "⪶", + "⪺": "⪺", + "⋩": "⋩", + "⨓": "⨓", + "≿": "≿", + "с": "с", + "⋅": "⋅", + "⊡": "⊡", + "⩦": "⩦", + "⇘": "⇘", + "⤥": "⤥", + "↘": "↘", + "↘": "↘", + "§": "§", + ";": ";", + "⤩": "⤩", + "∖": "∖", + "∖": "∖", + "✶": "✶", + "𝔰": "𝔰", + "⌢": "⌢", + "♯": "♯", + "щ": "щ", + "ш": "ш", + "∣": "∣", + "∥": "∥", + "­": "­", + "σ": "σ", + "ς": "ς", + "ς": "ς", + "∼": "∼", + "⩪": "⩪", + "≃": "≃", + "≃": "≃", + "⪞": "⪞", + "⪠": "⪠", + "⪝": "⪝", + "⪟": "⪟", + "≆": "≆", + "⨤": "⨤", + "⥲": "⥲", + "←": "←", + "∖": "∖", + "⨳": "⨳", + "⧤": "⧤", + "∣": "∣", + "⌣": "⌣", + "⪪": "⪪", + "⪬": "⪬", + "⪬︀": "⪬︀", + "ь": "ь", + "/": "/", + "⧄": "⧄", + "⌿": "⌿", + "𝕤": "𝕤", + "♠": "♠", + "♠": "♠", + "∥": "∥", + "⊓": "⊓", + "⊓︀": "⊓︀", + "⊔": "⊔", + "⊔︀": "⊔︀", + "⊏": "⊏", + "⊑": "⊑", + "⊏": "⊏", + "⊑": "⊑", + "⊐": "⊐", + "⊒": "⊒", + "⊐": "⊐", + "⊒": "⊒", + "□": "□", + "□": "□", + "▪": "▪", + "▪": "▪", + "→": "→", + "𝓈": "𝓈", + "∖": "∖", + "⌣": "⌣", + "⋆": "⋆", + "☆": "☆", + "★": "★", + "ϵ": "ϵ", + "ϕ": "ϕ", + "¯": "¯", + "⊂": "⊂", + "⫅": "⫅", + "⪽": "⪽", + "⊆": "⊆", + "⫃": "⫃", + "⫁": "⫁", + "⫋": "⫋", + "⊊": "⊊", + "⪿": "⪿", + "⥹": "⥹", + "⊂": "⊂", + "⊆": "⊆", + "⫅": "⫅", + "⊊": "⊊", + "⫋": "⫋", + "⫇": "⫇", + "⫕": "⫕", + "⫓": "⫓", + "≻": "≻", + "⪸": "⪸", + "≽": "≽", + "⪰": "⪰", + "⪺": "⪺", + "⪶": "⪶", + "⋩": "⋩", + "≿": "≿", + "∑": "∑", + "♪": "♪", + "¹": "¹", + "²": "²", + "³": "³", + "⊃": "⊃", + "⫆": "⫆", + "⪾": "⪾", + "⫘": "⫘", + "⊇": "⊇", + "⫄": "⫄", + "⟉": "⟉", + "⫗": "⫗", + "⥻": "⥻", + "⫂": "⫂", + "⫌": "⫌", + "⊋": "⊋", + "⫀": "⫀", + "⊃": "⊃", + "⊇": "⊇", + "⫆": "⫆", + "⊋": "⊋", + "⫌": "⫌", + "⫈": "⫈", + "⫔": "⫔", + "⫖": "⫖", + "⇙": "⇙", + "⤦": "⤦", + "↙": "↙", + "↙": "↙", + "⤪": "⤪", + "ß": "ß", + "⌖": "⌖", + "τ": "τ", + "⎴": "⎴", + "ť": "ť", + "ţ": "ţ", + "т": "т", + "⃛": "⃛", + "⌕": "⌕", + "𝔱": "𝔱", + "∴": "∴", + "∴": "∴", + "θ": "θ", + "ϑ": "ϑ", + "ϑ": "ϑ", + "≈": "≈", + "∼": "∼", + " ": " ", + "≈": "≈", + "∼": "∼", + "þ": "þ", + "˜": "˜", + "×": "×", + "⊠": "⊠", + "⨱": "⨱", + "⨰": "⨰", + "∭": "∭", + "⤨": "⤨", + "⊤": "⊤", + "⌶": "⌶", + "⫱": "⫱", + "𝕥": "𝕥", + "⫚": "⫚", + "⤩": "⤩", + "‴": "‴", + "™": "™", + "▵": "▵", + "▿": "▿", + "◃": "◃", + "⊴": "⊴", + "≜": "≜", + "▹": "▹", + "⊵": "⊵", + "◬": "◬", + "≜": "≜", + "⨺": "⨺", + "⨹": "⨹", + "⧍": "⧍", + "⨻": "⨻", + "⏢": "⏢", + "𝓉": "𝓉", + "ц": "ц", + "ћ": "ћ", + "ŧ": "ŧ", + "≬": "≬", + "↞": "↞", + "↠": "↠", + "⇑": "⇑", + "⥣": "⥣", + "ú": "ú", + "↑": "↑", + "ў": "ў", + "ŭ": "ŭ", + "û": "û", + "у": "у", + "⇅": "⇅", + "ű": "ű", + "⥮": "⥮", + "⥾": "⥾", + "𝔲": "𝔲", + "ù": "ù", + "↿": "↿", + "↾": "↾", + "▀": "▀", + "⌜": "⌜", + "⌜": "⌜", + "⌏": "⌏", + "◸": "◸", + "ū": "ū", + "¨": "¨", + "ų": "ų", + "𝕦": "𝕦", + "↑": "↑", + "↕": "↕", + "↿": "↿", + "↾": "↾", + "⊎": "⊎", + "υ": "υ", + "ϒ": "ϒ", + "υ": "υ", + "⇈": "⇈", + "⌝": "⌝", + "⌝": "⌝", + "⌎": "⌎", + "ů": "ů", + "◹": "◹", + "𝓊": "𝓊", + "⋰": "⋰", + "ũ": "ũ", + "▵": "▵", + "▴": "▴", + "⇈": "⇈", + "ü": "ü", + "⦧": "⦧", + "⇕": "⇕", + "⫨": "⫨", + "⫩": "⫩", + "⊨": "⊨", + "⦜": "⦜", + "ϵ": "ϵ", + "ϰ": "ϰ", + "∅": "∅", + "ϕ": "ϕ", + "ϖ": "ϖ", + "∝": "∝", + "↕": "↕", + "ϱ": "ϱ", + "ς": "ς", + "⊊︀": "⊊︀", + "⫋︀": "⫋︀", + "⊋︀": "⊋︀", + "⫌︀": "⫌︀", + "ϑ": "ϑ", + "⊲": "⊲", + "⊳": "⊳", + "в": "в", + "⊢": "⊢", + "∨": "∨", + "⊻": "⊻", + "≚": "≚", + "⋮": "⋮", + "|": "|", + "|": "|", + "𝔳": "𝔳", + "⊲": "⊲", + "⊂⃒": "⊂⃒", + "⊃⃒": "⊃⃒", + "𝕧": "𝕧", + "∝": "∝", + "⊳": "⊳", + "𝓋": "𝓋", + "⫋︀": "⫋︀", + "⊊︀": "⊊︀", + "⫌︀": "⫌︀", + "⊋︀": "⊋︀", + "⦚": "⦚", + "ŵ": "ŵ", + "⩟": "⩟", + "∧": "∧", + "≙": "≙", + "℘": "℘", + "𝔴": "𝔴", + "𝕨": "𝕨", + "℘": "℘", + "≀": "≀", + "≀": "≀", + "𝓌": "𝓌", + "⋂": "⋂", + "◯": "◯", + "⋃": "⋃", + "▽": "▽", + "𝔵": "𝔵", + "⟺": "⟺", + "⟷": "⟷", + "ξ": "ξ", + "⟸": "⟸", + "⟵": "⟵", + "⟼": "⟼", + "⋻": "⋻", + "⨀": "⨀", + "𝕩": "𝕩", + "⨁": "⨁", + "⨂": "⨂", + "⟹": "⟹", + "⟶": "⟶", + "𝓍": "𝓍", + "⨆": "⨆", + "⨄": "⨄", + "△": "△", + "⋁": "⋁", + "⋀": "⋀", + "ý": "ý", + "я": "я", + "ŷ": "ŷ", + "ы": "ы", + "¥": "¥", + "𝔶": "𝔶", + "ї": "ї", + "𝕪": "𝕪", + "𝓎": "𝓎", + "ю": "ю", + "ÿ": "ÿ", + "ź": "ź", + "ž": "ž", + "з": "з", + "ż": "ż", + "ℨ": "ℨ", + "ζ": "ζ", + "𝔷": "𝔷", + "ж": "ж", + "⇝": "⇝", + "𝕫": "𝕫", + "𝓏": "𝓏", + "‍": "‍", + "‌": "‌" +}; diff --git a/pkgs/markdown/lib/src/ast.dart b/pkgs/markdown/lib/src/ast.dart new file mode 100644 index 000000000..e5530cb3e --- /dev/null +++ b/pkgs/markdown/lib/src/ast.dart @@ -0,0 +1,113 @@ +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +typedef Resolver = Node? Function(String name, [String? title]); + +/// Base class for any AST item. +/// +/// Roughly corresponds to Node in the DOM. Will be either an Element or Text. +abstract class Node { + void accept(NodeVisitor visitor); + + String get textContent; +} + +/// A named tag that can contain other nodes. +class Element implements Node { + final String tag; + final List? children; + final Map attributes; + String? generatedId; + String? footnoteLabel; + + /// Instantiates a [tag] Element with [children]. + Element(this.tag, this.children) : attributes = {}; + + /// Instantiates an empty, self-closing [tag] Element. + Element.empty(this.tag) + : children = null, + attributes = {}; + + /// Instantiates a [tag] Element with no [children]. + Element.withTag(this.tag) + : children = const [], + attributes = {}; + + /// Instantiates a [tag] Element with a single Text child. + Element.text(this.tag, String text) + : children = [Text(text)], + attributes = {}; + + /// Whether this element is self-closing. + bool get isEmpty => children == null; + + @override + void accept(NodeVisitor visitor) { + if (visitor.visitElementBefore(this)) { + if (children != null) { + for (final child in children!) { + child.accept(visitor); + } + } + visitor.visitElementAfter(this); + } + } + + @override + String get textContent { + final children = this.children; + return children == null + ? '' + : children.map((child) => child.textContent).join(); + } +} + +/// A plain text element. +class Text implements Node { + final String text; + + Text(this.text); + + @override + void accept(NodeVisitor visitor) => visitor.visitText(this); + + @override + String get textContent => text; +} + +/// Inline content that has not been parsed into inline nodes (strong, links, +/// etc). +/// +/// These placeholder nodes should only remain in place while the block nodes +/// of a document are still being parsed, in order to gather all reference link +/// definitions. +class UnparsedContent implements Node { + @override + final String textContent; + + UnparsedContent(this.textContent); + + @override + void accept(NodeVisitor visitor) {} +} + +/// Visitor pattern for the AST. +/// +/// Renderers or other AST transformers should implement this. +abstract class NodeVisitor { + /// Called when a Text node has been reached. + void visitText(Text text); + + /// Called when an Element has been reached, before its children have been + /// visited. + /// + /// Returns `false` to skip its children. + bool visitElementBefore(Element element); + + /// Called when an Element has been reached, after its children have been + /// visited. + /// + /// Will not be called if [visitElementBefore] returns `false`. + void visitElementAfter(Element element); +} diff --git a/pkgs/markdown/lib/src/block_parser.dart b/pkgs/markdown/lib/src/block_parser.dart new file mode 100644 index 000000000..efe2352c3 --- /dev/null +++ b/pkgs/markdown/lib/src/block_parser.dart @@ -0,0 +1,216 @@ +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'ast.dart'; +import 'block_syntaxes/block_syntax.dart'; +import 'block_syntaxes/blockquote_syntax.dart'; +import 'block_syntaxes/code_block_syntax.dart'; +import 'block_syntaxes/dummy_block_syntax.dart'; +import 'block_syntaxes/empty_block_syntax.dart'; +import 'block_syntaxes/header_syntax.dart'; +import 'block_syntaxes/horizontal_rule_syntax.dart'; +import 'block_syntaxes/html_block_syntax.dart'; +import 'block_syntaxes/link_reference_definition_syntax.dart'; +import 'block_syntaxes/ordered_list_syntax.dart'; +import 'block_syntaxes/paragraph_syntax.dart'; +import 'block_syntaxes/setext_header_syntax.dart'; +import 'block_syntaxes/unordered_list_syntax.dart'; +import 'document.dart'; +import 'line.dart'; + +/// Maintains the internal state needed to parse a series of lines into blocks +/// of Markdown suitable for further inline parsing. +class BlockParser { + final List lines; + + /// The Markdown document this parser is parsing. + final Document document; + + /// The enabled block syntaxes. + /// + /// To turn a series of lines into blocks, each of these will be tried in + /// turn. Order matters here. + final List blockSyntaxes = []; + + /// Index of the current line. + int _pos = 0; + + /// Starting line of the last unconsumed content. + int _start = 0; + + /// The lines from [_start] to [_pos] (inclusive), it works as a buffer for + /// some blocks, for example: + /// When the [ParagraphSyntax] parsing process is interrupted by the + /// [SetextHeaderSyntax], so this structure is not a paragraph but a setext + /// heading, then the [ParagraphSyntax.parse] does not have to retreat the + /// reading position, it only needs to return `null`, the [SetextHeaderSyntax] + /// will pick up the lines in [linesToConsume]. + List get linesToConsume => lines.getRange(_start, _pos + 1).toList(); + + /// Whether the parser has encountered a blank line between two block-level + /// elements. + bool encounteredBlankLine = false; + + /// The collection of built-in block parsers. + final List standardBlockSyntaxes = [ + const EmptyBlockSyntax(), + const HtmlBlockSyntax(), + const SetextHeaderSyntax(), + const HeaderSyntax(), + const CodeBlockSyntax(), + const BlockquoteSyntax(), + const HorizontalRuleSyntax(), + const UnorderedListSyntax(), + const OrderedListSyntax(), + const LinkReferenceDefinitionSyntax(), + const ParagraphSyntax() + ]; + + BlockParser(this.lines, this.document) { + blockSyntaxes.addAll(document.blockSyntaxes); + + if (document.withDefaultBlockSyntaxes) { + blockSyntaxes.addAll(standardBlockSyntaxes); + } else { + blockSyntaxes.add(const DummyBlockSyntax()); + } + } + + /// Gets the current line. + Line get current => lines[_pos]; + + /// Gets the line after the current one or `null` if there is none. + Line? get next { + // Don't read past the end. + if (_pos >= lines.length - 1) return null; + return lines[_pos + 1]; + } + + /// Gets the line that is [linesAhead] lines ahead of the current one, or + /// `null` if there is none. + /// + /// `peek(0)` is equivalent to [current]. + /// + /// `peek(1)` is equivalent to [next]. + Line? peek(int linesAhead) { + if (linesAhead < 0) { + throw ArgumentError('Invalid linesAhead: $linesAhead; must be >= 0.'); + } + // Don't read past the end. + if (_pos >= lines.length - linesAhead) return null; + return lines[_pos + linesAhead]; + } + + /// Advances the reading position by one line. + void advance() { + _pos++; + } + + /// Retreats the reading position by one line. + void retreat() { + _pos--; + } + + /// Retreats the reading position by [count] lines. + void retreatBy(int count) { + _pos -= count; + } + + bool get isDone => _pos >= lines.length; + + /// Gets whether or not the current line matches the given pattern. + bool matches(RegExp regex) { + if (isDone) return false; + return regex.hasMatch(current.content); + } + + /// Gets whether or not the next line matches the given pattern. + bool matchesNext(RegExp regex) { + if (next == null) return false; + return regex.hasMatch(next!.content); + } + + /// The parent [BlockSyntax] when it is running inside a nested syntax. + BlockSyntax? get parentSyntax => _parentSyntax; + BlockSyntax? _parentSyntax; + + /// Whether the [SetextHeadingSyntax] is disabled temporarily. + bool get setextHeadingDisabled => _setextHeadingDisabled; + bool _setextHeadingDisabled = false; + + /// The [BlockSyntax] which is running now. + /// The value is `null` until we found the first matched [BlockSyntax]. + BlockSyntax? get currentSyntax => _currentSyntax; + BlockSyntax? _currentSyntax; + + /// The [BlockSyntax] which is running before the [currentSyntax]. + BlockSyntax? get previousSyntax => _previousSyntax; + BlockSyntax? _previousSyntax; + + List parseLines({ + BlockSyntax? parentSyntax, + bool disabledSetextHeading = false, + }) { + _parentSyntax = parentSyntax; + _setextHeadingDisabled = disabledSetextHeading; + + final blocks = []; + + // If the `_pos` does not change before and after `parse()`, never try to + // parse the line at `_pos` with the same syntax again. + // For example the `TableSyntax` might not advance the `_pos` in `parse` + // method, beause of the header row does not match the delimiter row in the + // number of cells, which makes a table like structure not be recognized. + BlockSyntax? neverMatch; + + var iterationsWithoutProgress = 0; + while (!isDone) { + final positionBefore = _pos; + for (final syntax in blockSyntaxes) { + if (neverMatch == syntax) { + continue; + } + + if (syntax.canParse(this)) { + _previousSyntax = _currentSyntax; + _currentSyntax = syntax; + final block = syntax.parse(this); + if (block != null) { + blocks.add(block); + } + neverMatch = _pos != positionBefore ? null : syntax; + + if (block != null || + syntax is EmptyBlockSyntax || + syntax is LinkReferenceDefinitionSyntax) { + _start = _pos; + } + + break; + } + } + // Count the number of iterations without progress. + // This ensures that we don't have an infinite loop. And if we have an + // infinite loop, it's easier to gracefully recover from an error, than + // it is to discover an kill an isolate that's stuck in an infinite loop. + // Technically, it should be perfectly safe to remove this check + // But as it's possible to inject custom BlockSyntax implementations and + // combine existing ones, it is hard to promise that no combination can't + // trigger an infinite loop + if (positionBefore == _pos) { + iterationsWithoutProgress++; + if (iterationsWithoutProgress > 2) { + // If this happens we throw an error to avoid having the parser + // running in an infinite loop. An error is easier to handle. + // If you see this error in production please file a bug! + throw AssertionError('BlockParser.parseLines is not advancing'); + } + } else { + iterationsWithoutProgress = 0; + } + } + + return blocks; + } +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/alert_block_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/alert_block_syntax.dart new file mode 100644 index 000000000..0f4f5b11a --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/alert_block_syntax.dart @@ -0,0 +1,109 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../block_parser.dart'; +import '../line.dart'; +import '../patterns.dart'; +import 'block_syntax.dart'; +import 'code_block_syntax.dart'; +import 'paragraph_syntax.dart'; + +/// Parses GitHub Alerts blocks. +/// +/// See also: https://docs.github.com/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts +class AlertBlockSyntax extends BlockSyntax { + const AlertBlockSyntax(); + + @override + RegExp get pattern => alertPattern; + + @override + bool canParse(BlockParser parser) { + return alertPattern.hasMatch(parser.current.content); + } + + /// Whether this alert ends with a lazy continuation line. + /// + /// The definition of lazy continuation lines: + /// https://spec.commonmark.org/0.30/#lazy-continuation-line + static bool _lazyContinuation = false; + static final _contentLineRegExp = RegExp(r'>?\s?(.*)*'); + + @override + List parseChildLines(BlockParser parser) { + // Grab all of the lines that form the alert, stripping off the ">". + final childLines = []; + _lazyContinuation = false; + + while (!parser.isDone) { + final lineContent = parser.current.content.trimLeft(); + final strippedContent = lineContent.replaceFirst(RegExp(r'^>?\s*'), ''); + final match = strippedContent.isEmpty && !lineContent.startsWith('>') + ? null + : _contentLineRegExp.firstMatch(strippedContent); + if (match != null) { + childLines.add(Line(strippedContent)); + parser.advance(); + _lazyContinuation = false; + continue; + } + + final lastLine = childLines.isEmpty ? Line('') : childLines.last; + + // A paragraph continuation is OK. This is content that cannot be parsed + // as any other syntax except Paragraph, and it doesn't match the bar in + // a Setext header. + // Because indented code blocks cannot interrupt paragraphs, a line + // matched CodeBlockSyntax is also paragraph continuation text. + final otherMatched = + parser.blockSyntaxes.firstWhere((s) => s.canParse(parser)); + if ((otherMatched is ParagraphSyntax && + !lastLine.isBlankLine && + !codeFencePattern.hasMatch(lastLine.content)) || + (otherMatched is CodeBlockSyntax && + !indentPattern.hasMatch(lastLine.content))) { + childLines.add(parser.current); + _lazyContinuation = true; + parser.advance(); + } else { + break; + } + } + + return childLines; + } + + @override + Node parse(BlockParser parser) { + // Parse the alert type from the first line. + final type = + pattern.firstMatch(parser.current.content)!.group(1)!.toLowerCase(); + parser.advance(); + final childLines = parseChildLines(parser); + // Recursively parse the contents of the alert. + final children = BlockParser(childLines, parser.document).parseLines( + // The setext heading underline cannot be a lazy continuation line in a + // block quote. + // https://spec.commonmark.org/0.30/#example-93 + disabledSetextHeading: _lazyContinuation, + parentSyntax: this, + ); + + // Mapping the alert title text. + const typeTextMap = { + 'note': 'Note', + 'tip': 'Tip', + 'important': 'Important', + 'caution': 'Caution', + 'warning': 'Warning', + }; + final titleText = typeTextMap[type]!; + final titleElement = Element('p', [Text(titleText)]) + ..attributes['class'] = 'markdown-alert-title'; + final elementClass = 'markdown-alert markdown-alert-$type'; + return Element('div', [titleElement, ...children]) + ..attributes['class'] = elementClass; + } +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/block_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/block_syntax.dart new file mode 100644 index 000000000..947824ab6 --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/block_syntax.dart @@ -0,0 +1,64 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../block_parser.dart'; +import '../line.dart'; + +abstract class BlockSyntax { + const BlockSyntax(); + + /// Gets the regex used to identify the beginning of this block, if any. + RegExp get pattern; + + bool canEndBlock(BlockParser parser) => true; + + bool canParse(BlockParser parser) { + return pattern.hasMatch(parser.current.content); + } + + Node? parse(BlockParser parser); + + List parseChildLines(BlockParser parser) { + // Grab all of the lines that form the block element. + final childLines = []; + + while (!parser.isDone) { + final match = pattern.firstMatch(parser.current.content); + if (match == null) break; + childLines.add(parser.current); + parser.advance(); + } + + return childLines; + } + + /// Returns the block which interrupts current syntax parsing if there is one, + /// otherwise returns `null`. + /// + /// Make sure to check if [parser] `isDone` is `false` first. + BlockSyntax? interruptedBy(BlockParser parser) { + for (final syntax in parser.blockSyntaxes) { + if (syntax.canParse(parser) && syntax.canEndBlock(parser)) { + return syntax; + } + } + return null; + } + + /// Gets whether or not [parser]'s current line should end the previous block. + static bool isAtBlockEnd(BlockParser parser) { + if (parser.isDone) return true; + return parser.blockSyntaxes + .any((s) => s.canParse(parser) && s.canEndBlock(parser)); + } + + /// Generates a valid HTML anchor from the inner text of [element]. + static String generateAnchorHash(Element element) => + element.children!.first.textContent + .toLowerCase() + .trim() + .replaceAll(RegExp('[^a-z0-9 _-]'), '') + .replaceAll(RegExp(r'\s'), '-'); +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/blockquote_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/blockquote_syntax.dart new file mode 100644 index 000000000..afbe23a0f --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/blockquote_syntax.dart @@ -0,0 +1,99 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../block_parser.dart'; +import '../charcode.dart'; +import '../line.dart'; +import '../patterns.dart'; +import '../util.dart'; +import 'block_syntax.dart'; +import 'code_block_syntax.dart'; +import 'paragraph_syntax.dart'; + +/// Parses email-style blockquotes: `> quote`. +class BlockquoteSyntax extends BlockSyntax { + @override + RegExp get pattern => blockquotePattern; + + const BlockquoteSyntax(); + + /// Whether this blockquote ends with a lazy continuation line. + // The definition of lazy continuation lines: + // https://spec.commonmark.org/0.30/#lazy-continuation-line + static var _lazyContinuation = false; + @override + List parseChildLines(BlockParser parser) { + // Grab all of the lines that form the blockquote, stripping off the ">". + final childLines = []; + _lazyContinuation = false; + + while (!parser.isDone) { + final currentLine = parser.current; + final match = pattern.firstMatch(parser.current.content); + if (match != null) { + // A block quote marker consists of a `>` together with an optional + // following space of indentation, see + // https://spec.commonmark.org/0.30/#block-quote-marker. + final markerStart = match.match.indexOf('>'); + int markerEnd; + if (currentLine.content.length > 1) { + var hasSpace = false; + // Check if there is a following space if the marker is not at the end + // of this line. + if (markerStart < currentLine.content.length - 1) { + final nextChar = currentLine.content.codeUnitAt(markerStart + 1); + hasSpace = nextChar == $tab || nextChar == $space; + } + markerEnd = markerStart + (hasSpace ? 2 : 1); + } else { + markerEnd = markerStart + 1; + } + childLines.add(Line(currentLine.content.substring(markerEnd))); + parser.advance(); + _lazyContinuation = false; + continue; + } + + final lastLine = childLines.last; + + // A paragraph continuation is OK. This is content that cannot be parsed + // as any other syntax except Paragraph, and it doesn't match the bar in + // a Setext header. + // Because indented code blocks cannot interrupt paragraphs, a line + // matched CodeBlockSyntax is also paragraph continuation text. + final otherMatched = + parser.blockSyntaxes.firstWhere((s) => s.canParse(parser)); + if ((otherMatched is ParagraphSyntax && + !lastLine.isBlankLine && + !codeFencePattern.hasMatch(lastLine.content)) || + (otherMatched is CodeBlockSyntax && + !indentPattern.hasMatch(lastLine.content))) { + childLines.add(parser.current); + _lazyContinuation = true; + parser.advance(); + } else { + break; + } + } + + return childLines; + } + + @override + Node parse(BlockParser parser) { + final childLines = parseChildLines(parser); + + // Recursively parse the contents of the blockquote. + final children = BlockParser(childLines, parser.document).parseLines( + // The setext heading underline cannot be a lazy continuation line in a + // block quote. + // https://spec.commonmark.org/0.30/#example-93 + disabledSetextHeading: _lazyContinuation, + parentSyntax: this, + ); + + return Element('blockquote', children); + } +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/code_block_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/code_block_syntax.dart new file mode 100644 index 000000000..1d30667a5 --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/code_block_syntax.dart @@ -0,0 +1,85 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../block_parser.dart'; +import '../line.dart'; +import '../patterns.dart'; +import '../util.dart'; +import 'block_syntax.dart'; + +/// Parses preformatted code blocks that are indented four spaces. +class CodeBlockSyntax extends BlockSyntax { + @override + RegExp get pattern => indentPattern; + + @override + bool canEndBlock(BlockParser parser) => false; + + const CodeBlockSyntax(); + + @override + List parseChildLines(BlockParser parser) { + final childLines = []; + + while (!parser.isDone) { + final isBlankLine = parser.current.isBlankLine; + if (isBlankLine && _shouldEnd(parser)) { + break; + } + + if (!isBlankLine && + childLines.isNotEmpty && + !pattern.hasMatch(parser.current.content)) { + break; + } + + childLines.add(Line( + parser.current.content.dedent().text, + tabRemaining: parser.current.tabRemaining, + )); + + parser.advance(); + } + + return childLines; + } + + @override + Node parse(BlockParser parser) { + final childLines = parseChildLines(parser); + + // The Markdown tests expect a trailing newline. + childLines.add(Line('')); + + var content = childLines + .map((e) => e.content.prependSpace(e.tabRemaining ?? 0)) + .join('\n'); + if (parser.document.encodeHtml) { + content = escapeHtml(content, escapeApos: false); + } + + return Element('pre', [Element.text('code', content)]); + } + + bool _shouldEnd(BlockParser parser) { + var i = 1; + while (true) { + final nextLine = parser.peek(i); + // EOF + if (nextLine == null) { + return true; + } + + // It does not matter how many blank lines between chunks: + // https://spec.commonmark.org/0.30/#example-111 + if (nextLine.isBlankLine) { + i++; + continue; + } + + return !pattern.hasMatch(nextLine.content); + } + } +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/dummy_block_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/dummy_block_syntax.dart new file mode 100644 index 000000000..c08c8a8dd --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/dummy_block_syntax.dart @@ -0,0 +1,36 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../block_parser.dart'; +import '../patterns.dart'; +import 'block_syntax.dart'; + +/// Walks the parser forward through the lines does not match any [BlockSyntax]. +/// +/// Returns a [UnparsedContent] with the unmatched lines as `textContent`. +class DummyBlockSyntax extends BlockSyntax { + const DummyBlockSyntax(); + + @override + RegExp get pattern => dummyPattern; + + @override + bool canEndBlock(BlockParser parser) => false; + + @override + bool canParse(BlockParser parser) => true; + + @override + Node parse(BlockParser parser) { + final childLines = []; + + while (!BlockSyntax.isAtBlockEnd(parser)) { + childLines.add(parser.current.content); + parser.advance(); + } + + return UnparsedContent(childLines.join('\n')); + } +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/empty_block_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/empty_block_syntax.dart new file mode 100644 index 000000000..54cc86515 --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/empty_block_syntax.dart @@ -0,0 +1,24 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../block_parser.dart'; +import '../patterns.dart'; +import 'block_syntax.dart'; + +class EmptyBlockSyntax extends BlockSyntax { + @override + RegExp get pattern => emptyPattern; + + const EmptyBlockSyntax(); + + @override + Node? parse(BlockParser parser) { + parser.encounteredBlankLine = true; + parser.advance(); + + // Don't actually emit anything. + return null; + } +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/fenced_blockquote_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/fenced_blockquote_syntax.dart new file mode 100644 index 000000000..9e18d4237 --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/fenced_blockquote_syntax.dart @@ -0,0 +1,45 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../block_parser.dart'; +import '../line.dart'; +import '../patterns.dart'; +import 'block_syntax.dart'; + +/// Parses lines fenced by `>>>` to blockquotes +class FencedBlockquoteSyntax extends BlockSyntax { + const FencedBlockquoteSyntax(); + + @override + RegExp get pattern => blockquoteFencePattern; + + @override + List parseChildLines(BlockParser parser) { + final childLines = []; + parser.advance(); + + while (!parser.isDone) { + final match = pattern.hasMatch(parser.current.content); + if (!match) { + childLines.add(parser.current); + parser.advance(); + } else { + parser.advance(); + break; + } + } + + return childLines; + } + + @override + Node? parse(BlockParser parser) { + final childLines = parseChildLines(parser); + + // Recursively parse the contents of the blockquote. + final children = BlockParser(childLines, parser.document).parseLines(); + return Element('blockquote', children); + } +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/fenced_code_block_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/fenced_code_block_syntax.dart new file mode 100644 index 000000000..cea110665 --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/fenced_code_block_syntax.dart @@ -0,0 +1,141 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../block_parser.dart'; +import '../line.dart'; +import '../patterns.dart'; +import '../util.dart'; +import 'block_syntax.dart'; + +/// Parses preformatted code blocks between two ~~~ or ``` sequences. +/// +/// See the CommonMark spec: +/// https://spec.commonmark.org/0.30/#fenced-code-blocks +class FencedCodeBlockSyntax extends BlockSyntax { + @override + RegExp get pattern => codeFencePattern; + + const FencedCodeBlockSyntax(); + + @override + Node parse(BlockParser parser) { + final openingFence = _FenceMatch.fromMatch(pattern.firstMatch( + escapePunctuation(parser.current.content), + )!); + + var text = parseChildLines( + parser, + openingFence.marker, + openingFence.indent, + ).map((e) => e.content).join('\n'); + + if (parser.document.encodeHtml) { + text = escapeHtml(text, escapeApos: false); + } + if (text.isNotEmpty) { + text = '$text\n'; + } + + final code = Element.text('code', text); + if (openingFence.hasLanguage) { + var language = decodeHtmlCharacters(openingFence.language); + if (parser.document.encodeHtml) { + language = escapeHtmlAttribute(language); + } + code.attributes['class'] = 'language-$language'; + } + + return Element('pre', [code]); + } + + String _removeIndentation(String content, int length) { + final text = content.replaceFirst(RegExp('^\\s{0,$length}'), ''); + return content.substring(content.length - text.length); + } + + @override + List parseChildLines( + BlockParser parser, [ + String openingMarker = '', + int indent = 0, + ]) { + final childLines = []; + + parser.advance(); + + _FenceMatch? closingFence; + while (!parser.isDone) { + final match = pattern.firstMatch(parser.current.content); + closingFence = match == null ? null : _FenceMatch.fromMatch(match); + + // Closing code fences cannot have info strings: + // https://spec.commonmark.org/0.30/#example-147 + if (closingFence == null || + !closingFence.marker.startsWith(openingMarker) || + closingFence.hasInfo) { + childLines.add( + Line(_removeIndentation(parser.current.content, indent)), + ); + parser.advance(); + } else { + parser.advance(); + break; + } + } + + // https://spec.commonmark.org/0.30/#example-127 + // https://spec.commonmark.org/0.30/#example-128 + if (closingFence == null && + childLines.isNotEmpty && + childLines.last.isBlankLine) { + childLines.removeLast(); + } + + return childLines; + } +} + +class _FenceMatch { + _FenceMatch._({ + required this.indent, + required this.marker, + required this.info, + }); + + factory _FenceMatch.fromMatch(RegExpMatch match) { + String marker; + String info; + + if (match.namedGroup('backtick') != null) { + marker = match.namedGroup('backtick')!; + info = match.namedGroup('backtickInfo')!; + } else { + marker = match.namedGroup('tilde')!; + info = match.namedGroup('tildeInfo')!; + } + + return _FenceMatch._( + indent: match[1]!.length, + marker: marker, + info: info.trim(), + ); + } + + final int indent; + final String marker; + + // The info-string should be trimmed, + // https://spec.commonmark.org/0.30/#info-string. + final String info; + + // The first word of the info string is typically used to specify the language + // of the code sample, + // https://spec.commonmark.org/0.30/#example-143. + String get language => info.split(' ').first; + + bool get hasInfo => info.isNotEmpty; + + bool get hasLanguage => language.isNotEmpty; +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/footnote_def_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/footnote_def_syntax.dart new file mode 100644 index 000000000..3e59dcf71 --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/footnote_def_syntax.dart @@ -0,0 +1,82 @@ +import '../ast.dart' show Element, Node; +import '../block_parser.dart' show BlockParser; +import '../line.dart'; +import '../patterns.dart' show dummyPattern, emptyPattern, footnotePattern; +import 'block_syntax.dart' show BlockSyntax; + +/// The spec of GFM about footnotes is [missing](https://github.com/github/cmark-gfm/issues/283#issuecomment-1378868725). +/// For online source code of cmark-gfm, see [master@c32ef78](https://github.com/github/cmark-gfm/blob/c32ef78/src/blocks.c#L1212). +/// A Rust implementation is also [available](https://github.com/wooorm/markdown-rs/blob/2498e31eecead798efc649502bbf5f86feaa94be/src/construct/gfm_footnote_definition.rs). +/// Footnote definition could contain multiple line-children and children could +/// be separated by one empty line. +/// Its first child-line would be the remaining part of the first line after +/// taking definition leading, combining with other child lines parsed by +/// [parseChildLines], is fed into [BlockParser]. +class FootnoteDefSyntax extends BlockSyntax { + const FootnoteDefSyntax(); + + @override + RegExp get pattern => footnotePattern; + + @override + Node? parse(BlockParser parser) { + final current = parser.current.content; + final match = pattern.firstMatch(current)!; + final label = match[2]!; + final refs = parser.document.footnoteReferences; + refs[label] = 0; + + final id = Uri.encodeComponent(label); + parser.advance(); + final lines = [ + Line(current.substring(match[0]!.length)), + ...parseChildLines(parser), + ]; + final children = BlockParser(lines, parser.document).parseLines(); + return Element('li', children) + ..attributes['id'] = 'fn-$id' + ..footnoteLabel = label; + } + + @override + List parseChildLines(BlockParser parser) { + final children = []; + // As one empty line should not split footnote definition, use this flag. + var shouldBeBlock = false; + late final syntaxList = parser.blockSyntaxes + .where((s) => !_excludingPattern.contains(s.pattern)); + + // Every line is footnote's children util two blank lines or a block. + while (!parser.isDone) { + final line = parser.current.content; + if (line.trim().isEmpty) { + children.add(line); + parser.advance(); + shouldBeBlock = true; + continue; + } else if (line.startsWith(' ')) { + children.add(line.substring(4)); + parser.advance(); + shouldBeBlock = false; + } else if (shouldBeBlock || _isBlock(syntaxList, line)) { + break; + } else { + children.add(line); + parser.advance(); + } + } + return children.map(Line.new).toList(growable: false); + } + + /// Patterns that would be used to decide if one line is a block. + static final _excludingPattern = { + emptyPattern, + dummyPattern, + }; + + /// Whether this line is any kind of block. + /// If `true`, the footnote block should end. + static bool _isBlock(Iterable syntaxList, String line) { + return syntaxList.any((s) => s.pattern.hasMatch(line)); + } +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/header_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/header_syntax.dart new file mode 100644 index 000000000..197b41767 --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/header_syntax.dart @@ -0,0 +1,47 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../block_parser.dart'; +import '../patterns.dart'; +import 'block_syntax.dart'; + +/// Parses atx-style headers: `## Header ##`. +class HeaderSyntax extends BlockSyntax { + @override + RegExp get pattern => headerPattern; + + const HeaderSyntax(); + + @override + Node parse(BlockParser parser) { + final match = pattern.firstMatch(parser.current.content)!; + final matchedText = match[0]!; + final openMarker = match[1]!; + final closeMarker = match[2]; + final level = openMarker.length; + final openMarkerStart = matchedText.indexOf(openMarker); + final openMarkerEnd = openMarkerStart + level; + + String? content; + if (closeMarker == null) { + content = parser.current.content.substring(openMarkerEnd); + } else { + final closeMarkerStart = matchedText.lastIndexOf(closeMarker); + content = parser.current.content.substring( + openMarkerEnd, + closeMarkerStart, + ); + } + content = content.trim(); + + // https://spec.commonmark.org/0.30/#example-79 + if (closeMarker == null && RegExp(r'^#+$').hasMatch(content)) { + content = null; + } + + parser.advance(); + return Element('h$level', [if (content != null) UnparsedContent(content)]); + } +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/header_with_id_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/header_with_id_syntax.dart new file mode 100644 index 000000000..8e2c50b28 --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/header_with_id_syntax.dart @@ -0,0 +1,24 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../block_parser.dart'; +import 'block_syntax.dart'; +import 'header_syntax.dart'; + +/// Parses atx-style headers, and adds generated IDs to the generated elements. +class HeaderWithIdSyntax extends HeaderSyntax { + const HeaderWithIdSyntax(); + + @override + Node parse(BlockParser parser) { + final element = super.parse(parser) as Element; + + if (element.children?.isNotEmpty ?? false) { + element.generatedId = BlockSyntax.generateAnchorHash(element); + } + + return element; + } +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/horizontal_rule_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/horizontal_rule_syntax.dart new file mode 100644 index 000000000..12e78392a --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/horizontal_rule_syntax.dart @@ -0,0 +1,22 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../block_parser.dart'; +import '../patterns.dart'; +import 'block_syntax.dart'; + +/// Parses horizontal rules like `---`, `_ _ _`, `* * *`, etc. +class HorizontalRuleSyntax extends BlockSyntax { + @override + RegExp get pattern => hrPattern; + + const HorizontalRuleSyntax(); + + @override + Node parse(BlockParser parser) { + parser.advance(); + return Element.empty('hr'); + } +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/html_block_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/html_block_syntax.dart new file mode 100644 index 000000000..c1aa85c86 --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/html_block_syntax.dart @@ -0,0 +1,99 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../block_parser.dart'; +import '../line.dart'; +import '../patterns.dart'; +import 'block_syntax.dart'; +import 'list_syntax.dart'; + +/// Parse HTML blocks. +// There are seven kinds of HTML block defined in the CommonMark spec: +// https://spec.commonmark.org/0.30/#html-blocks. +// These matching conditions and HTML block types mentioned in this syntax +// correspond to these ones in the CommonMark spec. +class HtmlBlockSyntax extends BlockSyntax { + @override + RegExp get pattern => htmlBlockPattern; + + // All types of HTML blocks except type 7 may interrupt a paragraph, see the + // second paragraph after https://spec.commonmark.org/0.30/#example-148 for + // more detail. + @override + bool canEndBlock(BlockParser parser) => + pattern.firstMatch(parser.current.content)!.namedGroup('condition_7') == + null; + + static final _endConditions = [ + // For condition 1, it does not need to match the start tag, see + // https://spec.commonmark.org/0.30/#end-condition + RegExp('', caseSensitive: false), + RegExp('-->'), + RegExp(r'\?>'), + RegExp('>'), + RegExp(']]>'), + emptyPattern, + emptyPattern, + ]; + + const HtmlBlockSyntax(); + + @override + List parseChildLines(BlockParser parser) { + final lines = []; + + final match = pattern.firstMatch(parser.current.content); + var matchedCondition = 0; + for (var i = 0; i < match!.groupCount; i++) { + if (match.group(i + 1) != null) { + matchedCondition = i; + break; + } + } + + final endCondition = _endConditions[matchedCondition]; + if (endCondition == emptyPattern) { + lines.add(parser.current); + parser.advance(); + + while (!parser.isDone && !endCondition.hasMatch(parser.current.content)) { + lines.add(parser.current); + parser.advance(); + } + } else { + while (!parser.isDone) { + lines.add(parser.current); + if (endCondition.hasMatch(parser.current.content)) { + break; + } + parser.advance(); + } + parser.advance(); + } + + // If the current line start an HTML block again, put them together with + // the previous HTML block. + if (!parser.isDone && pattern.hasMatch(parser.current.content)) { + lines.addAll(parseChildLines(parser)); + } + + return lines; + } + + @override + Node parse(BlockParser parser) { + final childLines = parseChildLines(parser); + + var text = childLines.map((e) => e.content).join('\n').trimRight(); + if (parser.previousSyntax != null || parser.parentSyntax != null) { + text = '\n$text'; + if (parser.parentSyntax is ListSyntax) { + text = '$text\n'; + } + } + + return Text(text); + } +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/link_reference_definition_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/link_reference_definition_syntax.dart new file mode 100644 index 000000000..5b2b1b5fd --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/link_reference_definition_syntax.dart @@ -0,0 +1,65 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../block_parser.dart'; +import '../document.dart'; +import '../line.dart'; +import '../link_parser.dart'; +import '../patterns.dart'; +import '../util.dart'; +import 'block_syntax.dart'; + +class LinkReferenceDefinitionSyntax extends BlockSyntax { + @override + RegExp get pattern => linkReferenceDefinitionPattern; + + @override + bool canEndBlock(BlockParser parser) => false; + + const LinkReferenceDefinitionSyntax(); + + @override + Node? parse(BlockParser parser) { + final lines = [parser.current]; + parser.advance(); + + while (!BlockSyntax.isAtBlockEnd(parser)) { + lines.add(parser.current); + parser.advance(); + } + + if (!_parseLinkReferenceDefinition(lines, parser)) { + parser.retreatBy(lines.length); + } + + return null; + } + + bool _parseLinkReferenceDefinition(List lines, BlockParser parser) { + final linkParser = LinkParser(lines.map((e) => e.content).join('\n')) + ..parseDefinition(); + + if (!linkParser.valid) { + return false; + } + + // Retreat the parsing position back to where the link reference definition + // ends, so that the next syntax can continue parsing from there. + parser.retreatBy(linkParser.unconsumedLines); + + final labelString = normalizeLinkLabel(linkParser.label!); + + parser.document.linkReferences.putIfAbsent( + labelString, + () => LinkReference( + labelString, + linkParser.destination!, + linkParser.title, + ), + ); + + return true; + } +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/list_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/list_syntax.dart new file mode 100644 index 000000000..534ca3e73 --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/list_syntax.dart @@ -0,0 +1,353 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../block_parser.dart'; +import '../charcode.dart'; +import '../line.dart'; +import '../patterns.dart'; +import '../text_parser.dart'; +import '../util.dart'; +import 'block_syntax.dart'; +import 'ordered_list_with_checkbox_syntax.dart'; +import 'unordered_list_with_checkbox_syntax.dart'; + +class ListItem { + const ListItem( + this.lines, { + this.taskListItemState, + }); + + final List lines; + final TaskListItemState? taskListItemState; +} + +enum TaskListItemState { checked, unchecked } + +/// Base class for both ordered and unordered lists. +abstract class ListSyntax extends BlockSyntax { + @override + bool canParse(BlockParser parser) => + pattern.hasMatch(parser.current.content) && + !hrPattern.hasMatch(parser.current.content); + + @override + bool canEndBlock(BlockParser parser) { + // An empty list cannot interrupt a paragraph. See + // https://spec.commonmark.org/0.30/#example-285. + // Ideally, [BlockSyntax.canEndBlock] should be changed to be a method + // which accepts a [BlockParser], but this would be a breaking change, + // so we're going with this temporarily. + final match = pattern.firstMatch(parser.current.content)!; + + // Allow only lists starting with 1 to interrupt paragraphs, if it is an + // ordered list. See https://spec.commonmark.org/0.30/#example-304. + // But there should be an exception for nested ordered lists, for example: + // ``` + // 1. one + // 2. two + // 3. three + // 4. four + // 5. five + // ``` + if (parser.parentSyntax is! ListSyntax && + match[1] != null && + match[1] != '1') { + return false; + } + + // An empty list item cannot interrupt a paragraph. See + // https://spec.commonmark.org/0.30/#example-285 + return match[2]?.isNotEmpty ?? false; + } + + const ListSyntax(); + + /// A list of patterns that can start a valid block within a list item. + static final blocksInList = [ + blockquotePattern, + headerPattern, + hrPattern, + indentPattern, + listPattern, + ]; + + @override + Node parse(BlockParser parser) { + final match = pattern.firstMatch(parser.current.content); + final ordered = match![1] != null; + + final taskListParserEnabled = this is UnorderedListWithCheckboxSyntax || + this is OrderedListWithCheckboxSyntax; + final items = []; + var childLines = []; + TaskListItemState? taskListItemState; + + void endItem() { + if (childLines.isNotEmpty) { + items.add(ListItem(childLines, taskListItemState: taskListItemState)); + childLines = []; + } + } + + String parseTaskListItem(String text) { + final pattern = RegExp(r'^ {0,3}\[([ xX])\][ \t]'); + + if (taskListParserEnabled && pattern.hasMatch(text)) { + return text.replaceFirstMapped(pattern, (match) { + taskListItemState = match[1] == ' ' + ? TaskListItemState.unchecked + : TaskListItemState.checked; + + return ''; + }); + } else { + taskListItemState = null; + return text; + } + } + + late Match? possibleMatch; + bool tryMatch(RegExp pattern) { + possibleMatch = pattern.firstMatch(parser.current.content); + return possibleMatch != null; + } + + String? listMarker; + int? indent; + // In case the first number in an ordered list is not 1, use it as the + // "start". + int? startNumber; + + int? blankLines; + + while (!parser.isDone) { + final currentIndent = parser.current.content.indentation() + + (parser.current.tabRemaining ?? 0); + + if (parser.current.isBlankLine) { + childLines.add(parser.current); + + if (blankLines != null) { + blankLines++; + } + } else if (indent != null && indent <= currentIndent) { + // A list item can begin with at most one blank line. See: + // https://spec.commonmark.org/0.30/#example-280 + if (blankLines != null && blankLines > 1) { + break; + } + + final indentedLine = parser.current.content.dedent(indent); + + childLines.add(Line( + blankLines == null + ? indentedLine.text + : parseTaskListItem(indentedLine.text), + tabRemaining: indentedLine.tabRemaining, + )); + } else if (tryMatch(hrPattern)) { + // Horizontal rule takes precedence to a new list item. + break; + } else if (tryMatch(listPattern)) { + blankLines = null; + final match = possibleMatch!; + final textParser = TextParser(parser.current.content); + var precedingWhitespaces = textParser.moveThroughWhitespace(); + final markerStart = textParser.pos; + final digits = match[1] ?? ''; + if (digits.isNotEmpty) { + startNumber ??= int.parse(digits); + textParser.advanceBy(digits.length); + } + textParser.advance(); + + // See https://spec.commonmark.org/0.30/#ordered-list-marker + final marker = textParser.substring( + markerStart, + textParser.pos, + ); + + var isBlank = true; + var contentWhitespances = 0; + var containsTab = false; + int? contentBlockStart; + + if (!textParser.isDone) { + containsTab = textParser.charAt() == $tab; + // Skip the first whitespace. + textParser.advance(); + contentBlockStart = textParser.pos; + if (!textParser.isDone) { + contentWhitespances = textParser.moveThroughWhitespace(); + + if (!textParser.isDone) { + isBlank = false; + } + } + } + + // Changing the bullet or ordered list delimiter starts a new list. + if (listMarker != null && listMarker.last() != marker.last()) { + break; + } + + // End the current list item and start a new one. + endItem(); + + // Start a new list item, the last item will be ended up outside of the + // `while` loop. + listMarker = marker; + precedingWhitespaces += digits.length + 2; + if (isBlank) { + // See https://spec.commonmark.org/0.30/#example-278. + blankLines = 1; + indent = precedingWhitespaces; + } else if (contentWhitespances >= 4) { + // See https://spec.commonmark.org/0.30/#example-270. + // + // If the list item starts with indented code, we need to _not_ count + // any indentation past the required whitespace character. + indent = precedingWhitespaces; + } else { + indent = precedingWhitespaces + contentWhitespances; + } + + taskListItemState = null; + var content = contentBlockStart != null && !isBlank + ? parseTaskListItem(textParser.substring(contentBlockStart)) + : ''; + + if (content.isEmpty && containsTab) { + content = content.prependSpace(2); + } + + childLines.add(Line( + content, + tabRemaining: containsTab ? 2 : null, + )); + } else if (BlockSyntax.isAtBlockEnd(parser)) { + // Done with the list. + break; + } else { + // If the previous item is a blank line, this means we're done with the + // list and are starting a new top-level paragraph. + if (childLines.isNotEmpty && childLines.last.isBlankLine) { + parser.encounteredBlankLine = true; + break; + } + + // Anything else is paragraph continuation text. + childLines.add(parser.current); + } + parser.advance(); + } + + endItem(); + final itemNodes = []; + + items.forEach(_removeLeadingEmptyLine); + final anyEmptyLines = _removeTrailingEmptyLines(items); + var anyEmptyLinesBetweenBlocks = false; + var containsTaskList = false; + const taskListClass = 'task-list-item'; + + for (final item in items) { + Element? checkboxToInsert; + if (item.taskListItemState != null) { + containsTaskList = true; + checkboxToInsert = Element.withTag('input') + ..attributes['type'] = 'checkbox'; + if (item.taskListItemState == TaskListItemState.checked) { + checkboxToInsert.attributes['checked'] = 'true'; + } + } + + final itemParser = BlockParser(item.lines, parser.document); + final children = itemParser.parseLines(parentSyntax: this); + final itemElement = checkboxToInsert == null + ? Element('li', children) + : (Element('li', _addCheckbox(children, checkboxToInsert)) + ..attributes['class'] = taskListClass); + + itemNodes.add(itemElement); + anyEmptyLinesBetweenBlocks = + anyEmptyLinesBetweenBlocks || itemParser.encounteredBlankLine; + } + + // Must strip paragraph tags if the list is "tight". + // https://spec.commonmark.org/0.30/#lists + final listIsTight = !anyEmptyLines && !anyEmptyLinesBetweenBlocks; + + if (listIsTight) { + // We must post-process the list items, converting any top-level paragraph + // elements to just text elements. + for (final item in itemNodes) { + final isTaskList = item.attributes['class'] == taskListClass; + final children = item.children; + if (children != null) { + Node? lastNode; + for (var i = 0; i < children.length; i++) { + final child = children[i]; + if (child is Element && child.tag == 'p') { + final childContent = child.children!; + if (lastNode is Element && !isTaskList) { + childContent.insert(0, Text('\n')); + } + + children + ..removeAt(i) + ..insertAll(i, childContent); + } + + lastNode = child; + } + } + } + } + + final listElement = Element(ordered ? 'ol' : 'ul', itemNodes); + if (ordered && startNumber != 1) { + listElement.attributes['start'] = '$startNumber'; + } + + if (containsTaskList) { + listElement.attributes['class'] = 'contains-task-list'; + } + return listElement; + } + + List _addCheckbox(List children, Element checkbox) { + if (children.isNotEmpty) { + final firstChild = children.first; + if (firstChild is Element && firstChild.tag == 'p') { + firstChild.children!.insert(0, checkbox); + return children; + } + } + return [checkbox, ...children]; + } + + void _removeLeadingEmptyLine(ListItem item) { + if (item.lines.isNotEmpty && item.lines.first.isBlankLine) { + item.lines.removeAt(0); + } + } + + /// Removes any trailing empty lines and notes whether any items are separated + /// by such lines. + bool _removeTrailingEmptyLines(List items) { + var anyEmpty = false; + for (var i = 0; i < items.length; i++) { + if (items[i].lines.length == 1) continue; + while (items[i].lines.isNotEmpty && items[i].lines.last.isBlankLine) { + if (i < items.length - 1) { + anyEmpty = true; + } + items[i].lines.removeLast(); + } + } + return anyEmpty; + } +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/ordered_list_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/ordered_list_syntax.dart new file mode 100644 index 000000000..53c473049 --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/ordered_list_syntax.dart @@ -0,0 +1,14 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../patterns.dart'; +import 'list_syntax.dart'; + +/// Parses ordered lists. +class OrderedListSyntax extends ListSyntax { + @override + RegExp get pattern => listPattern; + + const OrderedListSyntax(); +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/ordered_list_with_checkbox_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/ordered_list_with_checkbox_syntax.dart new file mode 100644 index 000000000..8d865e872 --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/ordered_list_with_checkbox_syntax.dart @@ -0,0 +1,10 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'ordered_list_syntax.dart'; + +/// Parses ordered lists with checkboxes. +class OrderedListWithCheckboxSyntax extends OrderedListSyntax { + const OrderedListWithCheckboxSyntax(); +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/paragraph_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/paragraph_syntax.dart new file mode 100644 index 000000000..53d496d10 --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/paragraph_syntax.dart @@ -0,0 +1,49 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../block_parser.dart'; +import '../patterns.dart'; +import 'block_syntax.dart'; +import 'setext_header_syntax.dart'; + +/// Parses paragraphs of regular text. +class ParagraphSyntax extends BlockSyntax { + @override + RegExp get pattern => dummyPattern; + + @override + bool canEndBlock(BlockParser parser) => false; + + const ParagraphSyntax(); + + @override + bool canParse(BlockParser parser) => true; + + @override + Node? parse(BlockParser parser) { + final childLines = [parser.current.content]; + + parser.advance(); + var interruptedBySetextHeading = false; + // Eat until we hit something that ends a paragraph. + while (!parser.isDone) { + final syntax = interruptedBy(parser); + if (syntax != null) { + interruptedBySetextHeading = syntax is SetextHeaderSyntax; + break; + } + childLines.add(parser.current.content); + parser.advance(); + } + + // It is not a paragraph, but a setext heading. + if (interruptedBySetextHeading) { + return null; + } + + final contents = UnparsedContent(childLines.join('\n').trimRight()); + return Element('p', [contents]); + } +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/setext_header_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/setext_header_syntax.dart new file mode 100644 index 000000000..49f4eda27 --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/setext_header_syntax.dart @@ -0,0 +1,44 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../block_parser.dart'; +import '../patterns.dart'; +import 'block_syntax.dart'; +import 'paragraph_syntax.dart'; + +/// Parses setext-style headers. +class SetextHeaderSyntax extends BlockSyntax { + @override + RegExp get pattern => setextPattern; + + const SetextHeaderSyntax(); + + @override + bool canParse(BlockParser parser) { + final lastSyntax = parser.currentSyntax; + if (parser.setextHeadingDisabled || lastSyntax is! ParagraphSyntax) { + return false; + } + return pattern.hasMatch(parser.current.content); + } + + @override + Node? parse(BlockParser parser) { + final lines = parser.linesToConsume; + if (lines.length < 2) { + return null; + } + + // Remove the last line which is a marker. + lines.removeLast(); + + final marker = parser.current.content.trim(); + final level = (marker[0] == '=') ? '1' : '2'; + final content = lines.map((e) => e.content).join('\n').trimRight(); + + parser.advance(); + return Element('h$level', [UnparsedContent(content)]); + } +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/setext_header_with_id_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/setext_header_with_id_syntax.dart new file mode 100644 index 000000000..fffe99289 --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/setext_header_with_id_syntax.dart @@ -0,0 +1,21 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../block_parser.dart'; +import 'block_syntax.dart'; +import 'setext_header_syntax.dart'; + +/// Parses setext-style headers, and adds generated IDs to the generated +/// elements. +class SetextHeaderWithIdSyntax extends SetextHeaderSyntax { + const SetextHeaderWithIdSyntax(); + + @override + Node parse(BlockParser parser) { + final element = super.parse(parser) as Element; + element.generatedId = BlockSyntax.generateAnchorHash(element); + return element; + } +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/table_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/table_syntax.dart new file mode 100644 index 000000000..89cbd905f --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/table_syntax.dart @@ -0,0 +1,225 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../block_parser.dart'; +import '../charcode.dart'; +import '../patterns.dart'; +import 'block_syntax.dart'; + +/// Parses tables. +class TableSyntax extends BlockSyntax { + @override + bool canEndBlock(BlockParser parser) => true; + + @override + RegExp get pattern => dummyPattern; + + const TableSyntax(); + + @override + bool canParse(BlockParser parser) { + // Note: matches *next* line, not the current one. We're looking for the + // bar separating the head row from the body rows. + return parser.matchesNext(tablePattern); + } + + /// Parses a table into its three parts: + /// + /// * a head row of head cells (`` cells) + /// * a divider of hyphens and pipes (not rendered) + /// * many body rows of body cells (`` cells) + @override + Node? parse(BlockParser parser) { + final alignments = _parseAlignments(parser.next!.content); + final columnCount = alignments.length; + final headRow = _parseRow(parser, alignments, 'th'); + if (headRow.children!.length != columnCount) { + parser.retreat(); + return null; + } + final head = Element('thead', [headRow]); + + // Advance past the divider of hyphens. + parser.advance(); + + final rows = []; + while (!parser.isDone && !BlockSyntax.isAtBlockEnd(parser)) { + final row = _parseRow(parser, alignments, 'td'); + final children = row.children; + if (children != null) { + while (children.length < columnCount) { + // Insert synthetic empty cells. + children.add(Element('td', [])); + } + while (children.length > columnCount) { + children.removeLast(); + } + } + while (row.children!.length > columnCount) { + row.children!.removeLast(); + } + rows.add(row); + } + if (rows.isEmpty) { + return Element('table', [head]); + } else { + final body = Element('tbody', rows); + + return Element('table', [head, body]); + } + } + + List _parseAlignments(String line) { + final columns = []; + // Set the value to `true` when hitting a non whitespace character other + // than the first pipe character. + var started = false; + var hitDash = false; + String? alignment; + + for (var i = 0; i < line.length; i++) { + final char = line.codeUnitAt(i); + if (char == $space || char == $tab || (!started && char == $pipe)) { + continue; + } + started = true; + + if (char == $colon) { + if (hitDash) { + alignment = alignment == 'left' ? 'center' : 'right'; + } else { + alignment = 'left'; + } + } + + if (char == $pipe) { + columns.add(alignment); + hitDash = false; + alignment = null; + } else { + hitDash = true; + } + } + + if (hitDash) { + columns.add(alignment); + } + + return columns; + } + + /// Parses a table row at the current line into a table row element, with + /// parsed table cells. + /// + /// [alignments] is used to annotate an alignment on each cell, and + /// [cellType] is used to declare either "td" or "th" cells. + Element _parseRow( + BlockParser parser, + List alignments, + String cellType, + ) { + final line = parser.current; + final cells = []; + var index = _walkPastOpeningPipe(line.content); + final cellBuffer = StringBuffer(); + + while (true) { + if (index >= line.content.length) { + // This row ended without a trailing pipe, which is fine. + cells.add(cellBuffer.toString().trimRight()); + cellBuffer.clear(); + break; + } + final ch = line.content.codeUnitAt(index); + if (ch == $backslash) { + if (index == line.content.length - 1) { + // A table row ending in a backslash is not well-specified, but it + // looks like GitHub just allows the character as part of the text of + // the last cell. + cellBuffer.writeCharCode(ch); + cells.add(cellBuffer.toString().trimRight()); + cellBuffer.clear(); + break; + } + final escaped = line.content.codeUnitAt(index + 1); + if (escaped == $pipe) { + // GitHub Flavored Markdown has a strange bit here; the pipe is to be + // escaped before any other inline processing. One consequence, for + // example, is that "| `\|` |" should be parsed as a cell with a code + // element with text "|", rather than "\|". Most parsers are not + // compliant with this corner, but this is what is specified, and what + // GitHub does in practice. + cellBuffer.writeCharCode(escaped); + } else { + // The [InlineParser] will handle the escaping. + cellBuffer.writeCharCode(ch); + cellBuffer.writeCharCode(escaped); + } + index += 2; + } else if (ch == $pipe) { + cells.add(cellBuffer.toString().trimRight()); + cellBuffer.clear(); + // Walk forward past any whitespace which leads the next cell. + index++; + index = _walkPastWhitespace(line.content, index); + if (index >= line.content.length) { + // This row ended with a trailing pipe. + break; + } + } else { + cellBuffer.writeCharCode(ch); + index++; + } + } + parser.advance(); + final row = [ + for (final cell in cells) Element(cellType, [UnparsedContent(cell)]) + ]; + + for (var i = 0; i < row.length && i < alignments.length; i++) { + if (alignments[i] == null) continue; + row[i].attributes['align'] = '${alignments[i]}'; + } + + return Element('tr', row); + } + + /// Walks past whitespace in [line] starting at [index]. + /// + /// Returns the index of the first non-whitespace character. + int _walkPastWhitespace(String line, int index) { + while (index < line.length) { + final ch = line.codeUnitAt(index); + if (ch != $space && ch != $tab) { + break; + } + index++; + } + return index; + } + + /// Walks past the opening pipe (and any whitespace that surrounds it) in + /// [line]. + /// + /// Returns the index of the first non-whitespace character after the pipe. + /// If no opening pipe is found, this just returns the index of the first + /// non-whitespace character. + int _walkPastOpeningPipe(String line) { + var index = 0; + while (index < line.length) { + final ch = line.codeUnitAt(index); + if (ch == $pipe) { + index++; + index = _walkPastWhitespace(line, index); + } + if (ch != $space && ch != $tab) { + // No leading pipe. + break; + } + index++; + } + return index; + } +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/unordered_list_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/unordered_list_syntax.dart new file mode 100644 index 000000000..35dd670d7 --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/unordered_list_syntax.dart @@ -0,0 +1,30 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../block_parser.dart'; +import '../patterns.dart'; +import 'list_syntax.dart'; + +/// Parses unordered lists. +class UnorderedListSyntax extends ListSyntax { + @override + RegExp get pattern => listPattern; + + @override + bool canParse(BlockParser parser) { + // Check if it matches `hrPattern`, otherwise it will produce an infinite + // loop if put `UnorderedListSyntax` or `UnorderedListWithCheckboxSyntax` + // bofore `HorizontalRuleSyntax` and parse: + // ``` + // * * * + // ``` + if (hrPattern.hasMatch(parser.current.content)) { + return false; + } + + return pattern.hasMatch(parser.current.content); + } + + const UnorderedListSyntax(); +} diff --git a/pkgs/markdown/lib/src/block_syntaxes/unordered_list_with_checkbox_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/unordered_list_with_checkbox_syntax.dart new file mode 100644 index 000000000..5f3ddf04c --- /dev/null +++ b/pkgs/markdown/lib/src/block_syntaxes/unordered_list_with_checkbox_syntax.dart @@ -0,0 +1,10 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'unordered_list_syntax.dart'; + +/// Parses unordered lists with checkboxes. +class UnorderedListWithCheckboxSyntax extends UnorderedListSyntax { + const UnorderedListWithCheckboxSyntax(); +} diff --git a/pkgs/markdown/lib/src/charcode.dart b/pkgs/markdown/lib/src/charcode.dart new file mode 100644 index 000000000..693fcc524 --- /dev/null +++ b/pkgs/markdown/lib/src/charcode.dart @@ -0,0 +1,123 @@ +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source is governed by a +// BSD-style license that can be found in the LICENSE file + +/// "Horizontal Tab" control character, common name. +const int $tab = 0x09; + +/// "Line feed" control character. +const int $lf = 0x0A; + +/// "Vertical Tab" control character. +const int $vt = 0x0B; + +/// "Form feed" control character. +const int $ff = 0x0C; + +/// "Carriage return" control character. +const int $cr = 0x0D; + +/// Space character. +const int $space = 0x20; + +/// Character `!`. +const int $exclamation = 0x21; + +/// Character `"`. +const int $quote = 0x22; + +/// Character `"`. +const int $double_quote = 0x22; // ignore: constant_identifier_names + +/// Character `#`. +const int $hash = 0x23; + +/// Character `$`. +const int $dollar = 0x24; + +/// Character `%`. +const int $percent = 0x25; + +/// Character `&`. +const int $ampersand = 0x26; + +/// Character `'`. +const int $apostrophe = 0x27; + +/// Character `(`. +const int $lparen = 0x28; + +/// Character `)`. +const int $rparen = 0x29; + +/// Character `*`. +const int $asterisk = 0x2A; + +/// Character `+`. +const int $plus = 0x2B; + +/// Character `,`. +const int $comma = 0x2C; + +/// Character `-`. +const int $dash = 0x2D; + +/// Character `.`. +const int $dot = 0x2E; + +/// Character `/`. +const int $slash = 0x2F; + +/// Character `:`. +const int $colon = 0x3A; + +/// Character `;`. +const int $semicolon = 0x3B; + +/// Character `<`. +const int $lt = 0x3C; + +/// Character `=`. +const int $equal = 0x3D; + +/// Character `>`. +const int $gt = 0x3E; + +/// Character `?`. +const int $question = 0x3F; + +/// Character `@`. +const int $at = 0x40; + +/// Character `[`. +const int $lbracket = 0x5B; + +/// Character `\`. +const int $backslash = 0x5C; + +/// Character `]`. +const int $rbracket = 0x5D; + +/// Character `^`. +const int $caret = 0x5E; + +/// Character `_`. +const int $underscore = 0x5F; + +/// Character `` ` ``. +const int $backquote = 0x60; + +/// Character `{`. +const int $lbrace = 0x7B; + +/// Character `|`. +const int $pipe = 0x7C; + +/// Character `|`. +const int $bar = 0x7C; + +/// Character `}`. +const int $rbrace = 0x7D; + +/// Character `~`. +const int $tilde = 0x7E; diff --git a/pkgs/markdown/lib/src/document.dart b/pkgs/markdown/lib/src/document.dart new file mode 100644 index 000000000..f33ff33ff --- /dev/null +++ b/pkgs/markdown/lib/src/document.dart @@ -0,0 +1,217 @@ +// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'ast.dart'; +import 'block_parser.dart'; +import 'block_syntaxes/block_syntax.dart'; +import 'extension_set.dart'; +import 'inline_parser.dart'; +import 'inline_syntaxes/inline_syntax.dart'; +import 'line.dart'; +import 'util.dart'; + +/// Maintains the context needed to parse a Markdown document. +class Document { + final Map linkReferences = {}; + + /// Footnote ref count, keys are case-sensitive and added by define syntax. + final footnoteReferences = {}; + + /// Footnote labels by appearing order. + /// + /// They are case-insensitive and added by ref syntax. + final footnoteLabels = []; + final Resolver? linkResolver; + final Resolver? imageLinkResolver; + final bool encodeHtml; + + /// Whether to use default block syntaxes. + final bool withDefaultBlockSyntaxes; + + /// Whether to use default inline syntaxes. + /// + /// Need to set both [withDefaultInlineSyntaxes] and [encodeHtml] to + /// `false` to disable all inline syntaxes including html encoding syntaxes. + final bool withDefaultInlineSyntaxes; + + final _blockSyntaxes = {}; + final _inlineSyntaxes = {}; + final bool hasCustomInlineSyntaxes; + + Iterable get blockSyntaxes => _blockSyntaxes; + + Iterable get inlineSyntaxes => _inlineSyntaxes; + + Document({ + Iterable? blockSyntaxes, + Iterable? inlineSyntaxes, + ExtensionSet? extensionSet, + this.linkResolver, + this.imageLinkResolver, + this.encodeHtml = true, + this.withDefaultBlockSyntaxes = true, + this.withDefaultInlineSyntaxes = true, + }) : hasCustomInlineSyntaxes = (inlineSyntaxes?.isNotEmpty ?? false) || + (extensionSet?.inlineSyntaxes.isNotEmpty ?? false) { + if (blockSyntaxes != null) { + _blockSyntaxes.addAll(blockSyntaxes); + } + if (inlineSyntaxes != null) { + _inlineSyntaxes.addAll(inlineSyntaxes); + } + + if (extensionSet == null) { + if (withDefaultBlockSyntaxes) { + _blockSyntaxes.addAll(ExtensionSet.commonMark.blockSyntaxes); + } + + if (withDefaultInlineSyntaxes) { + _inlineSyntaxes.addAll(ExtensionSet.commonMark.inlineSyntaxes); + } + } else { + _blockSyntaxes.addAll(extensionSet.blockSyntaxes); + _inlineSyntaxes.addAll(extensionSet.inlineSyntaxes); + } + } + + /// Parses the given [lines] of Markdown to a series of AST nodes. + List parseLines(List lines) => + parseLineList(lines.map(Line.new).toList()); + + /// Parses the given [text] to a series of AST nodes. + List parse(String text) => parseLineList(text.toLines()); + + /// Parses the given [lines] of [Line] to a series of AST nodes. + List parseLineList(List lines) { + final nodes = BlockParser(lines, this).parseLines(); + _parseInlineContent(nodes); + // Do filter after parsing inline as we need ref count. + return _filterFootnotes(nodes); + } + + /// Parses the given inline Markdown [text] to a series of AST nodes. + List parseInline(String text) => InlineParser(text, this).parse(); + + void _parseInlineContent(List nodes) { + for (var i = 0; i < nodes.length; i++) { + final node = nodes[i]; + if (node is UnparsedContent) { + final inlineNodes = parseInline(node.textContent); + nodes.removeAt(i); + nodes.insertAll(i, inlineNodes); + i += inlineNodes.length - 1; + } else if (node is Element && node.children != null) { + _parseInlineContent(node.children!); + } + } + } + + /// Footnotes could be defined in arbitrary positions of a document, we need + /// to distinguish them and put them behind; and every footnote definition + /// may have multiple backrefs, we need to append backrefs for it. + List _filterFootnotes(List nodes) { + final footnotes = []; + final blocks = []; + for (final node in nodes) { + if (node is Element && + node.tag == 'li' && + footnoteReferences.containsKey(node.footnoteLabel)) { + final label = node.footnoteLabel; + var count = 0; + if (label != null && (count = footnoteReferences[label] ?? 0) > 0) { + footnotes.add(node); + final children = node.children; + if (children != null) { + _appendBackref(children, Uri.encodeComponent(label), count); + } + } + } else { + blocks.add(node); + } + } + + if (footnotes.isNotEmpty) { + // Sort footnotes by appearing order. + final ordinal = { + for (var i = 0; i < footnoteLabels.length; i++) + 'fn-${footnoteLabels[i]}': i, + }; + footnotes.sort((l, r) { + final idl = l.attributes['id']?.toLowerCase() ?? ''; + final idr = r.attributes['id']?.toLowerCase() ?? ''; + return (ordinal[idl] ?? 0) - (ordinal[idr] ?? 0); + }); + final list = Element('ol', footnotes); + + // Ignore GFM attribute: . + final section = Element('section', [list]) + ..attributes['class'] = 'footnotes'; + blocks.add(section); + } + return blocks; + } + + /// Generate backref nodes, append them to footnote definition's last child. + void _appendBackref(List children, String ref, int count) { + final refs = [ + for (var i = 0; i < count; i++) ...[ + Text(' '), + _ElementExt.footnoteAnchor(ref, i) + ] + ]; + if (children.isEmpty) { + children.addAll(refs); + } else { + final last = children.last; + if (last is Element) { + last.children?.addAll(refs); + } else { + children.last = Element('p', [last, ...refs]); + } + } + } +} + +extension _ElementExt on Element { + static Element footnoteAnchor(String ref, int i) { + final num = '${i + 1}'; + final suffix = i > 0 ? '-$num' : ''; + final e = Element.empty('tag'); + e.match; + return Element('a', [ + Text('\u21a9'), + if (i > 0) + Element('sup', [Text(num)])..attributes['class'] = 'footnote-ref', + ]) + // Ignore GFM's attributes: + // . + ..attributes['href'] = '#fnref-$ref$suffix' + ..attributes['class'] = 'footnote-backref'; + } + + String get match => tag; +} + +/// A [link reference +/// definition](https://spec.commonmark.org/0.30/#link-reference-definitions). +class LinkReference { + /// The [link label](https://spec.commonmark.org/0.30/#link-label). + /// + /// Temporarily, this class is also being used to represent the link data for + /// an inline link (the destination and title), but this should change before + /// the package is released. + final String label; + + /// The [link destination](https://spec.commonmark.org/0.30/#link-destination). + final String destination; + + /// The [link title](https://spec.commonmark.org/0.30/#link-title). + final String? title; + + /// Construct a new [LinkReference], with all necessary fields. + /// + /// If the parsed link reference definition does not include a title, use + /// `null` for the [title] parameter. + LinkReference(this.label, this.destination, this.title); +} diff --git a/pkgs/markdown/lib/src/emojis.dart b/pkgs/markdown/lib/src/emojis.dart new file mode 100644 index 000000000..cca1a280f --- /dev/null +++ b/pkgs/markdown/lib/src/emojis.dart @@ -0,0 +1,1904 @@ +// GENERATED FILE. DO NOT EDIT. +// +// This file was generated from GitHub's emoji API list endpoint: +// https://api.github.com/emojis +// at 2022-05-03 01:45:16.587812 by the script, tool/update_github_emojis.dart. + +const emojis = { + '+1': '👍', + '-1': '👎', + '100': '💯', + '1234': '🔢', + '1st_place_medal': '🥇', + '2nd_place_medal': '🥈', + '3rd_place_medal': '🥉', + '8ball': '🎱', + 'a': '🅰️', + 'ab': '🆎', + 'abacus': '🧮', + 'abc': '🔤', + 'abcd': '🔡', + 'accept': '🉑', + 'accordion': '🪗', + 'adhesive_bandage': '🩹', + 'adult': '🧑', + 'aerial_tramway': '🚡', + 'afghanistan': '🇦🇫', + 'airplane': '✈️', + 'aland_islands': '🇦🇽', + 'alarm_clock': '⏰', + 'albania': '🇦🇱', + 'alembic': '⚗', + 'algeria': '🇩🇿', + 'alien': '👽', + 'ambulance': '🚑', + 'american_samoa': '🇦🇸', + 'amphora': '🏺', + 'anatomical_heart': '🫀', + 'anchor': '⚓', + 'andorra': '🇦🇩', + 'angel': '👼', + 'anger': '💢', + 'angola': '🇦🇴', + 'angry': '😠', + 'anguilla': '🇦🇮', + 'anguished': '😧', + 'ant': '🐜', + 'antarctica': '🇦🇶', + 'antigua_barbuda': '🇦🇬', + 'apple': '🍎', + 'aquarius': '♒', + 'argentina': '🇦🇷', + 'aries': '♈', + 'armenia': '🇦🇲', + 'arrow_backward': '◀️', + 'arrow_double_down': '⏬', + 'arrow_double_up': '⏫', + 'arrow_down': '⬇️', + 'arrow_down_small': '🔽', + 'arrow_forward': '▶️', + 'arrow_heading_down': '⤵️', + 'arrow_heading_up': '⤴️', + 'arrow_left': '⬅️', + 'arrow_lower_left': '↙️', + 'arrow_lower_right': '↘️', + 'arrow_right': '➡️', + 'arrow_right_hook': '↪️', + 'arrow_up': '⬆️', + 'arrow_up_down': '↕️', + 'arrow_up_small': '🔼', + 'arrow_upper_left': '↖️', + 'arrow_upper_right': '↗️', + 'arrows_clockwise': '🔃', + 'arrows_counterclockwise': '🔄', + 'art': '🎨', + 'articulated_lorry': '🚛', + 'artificial_satellite': '🛰', + 'artist': '🧑️‍🎨', + 'aruba': '🇦🇼', + 'ascension_island': '🇦️‍🇨', + 'asterisk': '*⃣', + 'astonished': '😲', + 'astronaut': '🧑️‍🚀', + 'athletic_shoe': '👟', + 'atm': '🏧', + 'atom_symbol': '⚛', + 'australia': '🇦🇺', + 'austria': '🇦🇹', + 'auto_rickshaw': '🛺', + 'avocado': '🥑', + 'axe': '🪓', + 'azerbaijan': '🇦🇿', + 'b': '🅱️', + 'baby': '👶', + 'baby_bottle': '🍼', + 'baby_chick': '🐤', + 'baby_symbol': '🚼', + 'back': '🔙', + 'bacon': '🥓', + 'badger': '🦡', + 'badminton': '🏸', + 'bagel': '🥯', + 'baggage_claim': '🛄', + 'baguette_bread': '🥖', + 'bahamas': '🇧🇸', + 'bahrain': '🇧🇭', + 'balance_scale': '⚖', + 'bald_man': '👨️‍🦲', + 'bald_woman': '👩️‍🦲', + 'ballet_shoes': '🩰', + 'balloon': '🎈', + 'ballot_box': '🗳', + 'ballot_box_with_check': '☑️', + 'bamboo': '🎍', + 'banana': '🍌', + 'bangbang': '‼️', + 'bangladesh': '🇧🇩', + 'banjo': '🪕', + 'bank': '🏦', + 'bar_chart': '📊', + 'barbados': '🇧🇧', + 'barber': '💈', + 'baseball': '⚾', + 'basket': '🧺', + 'basketball': '🏀', + 'basketball_man': '⛹', + 'basketball_woman': '⛹️‍♀️', + 'bat': '🦇', + 'bath': '🛀', + 'bathtub': '🛁', + 'battery': '🔋', + 'beach_umbrella': '🏖', + 'bear': '🐻', + 'bearded_person': '🧔', + 'beaver': '🦫', + 'bed': '🛏', + 'bee': '🐝', + 'beer': '🍺', + 'beers': '🍻', + 'beetle': '🪲', + 'beginner': '🔰', + 'belarus': '🇧🇾', + 'belgium': '🇧🇪', + 'belize': '🇧🇿', + 'bell': '🔔', + 'bell_pepper': '🫑', + 'bellhop_bell': '🛎', + 'benin': '🇧🇯', + 'bento': '🍱', + 'bermuda': '🇧🇲', + 'beverage_box': '🧃', + 'bhutan': '🇧🇹', + 'bicyclist': '🚴', + 'bike': '🚲', + 'biking_man': '🚴', + 'biking_woman': '🚴‍♀️', + 'bikini': '👙', + 'billed_cap': '🧢', + 'billed_hat': '🧢', + 'biohazard': '☣', + 'bird': '🐦', + 'birthday': '🎂', + 'bison': '🦬', + 'black_cat': '🐈️‍⬛', + 'black_circle': '⚫', + 'black_flag': '🏴', + 'black_heart': '🖤', + 'black_joker': '🃏', + 'black_large_square': '⬛', + 'black_medium_small_square': '◾', + 'black_medium_square': '◼️', + 'black_nib': '✒️', + 'black_small_square': '▪️', + 'black_square_button': '🔲', + 'blond_haired_man': '👱️‍♂', + 'blond_haired_person': '👱', + 'blond_haired_woman': '👱️‍♀', + 'blonde_man': '👱', + 'blonde_woman': '👱‍♀️', + 'blossom': '🌼', + 'blowfish': '🐡', + 'blue_book': '📘', + 'blue_car': '🚙', + 'blue_heart': '💙', + 'blue_square': '🟦', + 'blueberries': '🫐', + 'blush': '😊', + 'boar': '🐗', + 'boat': '⛵', + 'bolivia': '🇧🇴', + 'bomb': '💣', + 'bone': '🦴', + 'book': '📖', + 'bookmark': '🔖', + 'bookmark_tabs': '📑', + 'books': '📚', + 'boom': '💥', + 'boomerang': '🪃', + 'boot': '👢', + 'bosnia_herzegovina': '🇧🇦', + 'botswana': '🇧🇼', + 'bouncing_ball_man': '⛹️‍♂', + 'bouncing_ball_person': '⛹', + 'bouncing_ball_woman': '⛹️‍♀', + 'bouquet': '💐', + 'bouvet_island': '🇧️‍🇻', + 'bow': '🙇', + 'bow_and_arrow': '🏹', + 'bowing_man': '🙇', + 'bowing_woman': '🙇‍♀️', + 'bowl_with_spoon': '🥣', + 'bowling': '🎳', + 'boxing_glove': '🥊', + 'boy': '👦', + 'brain': '🧠', + 'brazil': '🇧🇷', + 'bread': '🍞', + 'breast_feeding': '🤱', + 'breastfeeding': '🤱', + 'brick': '🧱', + 'bricks': '🧱', + 'bride_with_veil': '👰', + 'bridge_at_night': '🌉', + 'briefcase': '💼', + 'british_indian_ocean_territory': '🇮🇴', + 'british_virgin_islands': '🇻🇬', + 'broccoli': '🥦', + 'broken_heart': '💔', + 'broom': '🧹', + 'brown_circle': '🟤', + 'brown_heart': '🤎', + 'brown_square': '🟫', + 'brunei': '🇧🇳', + 'bubble_tea': '🧋', + 'bucket': '🪣', + 'bug': '🐛', + 'building_construction': '🏗', + 'bulb': '💡', + 'bulgaria': '🇧🇬', + 'bullettrain_front': '🚅', + 'bullettrain_side': '🚄', + 'burkina_faso': '🇧🇫', + 'burrito': '🌯', + 'burundi': '🇧🇮', + 'bus': '🚌', + 'business_suit_levitating': '🕴', + 'busstop': '🚏', + 'bust_in_silhouette': '👤', + 'busts_in_silhouette': '👥', + 'butter': '🧈', + 'butterfly': '🦋', + 'cactus': '🌵', + 'cake': '🍰', + 'calendar': '📆', + 'call_me_hand': '🤙', + 'calling': '📲', + 'cambodia': '🇰🇭', + 'camel': '🐫', + 'camera': '📷', + 'camera_flash': '📸', + 'cameroon': '🇨🇲', + 'camping': '🏕', + 'canada': '🇨🇦', + 'canary_islands': '🇮🇨', + 'cancer': '♋', + 'candle': '🕯', + 'candy': '🍬', + 'canned_food': '🥫', + 'canoe': '🛶', + 'cape_verde': '🇨🇻', + 'capital_abcd': '🔠', + 'capricorn': '♑', + 'car': '🚗', + 'card_file_box': '🗃', + 'card_index': '📇', + 'card_index_dividers': '🗂', + 'caribbean_netherlands': '🇧🇶', + 'carousel_horse': '🎠', + 'carpentry_saw': '🪚', + 'carrot': '🥕', + 'cartwheeling': '🤸', + 'cat': '🐱', + 'cat2': '🐈', + 'cayman_islands': '🇰🇾', + 'cd': '💿', + 'central_african_republic': '🇨🇫', + 'ceuta_melilla': '🇪️‍🇦', + 'chad': '🇹🇩', + 'chains': '⛓', + 'chair': '🪑', + 'champagne': '🍾', + 'chart': '💹', + 'chart_with_downwards_trend': '📉', + 'chart_with_upwards_trend': '📈', + 'checkered_flag': '🏁', + 'cheese': '🧀', + 'cherries': '🍒', + 'cherry_blossom': '🌸', + 'chess_pawn': '♟', + 'chestnut': '🌰', + 'chicken': '🐔', + 'child': '🧒', + 'children_crossing': '🚸', + 'chile': '🇨🇱', + 'chipmunk': '🐿', + 'chocolate_bar': '🍫', + 'chopsticks': '🥢', + 'christmas_island': '🇨🇽', + 'christmas_tree': '🎄', + 'church': '⛪', + 'cinema': '🎦', + 'circus_tent': '🎪', + 'city_sunrise': '🌇', + 'city_sunset': '🌆', + 'cityscape': '🏙', + 'cl': '🆑', + 'clamp': '🗜', + 'clap': '👏', + 'clapper': '🎬', + 'classical_building': '🏛', + 'climbing': '🧗', + 'climbing_man': '🧗‍♂️', + 'climbing_woman': '🧗‍♀️', + 'clinking_glasses': '🥂', + 'clipboard': '📋', + 'clipperton_island': '🇨️‍🇵', + 'clock1': '🕐', + 'clock10': '🕙', + 'clock1030': '🕥', + 'clock11': '🕚', + 'clock1130': '🕦', + 'clock12': '🕛', + 'clock1230': '🕧', + 'clock130': '🕜', + 'clock2': '🕑', + 'clock230': '🕝', + 'clock3': '🕒', + 'clock330': '🕞', + 'clock4': '🕓', + 'clock430': '🕟', + 'clock5': '🕔', + 'clock530': '🕠', + 'clock6': '🕕', + 'clock630': '🕡', + 'clock7': '🕖', + 'clock730': '🕢', + 'clock8': '🕗', + 'clock830': '🕣', + 'clock9': '🕘', + 'clock930': '🕤', + 'closed_book': '📕', + 'closed_lock_with_key': '🔐', + 'closed_umbrella': '🌂', + 'cloud': '☁️', + 'cloud_with_lightning': '🌩', + 'cloud_with_lightning_and_rain': '⛈', + 'cloud_with_rain': '🌧', + 'cloud_with_snow': '🌨', + 'clown_face': '🤡', + 'clubs': '♣️', + 'cn': '🇨🇳', + 'coat': '🧥', + 'cockroach': '🪳', + 'cocktail': '🍸', + 'coconut': '🥥', + 'cocos_islands': '🇨🇨', + 'coffee': '☕', + 'coffin': '⚰', + 'coin': '🪙', + 'cold': '🥶', + 'cold_face': '🥶', + 'cold_sweat': '😰', + 'collision': '💥', + 'colombia': '🇨🇴', + 'comet': '☄', + 'comoros': '🇰🇲', + 'compass': '🧭', + 'computer': '💻', + 'computer_mouse': '🖱', + 'confetti_ball': '🎊', + 'confounded': '😖', + 'confused': '😕', + 'congo_brazzaville': '🇨🇬', + 'congo_kinshasa': '🇨🇩', + 'congratulations': '㊗️', + 'construction': '🚧', + 'construction_worker': '👷', + 'construction_worker_man': '👷', + 'construction_worker_woman': '👷‍♀️', + 'control_knobs': '🎛', + 'convenience_store': '🏪', + 'cook': '🧑️‍🍳', + 'cook_islands': '🇨🇰', + 'cookie': '🍪', + 'cool': '🆒', + 'cop': '👮', + 'copyright': '©️', + 'corn': '🌽', + 'costa_rica': '🇨🇷', + 'cote_divoire': '🇨🇮', + 'couch_and_lamp': '🛋', + 'couple': '👫', + 'couple_with_heart': '💑', + 'couple_with_heart_man_man': '👨‍❤️‍👨', + 'couple_with_heart_woman_man': '💑', + 'couple_with_heart_woman_woman': '👩‍❤️‍👩', + 'couplekiss': '💏', + 'couplekiss_man_man': '👨‍❤️‍💋‍👨', + 'couplekiss_man_woman': '💏', + 'couplekiss_woman_woman': '👩‍❤️‍💋‍👩', + 'cow': '🐮', + 'cow2': '🐄', + 'cowboy_hat_face': '🤠', + 'crab': '🦀', + 'crayon': '🖍', + 'credit_card': '💳', + 'crescent_moon': '🌙', + 'cricket': '🦗', + 'cricket_game': '🏏', + 'croatia': '🇭🇷', + 'crocodile': '🐊', + 'croissant': '🥐', + 'crossed_fingers': '🤞', + 'crossed_flags': '🎌', + 'crossed_swords': '⚔', + 'crown': '👑', + 'cry': '😢', + 'crying_cat_face': '😿', + 'crystal_ball': '🔮', + 'cuba': '🇨🇺', + 'cucumber': '🥒', + 'cup_with_straw': '🥤', + 'cupcake': '🧁', + 'cupid': '💘', + 'curacao': '🇨🇼', + 'curling_stone': '🥌', + 'curly_haired_man': '👨️‍🦱', + 'curly_haired_woman': '👩️‍🦱', + 'curly_loop': '➰', + 'currency_exchange': '💱', + 'curry': '🍛', + 'cursing_face': '🤬', + 'custard': '🍮', + 'customs': '🛃', + 'cut_of_meat': '🥩', + 'cyclone': '🌀', + 'cyprus': '🇨🇾', + 'czech_republic': '🇨🇿', + 'dagger': '🗡', + 'dancer': '💃', + 'dancers': '👯', + 'dancing_men': '👯‍♂️', + 'dancing_women': '👯', + 'dango': '🍡', + 'dark_sunglasses': '🕶', + 'dart': '🎯', + 'dash': '💨', + 'date': '📅', + 'de': '🇩🇪', + 'deaf_man': '🧏️‍♂', + 'deaf_person': '🧏', + 'deaf_woman': '🧏️‍♀', + 'deciduous_tree': '🌳', + 'deer': '🦌', + 'denmark': '🇩🇰', + 'department_store': '🏬', + 'derelict_house': '🏚', + 'desert': '🏜', + 'desert_island': '🏝', + 'desktop_computer': '🖥', + 'detective': '🕵', + 'diamond_shape_with_a_dot_inside': '💠', + 'diamonds': '♦️', + 'diego_garcia': '🇩️‍🇬', + 'disappointed': '😞', + 'disappointed_relieved': '😥', + 'disguised_face': '🥸', + 'diving_mask': '🤿', + 'diya_lamp': '🪔', + 'dizzy': '💫', + 'dizzy_face': '😵', + 'djibouti': '🇩🇯', + 'dna': '🧬', + 'do_not_litter': '🚯', + 'dodo': '🦤', + 'dog': '🐶', + 'dog2': '🐕', + 'dollar': '💵', + 'dolls': '🎎', + 'dolphin': '🐬', + 'dominica': '🇩🇲', + 'dominican_republic': '🇩🇴', + 'door': '🚪', + 'doughnut': '🍩', + 'dove': '🕊', + 'dragon': '🐉', + 'dragon_face': '🐲', + 'dress': '👗', + 'dromedary_camel': '🐪', + 'drooling_face': '🤤', + 'drop_of_blood': '🩸', + 'droplet': '💧', + 'drum': '🥁', + 'duck': '🦆', + 'dumpling': '🥟', + 'dvd': '📀', + 'e-mail': '📧', + 'eagle': '🦅', + 'ear': '👂', + 'ear_of_rice': '🌾', + 'ear_with_hearing_aid': '🦻', + 'earth_africa': '🌍', + 'earth_americas': '🌎', + 'earth_asia': '🌏', + 'ecuador': '🇪🇨', + 'egg': '🥚', + 'eggplant': '🍆', + 'egypt': '🇪🇬', + 'eight': '8️⃣', + 'eight_pointed_black_star': '✴️', + 'eight_spoked_asterisk': '✳️', + 'eject_button': '⏏️', + 'el_salvador': '🇸🇻', + 'electric_plug': '🔌', + 'elephant': '🐘', + 'elevator': '🛗', + 'elf': '🧝', + 'elf_man': '🧝️‍♂', + 'elf_woman': '🧝️‍♀', + 'email': '✉️', + 'end': '🔚', + 'england': '🏴󠁧󠁢󠁥󠁮󠁧󠁿', + 'envelope': '✉', + 'envelope_with_arrow': '📩', + 'equatorial_guinea': '🇬🇶', + 'eritrea': '🇪🇷', + 'es': '🇪🇸', + 'estonia': '🇪🇪', + 'ethiopia': '🇪🇹', + 'eu': '🇪🇺', + 'euro': '💶', + 'european_castle': '🏰', + 'european_post_office': '🏤', + 'european_union': '🇪️‍🇺', + 'evergreen_tree': '🌲', + 'exclamation': '❗', + 'exploding_head': '🤯', + 'expressionless': '😑', + 'eye': '👁', + 'eye_speech_bubble': '👁️‍🗨', + 'eyeglasses': '👓', + 'eyes': '👀', + 'face_exhaling': '😮️‍💨', + 'face_in_clouds': '😶️‍🌫', + 'face_with_head_bandage': '🤕', + 'face_with_spiral_eyes': '😵️‍💫', + 'face_with_thermometer': '🤒', + 'facepalm': '🤦', + 'facepunch': '👊', + 'factory': '🏭', + 'factory_worker': '🧑️‍🏭', + 'fairy': '🧚', + 'fairy_man': '🧚️‍♂', + 'fairy_woman': '🧚️‍♀', + 'falafel': '🧆', + 'falkland_islands': '🇫🇰', + 'fallen_leaf': '🍂', + 'family': '👪', + 'family_man_boy': '👨‍👦', + 'family_man_boy_boy': '👨‍👦‍👦', + 'family_man_girl': '👨‍👧', + 'family_man_girl_boy': '👨‍👧‍👦', + 'family_man_girl_girl': '👨‍👧‍👧', + 'family_man_man_boy': '👨‍👨‍👦', + 'family_man_man_boy_boy': '👨‍👨‍👦‍👦', + 'family_man_man_girl': '👨‍👨‍👧', + 'family_man_man_girl_boy': '👨‍👨‍👧‍👦', + 'family_man_man_girl_girl': '👨‍👨‍👧‍👧', + 'family_man_woman_boy': '👪', + 'family_man_woman_boy_boy': '👨‍👩‍👦‍👦', + 'family_man_woman_girl': '👨‍👩‍👧', + 'family_man_woman_girl_boy': '👨‍👩‍👧‍👦', + 'family_man_woman_girl_girl': '👨‍👩‍👧‍👧', + 'family_woman_boy': '👩‍👦', + 'family_woman_boy_boy': '👩‍👦‍👦', + 'family_woman_girl': '👩‍👧', + 'family_woman_girl_boy': '👩‍👧‍👦', + 'family_woman_girl_girl': '👩‍👧‍👧', + 'family_woman_woman_boy': '👩‍👩‍👦', + 'family_woman_woman_boy_boy': '👩‍👩‍👦‍👦', + 'family_woman_woman_girl': '👩‍👩‍👧', + 'family_woman_woman_girl_boy': '👩‍👩‍👧‍👦', + 'family_woman_woman_girl_girl': '👩‍👩‍👧‍👧', + 'farmer': '🧑️‍🌾', + 'faroe_islands': '🇫🇴', + 'fast_forward': '⏩', + 'fax': '📠', + 'fearful': '😨', + 'feather': '🪶', + 'feet': '🐾', + 'female_detective': '🕵️‍♀️', + 'female_sign': '♀', + 'ferris_wheel': '🎡', + 'ferry': '⛴', + 'field_hockey': '🏑', + 'fiji': '🇫🇯', + 'file_cabinet': '🗄', + 'file_folder': '📁', + 'film_projector': '📽', + 'film_strip': '🎞', + 'finland': '🇫🇮', + 'fire': '🔥', + 'fire_engine': '🚒', + 'fire_extinguisher': '🧯', + 'firecracker': '🧨', + 'firefighter': '🧑️‍🚒', + 'fireworks': '🎆', + 'first_quarter_moon': '🌓', + 'first_quarter_moon_with_face': '🌛', + 'fish': '🐟', + 'fish_cake': '🍥', + 'fishing_pole_and_fish': '🎣', + 'fist': '✊', + 'fist_left': '🤛', + 'fist_oncoming': '👊', + 'fist_raised': '✊', + 'fist_right': '🤜', + 'five': '5️⃣', + 'flags': '🎏', + 'flamingo': '🦩', + 'flashlight': '🔦', + 'flat_shoe': '🥿', + 'flatbread': '🫓', + 'fleur_de_lis': '⚜', + 'flight_arrival': '🛬', + 'flight_departure': '🛫', + 'flipper': '🐬', + 'floppy_disk': '💾', + 'flower_playing_cards': '🎴', + 'flushed': '😳', + 'fly': '🪰', + 'flying_disc': '🥏', + 'flying_saucer': '🛸', + 'fog': '🌫', + 'foggy': '🌁', + 'fondue': '🫕', + 'foot': '🦶', + 'football': '🏈', + 'footprints': '👣', + 'fork_and_knife': '🍴', + 'fortune_cookie': '🥠', + 'fountain': '⛲', + 'fountain_pen': '🖋', + 'four': '4️⃣', + 'four_leaf_clover': '🍀', + 'fox_face': '🦊', + 'fr': '🇫🇷', + 'framed_picture': '🖼', + 'free': '🆓', + 'french_guiana': '🇬🇫', + 'french_polynesia': '🇵🇫', + 'french_southern_territories': '🇹🇫', + 'fried_egg': '🍳', + 'fried_shrimp': '🍤', + 'fries': '🍟', + 'frog': '🐸', + 'frowning': '😦', + 'frowning_face': '☹', + 'frowning_man': '🙍‍♂️', + 'frowning_person': '🙍', + 'frowning_woman': '🙍', + 'fu': '🖕', + 'fuelpump': '⛽', + 'full_moon': '🌕', + 'full_moon_with_face': '🌝', + 'funeral_urn': '⚱', + 'gabon': '🇬🇦', + 'gambia': '🇬🇲', + 'game_die': '🎲', + 'garlic': '🧄', + 'gb': '🇬️‍🇧', + 'gear': '⚙', + 'gem': '💎', + 'gemini': '♊', + 'genie': '🧞', + 'genie_man': '🧞️‍♂', + 'genie_woman': '🧞️‍♀', + 'georgia': '🇬🇪', + 'ghana': '🇬🇭', + 'ghost': '👻', + 'gibraltar': '🇬🇮', + 'gift': '🎁', + 'gift_heart': '💝', + 'giraffe': '🦒', + 'girl': '👧', + 'globe_with_meridians': '🌐', + 'gloves': '🧤', + 'goal_net': '🥅', + 'goat': '🐐', + 'goggles': '🥽', + 'golf': '⛳', + 'golfing': '🏌', + 'golfing_man': '🏌', + 'golfing_woman': '🏌️‍♀️', + 'gorilla': '🦍', + 'grapes': '🍇', + 'grasshopper': '🦗', + 'greece': '🇬🇷', + 'green_apple': '🍏', + 'green_book': '📗', + 'green_circle': '🟢', + 'green_heart': '💚', + 'green_salad': '🥗', + 'green_square': '🟩', + 'greenland': '🇬🇱', + 'grenada': '🇬🇩', + 'grey_exclamation': '❕', + 'grey_question': '❔', + 'grimacing': '😬', + 'grin': '😁', + 'grinning': '😀', + 'guadeloupe': '🇬🇵', + 'guam': '🇬🇺', + 'guard': '💂', + 'guardsman': '💂', + 'guardswoman': '💂‍♀️', + 'guatemala': '🇬🇹', + 'guernsey': '🇬🇬', + 'guide_dog': '🦮', + 'guinea': '🇬🇳', + 'guinea_bissau': '🇬🇼', + 'guitar': '🎸', + 'gun': '🔫', + 'guyana': '🇬🇾', + 'haircut': '💇', + 'haircut_man': '💇‍♂️', + 'haircut_woman': '💇', + 'haiti': '🇭🇹', + 'hamburger': '🍔', + 'hammer': '🔨', + 'hammer_and_pick': '⚒', + 'hammer_and_wrench': '🛠', + 'hamster': '🐹', + 'hand': '✋', + 'hand_over_mouth': '🤭', + 'handbag': '👜', + 'handball_person': '🤾', + 'handshake': '🤝', + 'hankey': '💩', + 'hash': '#️⃣', + 'hatched_chick': '🐥', + 'hatching_chick': '🐣', + 'headphones': '🎧', + 'headstone': '🪦', + 'health_worker': '🧑️‍⚕', + 'hear_no_evil': '🙉', + 'heard_mcdonald_islands': '🇭️‍🇲', + 'heart': '❤️', + 'heart_decoration': '💟', + 'heart_eyes': '😍', + 'heart_eyes_cat': '😻', + 'heart_on_fire': '❤️‍🔥', + 'heartbeat': '💓', + 'heartpulse': '💗', + 'hearts': '♥️', + 'heavy_check_mark': '✔️', + 'heavy_division_sign': '➗', + 'heavy_dollar_sign': '💲', + 'heavy_exclamation_mark': '❗', + 'heavy_heart_exclamation': '❣', + 'heavy_minus_sign': '➖', + 'heavy_multiplication_x': '✖️', + 'heavy_plus_sign': '➕', + 'hedgehog': '🦔', + 'helicopter': '🚁', + 'herb': '🌿', + 'hibiscus': '🌺', + 'high_brightness': '🔆', + 'high_heel': '👠', + 'hiking_boot': '🥾', + 'hindu_temple': '🛕', + 'hippopotamus': '🦛', + 'hocho': '🔪', + 'hole': '🕳', + 'honduras': '🇭🇳', + 'honey_pot': '🍯', + 'honeybee': '🐝', + 'hong_kong': '🇭🇰', + 'hook': '🪝', + 'horse': '🐴', + 'horse_racing': '🏇', + 'hospital': '🏥', + 'hot': '🥵', + 'hot_face': '🥵', + 'hot_pepper': '🌶', + 'hotdog': '🌭', + 'hotel': '🏨', + 'hotsprings': '♨️', + 'hourglass': '⌛', + 'hourglass_flowing_sand': '⏳', + 'house': '🏠', + 'house_with_garden': '🏡', + 'houses': '🏘', + 'hugs': '🤗', + 'hungary': '🇭🇺', + 'hushed': '😯', + 'hut': '🛖', + 'ice_cream': '🍨', + 'ice_cube': '🧊', + 'ice_hockey': '🏒', + 'ice_skate': '⛸', + 'icecream': '🍦', + 'iceland': '🇮🇸', + 'id': '🆔', + 'ideograph_advantage': '🉐', + 'imp': '👿', + 'inbox_tray': '📥', + 'incoming_envelope': '📨', + 'india': '🇮🇳', + 'indonesia': '🇮🇩', + 'infinity': '♾', + 'information_desk_person': '💁', + 'information_source': 'ℹ️', + 'innocent': '😇', + 'interrobang': '⁉️', + 'iphone': '📱', + 'iran': '🇮🇷', + 'iraq': '🇮🇶', + 'ireland': '🇮🇪', + 'isle_of_man': '🇮🇲', + 'israel': '🇮🇱', + 'it': '🇮🇹', + 'izakaya_lantern': '🏮', + 'jack_o_lantern': '🎃', + 'jamaica': '🇯🇲', + 'japan': '🗾', + 'japanese_castle': '🏯', + 'japanese_goblin': '👺', + 'japanese_ogre': '👹', + 'jeans': '👖', + 'jersey': '🇯🇪', + 'jigsaw': '🧩', + 'jordan': '🇯🇴', + 'joy': '😂', + 'joy_cat': '😹', + 'joystick': '🕹', + 'jp': '🇯🇵', + 'judge': '🧑️‍⚖', + 'juggling_person': '🤹', + 'kaaba': '🕋', + 'kangaroo': '🦘', + 'kazakhstan': '🇰🇿', + 'kenya': '🇰🇪', + 'key': '🔑', + 'keyboard': '⌨', + 'keycap_ten': '🔟', + 'kick_scooter': '🛴', + 'kimono': '👘', + 'kiribati': '🇰🇮', + 'kiss': '💋', + 'kissing': '😗', + 'kissing_cat': '😽', + 'kissing_closed_eyes': '😚', + 'kissing_heart': '😘', + 'kissing_smiling_eyes': '😙', + 'kite': '🪁', + 'kiwi_fruit': '🥝', + 'kneeling_man': '🧎️‍♂', + 'kneeling_person': '🧎', + 'kneeling_woman': '🧎️‍♀', + 'knife': '🔪', + 'knot': '🪢', + 'koala': '🐨', + 'koko': '🈁', + 'kosovo': '🇽🇰', + 'kr': '🇰🇷', + 'kuwait': '🇰🇼', + 'kyrgyzstan': '🇰🇬', + 'lab_coat': '🥼', + 'labcoat': '🥼', + 'label': '🏷', + 'lacrosse': '🥍', + 'ladder': '🪜', + 'lady_beetle': '🐞', + 'lantern': '🏮', + 'laos': '🇱🇦', + 'large_blue_circle': '🔵', + 'large_blue_diamond': '🔷', + 'large_orange_diamond': '🔶', + 'last_quarter_moon': '🌗', + 'last_quarter_moon_with_face': '🌜', + 'latin_cross': '✝', + 'latvia': '🇱🇻', + 'laughing': '😆', + 'leafy_green': '🥬', + 'leafy_greens': '🥬', + 'leaves': '🍃', + 'lebanon': '🇱🇧', + 'ledger': '📒', + 'left_luggage': '🛅', + 'left_right_arrow': '↔️', + 'left_speech_bubble': '🗨', + 'leftwards_arrow_with_hook': '↩️', + 'leg': '🦵', + 'lemon': '🍋', + 'leo': '♌', + 'leopard': '🐆', + 'lesotho': '🇱🇸', + 'level_slider': '🎚', + 'liberia': '🇱🇷', + 'libra': '♎', + 'libya': '🇱🇾', + 'liechtenstein': '🇱🇮', + 'light_rail': '🚈', + 'link': '🔗', + 'lion': '🦁', + 'lips': '👄', + 'lipstick': '💄', + 'lithuania': '🇱🇹', + 'lizard': '🦎', + 'llama': '🦙', + 'lobster': '🦞', + 'lock': '🔒', + 'lock_with_ink_pen': '🔏', + 'lollipop': '🍭', + 'long_drum': '🪘', + 'loop': '➿', + 'lotion_bottle': '🧴', + 'lotus_position': '🧘', + 'lotus_position_man': '🧘️‍♂', + 'lotus_position_woman': '🧘️‍♀', + 'loud_sound': '🔊', + 'loudspeaker': '📢', + 'love_hotel': '🏩', + 'love_letter': '💌', + 'love_you': '🤟', + 'love_you_gesture': '🤟', + 'low_brightness': '🔅', + 'luggage': '🧳', + 'lungs': '🫁', + 'luxembourg': '🇱🇺', + 'lying_face': '🤥', + 'm': 'Ⓜ️', + 'macau': '🇲🇴', + 'macedonia': '🇲🇰', + 'madagascar': '🇲🇬', + 'mag': '🔍', + 'mag_right': '🔎', + 'mage': '🧙', + 'mage_man': '🧙️‍♂', + 'mage_woman': '🧙️‍♀', + 'magic_wand': '🪄', + 'magnet': '🧲', + 'mahjong': '🀄', + 'mailbox': '📫', + 'mailbox_closed': '📪', + 'mailbox_with_mail': '📬', + 'mailbox_with_no_mail': '📭', + 'malawi': '🇲🇼', + 'malaysia': '🇲🇾', + 'maldives': '🇲🇻', + 'male_detective': '🕵', + 'male_sign': '♂', + 'mali': '🇲🇱', + 'malta': '🇲🇹', + 'mammoth': '🦣', + 'man': '👨', + 'man_artist': '👨‍🎨', + 'man_astronaut': '👨‍🚀', + 'man_beard': '🧔️‍♂', + 'man_cartwheeling': '🤸‍♂️', + 'man_cook': '👨‍🍳', + 'man_dancing': '🕺', + 'man_elf': '🧝‍♂️', + 'man_facepalming': '🤦‍♂️', + 'man_factory_worker': '👨‍🏭', + 'man_fairy': '🧚‍♂️', + 'man_farmer': '👨‍🌾', + 'man_feeding_baby': '👨️‍🍼', + 'man_firefighter': '👨‍🚒', + 'man_genie': '🧞‍♂️', + 'man_health_worker': '👨‍⚕️', + 'man_in_lotus_position': '🧘‍♂️', + 'man_in_manual_wheelchair': '👨️‍🦽', + 'man_in_motorized_wheelchair': '👨️‍🦼', + 'man_in_steamy_room': '🧖‍♂️', + 'man_in_tuxedo': '🤵', + 'man_judge': '👨‍⚖️', + 'man_juggling': '🤹‍♂️', + 'man_mechanic': '👨‍🔧', + 'man_office_worker': '👨‍💼', + 'man_pilot': '👨‍✈️', + 'man_playing_handball': '🤾‍♂️', + 'man_playing_water_polo': '🤽‍♂️', + 'man_scientist': '👨‍🔬', + 'man_shrugging': '🤷‍♂️', + 'man_singer': '👨‍🎤', + 'man_student': '👨‍🎓', + 'man_superhero': '🦸‍♂️', + 'man_supervillain': '🦹‍♂️', + 'man_teacher': '👨‍🏫', + 'man_technologist': '👨‍💻', + 'man_vampire': '🧛‍♂️', + 'man_with_gua_pi_mao': '👲', + 'man_with_probing_cane': '👨️‍🦯', + 'man_with_turban': '👳', + 'man_with_veil': '👰️‍♂', + 'man_zombie': '🧟‍♂️', + 'mandarin': '🍊', + 'mango': '🥭', + 'mans_shoe': '👞', + 'mantelpiece_clock': '🕰', + 'manual_wheelchair': '🦽', + 'maple_leaf': '🍁', + 'marshall_islands': '🇲🇭', + 'martial_arts_uniform': '🥋', + 'martinique': '🇲🇶', + 'mask': '😷', + 'massage': '💆', + 'massage_man': '💆‍♂️', + 'massage_woman': '💆', + 'mate': '🧉', + 'mauritania': '🇲🇷', + 'mauritius': '🇲🇺', + 'mayotte': '🇾🇹', + 'meat_on_bone': '🍖', + 'mechanic': '🧑️‍🔧', + 'mechanical_arm': '🦾', + 'mechanical_leg': '🦿', + 'medal_military': '🎖', + 'medal_sports': '🏅', + 'medical_symbol': '⚕', + 'mega': '📣', + 'melon': '🍈', + 'memo': '📝', + 'men_wrestling': '🤼‍♂️', + 'mending_heart': '❤️‍🩹', + 'menorah': '🕎', + 'mens': '🚹', + 'mermaid': '🧜‍♀️', + 'merman': '🧜‍♂️', + 'merperson': '🧜', + 'metal': '🤘', + 'metro': '🚇', + 'mexico': '🇲🇽', + 'microbe': '🦠', + 'micronesia': '🇫🇲', + 'microphone': '🎤', + 'microscope': '🔬', + 'middle_finger': '🖕', + 'military_helmet': '🪖', + 'milk_glass': '🥛', + 'milky_way': '🌌', + 'minibus': '🚐', + 'minidisc': '💽', + 'mirror': '🪞', + 'mobile_phone_off': '📴', + 'moldova': '🇲🇩', + 'monaco': '🇲🇨', + 'money_mouth_face': '🤑', + 'money_with_wings': '💸', + 'moneybag': '💰', + 'mongolia': '🇲🇳', + 'monkey': '🐒', + 'monkey_face': '🐵', + 'monocle': '🧐', + 'monocle_face': '🧐', + 'monorail': '🚝', + 'montenegro': '🇲🇪', + 'montserrat': '🇲🇸', + 'moon': '🌔', + 'moon_cake': '🥮', + 'morocco': '🇲🇦', + 'mortar_board': '🎓', + 'mosque': '🕌', + 'mosquito': '🦟', + 'motor_boat': '🛥', + 'motor_scooter': '🛵', + 'motorcycle': '🏍', + 'motorized_wheelchair': '🦼', + 'motorway': '🛣', + 'mount_fuji': '🗻', + 'mountain': '⛰', + 'mountain_bicyclist': '🚵', + 'mountain_biking_man': '🚵', + 'mountain_biking_woman': '🚵‍♀️', + 'mountain_cableway': '🚠', + 'mountain_railway': '🚞', + 'mountain_snow': '🏔', + 'mouse': '🐭', + 'mouse2': '🐁', + 'mouse_trap': '🪤', + 'movie_camera': '🎥', + 'moyai': '🗿', + 'mozambique': '🇲🇿', + 'mrs_claus': '🤶', + 'muscle': '💪', + 'mushroom': '🍄', + 'musical_keyboard': '🎹', + 'musical_note': '🎵', + 'musical_score': '🎼', + 'mute': '🔇', + 'mx_claus': '🧑️‍🎄', + 'myanmar': '🇲🇲', + 'nail_care': '💅', + 'name_badge': '📛', + 'namibia': '🇳🇦', + 'national_park': '🏞', + 'nauru': '🇳🇷', + 'nauseated_face': '🤢', + 'nazar_amulet': '🧿', + 'necktie': '👔', + 'negative_squared_cross_mark': '❎', + 'nepal': '🇳🇵', + 'nerd_face': '🤓', + 'nesting_dolls': '🪆', + 'netherlands': '🇳🇱', + 'neutral_face': '😐', + 'new': '🆕', + 'new_caledonia': '🇳🇨', + 'new_moon': '🌑', + 'new_moon_with_face': '🌚', + 'new_zealand': '🇳🇿', + 'newspaper': '📰', + 'newspaper_roll': '🗞', + 'next_track_button': '⏭', + 'ng': '🆖', + 'ng_man': '🙅️‍♂', + 'ng_woman': '🙅️‍♀', + 'nicaragua': '🇳🇮', + 'niger': '🇳🇪', + 'nigeria': '🇳🇬', + 'night_with_stars': '🌃', + 'nine': '9️⃣', + 'ninja': '🥷', + 'niue': '🇳🇺', + 'no_bell': '🔕', + 'no_bicycles': '🚳', + 'no_entry': '⛔', + 'no_entry_sign': '🚫', + 'no_good': '🙅', + 'no_good_man': '🙅‍♂️', + 'no_good_woman': '🙅', + 'no_mobile_phones': '📵', + 'no_mouth': '😶', + 'no_pedestrians': '🚷', + 'no_smoking': '🚭', + 'non-potable_water': '🚱', + 'norfolk_island': '🇳🇫', + 'north_korea': '🇰🇵', + 'northern_mariana_islands': '🇲🇵', + 'norway': '🇳🇴', + 'nose': '👃', + 'notebook': '📓', + 'notebook_with_decorative_cover': '📔', + 'notes': '🎶', + 'nut_and_bolt': '🔩', + 'o': '⭕', + 'o2': '🅾️', + 'ocean': '🌊', + 'octopus': '🐙', + 'oden': '🍢', + 'office': '🏢', + 'office_worker': '🧑️‍💼', + 'oil_drum': '🛢', + 'ok': '🆗', + 'ok_hand': '👌', + 'ok_man': '🙆‍♂️', + 'ok_person': '🙆', + 'ok_woman': '🙆', + 'old_key': '🗝', + 'older_adult': '🧓', + 'older_man': '👴', + 'older_woman': '👵', + 'olive': '🫒', + 'om': '🕉', + 'oman': '🇴🇲', + 'on': '🔛', + 'oncoming_automobile': '🚘', + 'oncoming_bus': '🚍', + 'oncoming_police_car': '🚔', + 'oncoming_taxi': '🚖', + 'one': '1️⃣', + 'one_piece_swimsuit': '🩱', + 'onion': '🧅', + 'open_book': '📖', + 'open_file_folder': '📂', + 'open_hands': '👐', + 'open_mouth': '😮', + 'open_umbrella': '☂', + 'ophiuchus': '⛎', + 'orange': '🍊', + 'orange_book': '📙', + 'orange_circle': '🟠', + 'orange_heart': '🧡', + 'orange_square': '🟧', + 'orangutan': '🦧', + 'orthodox_cross': '☦', + 'otter': '🦦', + 'outbox_tray': '📤', + 'owl': '🦉', + 'ox': '🐂', + 'oyster': '🦪', + 'package': '📦', + 'page_facing_up': '📄', + 'page_with_curl': '📃', + 'pager': '📟', + 'paintbrush': '🖌', + 'pakistan': '🇵🇰', + 'palau': '🇵🇼', + 'palestinian_territories': '🇵🇸', + 'palm_tree': '🌴', + 'palms_up': '🤲', + 'palms_up_together': '🤲', + 'panama': '🇵🇦', + 'pancakes': '🥞', + 'panda_face': '🐼', + 'paperclip': '📎', + 'paperclips': '🖇', + 'papua_new_guinea': '🇵🇬', + 'parachute': '🪂', + 'paraguay': '🇵🇾', + 'parasol_on_ground': '⛱', + 'parking': '🅿️', + 'parrot': '🦜', + 'part_alternation_mark': '〽️', + 'partly_sunny': '⛅', + 'partying': '🥳', + 'partying_face': '🥳', + 'passenger_ship': '🛳', + 'passport_control': '🛂', + 'pause_button': '⏸', + 'paw_prints': '🐾', + 'peace_symbol': '☮', + 'peach': '🍑', + 'peacock': '🦚', + 'peanuts': '🥜', + 'pear': '🍐', + 'pen': '🖊', + 'pencil': '📝', + 'pencil2': '✏️', + 'penguin': '🐧', + 'pensive': '😔', + 'people_holding_hands': '🧑️‍🤝️‍🧑', + 'people_hugging': '🫂', + 'performing_arts': '🎭', + 'persevere': '😣', + 'person_bald': '🧑️‍🦲', + 'person_curly_hair': '🧑️‍🦱', + 'person_feeding_baby': '🧑️‍🍼', + 'person_fencing': '🤺', + 'person_in_manual_wheelchair': '🧑️‍🦽', + 'person_in_motorized_wheelchair': '🧑️‍🦼', + 'person_in_tuxedo': '🤵', + 'person_red_hair': '🧑️‍🦰', + 'person_white_hair': '🧑️‍🦳', + 'person_with_probing_cane': '🧑️‍🦯', + 'person_with_turban': '👳', + 'person_with_veil': '👰', + 'peru': '🇵🇪', + 'petri_dish': '🧫', + 'philippines': '🇵🇭', + 'phone': '☎️', + 'pick': '⛏', + 'pickup_truck': '🛻', + 'pie': '🥧', + 'pig': '🐷', + 'pig2': '🐖', + 'pig_nose': '🐽', + 'pill': '💊', + 'pilot': '🧑️‍✈', + 'pinata': '🪅', + 'pinched_fingers': '🤌', + 'pinching_hand': '🤏', + 'pineapple': '🍍', + 'ping_pong': '🏓', + 'pirate_flag': '🏴‍☠️', + 'pisces': '♓', + 'pitcairn_islands': '🇵🇳', + 'pizza': '🍕', + 'placard': '🪧', + 'place_of_worship': '🛐', + 'plate_with_cutlery': '🍽', + 'play_or_pause_button': '⏯', + 'pleading': '🥺', + 'pleading_face': '🥺', + 'plunger': '🪠', + 'point_down': '👇', + 'point_left': '👈', + 'point_right': '👉', + 'point_up': '☝', + 'point_up_2': '👆', + 'poland': '🇵🇱', + 'polar_bear': '🐻️‍❄', + 'police_car': '🚓', + 'police_officer': '👮', + 'policeman': '👮', + 'policewoman': '👮‍♀️', + 'poodle': '🐩', + 'poop': '💩', + 'popcorn': '🍿', + 'portugal': '🇵🇹', + 'post_office': '🏣', + 'postal_horn': '📯', + 'postbox': '📮', + 'potable_water': '🚰', + 'potato': '🥔', + 'potted_plant': '🪴', + 'pouch': '👝', + 'poultry_leg': '🍗', + 'pound': '💷', + 'pout': '😡', + 'pouting_cat': '😾', + 'pouting_face': '🙎', + 'pouting_man': '🙎‍♂️', + 'pouting_woman': '🙎', + 'pray': '🙏', + 'prayer_beads': '📿', + 'pregnant_woman': '🤰', + 'pretzel': '🥨', + 'previous_track_button': '⏮', + 'prince': '🤴', + 'princess': '👸', + 'printer': '🖨', + 'probing_cane': '🦯', + 'puerto_rico': '🇵🇷', + 'punch': '👊', + 'purple_circle': '🟣', + 'purple_heart': '💜', + 'purple_square': '🟪', + 'purse': '👛', + 'pushpin': '📌', + 'put_litter_in_its_place': '🚮', + 'qatar': '🇶🇦', + 'question': '❓', + 'rabbit': '🐰', + 'rabbit2': '🐇', + 'raccoon': '🦝', + 'racehorse': '🐎', + 'racing_car': '🏎', + 'radio': '📻', + 'radio_button': '🔘', + 'radioactive': '☢', + 'rage': '😡', + 'railway_car': '🚃', + 'railway_track': '🛤', + 'rainbow': '🌈', + 'rainbow_flag': '🏳️‍🌈', + 'raised_back_of_hand': '🤚', + 'raised_eyebrow': '🤨', + 'raised_hand': '✋', + 'raised_hand_with_fingers_splayed': '🖐', + 'raised_hands': '🙌', + 'raising_hand': '🙋', + 'raising_hand_man': '🙋‍♂️', + 'raising_hand_woman': '🙋', + 'ram': '🐏', + 'ramen': '🍜', + 'rat': '🐀', + 'razor': '🪒', + 'receipt': '🧾', + 'record_button': '⏺', + 'recycle': '♻️', + 'red_car': '🚗', + 'red_circle': '🔴', + 'red_envelope': '🧧', + 'red_haired_man': '👨️‍🦰', + 'red_haired_woman': '👩️‍🦰', + 'red_square': '🟥', + 'registered': '®️', + 'relaxed': '☺️', + 'relieved': '😌', + 'reminder_ribbon': '🎗', + 'repeat': '🔁', + 'repeat_one': '🔂', + 'rescue_worker_helmet': '⛑', + 'restroom': '🚻', + 'reunion': '🇷🇪', + 'revolving_hearts': '💞', + 'rewind': '⏪', + 'rhinoceros': '🦏', + 'ribbon': '🎀', + 'rice': '🍚', + 'rice_ball': '🍙', + 'rice_cracker': '🍘', + 'rice_scene': '🎑', + 'right_anger_bubble': '🗯', + 'ring': '💍', + 'ringed_planet': '🪐', + 'robot': '🤖', + 'rock': '🪨', + 'rocket': '🚀', + 'rofl': '🤣', + 'roll_eyes': '🙄', + 'roll_of_paper': '🧻', + 'roller_coaster': '🎢', + 'roller_skate': '🛼', + 'romania': '🇷🇴', + 'rooster': '🐓', + 'rose': '🌹', + 'rosette': '🏵', + 'rotating_light': '🚨', + 'round_pushpin': '📍', + 'rowboat': '🚣', + 'rowing_man': '🚣', + 'rowing_woman': '🚣‍♀️', + 'ru': '🇷🇺', + 'rugby_football': '🏉', + 'runner': '🏃', + 'running': '🏃', + 'running_man': '🏃', + 'running_shirt_with_sash': '🎽', + 'running_woman': '🏃‍♀️', + 'rwanda': '🇷🇼', + 'sa': '🈂️', + 'safety_pin': '🧷', + 'safety_vest': '🦺', + 'sagittarius': '♐', + 'sailboat': '⛵', + 'sake': '🍶', + 'salt': '🧂', + 'samoa': '🇼🇸', + 'san_marino': '🇸🇲', + 'sandal': '👡', + 'sandwich': '🥪', + 'santa': '🎅', + 'sao_tome_principe': '🇸🇹', + 'sari': '🥻', + 'sassy_man': '💁️‍♂', + 'sassy_woman': '💁️‍♀', + 'satellite': '📡', + 'satisfied': '😆', + 'saudi_arabia': '🇸🇦', + 'sauna_man': '🧖️‍♂', + 'sauna_person': '🧖', + 'sauna_woman': '🧖️‍♀', + 'sauropod': '🦕', + 'saxophone': '🎷', + 'scarf': '🧣', + 'school': '🏫', + 'school_satchel': '🎒', + 'scientist': '🧑️‍🔬', + 'scissors': '✂️', + 'scorpion': '🦂', + 'scorpius': '♏', + 'scotland': '🏴󠁧󠁢󠁳󠁣󠁴󠁿', + 'scream': '😱', + 'scream_cat': '🙀', + 'screwdriver': '🪛', + 'scroll': '📜', + 'seal': '🦭', + 'seat': '💺', + 'secret': '㊙️', + 'see_no_evil': '🙈', + 'seedling': '🌱', + 'selfie': '🤳', + 'senegal': '🇸🇳', + 'serbia': '🇷🇸', + 'service_dog': '🐕️‍🦺', + 'seven': '7️⃣', + 'sewing_needle': '🪡', + 'seychelles': '🇸🇨', + 'shallow_pan_of_food': '🥘', + 'shamrock': '☘', + 'shark': '🦈', + 'shaved_ice': '🍧', + 'sheep': '🐑', + 'shell': '🐚', + 'shield': '🛡', + 'shinto_shrine': '⛩', + 'ship': '🚢', + 'shirt': '👕', + 'shit': '💩', + 'shoe': '👞', + 'shopping': '🛍', + 'shopping_cart': '🛒', + 'shorts': '🩳', + 'shower': '🚿', + 'shrimp': '🦐', + 'shrug': '🤷', + 'shushing': '🤫', + 'shushing_face': '🤫', + 'sierra_leone': '🇸🇱', + 'signal_strength': '📶', + 'singapore': '🇸🇬', + 'singer': '🧑️‍🎤', + 'sint_maarten': '🇸🇽', + 'six': '6️⃣', + 'six_pointed_star': '🔯', + 'skateboard': '🛹', + 'ski': '🎿', + 'skier': '⛷', + 'skull': '💀', + 'skull_and_crossbones': '☠', + 'skunk': '🦨', + 'sled': '🛷', + 'sleeping': '😴', + 'sleeping_bed': '🛌', + 'sleepy': '😪', + 'slightly_frowning_face': '🙁', + 'slightly_smiling_face': '🙂', + 'slot_machine': '🎰', + 'sloth': '🦥', + 'slovakia': '🇸🇰', + 'slovenia': '🇸🇮', + 'small_airplane': '🛩', + 'small_blue_diamond': '🔹', + 'small_orange_diamond': '🔸', + 'small_red_triangle': '🔺', + 'small_red_triangle_down': '🔻', + 'smile': '😄', + 'smile_cat': '😸', + 'smiley': '😃', + 'smiley_cat': '😺', + 'smiling_face_with_tear': '🥲', + 'smiling_face_with_three_hearts': '🥰', + 'smiling_imp': '😈', + 'smirk': '😏', + 'smirk_cat': '😼', + 'smoking': '🚬', + 'snail': '🐌', + 'snake': '🐍', + 'sneezing_face': '🤧', + 'snowboarder': '🏂', + 'snowflake': '❄️', + 'snowman': '⛄', + 'snowman_with_snow': '☃', + 'soap': '🧼', + 'sob': '😭', + 'soccer': '⚽', + 'socks': '🧦', + 'softball': '🥎', + 'solomon_islands': '🇸🇧', + 'somalia': '🇸🇴', + 'soon': '🔜', + 'sorceress': '🧙‍♀️', + 'sos': '🆘', + 'sound': '🔉', + 'south_africa': '🇿🇦', + 'south_georgia_south_sandwich_islands': '🇬🇸', + 'south_sudan': '🇸🇸', + 'space_invader': '👾', + 'spades': '♠️', + 'spaghetti': '🍝', + 'sparkle': '❇️', + 'sparkler': '🎇', + 'sparkles': '✨', + 'sparkling_heart': '💖', + 'speak_no_evil': '🙊', + 'speaker': '🔈', + 'speaking_head': '🗣', + 'speech_balloon': '💬', + 'speedboat': '🚤', + 'spider': '🕷', + 'spider_web': '🕸', + 'spiral_calendar': '🗓', + 'spiral_notepad': '🗒', + 'sponge': '🧽', + 'spoon': '🥄', + 'squid': '🦑', + 'sri_lanka': '🇱🇰', + 'st_barthelemy': '🇧🇱', + 'st_helena': '🇸🇭', + 'st_kitts_nevis': '🇰🇳', + 'st_lucia': '🇱🇨', + 'st_martin': '🇲️‍🇫', + 'st_pierre_miquelon': '🇵🇲', + 'st_vincent_grenadines': '🇻🇨', + 'stadium': '🏟', + 'standing_man': '🧍️‍♂', + 'standing_person': '🧍', + 'standing_woman': '🧍️‍♀', + 'star': '⭐', + 'star2': '🌟', + 'star_and_crescent': '☪', + 'star_of_david': '✡', + 'star_struck': '🤩', + 'stars': '🌠', + 'station': '🚉', + 'statue_of_liberty': '🗽', + 'steak': '🥩', + 'steam_locomotive': '🚂', + 'stethoscope': '🩺', + 'stew': '🍲', + 'stop_button': '⏹', + 'stop_sign': '🛑', + 'stopwatch': '⏱', + 'straight_ruler': '📏', + 'strawberry': '🍓', + 'stuck_out_tongue': '😛', + 'stuck_out_tongue_closed_eyes': '😝', + 'stuck_out_tongue_winking_eye': '😜', + 'student': '🧑️‍🎓', + 'studio_microphone': '🎙', + 'stuffed_flatbread': '🥙', + 'sudan': '🇸🇩', + 'sun_behind_large_cloud': '🌥', + 'sun_behind_rain_cloud': '🌦', + 'sun_behind_small_cloud': '🌤', + 'sun_with_face': '🌞', + 'sunflower': '🌻', + 'sunglasses': '😎', + 'sunny': '☀️', + 'sunrise': '🌅', + 'sunrise_over_mountains': '🌄', + 'superhero': '🦸', + 'superhero_man': '🦸️‍♂', + 'superhero_woman': '🦸️‍♀', + 'supervillain': '🦹', + 'supervillain_man': '🦹️‍♂', + 'supervillain_woman': '🦹️‍♀', + 'surfer': '🏄', + 'surfing_man': '🏄', + 'surfing_woman': '🏄‍♀️', + 'suriname': '🇸🇷', + 'sushi': '🍣', + 'suspension_railway': '🚟', + 'svalbard_jan_mayen': '🇸️‍🇯', + 'swan': '🦢', + 'swaziland': '🇸🇿', + 'sweat': '😓', + 'sweat_drops': '💦', + 'sweat_smile': '😅', + 'sweden': '🇸🇪', + 'sweet_potato': '🍠', + 'swim_brief': '🩲', + 'swimmer': '🏊', + 'swimming_man': '🏊', + 'swimming_woman': '🏊‍♀️', + 'switzerland': '🇨🇭', + 'symbols': '🔣', + 'symbols_over_mouth': '🤬', + 'synagogue': '🕍', + 'syria': '🇸🇾', + 'syringe': '💉', + 't-rex': '🦖', + 'taco': '🌮', + 'tada': '🎉', + 'taiwan': '🇹🇼', + 'tajikistan': '🇹🇯', + 'takeout_box': '🥡', + 'tamale': '🫔', + 'tanabata_tree': '🎋', + 'tangerine': '🍊', + 'tanzania': '🇹🇿', + 'taurus': '♉', + 'taxi': '🚕', + 'tea': '🍵', + 'teacher': '🧑️‍🏫', + 'teapot': '🫖', + 'technologist': '🧑️‍💻', + 'teddy_bear': '🧸', + 'telephone': '☎️', + 'telephone_receiver': '📞', + 'telescope': '🔭', + 'tennis': '🎾', + 'tent': '⛺', + 'test_tube': '🧪', + 'thailand': '🇹🇭', + 'thermometer': '🌡', + 'thinking': '🤔', + 'thong_sandal': '🩴', + 'thought_balloon': '💭', + 'thread': '🧵', + 'three': '3️⃣', + 'thumbsdown': '👎', + 'thumbsup': '👍', + 'ticket': '🎫', + 'tickets': '🎟', + 'tiger': '🐯', + 'tiger2': '🐅', + 'timer_clock': '⏲', + 'timor_leste': '🇹🇱', + 'tipping_hand_man': '💁‍♂️', + 'tipping_hand_person': '💁', + 'tipping_hand_woman': '💁', + 'tired_face': '😫', + 'tm': '™️', + 'togo': '🇹🇬', + 'toilet': '🚽', + 'toilet_paper': '🧻', + 'tokelau': '🇹🇰', + 'tokyo_tower': '🗼', + 'tomato': '🍅', + 'tonga': '🇹🇴', + 'tongue': '👅', + 'toolbox': '🧰', + 'tooth': '🦷', + 'toothbrush': '🪥', + 'top': '🔝', + 'tophat': '🎩', + 'tornado': '🌪', + 'tr': '🇹🇷', + 'trackball': '🖲', + 'tractor': '🚜', + 'traffic_light': '🚥', + 'train': '🚋', + 'train2': '🚆', + 'tram': '🚊', + 'transgender_flag': '🏳️‍⚧', + 'transgender_symbol': '⚧', + 'triangular_flag_on_post': '🚩', + 'triangular_ruler': '📐', + 'trident': '🔱', + 'trinidad_tobago': '🇹🇹', + 'tristan_da_cunha': '🇹️‍🇦', + 'triumph': '😤', + 'trolleybus': '🚎', + 'trophy': '🏆', + 'tropical_drink': '🍹', + 'tropical_fish': '🐠', + 'truck': '🚚', + 'trumpet': '🎺', + 'tshirt': '👕', + 'tulip': '🌷', + 'tumbler_glass': '🥃', + 'tunisia': '🇹🇳', + 'turkey': '🦃', + 'turkmenistan': '🇹🇲', + 'turks_caicos_islands': '🇹🇨', + 'turtle': '🐢', + 'tuvalu': '🇹🇻', + 'tv': '📺', + 'twisted_rightwards_arrows': '🔀', + 'two': '2️⃣', + 'two_hearts': '💕', + 'two_men_holding_hands': '👬', + 'two_women_holding_hands': '👭', + 'u5272': '🈹', + 'u5408': '🈴', + 'u55b6': '🈺', + 'u6307': '🈯', + 'u6708': '🈷️', + 'u6709': '🈶', + 'u6e80': '🈵', + 'u7121': '🈚', + 'u7533': '🈸', + 'u7981': '🈲', + 'u7a7a': '🈳', + 'uganda': '🇺🇬', + 'uk': '🇬🇧', + 'ukraine': '🇺🇦', + 'umbrella': '☔', + 'unamused': '😒', + 'underage': '🔞', + 'unicorn': '🦄', + 'united_arab_emirates': '🇦🇪', + 'united_nations': '🇺🇳', + 'unlock': '🔓', + 'up': '🆙', + 'upside_down_face': '🙃', + 'uruguay': '🇺🇾', + 'us': '🇺🇸', + 'us_outlying_islands': '🇺️‍🇲', + 'us_virgin_islands': '🇻🇮', + 'uzbekistan': '🇺🇿', + 'v': '✌', + 'vampire': '🧛', + 'vampire_man': '🧛️‍♂', + 'vampire_woman': '🧛️‍♀', + 'vanuatu': '🇻🇺', + 'vatican_city': '🇻🇦', + 'venezuela': '🇻🇪', + 'vertical_traffic_light': '🚦', + 'vhs': '📼', + 'vibration_mode': '📳', + 'video_camera': '📹', + 'video_game': '🎮', + 'vietnam': '🇻🇳', + 'violin': '🎻', + 'virgo': '♍', + 'volcano': '🌋', + 'volleyball': '🏐', + 'vomiting': '🤮', + 'vomiting_face': '🤮', + 'vs': '🆚', + 'vulcan_salute': '🖖', + 'waffle': '🧇', + 'wales': '🏴󠁧󠁢󠁷󠁬󠁳󠁿', + 'walking': '🚶', + 'walking_man': '🚶', + 'walking_woman': '🚶‍♀️', + 'wallis_futuna': '🇼🇫', + 'waning_crescent_moon': '🌘', + 'waning_gibbous_moon': '🌖', + 'warning': '⚠️', + 'wastebasket': '🗑', + 'watch': '⌚', + 'water_buffalo': '🐃', + 'water_polo': '🤽', + 'watermelon': '🍉', + 'wave': '👋', + 'wavy_dash': '〰️', + 'waxing_crescent_moon': '🌒', + 'waxing_gibbous_moon': '🌔', + 'wc': '🚾', + 'weary': '😩', + 'wedding': '💒', + 'weight_lifting': '🏋', + 'weight_lifting_man': '🏋', + 'weight_lifting_woman': '🏋️‍♀️', + 'western_sahara': '🇪🇭', + 'whale': '🐳', + 'whale2': '🐋', + 'wheel_of_dharma': '☸', + 'wheelchair': '♿', + 'white_check_mark': '✅', + 'white_circle': '⚪', + 'white_flag': '🏳', + 'white_flower': '💮', + 'white_haired_man': '👨️‍🦳', + 'white_haired_woman': '👩️‍🦳', + 'white_heart': '🤍', + 'white_large_square': '⬜', + 'white_medium_small_square': '◽', + 'white_medium_square': '◻️', + 'white_small_square': '▫️', + 'white_square_button': '🔳', + 'wilted_flower': '🥀', + 'wind_chime': '🎐', + 'wind_face': '🌬', + 'window': '🪟', + 'wine_glass': '🍷', + 'wink': '😉', + 'wizard': '🧙‍♂️', + 'wolf': '🐺', + 'woman': '👩', + 'woman_artist': '👩‍🎨', + 'woman_astronaut': '👩‍🚀', + 'woman_beard': '🧔️‍♀', + 'woman_cartwheeling': '🤸‍♀️', + 'woman_cook': '👩‍🍳', + 'woman_dancing': '💃', + 'woman_elf': '🧝‍♀️', + 'woman_facepalming': '🤦‍♀️', + 'woman_factory_worker': '👩‍🏭', + 'woman_fairy': '🧚‍♀️', + 'woman_farmer': '👩‍🌾', + 'woman_feeding_baby': '👩️‍🍼', + 'woman_firefighter': '👩‍🚒', + 'woman_genie': '🧞‍♀️', + 'woman_health_worker': '👩‍⚕️', + 'woman_in_lotus_position': '🧘‍♀️', + 'woman_in_manual_wheelchair': '👩️‍🦽', + 'woman_in_motorized_wheelchair': '👩️‍🦼', + 'woman_in_steamy_room': '🧖‍♀️', + 'woman_in_tuxedo': '🤵️‍♀', + 'woman_judge': '👩‍⚖️', + 'woman_juggling': '🤹‍♀️', + 'woman_mechanic': '👩‍🔧', + 'woman_office_worker': '👩‍💼', + 'woman_pilot': '👩‍✈️', + 'woman_playing_handball': '🤾‍♀️', + 'woman_playing_water_polo': '🤽‍♀️', + 'woman_scientist': '👩‍🔬', + 'woman_shrugging': '🤷', + 'woman_singer': '👩‍🎤', + 'woman_student': '👩‍🎓', + 'woman_superhero': '🦸‍♀️', + 'woman_supervillain': '🦹‍♀️', + 'woman_teacher': '👩‍🏫', + 'woman_technologist': '👩‍💻', + 'woman_vampire': '🧛‍♀️', + 'woman_with_headscarf': '🧕', + 'woman_with_probing_cane': '👩️‍🦯', + 'woman_with_turban': '👳‍♀️', + 'woman_with_veil': '👰️‍♀', + 'woman_zombie': '🧟‍♀️', + 'womans_clothes': '👚', + 'womans_hat': '👒', + 'women_wrestling': '🤼‍♀️', + 'womens': '🚺', + 'wood': '🪵', + 'woozy': '🥴', + 'woozy_face': '🥴', + 'world_map': '🗺', + 'worm': '🪱', + 'worried': '😟', + 'wrench': '🔧', + 'wrestling': '🤼', + 'writing_hand': '✍', + 'x': '❌', + 'yarn': '🧶', + 'yawning_face': '🥱', + 'yellow_circle': '🟡', + 'yellow_heart': '💛', + 'yellow_square': '🟨', + 'yemen': '🇾🇪', + 'yen': '💴', + 'yin_yang': '☯', + 'yo_yo': '🪀', + 'yum': '😋', + 'zambia': '🇿🇲', + 'zany': '🤪', + 'zany_face': '🤪', + 'zap': '⚡', + 'zebra': '🦓', + 'zero': '0️⃣', + 'zimbabwe': '🇿🇼', + 'zipper_mouth_face': '🤐', + 'zombie': '🧟', + 'zombie_man': '🧟️‍♂', + 'zombie_woman': '🧟️‍♀', + 'zzz': '💤', +}; diff --git a/pkgs/markdown/lib/src/extension_set.dart b/pkgs/markdown/lib/src/extension_set.dart new file mode 100644 index 000000000..58a25d86a --- /dev/null +++ b/pkgs/markdown/lib/src/extension_set.dart @@ -0,0 +1,103 @@ +import 'block_syntaxes/alert_block_syntax.dart'; +import 'block_syntaxes/block_syntax.dart'; +import 'block_syntaxes/fenced_code_block_syntax.dart'; +import 'block_syntaxes/footnote_def_syntax.dart'; +import 'block_syntaxes/header_with_id_syntax.dart'; +import 'block_syntaxes/ordered_list_with_checkbox_syntax.dart'; +import 'block_syntaxes/setext_header_with_id_syntax.dart'; +import 'block_syntaxes/table_syntax.dart'; +import 'block_syntaxes/unordered_list_with_checkbox_syntax.dart'; +import 'inline_syntaxes/autolink_extension_syntax.dart'; +import 'inline_syntaxes/color_swatch_syntax.dart'; +import 'inline_syntaxes/emoji_syntax.dart'; +import 'inline_syntaxes/inline_html_syntax.dart'; +import 'inline_syntaxes/inline_syntax.dart'; +import 'inline_syntaxes/strikethrough_syntax.dart'; + +/// ExtensionSets provide a simple grouping mechanism for common Markdown +/// flavors. +/// +/// For example, the [gitHubFlavored] set of syntax extensions allows users to +/// output HTML from their Markdown in a similar fashion to GitHub's parsing. +class ExtensionSet { + /// The [ExtensionSet.none] extension set renders Markdown similar to + /// [Markdown.pl]. + /// + /// However, this set does not render _exactly_ the same as Markdown.pl; + /// rather it is more-or-less the CommonMark standard of Markdown, without + /// fenced code blocks, or inline HTML. + /// + /// [Markdown.pl]: http://daringfireball.net/projects/markdown/syntax + static final ExtensionSet none = ExtensionSet(const [], const []); + + /// The [commonMark] extension set is close to compliance with [CommonMark]. + /// + /// [CommonMark]: http://commonmark.org/ + static final ExtensionSet commonMark = ExtensionSet( + List.unmodifiable( + [const FencedCodeBlockSyntax()], + ), + List.unmodifiable( + [InlineHtmlSyntax()], + ), + ); + + /// The [gitHubWeb] extension set renders Markdown similarly to GitHub. + /// + /// This is different from the [gitHubFlavored] extension set in that GitHub + /// actually renders HTML different from straight [GitHub flavored Markdown]. + /// + /// (The only difference currently is that [gitHubWeb] renders headers with + /// linkable IDs.) + /// + /// [GitHub flavored Markdown]: https://github.github.com/gfm/ + static final ExtensionSet gitHubWeb = ExtensionSet( + List.unmodifiable( + [ + const FencedCodeBlockSyntax(), + const HeaderWithIdSyntax(), + const SetextHeaderWithIdSyntax(), + const TableSyntax(), + const UnorderedListWithCheckboxSyntax(), + const OrderedListWithCheckboxSyntax(), + const FootnoteDefSyntax(), + const AlertBlockSyntax(), + ], + ), + List.unmodifiable( + [ + InlineHtmlSyntax(), + StrikethroughSyntax(), + EmojiSyntax(), + ColorSwatchSyntax(), + AutolinkExtensionSyntax() + ], + ), + ); + + /// The [gitHubFlavored] extension set is close to compliance with the + /// [GitHub flavored Markdown spec](https://github.github.com/gfm/). + static final ExtensionSet gitHubFlavored = ExtensionSet( + List.unmodifiable( + [ + const FencedCodeBlockSyntax(), + const TableSyntax(), + const UnorderedListWithCheckboxSyntax(), + const OrderedListWithCheckboxSyntax(), + const FootnoteDefSyntax(), + ], + ), + List.unmodifiable( + [ + InlineHtmlSyntax(), + StrikethroughSyntax(), + AutolinkExtensionSyntax() + ], + ), + ); + + final List blockSyntaxes; + final List inlineSyntaxes; + + ExtensionSet(this.blockSyntaxes, this.inlineSyntaxes); +} diff --git a/pkgs/markdown/lib/src/html_renderer.dart b/pkgs/markdown/lib/src/html_renderer.dart new file mode 100644 index 000000000..404d870db --- /dev/null +++ b/pkgs/markdown/lib/src/html_renderer.dart @@ -0,0 +1,218 @@ +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:convert'; + +import 'ast.dart'; +import 'block_syntaxes/block_syntax.dart'; +import 'document.dart'; +import 'extension_set.dart'; +import 'inline_syntaxes/inline_syntax.dart'; + +/// Converts the given string of Markdown to HTML. +String markdownToHtml( + String markdown, { + Iterable blockSyntaxes = const [], + Iterable inlineSyntaxes = const [], + ExtensionSet? extensionSet, + Resolver? linkResolver, + Resolver? imageLinkResolver, + bool inlineOnly = false, + bool encodeHtml = true, + bool enableTagfilter = false, + bool withDefaultBlockSyntaxes = true, + bool withDefaultInlineSyntaxes = true, +}) { + final document = Document( + blockSyntaxes: blockSyntaxes, + inlineSyntaxes: inlineSyntaxes, + extensionSet: extensionSet, + linkResolver: linkResolver, + imageLinkResolver: imageLinkResolver, + encodeHtml: encodeHtml, + withDefaultBlockSyntaxes: withDefaultBlockSyntaxes, + withDefaultInlineSyntaxes: withDefaultInlineSyntaxes, + ); + + if (inlineOnly) return renderToHtml(document.parseInline(markdown)); + + final nodes = document.parse(markdown); + + return '${renderToHtml(nodes, enableTagfilter: enableTagfilter)}\n'; +} + +/// Renders [nodes] to HTML. +String renderToHtml(List nodes, {bool enableTagfilter = false}) => + HtmlRenderer( + enableTagfilter: enableTagfilter, + ).render(nodes); + +const _blockTags = [ + 'blockquote', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'hr', + 'li', + 'ol', + 'p', + 'pre', + 'ul', + 'address', + 'article', + 'aside', + 'details', + 'dd', + 'div', + 'dl', + 'dt', + 'figcaption', + 'figure', + 'footer', + 'header', + 'hgroup', + 'main', + 'nav', + 'section', + 'table', + 'thead', + 'tbody', + 'th', + 'tr', + 'td', +]; + +/// Translates a parsed AST to HTML. +class HtmlRenderer implements NodeVisitor { + late StringBuffer buffer; + late Set uniqueIds; + + final _elementStack = []; + String? _lastVisitedTag; + final bool _tagfilterEnabled; + + HtmlRenderer({ + bool enableTagfilter = false, + }) : _tagfilterEnabled = enableTagfilter; + + String render(List nodes) { + buffer = StringBuffer(); + uniqueIds = {}; + + for (final node in nodes) { + node.accept(this); + } + + return buffer.toString(); + } + + @override + void visitText(Text text) { + var content = text.textContent; + + if (_tagfilterEnabled) { + content = _filterTags(content); + } + if (const ['br', 'p', 'li'].contains(_lastVisitedTag)) { + final lines = LineSplitter.split(content); + content = content.contains('
')
+          ? lines.join('\n')
+          : lines.map((line) => line.trimLeft()).join('\n');
+      if (text.textContent.endsWith('\n')) {
+        content = '$content\n';
+      }
+    }
+    buffer.write(content);
+
+    _lastVisitedTag = null;
+  }
+
+  @override
+  bool visitElementBefore(Element element) {
+    // Hackish. Separate block-level elements with newlines.
+    if (buffer.isNotEmpty && _blockTags.contains(element.tag)) {
+      buffer.writeln();
+    }
+
+    buffer.write('<${element.tag}');
+
+    for (final entry in element.attributes.entries) {
+      buffer.write(' ${entry.key}="${entry.value}"');
+    }
+
+    final generatedId = element.generatedId;
+
+    // attach header anchor ids generated from text
+    if (generatedId != null) {
+      buffer.write(' id="${uniquifyId(generatedId)}"');
+    }
+
+    _lastVisitedTag = element.tag;
+
+    if (element.isEmpty) {
+      // Empty element like 
. + buffer.write(' />'); + + if (element.tag == 'br') { + buffer.write('\n'); + } + + return false; + } else { + _elementStack.add(element); + buffer.write('>'); + return true; + } + } + + @override + void visitElementAfter(Element element) { + assert(identical(_elementStack.last, element)); + + if (element.children != null && + element.children!.isNotEmpty && + _blockTags.contains(_lastVisitedTag) && + _blockTags.contains(element.tag)) { + buffer.writeln(); + } else if (element.tag == 'blockquote') { + buffer.writeln(); + } + buffer.write(''); + + _lastVisitedTag = _elementStack.removeLast().tag; + } + + /// Uniquifies an id generated from text. + String uniquifyId(String id) { + if (!uniqueIds.contains(id)) { + uniqueIds.add(id); + return id; + } + + var suffix = 2; + var suffixedId = '$id-$suffix'; + while (uniqueIds.contains(suffixedId)) { + suffixedId = '$id-${suffix++}'; + } + uniqueIds.add(suffixedId); + return suffixedId; + } + + /// Filters some particular tags, see: + /// https://github.github.com/gfm/#disallowed-raw-html-extension- + // As said in the specification, this process should happen when rendering + // HTML output, so there should not be a dedicated syntax for this extension. + String _filterTags(String content) => content.replaceAll( + RegExp( + '<(?=(?:' + 'title|textarea|style|xmp|iframe|noembed|noframes|script|plaintext' + ')>)', + caseSensitive: false, + multiLine: true, + ), + '<'); +} diff --git a/pkgs/markdown/lib/src/inline_parser.dart b/pkgs/markdown/lib/src/inline_parser.dart new file mode 100644 index 000000000..e700ecfd1 --- /dev/null +++ b/pkgs/markdown/lib/src/inline_parser.dart @@ -0,0 +1,355 @@ +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'ast.dart'; +import 'charcode.dart'; +import 'document.dart'; +import 'inline_syntaxes/autolink_syntax.dart'; +import 'inline_syntaxes/code_syntax.dart'; +import 'inline_syntaxes/decode_html_syntax.dart'; +import 'inline_syntaxes/delimiter_syntax.dart'; +import 'inline_syntaxes/email_autolink_syntax.dart'; +import 'inline_syntaxes/emphasis_syntax.dart'; +import 'inline_syntaxes/escape_html_syntax.dart'; +import 'inline_syntaxes/escape_syntax.dart'; +import 'inline_syntaxes/image_syntax.dart'; +import 'inline_syntaxes/inline_syntax.dart'; +import 'inline_syntaxes/line_break_syntax.dart'; +import 'inline_syntaxes/link_syntax.dart'; +import 'inline_syntaxes/soft_line_break_syntax.dart'; +import 'inline_syntaxes/text_syntax.dart'; + +/// Maintains the internal state needed to parse inline span elements in +/// Markdown. +class InlineParser { + static final List _defaultSyntaxes = + List.unmodifiable([ + EmailAutolinkSyntax(), + AutolinkSyntax(), + LineBreakSyntax(), + // Parse "**strong**" and "*emphasis*" tags. + EmphasisSyntax.asterisk(), + // Parse "__strong__" and "_emphasis_" tags. + EmphasisSyntax.underscore(), + CodeSyntax(), + SoftLineBreakSyntax(), + // We will add the LinkSyntax once we know about the specific link resolver. + ]); + + /// The string of Markdown being parsed. + final String source; + + /// The Markdown document this parser is parsing. + final Document document; + + final syntaxes = []; + + /// The current read position. + int pos = 0; + + /// Starting position of the last unconsumed text. + int start = 0; + + /// The delimiter stack tracking possible opening delimiters and closing + /// delimiters for [DelimiterSyntax] nodes. + final _delimiterStack = []; + + /// The tree of parsed HTML nodes. + final _tree = []; + + InlineParser(this.source, this.document) { + // User specified syntaxes are the first syntaxes to be evaluated. + syntaxes.addAll(document.inlineSyntaxes); + + // This first RegExp matches plain text to accelerate parsing. It's written + // so that it does not match any prefix of any following syntaxes. Most + // Markdown is plain text, so it's faster to match one RegExp per 'word' + // rather than fail to match all the following RegExps at each non-syntax + // character position. + if (document.hasCustomInlineSyntaxes) { + // We should be less aggressive in blowing past "words". + syntaxes.add(TextSyntax(r'[A-Za-z0-9]+(?=\s)')); + } else { + syntaxes.add(TextSyntax(r'[ \tA-Za-z0-9]*[A-Za-z0-9](?=\s)')); + } + + if (document.withDefaultInlineSyntaxes) { + // Custom link resolvers go after the generic text syntax. + syntaxes.addAll([ + EscapeSyntax(), + DecodeHtmlSyntax(), + LinkSyntax(linkResolver: document.linkResolver), + ImageSyntax(linkResolver: document.imageLinkResolver) + ]); + + syntaxes.addAll(_defaultSyntaxes); + } + + if (encodeHtml) { + syntaxes.addAll([ + EscapeHtmlSyntax(), + // Leave already-encoded HTML entities alone. Ensures we don't turn + // "&" into "&amp;" + TextSyntax('&[#a-zA-Z0-9]*;', startCharacter: $ampersand), + ]); + } + } + + List parse() { + while (!isDone) { + // A right bracket (']') is special. Hitting this character triggers the + // "look for link or image" procedure. + // See https://spec.commonmark.org/0.30/#an-algorithm-for-parsing-nested-emphasis-and-links. + if (charAt(pos) == $rbracket) { + writeText(); + _linkOrImage(); + continue; + } + + // See if the current text matches any defined Markdown syntax. + if (syntaxes.any((syntax) => syntax.tryMatch(this))) continue; + + // If we got here, it's just text. + advanceBy(1); + } + + // Write any trailing text content to a Text node. + writeText(); + _processDelimiterRun(-1); + _combineAdjacentText(_tree); + return _tree; + } + + /// Look back through the delimiter stack to see if we've found a link or + /// image. + /// + /// This is the "look for link or image" routine from the CommonMark spec: + /// https://spec.commonmark.org/0.30/#look-for-link-or-image. + void _linkOrImage() { + final index = _delimiterStack + .lastIndexWhere((d) => d.char == $lbracket || d.char == $exclamation); + if (index == -1) { + // Never found a possible open bracket. This is just a literal "]". + addNode(Text(']')); + advanceBy(1); + start = pos; + return; + } + final delimiter = _delimiterStack[index] as SimpleDelimiter; + if (!delimiter.isActive) { + _delimiterStack.removeAt(index); + addNode(Text(']')); + advanceBy(1); + start = pos; + return; + } + final syntax = delimiter.syntax; + if (syntax is LinkSyntax && syntaxes.any((e) => e is LinkSyntax)) { + final nodeIndex = _tree.lastIndexWhere((n) => n == delimiter.node); + final linkNodes = syntax.close(this, delimiter, null, getChildren: () { + _processDelimiterRun(index); + // All of the nodes which lie past [index] are children of this + // link/image. + final children = _tree.sublist(nodeIndex + 1, _tree.length); + _tree.removeRange(nodeIndex + 1, _tree.length); + return children; + }); + if (linkNodes != null) { + _delimiterStack.removeAt(index); + if (delimiter.char == $lbracket) { + for (final d in _delimiterStack.sublist(0, index)) { + if (d.char == $lbracket) d.isActive = false; + } + } + _tree.replaceRange(nodeIndex, _tree.length, linkNodes); + advanceBy(1); + start = pos; + } else { + _delimiterStack.removeAt(index); + pos = start; + advanceBy(1); + } + } else { + throw StateError('Non-link syntax delimiter found with character ' + '"${delimiter.char}"'); + } + } + + /// Rules 9 and 10. + bool _canFormEmphasis(Delimiter opener, Delimiter closer) { + if ((opener.canOpen && opener.canClose) || + (closer.canOpen && closer.canClose)) { + return (opener.length + closer.length) % 3 != 0 || + (opener.length % 3 == 0 && closer.length % 3 == 0); + } else { + return true; + } + } + + /// Processes [DelimiterRun] type delimiters from [bottomIndex] and up. + /// + /// This is the same strategy as "process emphasis" routine according to the + /// CommonMark spec: https://spec.commonmark.org/0.30/#phase-2-inline-structure. + void _processDelimiterRun(int bottomIndex) { + var currentIndex = bottomIndex + 1; + // Track the lowest index where we might find an open delimiter given a + // closing delimiter length modulo 3. + // Each key in this map is an open delimiter character. Each value is a + // 3-element list. Each value in the list is the lowest index for the given + // delimiter length modulo 3 (0, 1, 2). + final openersBottom = >{}; + while (currentIndex < _delimiterStack.length) { + final closer = _delimiterStack[currentIndex]; + if (!closer.canClose || closer is! DelimiterRun) { + currentIndex++; + continue; + } + openersBottom.putIfAbsent(closer.char, () => List.filled(3, bottomIndex)); + final openersBottomPerCloserLength = openersBottom[closer.char]!; + final openerBottom = openersBottomPerCloserLength[closer.length % 3]; + final openerIndex = _delimiterStack.lastIndexWhere( + (d) => + d.char == closer.char && d.canOpen && _canFormEmphasis(d, closer), + currentIndex - 1); + if (openerIndex > bottomIndex && openerIndex > openerBottom) { + // Found an opener for [closer]. + final opener = _delimiterStack[openerIndex]; + if (opener is! DelimiterRun) { + currentIndex++; + continue; + } + final matchedTagIndex = opener.tags.lastIndexWhere((e) => + opener.length >= e.indicatorLength && + closer.length >= e.indicatorLength); + if (matchedTagIndex == -1) { + currentIndex++; + continue; + } + final matchedTag = opener.tags[matchedTagIndex]; + final indicatorLength = matchedTag.indicatorLength; + final openerTextNode = opener.node; + final openerTextNodeIndex = _tree.indexOf(openerTextNode); + final closerTextNode = closer.node; + var closerTextNodeIndex = _tree.indexOf(closerTextNode); + final nodes = opener.syntax.close( + this, + opener, + closer, + tag: matchedTag.tag, + getChildren: () => _tree.sublist( + openerTextNodeIndex + 1, + closerTextNodeIndex, + ), + ); + // Replace all of the nodes between the opener and the closer (which + // are now the new emphasis node's children) with the emphasis node. + _tree.replaceRange( + openerTextNodeIndex + 1, + closerTextNodeIndex, + nodes!, + ); + // Slide [closerTextNodeIndex] back accordingly. + closerTextNodeIndex = openerTextNodeIndex + 2; + + _delimiterStack.removeRange(openerIndex + 1, currentIndex); + // Slide [currentIndex] back accordingly. + currentIndex = openerIndex + 1; + + // Remove delimiter characters, possibly removing nodes from the tree + // and Delimiters from the delimiter stack. + if (opener.length == indicatorLength) { + _tree.removeAt(openerTextNodeIndex); + _delimiterStack.removeAt(openerIndex); + // Slide [currentIndex] and [closerTextNodeIndex] back accordingly. + currentIndex--; + closerTextNodeIndex--; + } else { + final newOpenerTextNode = + Text(openerTextNode.text.substring(indicatorLength)); + _tree[openerTextNodeIndex] = newOpenerTextNode; + opener.node = newOpenerTextNode; + } + + if (closer.length == indicatorLength) { + _tree.removeAt(closerTextNodeIndex); + _delimiterStack.removeAt(currentIndex); + // [currentIndex] has just moved to point at the next delimiter; + // leave it. + } else { + final newCloserTextNode = + Text(closerTextNode.text.substring(indicatorLength)); + _tree[closerTextNodeIndex] = newCloserTextNode; + closer.node = newCloserTextNode; + // [currentIndex] needs to be considered again; leave it. + } + } else { + // No opener is found. + openersBottomPerCloserLength[closer.length % 3] = currentIndex - 1; + if (!closer.canOpen) { + _delimiterStack.removeAt(currentIndex); + // This advances [currentIndex] to the next delimiter. + } else { + currentIndex++; + } + } + } + + _delimiterStack.removeRange(bottomIndex + 1, _delimiterStack.length); + } + + // Combine any remaining adjacent Text nodes. This is important to produce + // correct output across newlines, where whitespace is sometimes compressed. + void _combineAdjacentText(List nodes) { + for (var i = 0; i < nodes.length - 1; i++) { + final node = nodes[i]; + if (node is Element && node.children != null) { + _combineAdjacentText(node.children!); + continue; + } + if (node is Text && nodes[i + 1] is Text) { + final buffer = + StringBuffer('${node.textContent}${nodes[i + 1].textContent}'); + var j = i + 2; + while (j < nodes.length && nodes[j] is Text) { + buffer.write(nodes[j].textContent); + j++; + } + nodes[i] = Text(buffer.toString()); + nodes.removeRange(i + 1, j); + } + } + } + + int charAt(int index) => source.codeUnitAt(index); + + void writeText() { + if (pos == start) { + return; + } + final text = source.substring(start, pos); + _tree.add(Text(text)); + start = pos; + } + + /// Add [node] to the current tree. + void addNode(Node node) { + _tree.add(node); + } + + /// Push [delimiter] onto the stack of [Delimiter]s. + void pushDelimiter(Delimiter delimiter) => _delimiterStack.add(delimiter); + + bool get isDone => pos == source.length; + + void advanceBy(int length) { + pos += length; + } + + void consume(int length) { + pos += length; + start = pos; + } + + bool get encodeHtml => document.encodeHtml; +} diff --git a/pkgs/markdown/lib/src/inline_syntaxes/autolink_extension_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/autolink_extension_syntax.dart new file mode 100644 index 000000000..0333abb3d --- /dev/null +++ b/pkgs/markdown/lib/src/inline_syntaxes/autolink_extension_syntax.dart @@ -0,0 +1,156 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../charcode.dart'; +import '../inline_parser.dart'; +import '../util.dart'; +import 'inline_syntax.dart'; + +/// Matches autolinks like `http://foo.com` and `foo@bar.com`. +class AutolinkExtensionSyntax extends InlineSyntax { + static const _linkPattern = + // Autolinks can only come at the beginning of a line, after whitespace, + // or any of the delimiting characters *, _, ~, and (. + // Note: Disable this piece for now, as Safari does not support + // lookarounds. Consider re-enabling later. + // r'(?<=^|[\s*_~(>])' + + // An extended url autolink will be recognised when one of the schemes + // http://, or https://, followed by a valid domain. See + // https://github.github.com/gfm/#extended-url-autolink. + r'(?:(?:https?|ftp):\/\/|www\.)' + + // A valid domain consists of segments of alphanumeric characters, + // underscores (_) and hyphens (-) separated by periods (.). There must + // be at least one period, and no underscores may be present in the last + // two segments of the domain. See + // https://github.github.com/gfm/#valid-domain. + r'(?:[-_a-z0-9]+\.)*(?:[-a-z0-9]+\.[-a-z0-9]+)' + + // After a valid domain, zero or more non-space non-< characters may + // follow. + r'[^\s<]*' + + // Trailing punctuation (specifically, ?, !, ., ,, :, *, _, and ~) will + // not be considered part of the autolink, though they may be included in + // the interior of the link. See + // https://github.github.com/gfm/#extended-autolink-path-validation. + // Note: Do not use negative lookbehind, as Safari does not support it. + // '(?`, it is invalid. See + // https://github.github.com/gfm/#autolinks-extension-. + if (startMatch[1] != null && parser.pos > 0) { + final precededBy = String.fromCharCode(parser.charAt(parser.pos - 1)); + const validPrecedingChars = {'\n', ' ', '*', '_', '~', '(', '>'}; + if (!validPrecedingChars.contains(precededBy)) { + return false; + } + } + + // When it is an email link and followed by `_` or `-`, it is invalid. See + // https://github.github.com/gfm/#example-633 + if (startMatch[2] != null && parser.source.length > startMatch.end) { + final followedBy = String.fromCharCode(parser.charAt(startMatch.end)); + const invalidFollowingChars = {'_', '-'}; + if (invalidFollowingChars.contains(followedBy)) { + return false; + } + } + + parser.writeText(); + return onMatch(parser, startMatch); + } + + @override + bool onMatch(InlineParser parser, Match match) { + int consumeLength; + + final isEmailLink = match[2] != null; + if (isEmailLink) { + consumeLength = match.match.length; + } else { + consumeLength = _getConsumeLength(match.match); + } + + var text = match.match.substring(0, consumeLength); + text = parser.encodeHtml ? escapeHtml(text) : text; + + var destination = text; + if (isEmailLink) { + destination = 'mailto:$destination'; + } else if (destination[0] == 'w') { + // When there is no scheme specified, insert the scheme `http`. + destination = 'http://$destination'; + } + + final anchor = Element.text('a', text) + ..attributes['href'] = Uri.encodeFull(destination); + + parser + ..addNode(anchor) + ..consume(consumeLength); + + return true; + } + + int _getConsumeLength(String text) { + var excludedLength = 0; + + // When an autolink ends in `)`, see + // https://github.github.com/gfm/#example-625. + if (text.endsWith(')')) { + final match = RegExp(r'(\(.*)?(\)+)$').firstMatch(text)!; + + if (match[1] == null) { + excludedLength = match[2]!.length; + } else { + var parenCount = 0; + for (var i = 0; i < text.length; i++) { + final char = text.codeUnitAt(i); + if (char == $lparen) { + parenCount++; + } else if (char == $rparen) { + parenCount--; + } + } + if (parenCount < 0) { + excludedLength = parenCount.abs(); + } + } + } + // If an autolink ends in a semicolon `;`, see + // https://github.github.com/gfm/#example-627 + else if (text.endsWith(';')) { + final match = RegExp(r'&[0-9a-z]+;$').firstMatch(text); + if (match != null) { + excludedLength = match.match.length; + } + } + + return text.length - excludedLength; + } +} diff --git a/pkgs/markdown/lib/src/inline_syntaxes/autolink_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/autolink_syntax.dart new file mode 100644 index 000000000..073c1cc22 --- /dev/null +++ b/pkgs/markdown/lib/src/inline_syntaxes/autolink_syntax.dart @@ -0,0 +1,27 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../inline_parser.dart'; +import '../util.dart'; +import 'inline_syntax.dart'; + +/// Matches autolinks like ``. +class AutolinkSyntax extends InlineSyntax { + AutolinkSyntax() : super(r'<(([a-zA-Z][a-zA-Z\-\+\.]+):(?://)?[^\s>]*)>'); + + @override + bool onMatch(InlineParser parser, Match match) { + final url = match[1]!; + final text = parser.encodeHtml ? escapeHtml(url) : url; + final anchor = Element.text('a', text); + + final destination = normalizeLinkDestination(url); + anchor.attributes['href'] = + parser.encodeHtml ? escapeHtml(destination) : destination; + parser.addNode(anchor); + + return true; + } +} diff --git a/pkgs/markdown/lib/src/inline_syntaxes/code_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/code_syntax.dart new file mode 100644 index 000000000..35783d396 --- /dev/null +++ b/pkgs/markdown/lib/src/inline_syntaxes/code_syntax.dart @@ -0,0 +1,88 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../charcode.dart'; +import '../inline_parser.dart'; +import '../util.dart'; +import 'inline_syntax.dart'; + +/// Matches backtick-enclosed inline code blocks. +class CodeSyntax extends InlineSyntax { + // This pattern matches: + // + // * a string of backticks (not followed by any more), followed by + // * a non-greedy string of anything, including newlines, ending with anything + // except a backtick, followed by + // * a string of backticks the same length as the first, not followed by any + // more. + // + // This conforms to the delimiters of inline code, both in Markdown.pl, and + // CommonMark. + static const _pattern = r'(`+(?!`))((?:.|\n)*?[^`])\1(?!`)'; + + CodeSyntax() : super(_pattern); + + @override + bool tryMatch(InlineParser parser, [int? startMatchPos]) { + if (parser.pos > 0 && parser.charAt(parser.pos - 1) == $backquote) { + // Not really a match! We can't just sneak past one backtick to try the + // next character. An example of this situation would be: + // + // before ``` and `` after. + // ^--parser.pos + return false; + } + + final match = pattern.matchAsPrefix(parser.source, parser.pos); + if (match == null) { + return false; + } + parser.writeText(); + if (onMatch(parser, match)) parser.consume(match.match.length); + return true; + } + + @override + bool onMatch(InlineParser parser, Match match) { + final markerLength = match[1]!.length; + final contentLength = match.match.length - markerLength * 2; + final contentStart = parser.pos + markerLength; + final contentEnd = contentStart + contentLength; + + var code = parser.source.substring(contentStart, contentEnd); + if (_shouldStrip(code)) { + code = code.substring(1, code.length - 1); + } + code = code.replaceAll('\n', ' '); + + if (parser.encodeHtml) { + code = escapeHtml(code, escapeApos: false); + } + + parser.addNode(Element.text('code', code)); + return true; + } + + bool _shouldStrip(String code) { + // No stripping occurs if the code span contains only spaces: + // https://spec.commonmark.org/0.30/#example-334. + if (code.trim().isEmpty) { + return false; + } + + // Only spaces, and not unicode whitespace in general, are stripped in this + // way, see https://spec.commonmark.org/0.30/#example-333. + final startsWithSpace = code.startsWith(' ') || code.startsWith('\n'); + final endsWithSpace = code.endsWith(' ') || code.endsWith('\n'); + + // The stripping only happens if the space is on both sides of the string: + // https://spec.commonmark.org/0.30/#example-332. + if (!startsWithSpace || !endsWithSpace) { + return false; + } + + return true; + } +} diff --git a/pkgs/markdown/lib/src/inline_syntaxes/color_swatch_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/color_swatch_syntax.dart new file mode 100644 index 000000000..e44fdbf5b --- /dev/null +++ b/pkgs/markdown/lib/src/inline_syntaxes/color_swatch_syntax.dart @@ -0,0 +1,79 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../charcode.dart'; +import '../inline_parser.dart'; +import '../util.dart'; +import 'inline_syntax.dart'; + +/// Matches code blocks containing a subset of CSS color syntax. +class ColorSwatchSyntax extends InlineSyntax { + /// This pattern matches: + /// * GitHub Flavored Markup supports fewer of these options, GitLab Flavored + /// Markup supports all of these. Presumably GitHub will be more complete at + /// some point. + /// * CSS style '#' prefixed color hex codes in 3,4,6 or 8 digits in length. + /// * CSS style RGB()/RgbA()/Hsl()/HSLA() style color declarations, of any + /// capitalization. + /// EXAMPLES: + /// * `#f00` + /// * `#BA` (2 digit hex, regex will not match) + /// * `#F00a` + /// * `#F0BAD` (5 digit hex, regex will not match) + /// * `#FF0000` + /// * `#F000BAD` (7 digit hex, regex will not match) + /// * `#FF0000aA` (GitHub supports only this style) + /// * `RGB(0,255,0)` + /// * `rgb(0,255,0)` + /// * `RGB(0%,100%,0%)` + /// * `rgb(0%,100%,0%)` + /// * `RGBA(0,255,0,0.3)` + /// * `rgba(0,255,0,0.3)` + /// * `HSL(540,70%,50%)` + /// * `hsl(540,70%,50%)` + /// * `HSLA(540,70%,50%,0.3)` + /// * `Hsla(540,70%,50%,0.3)` + static const _pattern = + '`((#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{4}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{8}))|' + r'([Rr][Gg][Bb][Aa]?\((\d+[%]?),(\d+[%]?),(\d+[%]?),?(\d+\.?\d+[%]?)?\))|' + r'([Hh][Ss][Ll][Aa]?\((\d+[%]?),(\d+[%]?),(\d+[%]?),?(\d+\.?\d+[%]?)?\)))`'; + + ColorSwatchSyntax() : super(_pattern); + + @override + bool tryMatch(InlineParser parser, [int? startMatchPos]) { + if (parser.pos > 0 && parser.charAt(parser.pos - 1) == $backquote) { + // Not really a match! We can't just sneak past one backtick to try the + // next character. An example of this situation would be: + // + // before ``` and `` after. + // ^--parser.pos + return false; + } + + final match = pattern.matchAsPrefix(parser.source, parser.pos); + if (match == null) { + return false; + } + parser.writeText(); + if (onMatch(parser, match)) parser.consume(match.match.length); + return true; + } + + @override + bool onMatch(InlineParser parser, Match match) { + var code = match[1]!.trim().replaceAll('\n', ' '); + + if (parser.encodeHtml) code = escapeHtml(code); + + parser.addNode(Element('code', [ + Text(code), + Element.withTag('span')..attributes['style'] = 'background-color:$code;', + ]) + ..attributes['class'] = 'gfm-color_chip'); + + return true; + } +} diff --git a/pkgs/markdown/lib/src/inline_syntaxes/decode_html_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/decode_html_syntax.dart new file mode 100644 index 000000000..1af15d53c --- /dev/null +++ b/pkgs/markdown/lib/src/inline_syntaxes/decode_html_syntax.dart @@ -0,0 +1,51 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../assets/html_entities.dart'; +import '../ast.dart'; +import '../charcode.dart'; +import '../inline_parser.dart'; +import '../patterns.dart'; +import '../util.dart'; +import 'inline_syntax.dart'; + +/// Decodes numeric character references, for example decode `#` to `#`. +// https://spec.commonmark.org/0.30/#entity-and-numeric-character-references +class DecodeHtmlSyntax extends InlineSyntax { + DecodeHtmlSyntax() + : super(htmlCharactersPattern.pattern, + caseSensitive: false, startCharacter: $ampersand); + + @override + bool tryMatch(InlineParser parser, [int? startMatchPos]) { + if (parser.pos > 0 && parser.charAt(parser.pos - 1) == $backquote) { + return false; + } + + final match = pattern.matchAsPrefix(parser.source, parser.pos); + if (match == null) { + return false; + } + + if (match[1] != null && htmlEntitiesMap[match.match] == null) { + return false; + } + + parser.writeText(); + if (onMatch(parser, match)) parser.consume(match.match.length); + return true; + } + + @override + bool onMatch(InlineParser parser, Match match) { + var decodedText = decodeHtmlCharacterFromMatch(match); + + if (parser.encodeHtml) { + decodedText = escapeHtml(decodedText); + } + + parser.addNode(Text(decodedText)); + return true; + } +} diff --git a/pkgs/markdown/lib/src/inline_syntaxes/delimiter_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/delimiter_syntax.dart new file mode 100644 index 000000000..f26bdc9b3 --- /dev/null +++ b/pkgs/markdown/lib/src/inline_syntaxes/delimiter_syntax.dart @@ -0,0 +1,337 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../inline_parser.dart'; +import '../patterns.dart'; +import 'inline_syntax.dart'; + +/// Matches syntax that has a pair of tags and becomes an element, like `*` for +/// ``. Allows nested tags. +class DelimiterSyntax extends InlineSyntax { + /// Whether this is parsed according to the same nesting rules as [emphasis + /// delimiters][]. + /// + /// [emphasis delimiters]: https://spec.commonmark.org/0.30/#can-open-emphasis + final bool requiresDelimiterRun; + + /// Whether to allow intra-word delimiter runs. CommonMark emphasis and + /// strong emphasis does not allow this, but GitHub-Flavored Markdown allows + /// it on strikethrough. + final bool allowIntraWord; + + final List? tags; + + /// Creates a new [DelimiterSyntax] which matches text on [pattern]. + /// + /// The [pattern] is used to find the matching text. If [requiresDelimiterRun] + /// is passed, this syntax parses according to the same nesting rules as + /// emphasis delimiters. If [startCharacter] is passed, it is used as a + /// pre-matching check which is faster than matching against [pattern]. + DelimiterSyntax( + super.pattern, { + this.requiresDelimiterRun = false, + super.startCharacter, + this.allowIntraWord = false, + this.tags, + }); + + @override + bool onMatch(InlineParser parser, Match match) { + final runLength = match.group(0)!.length; + final matchStart = parser.pos; + final matchEnd = parser.pos + runLength; + final text = Text(parser.source.substring(matchStart, matchEnd)); + if (!requiresDelimiterRun) { + parser.pushDelimiter(SimpleDelimiter( + node: text, + length: runLength, + char: parser.source.codeUnitAt(matchStart), + canOpen: true, + canClose: false, + syntax: this, + endPos: matchEnd, + )); + parser.addNode(text); + return true; + } + + final delimiterRun = DelimiterRun.tryParse( + parser, + matchStart, + matchEnd, + syntax: this, + node: text, + allowIntraWord: allowIntraWord, + tags: tags ?? const [], + ); + if (delimiterRun != null) { + parser.pushDelimiter(delimiterRun); + parser.addNode(text); + return true; + } else { + parser.advanceBy(runLength); + return false; + } + } + + /// Attempts to close this tag at the current position. + /// + /// If a tag cannot be closed at the current position (for example, if a link + /// reference cannot be found for a link tag's label), then `null` is + /// returned. + /// + /// If a tag can be closed at the current position, then this method calls + /// [getChildren], in which [parser] parses any nested text into child nodes. + /// The returned [Iterable] includes these children nodes. + Iterable? close( + InlineParser parser, + Delimiter opener, + Delimiter closer, { + required String tag, + required List Function() getChildren, + }) { + return [Element(tag, getChildren())]; + } +} + +class DelimiterTag { + DelimiterTag(this.tag, this.indicatorLength); + + // Tag name of the HTML element. + final String tag; + + final int indicatorLength; +} + +/// A delimiter indicating the possible "open" or possible "close" of a tag for +/// a [DelimiterSyntax]. +abstract class Delimiter { + /// The [Text] node representing the plain text representing this delimiter. + abstract Text node; + + /// The type of delimiter. + /// + /// For the two-character image delimiter, `![`, this is `!`. + int get char; + + /// The number of delimiters. + int get length; + + /// Whether the delimiter is active. + /// + /// Links cannot be nested, so we must "deactivate" any pending ones. For + /// example, take the following text: + /// + /// Text [link and [more](links)](links). + /// + /// Once we have parsed `Text [`, there is one (pending) link in the state + /// stack. It is, by default, active. Once we parse the next possible link, + /// `[more](links)`, as a real link, we must deactive the pending links (just + /// the one, in this case). + abstract bool isActive; + + /// Whether this delimiter can open emphasis or strong emphasis. + bool get canOpen; + + /// Whether this delimiter can close emphasis or strong emphasis. + bool get canClose; + + /// The syntax which uses this delimiter to parse a tag. + DelimiterSyntax get syntax; +} + +/// A simple delimiter implements the [Delimiter] interface with basic fields, +/// and does not have the concept of "left-flanking" or "right-flanking". +class SimpleDelimiter implements Delimiter { + @override + Text node; + + @override + final int char; + + @override + final int length; + + @override + bool isActive; + + @override + final bool canOpen; + + @override + final bool canClose; + + @override + final DelimiterSyntax syntax; + + final int endPos; + + SimpleDelimiter({ + required this.node, + required this.char, + required this.length, + required this.canOpen, + required this.canClose, + required this.syntax, + required this.endPos, + }) : isActive = true; +} + +/// An implementation of [Delimiter] which uses concepts of "left-flanking" and +/// "right-flanking" to determine the values of [canOpen] and [canClose]. +/// +/// This is primarily used when parsing emphasis and strong emphasis, but can +/// also be used by other extensions of [DelimiterSyntax]. +class DelimiterRun implements Delimiter { + /// According to + /// [CommonMark](https://spec.commonmark.org/0.30/#unicode-punctuation-character): + /// + /// > A punctuation character is an ASCII punctuation character or anything in + /// > the general Unicode categories `Pc`, `Pd`, `Pe`, `Pf`, `Pi`, `Po`, or + /// > `Ps`. + // This RegExp is inspired by + // https://github.com/commonmark/commonmark.js/blob/1f7d09099c20d7861a674674a5a88733f55ff729/lib/inlines.js#L39. + // I don't know if there is any way to simplify it or maintain it. + static final unicodePunctuationPattern = RegExp('[' + '$asciiPunctuationEscaped' + r'\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE' + r'\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E' + r'\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E' + r'\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14' + r'\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB' + r'\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736' + r'\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F' + r'\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E' + r'\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051' + r'\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A' + r'\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC' + r'\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E42' + r'\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE' + r'\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF' + r'\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF' + r'\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19' + r'\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03' + r'\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F' + r'\uFF5B\uFF5D\uFF5F-\uFF65' + ']'); + + /// Unicode whitespace. + // See https://spec.commonmark.org/0.30/#unicode-whitespace-character. + // Unicode Zs: https://www.compart.com/en/unicode/category. + static const unicodeWhitespace = '\u0020\u0009\u000A\u000C\u000D' + '\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008' + '\u2009\u200A\u202F\u205F\u3000'; + + @override + Text node; + + @override + final int char; + + @override + int get length => node.text.length; + + @override + bool isActive; + + @override + final DelimiterSyntax syntax; + + final bool allowIntraWord; + + @override + final bool canOpen; + + @override + final bool canClose; + + final List tags; + + DelimiterRun._({ + required this.node, + required this.char, + required this.syntax, + required this.tags, + required bool isLeftFlanking, + required bool isRightFlanking, + required bool isPrecededByPunctuation, + required bool isFollowedByPunctuation, + required this.allowIntraWord, + }) : canOpen = isLeftFlanking && + (!isRightFlanking || allowIntraWord || isPrecededByPunctuation), + canClose = isRightFlanking && + (!isLeftFlanking || allowIntraWord || isFollowedByPunctuation), + isActive = true; + + /// Tries to parse a delimiter run from [runStart] (inclusive) to [runEnd] + /// (exclusive). + static DelimiterRun? tryParse( + InlineParser parser, + int runStart, + int runEnd, { + required DelimiterSyntax syntax, + required List tags, + required Text node, + bool allowIntraWord = false, + }) { + bool precededByWhitespace; + bool followedByWhitespace; + bool precededByPunctuation; + bool followedByPunctuation; + + if (runStart == 0) { + precededByWhitespace = true; + precededByPunctuation = false; + } else { + final preceding = parser.source.substring(runStart - 1, runStart); + precededByWhitespace = unicodeWhitespace.contains(preceding); + precededByPunctuation = !precededByWhitespace && + unicodePunctuationPattern.hasMatch(preceding); + } + + if (runEnd == parser.source.length) { + followedByWhitespace = true; + followedByPunctuation = false; + } else { + final following = parser.source.substring(runEnd, runEnd + 1); + followedByWhitespace = unicodeWhitespace.contains(following); + followedByPunctuation = !followedByWhitespace && + unicodePunctuationPattern.hasMatch(following); + } + + // If it is a left-flanking delimiter run, see + // https://spec.commonmark.org/0.30/#left-flanking-delimiter-run. + final isLeftFlanking = !followedByWhitespace && + (!followedByPunctuation || + precededByWhitespace || + precededByPunctuation); + + // If it is a right-flanking delimiter run, see + // https://spec.commonmark.org/0.30/#right-flanking-delimiter-run. + final isRightFlanking = !precededByWhitespace && + (!precededByPunctuation || + followedByWhitespace || + followedByPunctuation); + + // Make sure the shorter delimiter takes precedence. + tags.sort((a, b) => a.indicatorLength.compareTo(b.indicatorLength)); + + return DelimiterRun._( + node: node, + char: parser.charAt(runStart), + syntax: syntax, + tags: tags, + isLeftFlanking: isLeftFlanking, + isRightFlanking: isRightFlanking, + isPrecededByPunctuation: precededByPunctuation, + isFollowedByPunctuation: followedByPunctuation, + allowIntraWord: allowIntraWord, + ); + } + + @override + String toString() => ''; +} diff --git a/pkgs/markdown/lib/src/inline_syntaxes/email_autolink_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/email_autolink_syntax.dart new file mode 100644 index 000000000..212f1a493 --- /dev/null +++ b/pkgs/markdown/lib/src/inline_syntaxes/email_autolink_syntax.dart @@ -0,0 +1,31 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../charcode.dart'; +import '../inline_parser.dart'; +import '../util.dart'; +import 'inline_syntax.dart'; + +/// Matches autolinks like ``. +/// +/// See . +class EmailAutolinkSyntax extends InlineSyntax { + static const _email = + r'''[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}''' + r'''[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*'''; + + EmailAutolinkSyntax() : super('<($_email)>', startCharacter: $lt); + + @override + bool onMatch(InlineParser parser, Match match) { + final url = match[1]!; + final text = parser.encodeHtml ? escapeHtml(url) : url; + final anchor = Element.text('a', text); + anchor.attributes['href'] = Uri.encodeFull('mailto:$url'); + parser.addNode(anchor); + + return true; + } +} diff --git a/pkgs/markdown/lib/src/inline_syntaxes/emoji_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/emoji_syntax.dart new file mode 100644 index 000000000..a068c6b46 --- /dev/null +++ b/pkgs/markdown/lib/src/inline_syntaxes/emoji_syntax.dart @@ -0,0 +1,32 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../emojis.dart'; +import '../inline_parser.dart'; +import 'inline_syntax.dart'; + +/// Matches GitHub Markdown emoji syntax like `:smile:`. +/// +/// There is no formal specification of GitHub's support for this colon-based +/// emoji support, so this syntax is based on the results of Markdown-enabled +/// text fields at github.com. +class EmojiSyntax extends InlineSyntax { + // Emoji "aliases" are mostly limited to lower-case letters, numbers, and + // underscores, but GitHub also supports `:+1:` and `:-1:`. + EmojiSyntax() : super(':([a-z0-9_+-]+):'); + + @override + bool onMatch(InlineParser parser, Match match) { + final alias = match[1]!; + final emoji = emojis[alias]; + if (emoji == null) { + parser.advanceBy(1); + return false; + } + parser.addNode(Text(emoji)); + + return true; + } +} diff --git a/pkgs/markdown/lib/src/inline_syntaxes/emphasis_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/emphasis_syntax.dart new file mode 100644 index 000000000..58f2e7001 --- /dev/null +++ b/pkgs/markdown/lib/src/inline_syntaxes/emphasis_syntax.dart @@ -0,0 +1,29 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../charcode.dart'; +import 'delimiter_syntax.dart'; + +class EmphasisSyntax extends DelimiterSyntax { + /// Parses `__strong__` and `_emphasis_`. + EmphasisSyntax.underscore() + : super( + '_+', + requiresDelimiterRun: true, + tags: _tags, + startCharacter: $underscore, + ); + + /// Parses `**strong**` and `*emphasis*`. + EmphasisSyntax.asterisk() + : super( + r'\*+', + requiresDelimiterRun: true, + allowIntraWord: true, + tags: _tags, + startCharacter: $asterisk, + ); + + static final _tags = [DelimiterTag('em', 1), DelimiterTag('strong', 2)]; +} diff --git a/pkgs/markdown/lib/src/inline_syntaxes/escape_html_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/escape_html_syntax.dart new file mode 100644 index 000000000..565f870a7 --- /dev/null +++ b/pkgs/markdown/lib/src/inline_syntaxes/escape_html_syntax.dart @@ -0,0 +1,20 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../inline_parser.dart'; +import '../util.dart'; +import 'inline_syntax.dart'; + +/// Encodes (`"`), (`<`), (`>`) and (`&`). +class EscapeHtmlSyntax extends InlineSyntax { + EscapeHtmlSyntax() : super('["<>&]'); + @override + bool onMatch(InlineParser parser, Match match) { + final text = escapeHtml(match[0]!); + parser.addNode(Text(text)); + + return true; + } +} diff --git a/pkgs/markdown/lib/src/inline_syntaxes/escape_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/escape_syntax.dart new file mode 100644 index 000000000..c112d930f --- /dev/null +++ b/pkgs/markdown/lib/src/inline_syntaxes/escape_syntax.dart @@ -0,0 +1,34 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../charcode.dart'; +import '../inline_parser.dart'; +import '../patterns.dart'; +import '../util.dart'; +import 'inline_syntax.dart'; + +/// Escape ASCII punctuation preceded by a backslash. +/// +/// Backslashes before other characters are treated as literal backslashes. +// See https://spec.commonmark.org/0.30/#backslash-escapes. +class EscapeSyntax extends InlineSyntax { + EscapeSyntax() + : super('\\\\([$asciiPunctuationEscaped])', startCharacter: $backslash); + + @override + bool onMatch(InlineParser parser, Match match) { + final chars = match.match; + + String text; + if ('&"<>'.contains(match[1]!) && parser.encodeHtml) { + text = escapeHtml(match[1]!); + } else { + text = chars[1]; + } + + parser.addNode(Text(text)); + return true; + } +} diff --git a/pkgs/markdown/lib/src/inline_syntaxes/footnote_ref_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/footnote_ref_syntax.dart new file mode 100644 index 000000000..155fd74c4 --- /dev/null +++ b/pkgs/markdown/lib/src/inline_syntaxes/footnote_ref_syntax.dart @@ -0,0 +1,72 @@ +import '../ast.dart' show Element, Node, Text; +import '../charcode.dart'; +import 'link_syntax.dart' show LinkContext; + +/// The spec of GFM about footnotes is +/// [missing](https://github.com/github/cmark-gfm/issues/283#issuecomment-1378868725). +/// For source code of cmark-gfm, see the `noMatch` label of the +/// `handle_close_bracket` function in [master@c32ef78](https://github.com/github/cmark-gfm/blob/c32ef78/src/inlines.c#L1236). +/// A Rust implementation is also [available](https://github.com/wooorm/markdown-rs/blob/2498e31eecead798efc649502bbf5f86feaa94be/src/construct/gfm_label_start_footnote.rs). +/// Footnotes shares the same syntax with [LinkSyntax], +/// but have a different branch of handling the close bracket. +class FootnoteRefSyntax { + static String? _footnoteLabel(String key) { + if (key.isEmpty || key.codeUnitAt(0) != $caret) { + return null; + } + key = key.substring(1).trim().toLowerCase(); + if (key.isEmpty) { + return null; + } + return key; + } + + static Iterable? tryCreateFootnoteLink( + LinkContext context, + String text, { + bool? secondary, + }) { + secondary ??= false; + final parser = context.parser; + final key = _footnoteLabel(text); + final refs = parser.document.footnoteReferences; + // `label` is what footnoteReferences stored, it is case sensitive. + final label = + refs.keys.firstWhere((k) => k.toLowerCase() == key, orElse: () => ''); + // `count != null` means footnote was valid. + var count = refs[label]; + // And then check if footnote was matched. + if (key == null || count == null) { + return null; + } + final result = []; + // There are 4 cases here: ![^...], [^...], ![...][^...], [...][^...] + if (context.opener.char == $exclamation) { + result.add(Text('!')); + } + refs[label] = ++count; + final labels = parser.document.footnoteLabels; + var pos = labels.indexOf(key); + if (pos < 0) { + pos = labels.length; + labels.add(key); + } + + // `children` are text segments after '[^' before ']'. + final children = context.getChildren(); + if (secondary) { + result.add(Text('[')); + result.addAll(children); + result.add(Text(']')); + } + final id = Uri.encodeComponent(label); + final suffix = count > 1 ? '-$count' : ''; + final link = Element('a', [Text('${pos + 1}')]) + // Ignore GitHub's attribute: . + ..attributes['href'] = '#fn-$id' + ..attributes['id'] = 'fnref-$id$suffix'; + final sup = Element('sup', [link])..attributes['class'] = 'footnote-ref'; + result.add(sup); + return result; + } +} diff --git a/pkgs/markdown/lib/src/inline_syntaxes/image_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/image_syntax.dart new file mode 100644 index 000000000..a8b2c3585 --- /dev/null +++ b/pkgs/markdown/lib/src/inline_syntaxes/image_syntax.dart @@ -0,0 +1,44 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../charcode.dart'; +import '../util.dart'; +import 'link_syntax.dart'; + +/// Matches images like `![alternate text](url "optional title")` and +/// `![alternate text][label]`. +class ImageSyntax extends LinkSyntax { + ImageSyntax({super.linkResolver}) + : super( + pattern: r'!\[', + startCharacter: $exclamation, + ); + + @override + Element createNode( + String destination, + String? title, { + required List Function() getChildren, + }) { + final element = Element.empty('img'); + final children = getChildren(); + element.attributes['src'] = normalizeLinkDestination( + escapePunctuation(destination), + ); + element.attributes['alt'] = children.map((node) { + // See https://spec.commonmark.org/0.30/#image-description. + // An image description may contain links. Fetch text from the alt + // attribute if this nested link is an image. + if (node is Element && node.tag == 'img') { + return node.attributes['alt']; + } + return node.textContent; + }).join(); + if (title != null && title.isNotEmpty) { + element.attributes['title'] = normalizeLinkTitle(title); + } + return element; + } +} diff --git a/pkgs/markdown/lib/src/inline_syntaxes/inline_html_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/inline_html_syntax.dart new file mode 100644 index 000000000..3a7ce77dd --- /dev/null +++ b/pkgs/markdown/lib/src/inline_syntaxes/inline_html_syntax.dart @@ -0,0 +1,44 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../../markdown.dart'; +import '../charcode.dart'; +import '../patterns.dart'; + +/// Leave inline HTML tags alone, from +/// [CommonMark 0.30](https://spec.commonmark.org/0.30/#raw-html). +/// +/// This is not actually a good definition (nor CommonMark's) of an HTML tag, +/// but it is fast. It will leave text like `]+-[^-<>]+)+|[^-<>]+)-->' + '|' + + // Processing-instruction, see + // https://spec.commonmark.org/0.30/#processing-instruction + r'<\?.*?\?>' + '|' + + // Declaration, see + // https://spec.commonmark.org/0.30/#declaration. + '()' + '|' + + // CDATA section, see + // https://spec.commonmark.org/0.30/#cdata-section. + r'()'; + + InlineHtmlSyntax() + : super(_pattern, startCharacter: $lt, caseSensitive: false); +} diff --git a/pkgs/markdown/lib/src/inline_syntaxes/inline_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/inline_syntax.dart new file mode 100644 index 000000000..997d03a75 --- /dev/null +++ b/pkgs/markdown/lib/src/inline_syntaxes/inline_syntax.dart @@ -0,0 +1,58 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../inline_parser.dart'; +import '../util.dart'; + +/// Represents one kind of Markdown tag that can be parsed. +abstract class InlineSyntax { + final RegExp pattern; + + /// The first character of [pattern], to be used as an efficient first check + /// that this syntax matches the current parser position. + final int? _startCharacter; + + /// Create a new [InlineSyntax] which matches text on [pattern]. + /// + /// If [startCharacter] is passed, it is used as a pre-matching check which + /// is faster than matching against [pattern]. + /// + /// If [caseSensitive] is disabled, then case is ignored when matching + /// the [pattern]. + InlineSyntax(String pattern, {int? startCharacter, bool caseSensitive = true}) + : pattern = + RegExp(pattern, multiLine: true, caseSensitive: caseSensitive), + _startCharacter = startCharacter; + + /// Tries to match at the parser's current position. + /// + /// The parser's position can be overriden with [startMatchPos]. + /// Returns whether or not the pattern successfully matched. + bool tryMatch(InlineParser parser, [int? startMatchPos]) { + startMatchPos ??= parser.pos; + + // Before matching with the regular expression [pattern], which can be + // expensive on some platforms, check if even the first character matches + // this syntax. + if (_startCharacter != null && + parser.source.codeUnitAt(startMatchPos) != _startCharacter) { + return false; + } + + final startMatch = pattern.matchAsPrefix(parser.source, startMatchPos); + if (startMatch == null) return false; + + // Write any existing plain text up to this point. + parser.writeText(); + + if (onMatch(parser, startMatch)) parser.consume(startMatch.match.length); + return true; + } + + /// Processes [match], adding nodes to [parser] and possibly advancing + /// [parser]. + /// + /// Returns whether the caller should advance [parser] by `match[0].length`. + bool onMatch(InlineParser parser, Match match); +} diff --git a/pkgs/markdown/lib/src/inline_syntaxes/line_break_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/line_break_syntax.dart new file mode 100644 index 000000000..0a5fb01ad --- /dev/null +++ b/pkgs/markdown/lib/src/inline_syntaxes/line_break_syntax.dart @@ -0,0 +1,19 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../inline_parser.dart'; +import 'inline_syntax.dart'; + +/// Represents a hard line break. +class LineBreakSyntax extends InlineSyntax { + LineBreakSyntax() : super(r'(?:\\| +)\n'); + + /// Create a void
element. + @override + bool onMatch(InlineParser parser, Match match) { + parser.addNode(Element.empty('br')); + return true; + } +} diff --git a/pkgs/markdown/lib/src/inline_syntaxes/link_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/link_syntax.dart new file mode 100644 index 000000000..bca3efbe0 --- /dev/null +++ b/pkgs/markdown/lib/src/inline_syntaxes/link_syntax.dart @@ -0,0 +1,479 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../charcode.dart'; +import '../document.dart'; +import '../inline_parser.dart'; +import '../util.dart'; +import 'delimiter_syntax.dart'; +import 'footnote_ref_syntax.dart'; + +/// A helper class holds params of link context. +/// Footnote creation needs other info in [_tryCreateReferenceLink]. +class LinkContext { + final InlineParser parser; + final SimpleDelimiter opener; + final List Function() getChildren; + + const LinkContext(this.parser, this.opener, this.getChildren); +} + +/// Matches links like `[blah][label]` and `[blah](url)`. +class LinkSyntax extends DelimiterSyntax { + static final _entirelyWhitespacePattern = RegExp(r'^\s*$'); + + final Resolver linkResolver; + + LinkSyntax({ + Resolver? linkResolver, + String pattern = r'\[', + int startCharacter = $lbracket, + }) : linkResolver = (linkResolver ?? ((String _, [String? __]) => null)), + super(pattern, startCharacter: startCharacter); + + @override + Iterable? close( + InlineParser parser, + covariant SimpleDelimiter opener, + Delimiter? closer, { + String? tag, + required List Function() getChildren, + }) { + final context = LinkContext(parser, opener, getChildren); + final text = parser.source.substring(opener.endPos, parser.pos); + // The current character is the `]` that closed the link text. Examine the + // next character, to determine what type of link we might have (a '(' + // means a possible inline link; otherwise a possible reference link). + if (parser.pos + 1 >= parser.source.length) { + // The `]` is at the end of the document, but this may still be a valid + // shortcut reference link. + return _tryCreateReferenceLink(context, text); + } + + // Peek at the next character; don't advance, so as to avoid later stepping + // backward. + final char = parser.charAt(parser.pos + 1); + + if (char == $lparen) { + // Maybe an inline link, like `[text](destination)`. + parser.advanceBy(1); + final leftParenIndex = parser.pos; + final inlineLink = _parseInlineLink(parser); + if (inlineLink != null) { + return [ + _tryCreateInlineLink( + parser, + inlineLink, + getChildren: getChildren, + ), + ]; + } + // At this point, we've matched `[...](`, but that `(` did not pan out to + // be an inline link. We must now check if `[...]` is simply a shortcut + // reference link. + + // Reset the parser position. + parser.pos = leftParenIndex; + parser.advanceBy(-1); + return _tryCreateReferenceLink(context, text); + } + + if (char == $lbracket) { + parser.advanceBy(1); + // At this point, we've matched `[...][`. Maybe a *full* reference link, + // like `[foo][bar]` or a *collapsed* reference link, like `[foo][]`. + if (parser.pos + 1 < parser.source.length && + parser.charAt(parser.pos + 1) == $rbracket) { + // That opening `[` is not actually part of the link. Maybe a + // *shortcut* reference link (followed by a `[`). + parser.advanceBy(1); + return _tryCreateReferenceLink(context, text); + } + final label = _parseReferenceLinkLabel(parser); + if (label != null) { + return _tryCreateReferenceLink(context, label, secondary: true); + } + return null; + } + + // The link text (inside `[...]`) was not followed with a opening `(` nor + // an opening `[`. Perhaps just a simple shortcut reference link (`[...]`). + return _tryCreateReferenceLink(context, text); + } + + /// Resolve a possible reference link. + /// + /// Uses [linkReferences], [linkResolver], and [createNode] to try to + /// resolve [label] into a [Node]. If [label] is defined in + /// [linkReferences] or can be resolved by [linkResolver], returns a [Node] + /// that links to the resolved URL. + /// + /// Otherwise, returns `null`. + /// + /// [label] does not need to be normalized. + Node? _resolveReferenceLink( + String label, + Map linkReferences, { + required List Function() getChildren, + }) { + final linkReference = linkReferences[normalizeLinkLabel(label)]; + if (linkReference != null) { + return createNode( + linkReference.destination, + linkReference.title, + getChildren: getChildren, + ); + } else { + // This link has no reference definition. But we allow users of the + // library to specify a custom resolver function ([linkResolver]) that + // may choose to handle this. Otherwise, it's just treated as plain + // text. + + // Normally, label text does not get parsed as inline Markdown. However, + // for the benefit of the link resolver, we need to at least escape + // brackets, so that, e.g. a link resolver can receive `[\[\]]` as `[]`. + final resolved = linkResolver(label + .replaceAll(r'\\', r'\') + .replaceAll(r'\[', '[') + .replaceAll(r'\]', ']')); + if (resolved != null) { + getChildren(); + } + return resolved; + } + } + + /// Create the node represented by a Markdown link. + Node createNode( + String destination, + String? title, { + required List Function() getChildren, + }) { + final children = getChildren(); + final element = Element('a', children); + element.attributes['href'] = normalizeLinkDestination( + escapePunctuation(destination), + ); + if (title != null && title.isNotEmpty) { + element.attributes['title'] = normalizeLinkTitle( + escapePunctuation(title), + ); + } + return element; + } + + /// Tries to create a reference link node. + /// + /// Returns the nodes if it was successfully created, `null` otherwise. + Iterable? _tryCreateReferenceLink( + LinkContext context, + String label, { + bool? secondary, + }) { + final parser = context.parser; + final getChildren = context.getChildren; + final link = _resolveReferenceLink( + label, + parser.document.linkReferences, + getChildren: getChildren, + ); + if (link != null) { + return [link]; + } + return FootnoteRefSyntax.tryCreateFootnoteLink( + context, + label, + secondary: secondary, + ); + } + + // Tries to create an inline link node. + // + /// Returns the link if it was successfully created, `null` otherwise. + Node _tryCreateInlineLink( + InlineParser parser, + InlineLink link, { + required List Function() getChildren, + }) { + return createNode(link.destination, link.title, getChildren: getChildren); + } + + /// Parse a reference link label at the current position. + /// + /// Specifically, [parser.pos] is expected to be pointing at the `[` which + /// opens the link label. + /// + /// Returns the label if it could be parsed, or `null` if not. + String? _parseReferenceLinkLabel(InlineParser parser) { + // Walk past the opening `[`. + parser.advanceBy(1); + if (parser.isDone) return null; + + final buffer = StringBuffer(); + while (true) { + final char = parser.charAt(parser.pos); + if (char == $backslash) { + parser.advanceBy(1); + if (parser.isDone) return null; + final next = parser.charAt(parser.pos); + if (next != $backslash && next != $rbracket) { + buffer.writeCharCode(char); + } + buffer.writeCharCode(next); + } else if (char == $lbracket) { + return null; + } else if (char == $rbracket) { + break; + } else { + buffer.writeCharCode(char); + } + parser.advanceBy(1); + if (parser.isDone) return null; + // TODO(srawlins): only check 999 characters, for performance reasons? + } + + final label = buffer.toString(); + + // A link label must contain at least one non-whitespace character. + if (_entirelyWhitespacePattern.hasMatch(label)) return null; + + return label; + } + + /// Parse an inline [InlineLink] at the current position. + /// + /// At this point, we have parsed a link's (or image's) opening `[`, and then + /// a matching closing `]`, and [parser.pos] is pointing at an opening `(`. + /// This method will then attempt to parse a link destination wrapped in `<>`, + /// such as `()`, or a bare link destination, such as + /// `(http://url)`, or a link destination with a title, such as + /// `(http://url "title")`. + /// + /// Returns the [InlineLink] if one was parsed, or `null` if not. + InlineLink? _parseInlineLink(InlineParser parser) { + // Start walking to the character just after the opening `(`. + parser.advanceBy(1); + + _moveThroughWhitespace(parser); + if (parser.isDone) return null; // EOF. Not a link. + + if (parser.charAt(parser.pos) == $lt) { + // Maybe a `<...>`-enclosed link destination. + return _parseInlineBracketedLink(parser); + } else { + return _parseInlineBareDestinationLink(parser); + } + } + + /// Parse an inline link with a bracketed destination (a destination wrapped + /// in `<...>`). The current position of the parser must be the first + /// character of the destination. + /// + /// Returns the link if it was successfully created, `null` otherwise. + InlineLink? _parseInlineBracketedLink(InlineParser parser) { + parser.advanceBy(1); + if (parser.isDone) return null; + + final buffer = StringBuffer(); + while (true) { + final char = parser.charAt(parser.pos); + if (char == $backslash) { + parser.advanceBy(1); + if (parser.isDone) return null; + final next = parser.charAt(parser.pos); + // TODO: Follow the backslash spec better here. + // https://spec.commonmark.org/0.30/#backslash-escapes + if (next != $backslash && next != $gt) { + buffer.writeCharCode(char); + } + buffer.writeCharCode(next); + } else if (char == $lf || char == $cr || char == $ff) { + // Not a link (no line breaks allowed within `<...>`). + return null; + } else if (char == $space) { + buffer.write('%20'); + } else if (char == $gt) { + break; + } else { + buffer.writeCharCode(char); + } + parser.advanceBy(1); + if (parser.isDone) return null; + } + final destination = buffer.toString(); + + parser.advanceBy(1); + if (parser.isDone) return null; + final char = parser.charAt(parser.pos); + if (char == $space || char == $lf || char == $cr || char == $ff) { + final title = _parseTitle(parser); + if (title == null && + (parser.isDone || parser.charAt(parser.pos) != $rparen)) { + // This looked like an inline link, until we found this $space + // followed by mystery characters; no longer a link. + return null; + } + return InlineLink(destination, title: title); + } else if (char == $rparen) { + return InlineLink(destination); + } else { + // We parsed something like `[foo](X`. Not a link. + return null; + } + } + + /// Parse an inline link with a "bare" destination (a destination _not_ + /// wrapped in `<...>`). The current position of the parser must be the first + /// character of the destination. + /// + /// Returns the link if it was successfully created, `null` otherwise. + InlineLink? _parseInlineBareDestinationLink(InlineParser parser) { + // According to + // [CommonMark](https://spec.commonmark.org/0.30/#link-destination): + // + // > A link destination consists of [...] a nonempty sequence of + // > characters [...], and includes parentheses only if (a) they are + // > backslash-escaped or (b) they are part of a balanced pair of + // > unescaped parentheses. + // + // We need to count the open parens. We start with 1 for the paren that + // opened the destination. + var parenCount = 1; + final buffer = StringBuffer(); + + while (true) { + final char = parser.charAt(parser.pos); + switch (char) { + case $backslash: + parser.advanceBy(1); + if (parser.isDone) return null; // EOF. Not a link. + final next = parser.charAt(parser.pos); + // Parentheses may be escaped. + // + // https://spec.commonmark.org/0.30/#example-494 + if (next != $backslash && next != $lparen && next != $rparen) { + buffer.writeCharCode(char); + } + buffer.writeCharCode(next); + break; + + case $space: + case $lf: + case $cr: + case $ff: + final destination = buffer.toString(); + final title = _parseTitle(parser); + if (title == null && + (parser.isDone || parser.charAt(parser.pos) != $rparen)) { + // This looked like an inline link, until we found this $space + // followed by mystery characters; no longer a link. + return null; + } + // [_parseTitle] made sure the title was follwed by a closing `)` + // (but it's up to the code here to examine the balance of + // parentheses). + parenCount--; + if (parenCount == 0) { + return InlineLink(destination, title: title); + } + break; + + case $lparen: + parenCount++; + buffer.writeCharCode(char); + break; + + case $rparen: + parenCount--; + if (parenCount == 0) { + final destination = buffer.toString(); + return InlineLink(destination); + } + buffer.writeCharCode(char); + break; + + default: + buffer.writeCharCode(char); + } + parser.advanceBy(1); + if (parser.isDone) return null; // EOF. Not a link. + } + } + + // Walk the parser forward through any whitespace. + void _moveThroughWhitespace(InlineParser parser) { + while (!parser.isDone) { + final char = parser.charAt(parser.pos); + if (char != $space && + char != $tab && + char != $lf && + char != $vt && + char != $cr && + char != $ff) { + return; + } + parser.advanceBy(1); + } + } + + /// Parses a link title in [parser] at it's current position. The parser's + /// current position should be a whitespace character that followed a link + /// destination. + /// + /// Returns the title if it was successfully parsed, `null` otherwise. + String? _parseTitle(InlineParser parser) { + _moveThroughWhitespace(parser); + if (parser.isDone) return null; + + // The whitespace should be followed by a title delimiter. + final delimiter = parser.charAt(parser.pos); + if (delimiter != $apostrophe && + delimiter != $quote && + delimiter != $lparen) { + return null; + } + + final closeDelimiter = delimiter == $lparen ? $rparen : delimiter; + parser.advanceBy(1); + if (parser.isDone) return null; + + // Now we look for an un-escaped closing delimiter. + final buffer = StringBuffer(); + while (true) { + final char = parser.charAt(parser.pos); + if (char == $backslash) { + parser.advanceBy(1); + if (parser.isDone) return null; + final next = parser.charAt(parser.pos); + if (next != $backslash && next != closeDelimiter) { + buffer.writeCharCode(char); + } + buffer.writeCharCode(next); + } else if (char == closeDelimiter) { + break; + } else { + buffer.writeCharCode(char); + } + parser.advanceBy(1); + if (parser.isDone) return null; + } + final title = buffer.toString(); + + // Advance past the closing delimiter. + parser.advanceBy(1); + if (parser.isDone) return null; + _moveThroughWhitespace(parser); + if (parser.isDone) return null; + if (parser.charAt(parser.pos) != $rparen) return null; + return title; + } +} + +class InlineLink { + final String destination; + final String? title; + + InlineLink(this.destination, {this.title}); +} diff --git a/pkgs/markdown/lib/src/inline_syntaxes/soft_line_break_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/soft_line_break_syntax.dart new file mode 100644 index 000000000..c8395d5c9 --- /dev/null +++ b/pkgs/markdown/lib/src/inline_syntaxes/soft_line_break_syntax.dart @@ -0,0 +1,21 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../charcode.dart'; +import '../inline_parser.dart'; +import 'inline_syntax.dart'; + +/// Removes the single space before the line ending. +// https://spec.commonmark.org/0.30/#soft-line-breaks. +// If there are more than one spaces before the line ending, it may hit the hard +// break syntax. +class SoftLineBreakSyntax extends InlineSyntax { + SoftLineBreakSyntax() : super(' \n', startCharacter: $space); + + @override + bool onMatch(InlineParser parser, Match match) { + parser.consume(1); + return false; + } +} diff --git a/pkgs/markdown/lib/src/inline_syntaxes/strikethrough_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/strikethrough_syntax.dart new file mode 100644 index 000000000..ebe5e1a66 --- /dev/null +++ b/pkgs/markdown/lib/src/inline_syntaxes/strikethrough_syntax.dart @@ -0,0 +1,18 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../charcode.dart'; +import 'delimiter_syntax.dart'; + +/// Matches strikethrough syntax according to the GFM spec. +class StrikethroughSyntax extends DelimiterSyntax { + StrikethroughSyntax() + : super( + '~+', + requiresDelimiterRun: true, + allowIntraWord: true, + startCharacter: $tilde, + tags: [DelimiterTag('del', 1), DelimiterTag('del', 2)], + ); +} diff --git a/pkgs/markdown/lib/src/inline_syntaxes/text_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/text_syntax.dart new file mode 100644 index 000000000..b73d09df8 --- /dev/null +++ b/pkgs/markdown/lib/src/inline_syntaxes/text_syntax.dart @@ -0,0 +1,45 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../ast.dart'; +import '../inline_parser.dart'; +import '../util.dart'; +import 'inline_syntax.dart'; + +/// Matches stuff that should just be passed through as straight text. +class TextSyntax extends InlineSyntax { + final String substitute; + + /// Create a new [TextSyntax] which matches text on [pattern]. + /// + /// If [sub] is passed, it is used as a simple replacement for [pattern]. If + /// [startCharacter] is passed, it is used as a pre-matching check which is + /// faster than matching against [pattern]. + TextSyntax( + super.pattern, { + String sub = '', + super.startCharacter, + super.caseSensitive, + }) : substitute = sub; + + /// Adds a [Text] node to [parser] and returns `true` if there is a + /// [substitute], as long as the preceding character (if any) is not a `/`. + /// + /// Otherwise, the parser is advanced by the length of [match] and `false` is + /// returned. + @override + bool onMatch(InlineParser parser, Match match) { + if (substitute.isEmpty || + (match.start > 0 && + match.input.substring(match.start - 1, match.start) == '/')) { + // Just use the original matched text. + parser.advanceBy(match.match.length); + return false; + } + + // Insert the substitution. + parser.addNode(Text(substitute)); + return true; + } +} diff --git a/pkgs/markdown/lib/src/legacy_emojis.dart b/pkgs/markdown/lib/src/legacy_emojis.dart new file mode 100644 index 000000000..d608841f7 --- /dev/null +++ b/pkgs/markdown/lib/src/legacy_emojis.dart @@ -0,0 +1,1578 @@ +// GENERATED FILE. DO NOT EDIT. +// +// This file was generated from emojilib's emoji data file: +// https://raw.githubusercontent.com/muan/emojilib/v2.4.0/emojis.json +// at 2022-05-02 10:18:54.685294 by the script, tool/update_emojis.dart. + +const emojis = { + '+1': '👍', + '-1': '👎', + '100': '💯', + '1234': '🔢', + '1st_place_medal': '🥇', + '2nd_place_medal': '🥈', + '3rd_place_medal': '🥉', + '8ball': '🎱', + 'a': '🅰️', + 'ab': '🆎', + 'abacus': '🧮', + 'abc': '🔤', + 'abcd': '🔡', + 'accept': '🉑', + 'adult': '🧑', + 'aerial_tramway': '🚡', + 'afghanistan': '🇦🇫', + 'airplane': '✈️', + 'aland_islands': '🇦🇽', + 'alarm_clock': '⏰', + 'albania': '🇦🇱', + 'alembic': '⚗', + 'algeria': '🇩🇿', + 'alien': '👽', + 'ambulance': '🚑', + 'american_samoa': '🇦🇸', + 'amphora': '🏺', + 'anchor': '⚓', + 'andorra': '🇦🇩', + 'angel': '👼', + 'anger': '💢', + 'angola': '🇦🇴', + 'angry': '😠', + 'anguilla': '🇦🇮', + 'anguished': '😧', + 'ant': '🐜', + 'antarctica': '🇦🇶', + 'antigua_barbuda': '🇦🇬', + 'apple': '🍎', + 'aquarius': '♒', + 'argentina': '🇦🇷', + 'aries': '♈', + 'armenia': '🇦🇲', + 'arrow_backward': '◀️', + 'arrow_double_down': '⏬', + 'arrow_double_up': '⏫', + 'arrow_down': '⬇️', + 'arrow_down_small': '🔽', + 'arrow_forward': '▶️', + 'arrow_heading_down': '⤵️', + 'arrow_heading_up': '⤴️', + 'arrow_left': '⬅️', + 'arrow_lower_left': '↙️', + 'arrow_lower_right': '↘️', + 'arrow_right': '➡️', + 'arrow_right_hook': '↪️', + 'arrow_up': '⬆️', + 'arrow_up_down': '↕️', + 'arrow_up_small': '🔼', + 'arrow_upper_left': '↖️', + 'arrow_upper_right': '↗️', + 'arrows_clockwise': '🔃', + 'arrows_counterclockwise': '🔄', + 'art': '🎨', + 'articulated_lorry': '🚛', + 'artificial_satellite': '🛰', + 'aruba': '🇦🇼', + 'asterisk': '*⃣', + 'astonished': '😲', + 'athletic_shoe': '👟', + 'atm': '🏧', + 'atom_symbol': '⚛', + 'australia': '🇦🇺', + 'austria': '🇦🇹', + 'avocado': '🥑', + 'azerbaijan': '🇦🇿', + 'b': '🅱️', + 'baby': '👶', + 'baby_bottle': '🍼', + 'baby_chick': '🐤', + 'baby_symbol': '🚼', + 'back': '🔙', + 'bacon': '🥓', + 'badger': '🦡', + 'badminton': '🏸', + 'bagel': '🥯', + 'baggage_claim': '🛄', + 'baguette_bread': '🥖', + 'bahamas': '🇧🇸', + 'bahrain': '🇧🇭', + 'balance_scale': '⚖', + 'balloon': '🎈', + 'ballot_box': '🗳', + 'ballot_box_with_check': '☑️', + 'bamboo': '🎍', + 'banana': '🍌', + 'bangbang': '‼️', + 'bangladesh': '🇧🇩', + 'bank': '🏦', + 'bar_chart': '📊', + 'barbados': '🇧🇧', + 'barber': '💈', + 'baseball': '⚾', + 'basket': '🧺', + 'basketball': '🏀', + 'basketball_man': '⛹', + 'basketball_woman': '⛹️‍♀️', + 'bat': '🦇', + 'bath': '🛀', + 'bathtub': '🛁', + 'battery': '🔋', + 'beach_umbrella': '🏖', + 'bear': '🐻', + 'bearded_person': '🧔', + 'bed': '🛏', + 'beer': '🍺', + 'beers': '🍻', + 'beetle': '🐞', + 'beginner': '🔰', + 'belarus': '🇧🇾', + 'belgium': '🇧🇪', + 'belize': '🇧🇿', + 'bell': '🔔', + 'bellhop_bell': '🛎', + 'benin': '🇧🇯', + 'bento': '🍱', + 'bermuda': '🇧🇲', + 'bhutan': '🇧🇹', + 'bike': '🚲', + 'biking_man': '🚴', + 'biking_woman': '🚴‍♀️', + 'bikini': '👙', + 'billed_hat': '🧢', + 'biohazard': '☣', + 'bird': '🐦', + 'birthday': '🎂', + 'black_circle': '⚫', + 'black_flag': '🏴', + 'black_heart': '🖤', + 'black_joker': '🃏', + 'black_large_square': '⬛', + 'black_medium_small_square': '◾', + 'black_medium_square': '◼️', + 'black_nib': '✒️', + 'black_small_square': '▪️', + 'black_square_button': '🔲', + 'blonde_man': '👱', + 'blonde_woman': '👱‍♀️', + 'blossom': '🌼', + 'blowfish': '🐡', + 'blue_book': '📘', + 'blue_car': '🚙', + 'blue_heart': '💙', + 'blush': '😊', + 'boar': '🐗', + 'bolivia': '🇧🇴', + 'bomb': '💣', + 'bone': '🦴', + 'bookmark': '🔖', + 'bookmark_tabs': '📑', + 'books': '📚', + 'boom': '💥', + 'boot': '👢', + 'bosnia_herzegovina': '🇧🇦', + 'botswana': '🇧🇼', + 'bouquet': '💐', + 'bow_and_arrow': '🏹', + 'bowing_man': '🙇', + 'bowing_woman': '🙇‍♀️', + 'bowl_with_spoon': '🥣', + 'bowling': '🎳', + 'boxing_glove': '🥊', + 'boy': '👦', + 'brain': '🧠', + 'brazil': '🇧🇷', + 'bread': '🍞', + 'breastfeeding': '🤱', + 'brick': '🧱', + 'bride_with_veil': '👰', + 'bridge_at_night': '🌉', + 'briefcase': '💼', + 'british_indian_ocean_territory': '🇮🇴', + 'british_virgin_islands': '🇻🇬', + 'broccoli': '🥦', + 'broken_heart': '💔', + 'broom': '🧹', + 'brunei': '🇧🇳', + 'bug': '🐛', + 'building_construction': '🏗', + 'bulb': '💡', + 'bulgaria': '🇧🇬', + 'bullettrain_front': '🚅', + 'bullettrain_side': '🚄', + 'burkina_faso': '🇧🇫', + 'burrito': '🌯', + 'burundi': '🇧🇮', + 'bus': '🚌', + 'business_suit_levitating': '🕴', + 'busstop': '🚏', + 'bust_in_silhouette': '👤', + 'busts_in_silhouette': '👥', + 'butterfly': '🦋', + 'cactus': '🌵', + 'cake': '🍰', + 'calendar': '📆', + 'call_me_hand': '🤙', + 'calling': '📲', + 'cambodia': '🇰🇭', + 'camel': '🐫', + 'camera': '📷', + 'camera_flash': '📸', + 'cameroon': '🇨🇲', + 'camping': '🏕', + 'canada': '🇨🇦', + 'canary_islands': '🇮🇨', + 'cancer': '♋', + 'candle': '🕯', + 'candy': '🍬', + 'canned_food': '🥫', + 'canoe': '🛶', + 'cape_verde': '🇨🇻', + 'capital_abcd': '🔠', + 'capricorn': '♑', + 'card_file_box': '🗃', + 'card_index': '📇', + 'card_index_dividers': '🗂', + 'caribbean_netherlands': '🇧🇶', + 'carousel_horse': '🎠', + 'carrot': '🥕', + 'cat': '🐱', + 'cat2': '🐈', + 'cayman_islands': '🇰🇾', + 'cd': '💿', + 'central_african_republic': '🇨🇫', + 'chad': '🇹🇩', + 'chains': '⛓', + 'champagne': '🍾', + 'chart': '💹', + 'chart_with_downwards_trend': '📉', + 'chart_with_upwards_trend': '📈', + 'checkered_flag': '🏁', + 'cheese': '🧀', + 'cherries': '🍒', + 'cherry_blossom': '🌸', + 'chess_pawn': '♟', + 'chestnut': '🌰', + 'chicken': '🐔', + 'child': '🧒', + 'children_crossing': '🚸', + 'chile': '🇨🇱', + 'chipmunk': '🐿', + 'chocolate_bar': '🍫', + 'chopsticks': '🥢', + 'christmas_island': '🇨🇽', + 'christmas_tree': '🎄', + 'church': '⛪', + 'cinema': '🎦', + 'circus_tent': '🎪', + 'city_sunrise': '🌇', + 'city_sunset': '🌆', + 'cityscape': '🏙', + 'cl': '🆑', + 'clamp': '🗜', + 'clap': '👏', + 'clapper': '🎬', + 'classical_building': '🏛', + 'climbing_man': '🧗‍♂️', + 'climbing_woman': '🧗‍♀️', + 'clinking_glasses': '🥂', + 'clipboard': '📋', + 'clock1': '🕐', + 'clock10': '🕙', + 'clock1030': '🕥', + 'clock11': '🕚', + 'clock1130': '🕦', + 'clock12': '🕛', + 'clock1230': '🕧', + 'clock130': '🕜', + 'clock2': '🕑', + 'clock230': '🕝', + 'clock3': '🕒', + 'clock330': '🕞', + 'clock4': '🕓', + 'clock430': '🕟', + 'clock5': '🕔', + 'clock530': '🕠', + 'clock6': '🕕', + 'clock630': '🕡', + 'clock7': '🕖', + 'clock730': '🕢', + 'clock8': '🕗', + 'clock830': '🕣', + 'clock9': '🕘', + 'clock930': '🕤', + 'closed_book': '📕', + 'closed_lock_with_key': '🔐', + 'closed_umbrella': '🌂', + 'cloud': '☁️', + 'cloud_with_lightning': '🌩', + 'cloud_with_lightning_and_rain': '⛈', + 'cloud_with_rain': '🌧', + 'cloud_with_snow': '🌨', + 'clown_face': '🤡', + 'clubs': '♣️', + 'cn': '🇨🇳', + 'coat': '🧥', + 'cocktail': '🍸', + 'coconut': '🥥', + 'cocos_islands': '🇨🇨', + 'coffee': '☕', + 'coffin': '⚰', + 'cold': '🥶', + 'cold_sweat': '😰', + 'colombia': '🇨🇴', + 'comet': '☄', + 'comoros': '🇰🇲', + 'compass': '🧭', + 'computer': '💻', + 'computer_mouse': '🖱', + 'confetti_ball': '🎊', + 'confounded': '😖', + 'confused': '😕', + 'congo_brazzaville': '🇨🇬', + 'congo_kinshasa': '🇨🇩', + 'congratulations': '㊗️', + 'construction': '🚧', + 'construction_worker_man': '👷', + 'construction_worker_woman': '👷‍♀️', + 'control_knobs': '🎛', + 'convenience_store': '🏪', + 'cook_islands': '🇨🇰', + 'cookie': '🍪', + 'cool': '🆒', + 'copyright': '©️', + 'corn': '🌽', + 'costa_rica': '🇨🇷', + 'cote_divoire': '🇨🇮', + 'couch_and_lamp': '🛋', + 'couple': '👫', + 'couple_with_heart_man_man': '👨‍❤️‍👨', + 'couple_with_heart_woman_man': '💑', + 'couple_with_heart_woman_woman': '👩‍❤️‍👩', + 'couplekiss_man_man': '👨‍❤️‍💋‍👨', + 'couplekiss_man_woman': '💏', + 'couplekiss_woman_woman': '👩‍❤️‍💋‍👩', + 'cow': '🐮', + 'cow2': '🐄', + 'cowboy_hat_face': '🤠', + 'crab': '🦀', + 'crayon': '🖍', + 'credit_card': '💳', + 'crescent_moon': '🌙', + 'cricket': '🏏', + 'croatia': '🇭🇷', + 'crocodile': '🐊', + 'croissant': '🥐', + 'crossed_fingers': '🤞', + 'crossed_flags': '🎌', + 'crossed_swords': '⚔', + 'crown': '👑', + 'cry': '😢', + 'crying_cat_face': '😿', + 'crystal_ball': '🔮', + 'cuba': '🇨🇺', + 'cucumber': '🥒', + 'cup_with_straw': '🥤', + 'cupcake': '🧁', + 'cupid': '💘', + 'curacao': '🇨🇼', + 'curling_stone': '🥌', + 'curly_loop': '➰', + 'currency_exchange': '💱', + 'curry': '🍛', + 'custard': '🍮', + 'customs': '🛃', + 'cyclone': '🌀', + 'cyprus': '🇨🇾', + 'czech_republic': '🇨🇿', + 'dagger': '🗡', + 'dancer': '💃', + 'dancing_men': '👯‍♂️', + 'dancing_women': '👯', + 'dango': '🍡', + 'dark_sunglasses': '🕶', + 'dart': '🎯', + 'dash': '💨', + 'date': '📅', + 'de': '🇩🇪', + 'deciduous_tree': '🌳', + 'deer': '🦌', + 'denmark': '🇩🇰', + 'department_store': '🏬', + 'derelict_house': '🏚', + 'desert': '🏜', + 'desert_island': '🏝', + 'desktop_computer': '🖥', + 'diamond_shape_with_a_dot_inside': '💠', + 'diamonds': '♦️', + 'disappointed': '😞', + 'disappointed_relieved': '😥', + 'dizzy': '💫', + 'dizzy_face': '😵', + 'djibouti': '🇩🇯', + 'dna': '🧬', + 'do_not_litter': '🚯', + 'dog': '🐶', + 'dog2': '🐕', + 'dollar': '💵', + 'dolls': '🎎', + 'dolphin': '🐬', + 'dominica': '🇩🇲', + 'dominican_republic': '🇩🇴', + 'door': '🚪', + 'doughnut': '🍩', + 'dove': '🕊', + 'dragon': '🐉', + 'dragon_face': '🐲', + 'dress': '👗', + 'dromedary_camel': '🐪', + 'drooling_face': '🤤', + 'droplet': '💧', + 'drum': '🥁', + 'duck': '🦆', + 'dumpling': '🥟', + 'dvd': '📀', + 'e-mail': '📧', + 'eagle': '🦅', + 'ear': '👂', + 'ear_of_rice': '🌾', + 'earth_africa': '🌍', + 'earth_americas': '🌎', + 'earth_asia': '🌏', + 'ecuador': '🇪🇨', + 'egg': '🥚', + 'eggplant': '🍆', + 'egypt': '🇪🇬', + 'eight': '8️⃣', + 'eight_pointed_black_star': '✴️', + 'eight_spoked_asterisk': '✳️', + 'eject_button': '⏏️', + 'el_salvador': '🇸🇻', + 'electric_plug': '🔌', + 'elephant': '🐘', + 'email': '✉️', + 'end': '🔚', + 'england': '🏴󠁧󠁢󠁥󠁮󠁧󠁿', + 'envelope_with_arrow': '📩', + 'equatorial_guinea': '🇬🇶', + 'eritrea': '🇪🇷', + 'es': '🇪🇸', + 'estonia': '🇪🇪', + 'ethiopia': '🇪🇹', + 'eu': '🇪🇺', + 'euro': '💶', + 'european_castle': '🏰', + 'european_post_office': '🏤', + 'evergreen_tree': '🌲', + 'exclamation': '❗', + 'exploding_head': '🤯', + 'expressionless': '😑', + 'eye': '👁', + 'eyeglasses': '👓', + 'eyes': '👀', + 'face_with_head_bandage': '🤕', + 'face_with_thermometer': '🤒', + 'facepunch': '👊', + 'factory': '🏭', + 'falkland_islands': '🇫🇰', + 'fallen_leaf': '🍂', + 'family_man_boy': '👨‍👦', + 'family_man_boy_boy': '👨‍👦‍👦', + 'family_man_girl': '👨‍👧', + 'family_man_girl_boy': '👨‍👧‍👦', + 'family_man_girl_girl': '👨‍👧‍👧', + 'family_man_man_boy': '👨‍👨‍👦', + 'family_man_man_boy_boy': '👨‍👨‍👦‍👦', + 'family_man_man_girl': '👨‍👨‍👧', + 'family_man_man_girl_boy': '👨‍👨‍👧‍👦', + 'family_man_man_girl_girl': '👨‍👨‍👧‍👧', + 'family_man_woman_boy': '👪', + 'family_man_woman_boy_boy': '👨‍👩‍👦‍👦', + 'family_man_woman_girl': '👨‍👩‍👧', + 'family_man_woman_girl_boy': '👨‍👩‍👧‍👦', + 'family_man_woman_girl_girl': '👨‍👩‍👧‍👧', + 'family_woman_boy': '👩‍👦', + 'family_woman_boy_boy': '👩‍👦‍👦', + 'family_woman_girl': '👩‍👧', + 'family_woman_girl_boy': '👩‍👧‍👦', + 'family_woman_girl_girl': '👩‍👧‍👧', + 'family_woman_woman_boy': '👩‍👩‍👦', + 'family_woman_woman_boy_boy': '👩‍👩‍👦‍👦', + 'family_woman_woman_girl': '👩‍👩‍👧', + 'family_woman_woman_girl_boy': '👩‍👩‍👧‍👦', + 'family_woman_woman_girl_girl': '👩‍👩‍👧‍👧', + 'faroe_islands': '🇫🇴', + 'fast_forward': '⏩', + 'fax': '📠', + 'fearful': '😨', + 'female_detective': '🕵️‍♀️', + 'ferris_wheel': '🎡', + 'ferry': '⛴', + 'field_hockey': '🏑', + 'fiji': '🇫🇯', + 'file_cabinet': '🗄', + 'file_folder': '📁', + 'film_projector': '📽', + 'film_strip': '🎞', + 'finland': '🇫🇮', + 'fire': '🔥', + 'fire_engine': '🚒', + 'fire_extinguisher': '🧯', + 'firecracker': '🧨', + 'fireworks': '🎆', + 'first_quarter_moon': '🌓', + 'first_quarter_moon_with_face': '🌛', + 'fish': '🐟', + 'fish_cake': '🍥', + 'fishing_pole_and_fish': '🎣', + 'fist': '✊', + 'fist_left': '🤛', + 'fist_right': '🤜', + 'five': '5️⃣', + 'flags': '🎏', + 'flashlight': '🔦', + 'flat_shoe': '🥿', + 'fleur_de_lis': '⚜', + 'flight_arrival': '🛬', + 'flight_departure': '🛫', + 'floppy_disk': '💾', + 'flower_playing_cards': '🎴', + 'flushed': '😳', + 'flying_disc': '🥏', + 'flying_saucer': '🛸', + 'fog': '🌫', + 'foggy': '🌁', + 'foot': '🦶', + 'football': '🏈', + 'footprints': '👣', + 'fork_and_knife': '🍴', + 'fortune_cookie': '🥠', + 'fountain': '⛲', + 'fountain_pen': '🖋', + 'four': '4️⃣', + 'four_leaf_clover': '🍀', + 'fox_face': '🦊', + 'fr': '🇫🇷', + 'framed_picture': '🖼', + 'free': '🆓', + 'french_guiana': '🇬🇫', + 'french_polynesia': '🇵🇫', + 'french_southern_territories': '🇹🇫', + 'fried_egg': '🍳', + 'fried_shrimp': '🍤', + 'fries': '🍟', + 'frog': '🐸', + 'frowning': '😦', + 'frowning_face': '☹', + 'frowning_man': '🙍‍♂️', + 'frowning_woman': '🙍', + 'fu': '🖕', + 'fuelpump': '⛽', + 'full_moon': '🌕', + 'full_moon_with_face': '🌝', + 'funeral_urn': '⚱', + 'gabon': '🇬🇦', + 'gambia': '🇬🇲', + 'game_die': '🎲', + 'gear': '⚙', + 'gem': '💎', + 'gemini': '♊', + 'georgia': '🇬🇪', + 'ghana': '🇬🇭', + 'ghost': '👻', + 'gibraltar': '🇬🇮', + 'gift': '🎁', + 'gift_heart': '💝', + 'giraffe': '🦒', + 'girl': '👧', + 'globe_with_meridians': '🌐', + 'gloves': '🧤', + 'goal_net': '🥅', + 'goat': '🐐', + 'goggles': '🥽', + 'golf': '⛳', + 'golfing_man': '🏌', + 'golfing_woman': '🏌️‍♀️', + 'gorilla': '🦍', + 'grapes': '🍇', + 'grasshopper': '🦗', + 'greece': '🇬🇷', + 'green_apple': '🍏', + 'green_book': '📗', + 'green_heart': '💚', + 'green_salad': '🥗', + 'greenland': '🇬🇱', + 'grenada': '🇬🇩', + 'grey_exclamation': '❕', + 'grey_question': '❔', + 'grimacing': '😬', + 'grin': '😁', + 'grinning': '😀', + 'guadeloupe': '🇬🇵', + 'guam': '🇬🇺', + 'guardsman': '💂', + 'guardswoman': '💂‍♀️', + 'guatemala': '🇬🇹', + 'guernsey': '🇬🇬', + 'guinea': '🇬🇳', + 'guinea_bissau': '🇬🇼', + 'guitar': '🎸', + 'gun': '🔫', + 'guyana': '🇬🇾', + 'haircut_man': '💇‍♂️', + 'haircut_woman': '💇', + 'haiti': '🇭🇹', + 'hamburger': '🍔', + 'hammer': '🔨', + 'hammer_and_pick': '⚒', + 'hammer_and_wrench': '🛠', + 'hamster': '🐹', + 'hand_over_mouth': '🤭', + 'handbag': '👜', + 'handshake': '🤝', + 'hash': '#️⃣', + 'hatched_chick': '🐥', + 'hatching_chick': '🐣', + 'headphones': '🎧', + 'hear_no_evil': '🙉', + 'heart': '❤️', + 'heart_decoration': '💟', + 'heart_eyes': '😍', + 'heart_eyes_cat': '😻', + 'heartbeat': '💓', + 'heartpulse': '💗', + 'hearts': '♥️', + 'heavy_check_mark': '✔️', + 'heavy_division_sign': '➗', + 'heavy_dollar_sign': '💲', + 'heavy_heart_exclamation': '❣', + 'heavy_minus_sign': '➖', + 'heavy_multiplication_x': '✖️', + 'heavy_plus_sign': '➕', + 'hedgehog': '🦔', + 'helicopter': '🚁', + 'herb': '🌿', + 'hibiscus': '🌺', + 'high_brightness': '🔆', + 'high_heel': '👠', + 'hiking_boot': '🥾', + 'hippopotamus': '🦛', + 'hocho': '🔪', + 'hole': '🕳', + 'honduras': '🇭🇳', + 'honey_pot': '🍯', + 'honeybee': '🐝', + 'hong_kong': '🇭🇰', + 'horse': '🐴', + 'horse_racing': '🏇', + 'hospital': '🏥', + 'hot': '🥵', + 'hot_pepper': '🌶', + 'hotdog': '🌭', + 'hotel': '🏨', + 'hotsprings': '♨️', + 'hourglass': '⌛', + 'hourglass_flowing_sand': '⏳', + 'house': '🏠', + 'house_with_garden': '🏡', + 'houses': '🏘', + 'hugs': '🤗', + 'hungary': '🇭🇺', + 'hushed': '😯', + 'ice_cream': '🍨', + 'ice_hockey': '🏒', + 'ice_skate': '⛸', + 'icecream': '🍦', + 'iceland': '🇮🇸', + 'id': '🆔', + 'ideograph_advantage': '🉐', + 'imp': '👿', + 'inbox_tray': '📥', + 'incoming_envelope': '📨', + 'india': '🇮🇳', + 'indonesia': '🇮🇩', + 'infinity': '♾', + 'information_source': 'ℹ️', + 'innocent': '😇', + 'interrobang': '⁉️', + 'iphone': '📱', + 'iran': '🇮🇷', + 'iraq': '🇮🇶', + 'ireland': '🇮🇪', + 'isle_of_man': '🇮🇲', + 'israel': '🇮🇱', + 'it': '🇮🇹', + 'izakaya_lantern': '🏮', + 'jack_o_lantern': '🎃', + 'jamaica': '🇯🇲', + 'japan': '🗾', + 'japanese_castle': '🏯', + 'japanese_goblin': '👺', + 'japanese_ogre': '👹', + 'jeans': '👖', + 'jersey': '🇯🇪', + 'jigsaw': '🧩', + 'jordan': '🇯🇴', + 'joy': '😂', + 'joy_cat': '😹', + 'joystick': '🕹', + 'jp': '🇯🇵', + 'kaaba': '🕋', + 'kangaroo': '🦘', + 'kazakhstan': '🇰🇿', + 'kenya': '🇰🇪', + 'key': '🔑', + 'keyboard': '⌨', + 'keycap_ten': '🔟', + 'kick_scooter': '🛴', + 'kimono': '👘', + 'kiribati': '🇰🇮', + 'kiss': '💋', + 'kissing': '😗', + 'kissing_cat': '😽', + 'kissing_closed_eyes': '😚', + 'kissing_heart': '😘', + 'kissing_smiling_eyes': '😙', + 'kiwi_fruit': '🥝', + 'koala': '🐨', + 'koko': '🈁', + 'kosovo': '🇽🇰', + 'kr': '🇰🇷', + 'kuwait': '🇰🇼', + 'kyrgyzstan': '🇰🇬', + 'labcoat': '🥼', + 'label': '🏷', + 'lacrosse': '🥍', + 'laos': '🇱🇦', + 'large_blue_circle': '🔵', + 'large_blue_diamond': '🔷', + 'large_orange_diamond': '🔶', + 'last_quarter_moon': '🌗', + 'last_quarter_moon_with_face': '🌜', + 'latin_cross': '✝', + 'latvia': '🇱🇻', + 'laughing': '😆', + 'leafy_greens': '🥬', + 'leaves': '🍃', + 'lebanon': '🇱🇧', + 'ledger': '📒', + 'left_luggage': '🛅', + 'left_right_arrow': '↔️', + 'left_speech_bubble': '🗨', + 'leftwards_arrow_with_hook': '↩️', + 'leg': '🦵', + 'lemon': '🍋', + 'leo': '♌', + 'leopard': '🐆', + 'lesotho': '🇱🇸', + 'level_slider': '🎚', + 'liberia': '🇱🇷', + 'libra': '♎', + 'libya': '🇱🇾', + 'liechtenstein': '🇱🇮', + 'light_rail': '🚈', + 'link': '🔗', + 'lion': '🦁', + 'lips': '👄', + 'lipstick': '💄', + 'lithuania': '🇱🇹', + 'lizard': '🦎', + 'llama': '🦙', + 'lobster': '🦞', + 'lock': '🔒', + 'lock_with_ink_pen': '🔏', + 'lollipop': '🍭', + 'loop': '➿', + 'lotion_bottle': '🧴', + 'loud_sound': '🔊', + 'loudspeaker': '📢', + 'love_hotel': '🏩', + 'love_letter': '💌', + 'love_you': '🤟', + 'low_brightness': '🔅', + 'luggage': '🧳', + 'luxembourg': '🇱🇺', + 'lying_face': '🤥', + 'm': 'Ⓜ️', + 'macau': '🇲🇴', + 'macedonia': '🇲🇰', + 'madagascar': '🇲🇬', + 'mag': '🔍', + 'mag_right': '🔎', + 'magnet': '🧲', + 'mahjong': '🀄', + 'mailbox': '📫', + 'mailbox_closed': '📪', + 'mailbox_with_mail': '📬', + 'mailbox_with_no_mail': '📭', + 'malawi': '🇲🇼', + 'malaysia': '🇲🇾', + 'maldives': '🇲🇻', + 'male_detective': '🕵', + 'mali': '🇲🇱', + 'malta': '🇲🇹', + 'man': '👨', + 'man_artist': '👨‍🎨', + 'man_astronaut': '👨‍🚀', + 'man_cartwheeling': '🤸‍♂️', + 'man_cook': '👨‍🍳', + 'man_dancing': '🕺', + 'man_elf': '🧝‍♂️', + 'man_facepalming': '🤦‍♂️', + 'man_factory_worker': '👨‍🏭', + 'man_fairy': '🧚‍♂️', + 'man_farmer': '👨‍🌾', + 'man_firefighter': '👨‍🚒', + 'man_genie': '🧞‍♂️', + 'man_health_worker': '👨‍⚕️', + 'man_in_lotus_position': '🧘‍♂️', + 'man_in_steamy_room': '🧖‍♂️', + 'man_in_tuxedo': '🤵', + 'man_judge': '👨‍⚖️', + 'man_juggling': '🤹‍♂️', + 'man_mechanic': '👨‍🔧', + 'man_office_worker': '👨‍💼', + 'man_pilot': '👨‍✈️', + 'man_playing_handball': '🤾‍♂️', + 'man_playing_water_polo': '🤽‍♂️', + 'man_scientist': '👨‍🔬', + 'man_shrugging': '🤷‍♂️', + 'man_singer': '👨‍🎤', + 'man_student': '👨‍🎓', + 'man_superhero': '🦸‍♂️', + 'man_supervillain': '🦹‍♂️', + 'man_teacher': '👨‍🏫', + 'man_technologist': '👨‍💻', + 'man_vampire': '🧛‍♂️', + 'man_with_gua_pi_mao': '👲', + 'man_with_turban': '👳', + 'man_zombie': '🧟‍♂️', + 'mango': '🥭', + 'mans_shoe': '👞', + 'mantelpiece_clock': '🕰', + 'maple_leaf': '🍁', + 'marshall_islands': '🇲🇭', + 'martial_arts_uniform': '🥋', + 'martinique': '🇲🇶', + 'mask': '😷', + 'massage_man': '💆‍♂️', + 'massage_woman': '💆', + 'mauritania': '🇲🇷', + 'mauritius': '🇲🇺', + 'mayotte': '🇾🇹', + 'meat_on_bone': '🍖', + 'medal_military': '🎖', + 'medal_sports': '🏅', + 'mega': '📣', + 'melon': '🍈', + 'memo': '📝', + 'men_wrestling': '🤼‍♂️', + 'menorah': '🕎', + 'mens': '🚹', + 'mermaid': '🧜‍♀️', + 'merman': '🧜‍♂️', + 'metal': '🤘', + 'metro': '🚇', + 'mexico': '🇲🇽', + 'microbe': '🦠', + 'micronesia': '🇫🇲', + 'microphone': '🎤', + 'microscope': '🔬', + 'milk_glass': '🥛', + 'milky_way': '🌌', + 'minibus': '🚐', + 'minidisc': '💽', + 'mobile_phone_off': '📴', + 'moldova': '🇲🇩', + 'monaco': '🇲🇨', + 'money_mouth_face': '🤑', + 'money_with_wings': '💸', + 'moneybag': '💰', + 'mongolia': '🇲🇳', + 'monkey': '🐒', + 'monkey_face': '🐵', + 'monocle': '🧐', + 'monorail': '🚝', + 'montenegro': '🇲🇪', + 'montserrat': '🇲🇸', + 'moon_cake': '🥮', + 'morocco': '🇲🇦', + 'mortar_board': '🎓', + 'mosque': '🕌', + 'mosquito': '🦟', + 'motor_boat': '🛥', + 'motor_scooter': '🛵', + 'motorcycle': '🏍', + 'motorway': '🛣', + 'mount_fuji': '🗻', + 'mountain': '⛰', + 'mountain_biking_man': '🚵', + 'mountain_biking_woman': '🚵‍♀️', + 'mountain_cableway': '🚠', + 'mountain_railway': '🚞', + 'mountain_snow': '🏔', + 'mouse': '🐭', + 'mouse2': '🐁', + 'movie_camera': '🎥', + 'moyai': '🗿', + 'mozambique': '🇲🇿', + 'mrs_claus': '🤶', + 'muscle': '💪', + 'mushroom': '🍄', + 'musical_keyboard': '🎹', + 'musical_note': '🎵', + 'musical_score': '🎼', + 'mute': '🔇', + 'myanmar': '🇲🇲', + 'nail_care': '💅', + 'name_badge': '📛', + 'namibia': '🇳🇦', + 'national_park': '🏞', + 'nauru': '🇳🇷', + 'nauseated_face': '🤢', + 'nazar_amulet': '🧿', + 'necktie': '👔', + 'negative_squared_cross_mark': '❎', + 'nepal': '🇳🇵', + 'nerd_face': '🤓', + 'netherlands': '🇳🇱', + 'neutral_face': '😐', + 'new': '🆕', + 'new_caledonia': '🇳🇨', + 'new_moon': '🌑', + 'new_moon_with_face': '🌚', + 'new_zealand': '🇳🇿', + 'newspaper': '📰', + 'newspaper_roll': '🗞', + 'next_track_button': '⏭', + 'ng': '🆖', + 'nicaragua': '🇳🇮', + 'niger': '🇳🇪', + 'nigeria': '🇳🇬', + 'night_with_stars': '🌃', + 'nine': '9️⃣', + 'niue': '🇳🇺', + 'no_bell': '🔕', + 'no_bicycles': '🚳', + 'no_entry': '⛔', + 'no_entry_sign': '🚫', + 'no_good_man': '🙅‍♂️', + 'no_good_woman': '🙅', + 'no_mobile_phones': '📵', + 'no_mouth': '😶', + 'no_pedestrians': '🚷', + 'no_smoking': '🚭', + 'non-potable_water': '🚱', + 'norfolk_island': '🇳🇫', + 'north_korea': '🇰🇵', + 'northern_mariana_islands': '🇲🇵', + 'norway': '🇳🇴', + 'nose': '👃', + 'notebook': '📓', + 'notebook_with_decorative_cover': '📔', + 'notes': '🎶', + 'nut_and_bolt': '🔩', + 'o': '⭕', + 'o2': '🅾️', + 'ocean': '🌊', + 'octopus': '🐙', + 'oden': '🍢', + 'office': '🏢', + 'oil_drum': '🛢', + 'ok': '🆗', + 'ok_hand': '👌', + 'ok_man': '🙆‍♂️', + 'ok_woman': '🙆', + 'old_key': '🗝', + 'older_adult': '🧓', + 'older_man': '👴', + 'older_woman': '👵', + 'om': '🕉', + 'oman': '🇴🇲', + 'on': '🔛', + 'oncoming_automobile': '🚘', + 'oncoming_bus': '🚍', + 'oncoming_police_car': '🚔', + 'oncoming_taxi': '🚖', + 'one': '1️⃣', + 'open_book': '📖', + 'open_file_folder': '📂', + 'open_hands': '👐', + 'open_mouth': '😮', + 'open_umbrella': '☂', + 'ophiuchus': '⛎', + 'orange_book': '📙', + 'orange_heart': '🧡', + 'orthodox_cross': '☦', + 'outbox_tray': '📤', + 'owl': '🦉', + 'ox': '🐂', + 'package': '📦', + 'page_facing_up': '📄', + 'page_with_curl': '📃', + 'pager': '📟', + 'paintbrush': '🖌', + 'pakistan': '🇵🇰', + 'palau': '🇵🇼', + 'palestinian_territories': '🇵🇸', + 'palm_tree': '🌴', + 'palms_up': '🤲', + 'panama': '🇵🇦', + 'pancakes': '🥞', + 'panda_face': '🐼', + 'paperclip': '📎', + 'paperclips': '🖇', + 'papua_new_guinea': '🇵🇬', + 'paraguay': '🇵🇾', + 'parasol_on_ground': '⛱', + 'parking': '🅿️', + 'parrot': '🦜', + 'part_alternation_mark': '〽️', + 'partly_sunny': '⛅', + 'partying': '🥳', + 'passenger_ship': '🛳', + 'passport_control': '🛂', + 'pause_button': '⏸', + 'paw_prints': '🐾', + 'peace_symbol': '☮', + 'peach': '🍑', + 'peacock': '🦚', + 'peanuts': '🥜', + 'pear': '🍐', + 'pen': '🖊', + 'pencil2': '✏️', + 'penguin': '🐧', + 'pensive': '😔', + 'performing_arts': '🎭', + 'persevere': '😣', + 'person_fencing': '🤺', + 'peru': '🇵🇪', + 'petri_dish': '🧫', + 'philippines': '🇵🇭', + 'phone': '☎️', + 'pick': '⛏', + 'pie': '🥧', + 'pig': '🐷', + 'pig2': '🐖', + 'pig_nose': '🐽', + 'pill': '💊', + 'pineapple': '🍍', + 'ping_pong': '🏓', + 'pirate_flag': '🏴‍☠️', + 'pisces': '♓', + 'pitcairn_islands': '🇵🇳', + 'pizza': '🍕', + 'place_of_worship': '🛐', + 'plate_with_cutlery': '🍽', + 'play_or_pause_button': '⏯', + 'pleading': '🥺', + 'point_down': '👇', + 'point_left': '👈', + 'point_right': '👉', + 'point_up': '☝', + 'point_up_2': '👆', + 'poland': '🇵🇱', + 'police_car': '🚓', + 'policeman': '👮', + 'policewoman': '👮‍♀️', + 'poodle': '🐩', + 'poop': '💩', + 'popcorn': '🍿', + 'portugal': '🇵🇹', + 'post_office': '🏣', + 'postal_horn': '📯', + 'postbox': '📮', + 'potable_water': '🚰', + 'potato': '🥔', + 'pouch': '👝', + 'poultry_leg': '🍗', + 'pound': '💷', + 'pouting_cat': '😾', + 'pouting_man': '🙎‍♂️', + 'pouting_woman': '🙎', + 'pray': '🙏', + 'prayer_beads': '📿', + 'pregnant_woman': '🤰', + 'pretzel': '🥨', + 'previous_track_button': '⏮', + 'prince': '🤴', + 'princess': '👸', + 'printer': '🖨', + 'puerto_rico': '🇵🇷', + 'purple_heart': '💜', + 'purse': '👛', + 'pushpin': '📌', + 'put_litter_in_its_place': '🚮', + 'qatar': '🇶🇦', + 'question': '❓', + 'rabbit': '🐰', + 'rabbit2': '🐇', + 'raccoon': '🦝', + 'racehorse': '🐎', + 'racing_car': '🏎', + 'radio': '📻', + 'radio_button': '🔘', + 'radioactive': '☢', + 'rage': '😡', + 'railway_car': '🚃', + 'railway_track': '🛤', + 'rainbow': '🌈', + 'rainbow_flag': '🏳️‍🌈', + 'raised_back_of_hand': '🤚', + 'raised_eyebrow': '🤨', + 'raised_hand': '✋', + 'raised_hand_with_fingers_splayed': '🖐', + 'raised_hands': '🙌', + 'raising_hand_man': '🙋‍♂️', + 'raising_hand_woman': '🙋', + 'ram': '🐏', + 'ramen': '🍜', + 'rat': '🐀', + 'receipt': '🧾', + 'record_button': '⏺', + 'recycle': '♻️', + 'red_car': '🚗', + 'red_circle': '🔴', + 'red_envelope': '🧧', + 'registered': '®️', + 'relaxed': '☺️', + 'relieved': '😌', + 'reminder_ribbon': '🎗', + 'repeat': '🔁', + 'repeat_one': '🔂', + 'rescue_worker_helmet': '⛑', + 'restroom': '🚻', + 'reunion': '🇷🇪', + 'revolving_hearts': '💞', + 'rewind': '⏪', + 'rhinoceros': '🦏', + 'ribbon': '🎀', + 'rice': '🍚', + 'rice_ball': '🍙', + 'rice_cracker': '🍘', + 'rice_scene': '🎑', + 'right_anger_bubble': '🗯', + 'ring': '💍', + 'robot': '🤖', + 'rocket': '🚀', + 'rofl': '🤣', + 'roll_eyes': '🙄', + 'roller_coaster': '🎢', + 'romania': '🇷🇴', + 'rooster': '🐓', + 'rose': '🌹', + 'rosette': '🏵', + 'rotating_light': '🚨', + 'round_pushpin': '📍', + 'rowing_man': '🚣', + 'rowing_woman': '🚣‍♀️', + 'ru': '🇷🇺', + 'rugby_football': '🏉', + 'running_man': '🏃', + 'running_shirt_with_sash': '🎽', + 'running_woman': '🏃‍♀️', + 'rwanda': '🇷🇼', + 'sa': '🈂️', + 'safety_pin': '🧷', + 'sagittarius': '♐', + 'sailboat': '⛵', + 'sake': '🍶', + 'salt': '🧂', + 'samoa': '🇼🇸', + 'san_marino': '🇸🇲', + 'sandal': '👡', + 'sandwich': '🥪', + 'santa': '🎅', + 'sao_tome_principe': '🇸🇹', + 'satellite': '📡', + 'saudi_arabia': '🇸🇦', + 'sauropod': '🦕', + 'saxophone': '🎷', + 'scarf': '🧣', + 'school': '🏫', + 'school_satchel': '🎒', + 'scissors': '✂️', + 'scorpion': '🦂', + 'scorpius': '♏', + 'scotland': '🏴󠁧󠁢󠁳󠁣󠁴󠁿', + 'scream': '😱', + 'scream_cat': '🙀', + 'scroll': '📜', + 'seat': '💺', + 'secret': '㊙️', + 'see_no_evil': '🙈', + 'seedling': '🌱', + 'selfie': '🤳', + 'senegal': '🇸🇳', + 'serbia': '🇷🇸', + 'seven': '7️⃣', + 'seychelles': '🇸🇨', + 'shallow_pan_of_food': '🥘', + 'shamrock': '☘', + 'shark': '🦈', + 'shaved_ice': '🍧', + 'sheep': '🐑', + 'shell': '🐚', + 'shield': '🛡', + 'shinto_shrine': '⛩', + 'ship': '🚢', + 'shopping': '🛍', + 'shopping_cart': '🛒', + 'shower': '🚿', + 'shrimp': '🦐', + 'shushing': '🤫', + 'sierra_leone': '🇸🇱', + 'signal_strength': '📶', + 'singapore': '🇸🇬', + 'sint_maarten': '🇸🇽', + 'six': '6️⃣', + 'six_pointed_star': '🔯', + 'skateboard': '🛹', + 'ski': '🎿', + 'skier': '⛷', + 'skull': '💀', + 'skull_and_crossbones': '☠', + 'sled': '🛷', + 'sleeping': '😴', + 'sleeping_bed': '🛌', + 'sleepy': '😪', + 'slightly_frowning_face': '🙁', + 'slightly_smiling_face': '🙂', + 'slot_machine': '🎰', + 'slovakia': '🇸🇰', + 'slovenia': '🇸🇮', + 'small_airplane': '🛩', + 'small_blue_diamond': '🔹', + 'small_orange_diamond': '🔸', + 'small_red_triangle': '🔺', + 'small_red_triangle_down': '🔻', + 'smile': '😄', + 'smile_cat': '😸', + 'smiley': '😃', + 'smiley_cat': '😺', + 'smiling_face_with_three_hearts': '🥰', + 'smiling_imp': '😈', + 'smirk': '😏', + 'smirk_cat': '😼', + 'smoking': '🚬', + 'snail': '🐌', + 'snake': '🐍', + 'sneezing_face': '🤧', + 'snowboarder': '🏂', + 'snowflake': '❄️', + 'snowman': '⛄', + 'snowman_with_snow': '☃', + 'soap': '🧼', + 'sob': '😭', + 'soccer': '⚽', + 'socks': '🧦', + 'softball': '🥎', + 'solomon_islands': '🇸🇧', + 'somalia': '🇸🇴', + 'soon': '🔜', + 'sorceress': '🧙‍♀️', + 'sos': '🆘', + 'sound': '🔉', + 'south_africa': '🇿🇦', + 'south_georgia_south_sandwich_islands': '🇬🇸', + 'south_sudan': '🇸🇸', + 'space_invader': '👾', + 'spades': '♠️', + 'spaghetti': '🍝', + 'sparkle': '❇️', + 'sparkler': '🎇', + 'sparkles': '✨', + 'sparkling_heart': '💖', + 'speak_no_evil': '🙊', + 'speaker': '🔈', + 'speaking_head': '🗣', + 'speech_balloon': '💬', + 'speedboat': '🚤', + 'spider': '🕷', + 'spider_web': '🕸', + 'spiral_calendar': '🗓', + 'spiral_notepad': '🗒', + 'sponge': '🧽', + 'spoon': '🥄', + 'squid': '🦑', + 'sri_lanka': '🇱🇰', + 'st_barthelemy': '🇧🇱', + 'st_helena': '🇸🇭', + 'st_kitts_nevis': '🇰🇳', + 'st_lucia': '🇱🇨', + 'st_pierre_miquelon': '🇵🇲', + 'st_vincent_grenadines': '🇻🇨', + 'stadium': '🏟', + 'star': '⭐', + 'star2': '🌟', + 'star_and_crescent': '☪', + 'star_of_david': '✡', + 'star_struck': '🤩', + 'stars': '🌠', + 'station': '🚉', + 'statue_of_liberty': '🗽', + 'steak': '🥩', + 'steam_locomotive': '🚂', + 'stew': '🍲', + 'stop_button': '⏹', + 'stop_sign': '🛑', + 'stopwatch': '⏱', + 'straight_ruler': '📏', + 'strawberry': '🍓', + 'stuck_out_tongue': '😛', + 'stuck_out_tongue_closed_eyes': '😝', + 'stuck_out_tongue_winking_eye': '😜', + 'studio_microphone': '🎙', + 'stuffed_flatbread': '🥙', + 'sudan': '🇸🇩', + 'sun_behind_large_cloud': '🌥', + 'sun_behind_rain_cloud': '🌦', + 'sun_behind_small_cloud': '🌤', + 'sun_with_face': '🌞', + 'sunflower': '🌻', + 'sunglasses': '😎', + 'sunny': '☀️', + 'sunrise': '🌅', + 'sunrise_over_mountains': '🌄', + 'surfing_man': '🏄', + 'surfing_woman': '🏄‍♀️', + 'suriname': '🇸🇷', + 'sushi': '🍣', + 'suspension_railway': '🚟', + 'swan': '🦢', + 'swaziland': '🇸🇿', + 'sweat': '😓', + 'sweat_drops': '💦', + 'sweat_smile': '😅', + 'sweden': '🇸🇪', + 'sweet_potato': '🍠', + 'swimming_man': '🏊', + 'swimming_woman': '🏊‍♀️', + 'switzerland': '🇨🇭', + 'symbols': '🔣', + 'symbols_over_mouth': '🤬', + 'synagogue': '🕍', + 'syria': '🇸🇾', + 'syringe': '💉', + 't-rex': '🦖', + 'taco': '🌮', + 'tada': '🎉', + 'taiwan': '🇹🇼', + 'tajikistan': '🇹🇯', + 'takeout_box': '🥡', + 'tanabata_tree': '🎋', + 'tangerine': '🍊', + 'tanzania': '🇹🇿', + 'taurus': '♉', + 'taxi': '🚕', + 'tea': '🍵', + 'teddy_bear': '🧸', + 'telephone_receiver': '📞', + 'telescope': '🔭', + 'tennis': '🎾', + 'tent': '⛺', + 'test_tube': '🧪', + 'thailand': '🇹🇭', + 'thermometer': '🌡', + 'thinking': '🤔', + 'thought_balloon': '💭', + 'thread': '🧵', + 'three': '3️⃣', + 'ticket': '🎫', + 'tickets': '🎟', + 'tiger': '🐯', + 'tiger2': '🐅', + 'timer_clock': '⏲', + 'timor_leste': '🇹🇱', + 'tipping_hand_man': '💁‍♂️', + 'tipping_hand_woman': '💁', + 'tired_face': '😫', + 'tm': '™️', + 'togo': '🇹🇬', + 'toilet': '🚽', + 'toilet_paper': '🧻', + 'tokelau': '🇹🇰', + 'tokyo_tower': '🗼', + 'tomato': '🍅', + 'tonga': '🇹🇴', + 'tongue': '👅', + 'toolbox': '🧰', + 'tooth': '🦷', + 'top': '🔝', + 'tophat': '🎩', + 'tornado': '🌪', + 'tr': '🇹🇷', + 'trackball': '🖲', + 'tractor': '🚜', + 'traffic_light': '🚥', + 'train': '🚋', + 'train2': '🚆', + 'tram': '🚊', + 'triangular_flag_on_post': '🚩', + 'triangular_ruler': '📐', + 'trident': '🔱', + 'trinidad_tobago': '🇹🇹', + 'triumph': '😤', + 'trolleybus': '🚎', + 'trophy': '🏆', + 'tropical_drink': '🍹', + 'tropical_fish': '🐠', + 'truck': '🚚', + 'trumpet': '🎺', + 'tshirt': '👕', + 'tulip': '🌷', + 'tumbler_glass': '🥃', + 'tunisia': '🇹🇳', + 'turkey': '🦃', + 'turkmenistan': '🇹🇲', + 'turks_caicos_islands': '🇹🇨', + 'turtle': '🐢', + 'tuvalu': '🇹🇻', + 'tv': '📺', + 'twisted_rightwards_arrows': '🔀', + 'two': '2️⃣', + 'two_hearts': '💕', + 'two_men_holding_hands': '👬', + 'two_women_holding_hands': '👭', + 'u5272': '🈹', + 'u5408': '🈴', + 'u55b6': '🈺', + 'u6307': '🈯', + 'u6708': '🈷️', + 'u6709': '🈶', + 'u6e80': '🈵', + 'u7121': '🈚', + 'u7533': '🈸', + 'u7981': '🈲', + 'u7a7a': '🈳', + 'uganda': '🇺🇬', + 'uk': '🇬🇧', + 'ukraine': '🇺🇦', + 'umbrella': '☔', + 'unamused': '😒', + 'underage': '🔞', + 'unicorn': '🦄', + 'united_arab_emirates': '🇦🇪', + 'united_nations': '🇺🇳', + 'unlock': '🔓', + 'up': '🆙', + 'upside_down_face': '🙃', + 'uruguay': '🇺🇾', + 'us': '🇺🇸', + 'us_virgin_islands': '🇻🇮', + 'uzbekistan': '🇺🇿', + 'v': '✌', + 'vanuatu': '🇻🇺', + 'vatican_city': '🇻🇦', + 'venezuela': '🇻🇪', + 'vertical_traffic_light': '🚦', + 'vhs': '📼', + 'vibration_mode': '📳', + 'video_camera': '📹', + 'video_game': '🎮', + 'vietnam': '🇻🇳', + 'violin': '🎻', + 'virgo': '♍', + 'volcano': '🌋', + 'volleyball': '🏐', + 'vomiting': '🤮', + 'vs': '🆚', + 'vulcan_salute': '🖖', + 'wales': '🏴󠁧󠁢󠁷󠁬󠁳󠁿', + 'walking_man': '🚶', + 'walking_woman': '🚶‍♀️', + 'wallis_futuna': '🇼🇫', + 'waning_crescent_moon': '🌘', + 'waning_gibbous_moon': '🌖', + 'warning': '⚠️', + 'wastebasket': '🗑', + 'watch': '⌚', + 'water_buffalo': '🐃', + 'watermelon': '🍉', + 'wave': '👋', + 'wavy_dash': '〰️', + 'waxing_crescent_moon': '🌒', + 'waxing_gibbous_moon': '🌔', + 'wc': '🚾', + 'weary': '😩', + 'wedding': '💒', + 'weight_lifting_man': '🏋', + 'weight_lifting_woman': '🏋️‍♀️', + 'western_sahara': '🇪🇭', + 'whale': '🐳', + 'whale2': '🐋', + 'wheel_of_dharma': '☸', + 'wheelchair': '♿', + 'white_check_mark': '✅', + 'white_circle': '⚪', + 'white_flag': '🏳', + 'white_flower': '💮', + 'white_large_square': '⬜', + 'white_medium_small_square': '◽', + 'white_medium_square': '◻️', + 'white_small_square': '▫️', + 'white_square_button': '🔳', + 'wilted_flower': '🥀', + 'wind_chime': '🎐', + 'wind_face': '🌬', + 'wine_glass': '🍷', + 'wink': '😉', + 'wizard': '🧙‍♂️', + 'wolf': '🐺', + 'woman': '👩', + 'woman_artist': '👩‍🎨', + 'woman_astronaut': '👩‍🚀', + 'woman_cartwheeling': '🤸‍♀️', + 'woman_cook': '👩‍🍳', + 'woman_elf': '🧝‍♀️', + 'woman_facepalming': '🤦‍♀️', + 'woman_factory_worker': '👩‍🏭', + 'woman_fairy': '🧚‍♀️', + 'woman_farmer': '👩‍🌾', + 'woman_firefighter': '👩‍🚒', + 'woman_genie': '🧞‍♀️', + 'woman_health_worker': '👩‍⚕️', + 'woman_in_lotus_position': '🧘‍♀️', + 'woman_in_steamy_room': '🧖‍♀️', + 'woman_judge': '👩‍⚖️', + 'woman_juggling': '🤹‍♀️', + 'woman_mechanic': '👩‍🔧', + 'woman_office_worker': '👩‍💼', + 'woman_pilot': '👩‍✈️', + 'woman_playing_handball': '🤾‍♀️', + 'woman_playing_water_polo': '🤽‍♀️', + 'woman_scientist': '👩‍🔬', + 'woman_shrugging': '🤷', + 'woman_singer': '👩‍🎤', + 'woman_student': '👩‍🎓', + 'woman_superhero': '🦸‍♀️', + 'woman_supervillain': '🦹‍♀️', + 'woman_teacher': '👩‍🏫', + 'woman_technologist': '👩‍💻', + 'woman_vampire': '🧛‍♀️', + 'woman_with_headscarf': '🧕', + 'woman_with_turban': '👳‍♀️', + 'woman_zombie': '🧟‍♀️', + 'womans_clothes': '👚', + 'womans_hat': '👒', + 'women_wrestling': '🤼‍♀️', + 'womens': '🚺', + 'woozy': '🥴', + 'world_map': '🗺', + 'worried': '😟', + 'wrench': '🔧', + 'writing_hand': '✍', + 'x': '❌', + 'yarn': '🧶', + 'yellow_heart': '💛', + 'yemen': '🇾🇪', + 'yen': '💴', + 'yin_yang': '☯', + 'yum': '😋', + 'zambia': '🇿🇲', + 'zany': '🤪', + 'zap': '⚡', + 'zebra': '🦓', + 'zero': '0️⃣', + 'zimbabwe': '🇿🇼', + 'zipper_mouth_face': '🤐', + 'zzz': '💤', +}; diff --git a/pkgs/markdown/lib/src/line.dart b/pkgs/markdown/lib/src/line.dart new file mode 100644 index 000000000..1ccd5da2f --- /dev/null +++ b/pkgs/markdown/lib/src/line.dart @@ -0,0 +1,47 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'patterns.dart'; + +/// A [Line] is a sequence of zero or more characters other than line feed +/// (`U+000A`) or carriage return (`U+000D`), followed by a line ending or by +/// the end of file. +// See https://spec.commonmark.org/0.30/#line. +class Line { + /// A sequence of zero or more characters other than the line ending. + final String content; + + /// How many spaces of a tab that remains after part of it has been consumed. + // See: https://spec.commonmark.org/0.30/#example-6 + // We cannot simply expand the `tabRemaining` to spaces, for example + // + // `>\t\tfoo` + // + // If we expand the 2 space width `tabRemaining` from blockquote block into 2 + // spaces, so the string segment for the indented code block is: + // + // ` \tfoo`, + // + // then the output will be: + // ```html + //
foo
+  // 
+ // ``` + // instead of the expected: + // ```html + //
  foo
+  // 
+ // ``` + final int? tabRemaining; + + // A line containing no characters, or a line containing only spaces + // (`U+0020`) or tabs (`U+0009`), is called a blank line. + // https://spec.commonmark.org/0.30/#blank-line + final bool isBlankLine; + + Line( + this.content, { + this.tabRemaining, + }) : isBlankLine = emptyPattern.hasMatch(content); +} diff --git a/pkgs/markdown/lib/src/link_parser.dart b/pkgs/markdown/lib/src/link_parser.dart new file mode 100644 index 000000000..4db22ad36 --- /dev/null +++ b/pkgs/markdown/lib/src/link_parser.dart @@ -0,0 +1,270 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'charcode.dart'; +import 'text_parser.dart'; +import 'util.dart'; + +class LinkParser extends TextParser { + /// If there is a valid link formed. + bool get valid => _valid; + bool _valid = false; + + /// Link label. + String? get label => _label; + String? _label; + + /// Link destination. + String? get destination => _destination; + String? _destination; + + /// Link title. + String? get title => _title; + String? _title; + + LinkParser(super.source); + + /// How many lines of the [source] have been consumed by link reference + /// definition. + int get unconsumedLines => _unconsumedLines; + int _unconsumedLines = 0; + + /// Parses [source] to a link reference definition. + void parseDefinition() { + if (!parseLabel() || isDone || charAt() != $colon) { + return; + } + + // Advance to the next character after the colon. + advance(); + if (!_parseDestination()) { + return; + } + + var precedingWhitespaces = moveThroughWhitespace(); + if (isDone) { + _valid = true; + return; + } + + final multiline = charAt() == $lf; + precedingWhitespaces += moveThroughWhitespace(multiLine: true); + + // The title must be preceded by whitespaces. + if (precedingWhitespaces == 0 || isDone) { + _valid = isDone; + return; + } + + final hasValidTitle = _parseTitle(); + // For example: `[foo]: "baz` is a invalid definition, but this one is + // valid: + // ``` + // [foo]: + // "baz + // ``` + if (!hasValidTitle && !multiline) { + return; + } + + if (hasValidTitle) { + moveThroughWhitespace(); + if (!isDone && charAt() != $lf) { + // It is not a valid definition if the title is followed by + // non-whitespace characters, for example: `[foo]: "baz" hello`. + // See https://spec.commonmark.org/0.30/#example-209. + if (!multiline) { + return; + } + // But it is a valid link reference definition if this definition is + // multiline, see https://spec.commonmark.org/0.30/#example-210. + _title = null; + } + } + + final linesUnconsumed = source.substring(pos).split('\n'); + if (linesUnconsumed.isNotEmpty && linesUnconsumed.first.isBlank) { + linesUnconsumed.removeAt(0); + } + _unconsumedLines = linesUnconsumed.length; + + _valid = true; + } + + /// Parses the link label, returns `true` if there is a valid link label. + bool parseLabel() { + moveThroughWhitespace(multiLine: true); + + if (length - pos < 2) { + return false; + } + + if (charAt() != $lbracket) { + return false; + } + + // Advance past the opening `[`. + advance(); + final start = pos; + + // A link label can have at most 999 characters inside the square brackets. + // See https://spec.commonmark.org/0.30/#link-label. + var maxLoop = 999; + while (true) { + if (maxLoop-- < 0) { + return false; + } + final char = charAt(pos); + if (char == $backslash) { + advance(); + } else if (char == $lbracket) { + return false; + } else if (char == $rbracket) { + break; + } + advance(); + if (isDone) { + return false; + } + } + + final text = substring(start, pos); + if (text.isBlank) { + return false; + } + + // Advance past the closing `]`. + advance(); + _label = text; + return true; + } + + /// Parses the link destination, returns `true` there is a valid link + /// destination. + bool _parseDestination() { + moveThroughWhitespace(multiLine: true); + if (isDone) { + return false; + } + + final isValidDestination = charAt() == $lt + ? _parseBracketedDestination() + : _parseBareDestination(); + + return isValidDestination; + } + + /// Parses bracketed destinations (destinations wrapped in `<...>`). The + /// current position of the parser must be the first character of the + /// destination. + /// + /// Returns `true` if there is a valid link destination. + bool _parseBracketedDestination() { + // Walk past the opening `<`. + advance(); + + final start = pos; + while (true) { + final char = charAt(); + if (char == $backslash) { + advance(); + } else if (char == $lf || char == $cr || char == $ff) { + return false; + } else if (char == $gt) { + break; + } + advance(); + if (isDone) { + return false; + } + } + + _destination = substring(start, pos); + + // Advance past the closing `>`. + advance(); + return true; + } + + /// Parse "bare" destinations (destinations _not_ wrapped in `<...>`). The + /// current position of the parser must be the first character of the + /// destination. + /// + /// Returns `true` if there is a valid link destination. + bool _parseBareDestination() { + var parenCount = 0; + final start = pos; + + while (true) { + final char = charAt(); + if (char == $backslash) { + advance(); + } else if (char == $space || char == $lf || char == $cr || char == $ff) { + break; + } else if (char == $lparen) { + parenCount++; + } else if (char == $rparen) { + parenCount--; + if (parenCount == 0) { + advance(); + break; + } + } + advance(); + + // There is no ending delimiter, so `isDone` also means it is at the end + // of a link destination. + if (isDone) { + break; + } + } + + _destination = substring(start, pos); + return true; + } + + /// Parses the **optional** link title, returns `true` if there is a valid + /// link title. + bool _parseTitle() { + // See: https://spec.commonmark.org/0.30/#link-title + // The whitespace should be followed by a title delimiter. + final delimiter = charAt(); + if (delimiter != $apostrophe && + delimiter != $quote && + delimiter != $lparen) { + return false; + } + + final closeDelimiter = delimiter == $lparen ? $rparen : delimiter; + advance(); + if (isDone) { + return false; + } + final start = pos; + + // Looking for an un-escaped closing delimiter. + while (true) { + final char = charAt(); + if (char == $backslash) { + advance(); + } else if (char == closeDelimiter) { + break; + } + advance(); + if (isDone) { + return false; + } + } + + if (isDone) { + return false; + } + + _title = substring(start, pos); + + // Advance past the closing delimiter. + advance(); + return true; + } +} diff --git a/pkgs/markdown/lib/src/patterns.dart b/pkgs/markdown/lib/src/patterns.dart new file mode 100644 index 000000000..2690419cc --- /dev/null +++ b/pkgs/markdown/lib/src/patterns.dart @@ -0,0 +1,162 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// The line contains only whitespace or is empty. +final emptyPattern = RegExp(r'^(?:[ \t]*)$'); + +/// A series of `=` or `-` (on the next line) define setext-style headers. +final setextPattern = RegExp(r'^[ ]{0,3}(=+|-+)\s*$'); + +/// Leading (and trailing) `#` define atx-style headers. +/// +/// Starts with 1-6 unescaped `#` characters which must not be followed by a +/// non-space character. Line may end with any number of `#` characters,. +final headerPattern = + RegExp(r'^ {0,3}(#{1,6})(?:[ \x09\x0b\x0c].*?)?(?:\s(#*)\s*)?$'); + +/// The line starts with `>` with one optional space after. +final blockquotePattern = RegExp(r'^[ ]{0,3}>[ \t]?.*$'); + +/// A line indented four spaces. Used for code blocks and lists. +final indentPattern = RegExp(r'^(?: | {0,3}\t)(.*)$'); + +/// Fenced code block. +final codeFencePattern = RegExp( + '^([ ]{0,3})(?:(?`{3,})(?[^`]*)|' + r'(?~{3,})(?.*))$', +); + +/// Fenced blockquotes. +final blockquoteFencePattern = RegExp(r'^>{3}\s*$'); + +/// Three or more hyphens, asterisks or underscores by themselves. Note that +/// a line like `----` is valid as both HR and SETEXT. In case of a tie, +/// SETEXT should win. +final hrPattern = RegExp(r'^ {0,3}([-*_])[ \t]*\1[ \t]*\1(?:\1|[ \t])*$'); + +/// **Unordered list** +/// A line starting with one of these markers: `-`, `*`, `+`. May have up to +/// three leading spaces before the marker and any number of spaces or tabs +/// after. +/// +/// **Ordered list** +/// +/// A line starting with a number like `123.`. May have up to three leading +/// spaces before the marker and any number of spaces or tabs after. +final listPattern = + RegExp(r'^[ ]{0,3}(?:(\d{1,9})[\.)]|[*+-])(?:[ \t]+(.*))?$'); + +/// A line of hyphens separated by at least one pipe. +final tablePattern = RegExp( + r'^[ ]{0,3}\|?([ \t]*:?\-+:?[ \t]*\|[ \t]*)+([ \t]|[ \t]*:?\-+:?[ \t]*)?$'); + +/// A line starting with `[^` and contains with `]:`, but without special chars +/// (`\] \r\n\x00\t`) between. Same as [GFM](cmark-gfm/src/scanners.re:318). +final footnotePattern = RegExp(r'(^[ ]{0,3})\[\^([^\] \r\n\x00\t]+)\]:[ \t]*'); + +/// A pattern which should never be used. It just satisfies non-nullability of +/// pattern fields. +final dummyPattern = RegExp(''); + +/// A [String] pattern to match a named tag like `` or `
`. +const namedTagDefinition = + // Opening tag begins. + '<' + + // Tag name. + '[a-z][a-z0-9-]*' + + // Attribute begins, see + // https://spec.commonmark.org/0.30/#attribute. + r'(?:\s+' + + // Attribute name, see + // https://spec.commonmark.org/0.30/#attribute-name. + '[a-z_:][a-z0-9._:-]*' + + // + '(?:' + // Attribute value specification, see + // https://spec.commonmark.org/0.30/#attribute-value-specification. + r'\s*=\s*' + + // Attribute value, see + // https://spec.commonmark.org/0.30/#unquoted-attribute-value. + r'''(?:[^\s"'=<>`]+?|'[^']*?'|"[^"]*?")''' + + // Attribute ends. + ')?)*' + + // Opening tag ends. + r'\s*/?>' + + // Or + '|' + + // Closing tag, see + // https://spec.commonmark.org/0.30/#closing-tag. + r''; + +/// A pattern to match the start of an HTML block. +/// +/// The 7 conditions here correspond to the 7 start conditions in the Commonmark +/// specification one by one: https://spec.commonmark.org/0.30/#html-block. +final htmlBlockPattern = RegExp( + '^ {0,3}(?:' + '<(?pre|script|style|textarea)' + r'(?:\s|>|$)' + '|' + '(?', + '";alert(123);t="', + '\';alert(123);t=\'', + 'JavaSCript:alert(123)', + ';alert(123);', + 'src=JaVaSCript:prompt(132)', + '">javascript:alert(1);', + 'javascript:alert(1);', + 'javascript:alert(1);', + 'javascript:alert(1);', + 'javascript:alert(1);', + 'javascript:alert(1);', + 'javascript:alert(1);', + '\'`"><\\x3Cscript>javascript:alert(1)', + '\'`"><\\x00script>javascript:alert(1)', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'ABC
DEF', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + 'test', + '`"\'>', + '`"\'>', + '`"\'>', + '`"\'>', + '`"\'>', + '`"\'>', + '`"\'>', + '`"\'>', + '`"\'>', + '`"\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '"`\'>', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + 'XXX', + '', + '', + '', + '<a href=http://foo.bar/#x=`y></a><img alt="`><img src=x:x onerror=javascript:alert(1)></a>">', + '<!--[if]><script>javascript:alert(1)</script -->', + '<!--[if<img src=x onerror=javascript:alert(1)//]> -->', + '<script src="/\\%(jscript)s"></script>', + '<script src="\\\\%(jscript)s"></script>', + '<IMG """><SCRIPT>alert("XSS")</SCRIPT>">', + '<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>', + '<IMG SRC=# onmouseover="alert(\'xxs\')">', + '<IMG SRC= onmouseover="alert(\'xxs\')">', + '<IMG onmouseover="alert(\'xxs\')">', + '<IMG SRC=javascript:alert('XSS')>', + '<IMG SRC=javascript:alert('XSS')>', + '<IMG SRC=javascript:alert('XSS')>', + '<IMG SRC="jav ascript:alert(\'XSS\');">', + '<IMG SRC="jav ascript:alert(\'XSS\');">', + '<IMG SRC="jav ascript:alert(\'XSS\');">', + '<IMG SRC="jav ascript:alert(\'XSS\');">', + 'perl -e \'print "<IMG SRC=java\\0script:alert(\\"XSS\\")>";\' > out', + '<IMG SRC="  javascript:alert(\'XSS\');">', + '<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>', + '<BODY onload!#\$%&()*~+-_.,:;?@[/|\\]^`=alert("XSS")>', + '<SCRIPT/SRC="http://ha.ckers.org/xss.js"></SCRIPT>', + '<<SCRIPT>alert("XSS");//<</SCRIPT>', + '<SCRIPT SRC=http://ha.ckers.org/xss.js?< B >', + '<SCRIPT SRC=//ha.ckers.org/.j>', + '<IMG SRC="javascript:alert(\'XSS\')"', + '<iframe src=http://ha.ckers.org/scriptlet.html <', + '\\";alert(\'XSS\');//', + '<u oncopy=alert()> Copy me</u>', + '<i onwheel=alert(1)> Scroll over me </i>', + '<plaintext>', + 'http://a/%%30%30', + '</textarea><script>alert(123)</script>', + '1;DROP TABLE users', + '1\'; DROP TABLE users-- 1', + '\' OR 1=1 -- 1', + '\' OR \'1\'=\'1', + '\'; EXEC sp_MSForEachTable \'DROP TABLE ?\'; --', + ' ', + '%', + '_', + '-', + '--', + '--version', + '--help', + '\$USER', + '/dev/null; touch /tmp/blns.fail ; echo', + '`touch /tmp/blns.fail`', + '\$(touch /tmp/blns.fail)', + '@{[system "touch /tmp/blns.fail"]}', + 'eval("puts \'hello world\'")', + 'System("ls -al /")', + '`ls -al /`', + 'Kernel.exec("ls -al /")', + 'Kernel.exit(1)', + '%x(\'ls -al /\')', + '<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE foo [ <!ELEMENT foo ANY ><!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo>', + '\$HOME', + '\$ENV{\'HOME\'}', + '%d', + '%s%s%s%s%s', + '{0}', + '%*.*s', + '%@', + '%n', + 'File:///', + '../../../../../../../../../../../etc/passwd%00', + '../../../../../../../../../../../etc/hosts', + '() { 0; }; touch /tmp/blns.shellshock1.fail;', + '() { _; } >_[\$(\$())] { touch /tmp/blns.shellshock2.fail; }', + '<<< %s(un=\'%s\') = %u', + '+++ATH0', + 'CON', + 'PRN', + 'AUX', + 'CLOCK\$', + 'NUL', + 'A:', + 'ZZ:', + 'COM1', + 'LPT1', + 'LPT2', + 'LPT3', + 'COM2', + 'COM3', + 'COM4', + 'DCC SEND STARTKEYLOGGER 0 0 0', + 'Scunthorpe General Hospital', + 'Penistone Community Church', + 'Lightwater Country Park', + 'Jimmy Clitheroe', + 'Horniman Museum', + 'shitake mushrooms', + 'RomansInSussex.co.uk', + 'http://www.cum.qc.ca/', + 'Craig Cockburn, Software Specialist', + 'Linda Callahan', + 'Dr. Herman I. Libshitz', + 'magna cum laude', + 'Super Bowl XXX', + 'medieval erection of parapets', + 'evaluate', + 'mocha', + 'expression', + 'Arsenal canal', + 'classic', + 'Tyson Gay', + 'Dick Van Dyke', + 'basement', + 'If you\'re reading this, you\'ve been in a coma for almost 20 years now. We\'re trying a new technique. We don\'t know where this message will end up in your dream, but we hope it works. Please wake up, we miss you.', + 'Roses are red, violets are blue. Hope you enjoy terminal hue', + 'But now...for my greatest trick...', + 'The quick brown fox... [Beeeep]', + 'Powerلُلُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ冗', + '🏳0🌈️', + 'జ్ఞ‌ా', + 'گچپژ', + '{% print \'x\' * 64 * 1024**3 %}', + '{{ "".__class__.__mro__[2].__subclasses__()[40]("/etc/passwd").read() }}', +]; diff --git a/pkgs/markdown/test/blns_test.dart b/pkgs/markdown/test/blns_test.dart new file mode 100644 index 000000000..69790ef8d --- /dev/null +++ b/pkgs/markdown/test/blns_test.dart @@ -0,0 +1,39 @@ +// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:markdown/markdown.dart'; +import 'package:test/test.dart'; + +import 'blns.dart'; + +// The BLNS tests merely test that `markdownToHtml` does not throw or hang while +// processing "naughty string" inputs. While there are examples of multi-byte +// characters, non-visible characters, etc., these tests should not be _relied +// upon_ for testing multi-byte character support, etc. +void main() { + test('parsing blns', () { + // This is more a test of update_blns.dart: we're testing that the strings + // were encoded half-decently, and nothing got globbed up into a big + // multiline string. + expect(blns, hasLength(515)); + }); + + var index = 0; + for (final str in blns) { + test('blns string $index', () { + final result = markdownToHtml(str); + expect(result, const TypeMatcher<String>()); + }); + index++; + } + + index = 0; + for (final str in blns) { + test('blns string $index w/ gitHubWeb', () { + final result = markdownToHtml(str, extensionSet: ExtensionSet.gitHubWeb); + expect(result, const TypeMatcher<String>()); + }); + index++; + } +} diff --git a/pkgs/markdown/test/common_mark/atx_headings.unit b/pkgs/markdown/test/common_mark/atx_headings.unit new file mode 100644 index 000000000..1cb7e98b5 --- /dev/null +++ b/pkgs/markdown/test/common_mark/atx_headings.unit @@ -0,0 +1,112 @@ +>>> ATX headings - 62 +# foo +## foo +### foo +#### foo +##### foo +###### foo +<<< +<h1>foo</h1> +<h2>foo</h2> +<h3>foo</h3> +<h4>foo</h4> +<h5>foo</h5> +<h6>foo</h6> +>>> ATX headings - 63 +####### foo +<<< +<p>####### foo</p> +>>> ATX headings - 64 +#5 bolt + +#hashtag +<<< +<p>#5 bolt</p> +<p>#hashtag</p> +>>> ATX headings - 65 +\## foo +<<< +<p>## foo</p> +>>> ATX headings - 66 +# foo *bar* \*baz\* +<<< +<h1>foo <em>bar</em> *baz*</h1> +>>> ATX headings - 67 +# foo +<<< +<h1>foo</h1> +>>> ATX headings - 68 + ### foo + ## foo + # foo +<<< +<h3>foo</h3> +<h2>foo</h2> +<h1>foo</h1> +>>> ATX headings - 69 + # foo +<<< +<pre><code># foo +</code></pre> +>>> ATX headings - 70 +foo + # bar +<<< +<p>foo +# bar</p> +>>> ATX headings - 71 +## foo ## + ### bar ### +<<< +<h2>foo</h2> +<h3>bar</h3> +>>> ATX headings - 72 +# foo ################################## +##### foo ## +<<< +<h1>foo</h1> +<h5>foo</h5> +>>> ATX headings - 73 +### foo ### +<<< +<h3>foo</h3> +>>> ATX headings - 74 +### foo ### b +<<< +<h3>foo ### b</h3> +>>> ATX headings - 75 +# foo# +<<< +<h1>foo#</h1> +>>> ATX headings - 76 +### foo \### +## foo #\## +# foo \# +<<< +<h3>foo ###</h3> +<h2>foo ###</h2> +<h1>foo #</h1> +>>> ATX headings - 77 +**** +## foo +**** +<<< +<hr /> +<h2>foo</h2> +<hr /> +>>> ATX headings - 78 +Foo bar +# baz +Bar foo +<<< +<p>Foo bar</p> +<h1>baz</h1> +<p>Bar foo</p> +>>> ATX headings - 79 +## +# +### ### +<<< +<h2></h2> +<h1></h1> +<h3></h3> diff --git a/pkgs/markdown/test/common_mark/autolinks.unit b/pkgs/markdown/test/common_mark/autolinks.unit new file mode 100644 index 000000000..0bb319c21 --- /dev/null +++ b/pkgs/markdown/test/common_mark/autolinks.unit @@ -0,0 +1,76 @@ +>>> Autolinks - 594 +<http://foo.bar.baz> +<<< +<p><a href="http://foo.bar.baz">http://foo.bar.baz</a></p> +>>> Autolinks - 595 +<https://foo.bar.baz/test?q=hello&id=22&boolean> +<<< +<p><a href="https://foo.bar.baz/test?q=hello&id=22&boolean">https://foo.bar.baz/test?q=hello&id=22&boolean</a></p> +>>> Autolinks - 596 +<irc://foo.bar:2233/baz> +<<< +<p><a href="irc://foo.bar:2233/baz">irc://foo.bar:2233/baz</a></p> +>>> Autolinks - 597 +<MAILTO:FOO@BAR.BAZ> +<<< +<p><a href="MAILTO:FOO@BAR.BAZ">MAILTO:FOO@BAR.BAZ</a></p> +>>> Autolinks - 598 +<a+b+c:d> +<<< +<p><a href="a+b+c:d">a+b+c:d</a></p> +>>> Autolinks - 599 +<made-up-scheme://foo,bar> +<<< +<p><a href="made-up-scheme://foo,bar">made-up-scheme://foo,bar</a></p> +>>> Autolinks - 600 +<https://../> +<<< +<p><a href="https://../">https://../</a></p> +>>> Autolinks - 601 +<localhost:5001/foo> +<<< +<p><a href="localhost:5001/foo">localhost:5001/foo</a></p> +>>> Autolinks - 602 +<https://foo.bar/baz bim> +<<< +<p><https://foo.bar/baz bim></p> +>>> Autolinks - 603 +<https://example.com/\[\> +<<< +<p><a href="https://example.com/%5C%5B%5C">https://example.com/\[\</a></p> +>>> Autolinks - 604 +<foo@bar.example.com> +<<< +<p><a href="mailto:foo@bar.example.com">foo@bar.example.com</a></p> +>>> Autolinks - 605 +<foo+special@Bar.baz-bar0.com> +<<< +<p><a href="mailto:foo+special@Bar.baz-bar0.com">foo+special@Bar.baz-bar0.com</a></p> +>>> Autolinks - 606 +<foo\+@bar.example.com> +<<< +<p><foo+@bar.example.com></p> +>>> Autolinks - 607 +<> +<<< +<p><></p> +>>> Autolinks - 608 +< https://foo.bar > +<<< +<p>< https://foo.bar ></p> +>>> Autolinks - 609 +<m:abc> +<<< +<p><m:abc></p> +>>> Autolinks - 610 +<foo.bar.baz> +<<< +<p><foo.bar.baz></p> +>>> Autolinks - 611 +https://example.com +<<< +<p>https://example.com</p> +>>> Autolinks - 612 +foo@bar.example.com +<<< +<p>foo@bar.example.com</p> diff --git a/pkgs/markdown/test/common_mark/backslash_escapes.unit b/pkgs/markdown/test/common_mark/backslash_escapes.unit new file mode 100644 index 000000000..54766e41f --- /dev/null +++ b/pkgs/markdown/test/common_mark/backslash_escapes.unit @@ -0,0 +1,79 @@ +>>> Backslash escapes - 12 +\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~ +<<< +<p>!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~</p> +>>> Backslash escapes - 13 +\ \A\a\ \3\φ\« +<<< +<p>\ \A\a\ \3\φ\«</p> +>>> Backslash escapes - 14 +\*not emphasized* +\<br/> not a tag +\[not a link](/foo) +\`not code` +1\. not a list +\* not a list +\# not a heading +\[foo]: /url "not a reference" +\ö not a character entity +<<< +<p>*not emphasized* +<br/> not a tag +[not a link](/foo) +`not code` +1. not a list +* not a list +# not a heading +[foo]: /url "not a reference" +&ouml; not a character entity</p> +>>> Backslash escapes - 15 +\\*emphasis* +<<< +<p>\<em>emphasis</em></p> +>>> Backslash escapes - 16 +foo\ +bar +<<< +<p>foo<br /> +bar</p> +>>> Backslash escapes - 17 +`` \[\` `` +<<< +<p><code>\[\`</code></p> +>>> Backslash escapes - 18 + \[\] +<<< +<pre><code>\[\] +</code></pre> +>>> Backslash escapes - 19 +~~~ +\[\] +~~~ +<<< +<pre><code>\[\] +</code></pre> +>>> Backslash escapes - 20 +<https://example.com?find=\*> +<<< +<p><a href="https://example.com?find=%5C*">https://example.com?find=\*</a></p> +>>> Backslash escapes - 21 +<a href="/bar\/)"> +<<< +<a href="/bar\/)"> +>>> Backslash escapes - 22 +[foo](/bar\* "ti\*tle") +<<< +<p><a href="/bar*" title="ti*tle">foo</a></p> +>>> Backslash escapes - 23 +[foo] + +[foo]: /bar\* "ti\*tle" +<<< +<p><a href="/bar*" title="ti*tle">foo</a></p> +>>> Backslash escapes - 24 +``` foo\+bar +foo +``` +<<< +<pre><code class="language-foo+bar">foo +</code></pre> diff --git a/pkgs/markdown/test/common_mark/blank_lines.unit b/pkgs/markdown/test/common_mark/blank_lines.unit new file mode 100644 index 000000000..86977bdb1 --- /dev/null +++ b/pkgs/markdown/test/common_mark/blank_lines.unit @@ -0,0 +1,12 @@ +>>> Blank lines - 227 + + +aaa + + +# aaa + + +<<< +<p>aaa</p> +<h1>aaa</h1> diff --git a/pkgs/markdown/test/common_mark/block_quotes.unit b/pkgs/markdown/test/common_mark/block_quotes.unit new file mode 100644 index 000000000..99310440c --- /dev/null +++ b/pkgs/markdown/test/common_mark/block_quotes.unit @@ -0,0 +1,239 @@ +>>> Block quotes - 228 +> # Foo +> bar +> baz +<<< +<blockquote> +<h1>Foo</h1> +<p>bar +baz</p> +</blockquote> +>>> Block quotes - 229 +># Foo +>bar +> baz +<<< +<blockquote> +<h1>Foo</h1> +<p>bar +baz</p> +</blockquote> +>>> Block quotes - 230 + > # Foo + > bar + > baz +<<< +<blockquote> +<h1>Foo</h1> +<p>bar +baz</p> +</blockquote> +>>> Block quotes - 231 + > # Foo + > bar + > baz +<<< +<pre><code>> # Foo +> bar +> baz +</code></pre> +>>> Block quotes - 232 +> # Foo +> bar +baz +<<< +<blockquote> +<h1>Foo</h1> +<p>bar +baz</p> +</blockquote> +>>> Block quotes - 233 +> bar +baz +> foo +<<< +<blockquote> +<p>bar +baz +foo</p> +</blockquote> +>>> Block quotes - 234 +> foo +--- +<<< +<blockquote> +<p>foo</p> +</blockquote> +<hr /> +>>> Block quotes - 235 +> - foo +- bar +<<< +<blockquote> +<ul> +<li>foo</li> +</ul> +</blockquote> +<ul> +<li>bar</li> +</ul> +>>> Block quotes - 236 +> foo + bar +<<< +<blockquote> +<pre><code>foo +</code></pre> +</blockquote> +<pre><code>bar +</code></pre> +>>> Block quotes - 237 +> ``` +foo +``` +<<< +<blockquote> +<pre><code></code></pre> +</blockquote> +<p>foo</p> +<pre><code></code></pre> +>>> Block quotes - 238 +> foo + - bar +<<< +<blockquote> +<p>foo +- bar</p> +</blockquote> +>>> Block quotes - 239 +> +<<< +<blockquote> +</blockquote> +>>> Block quotes - 240 +> +> +> +<<< +<blockquote> +</blockquote> +>>> Block quotes - 241 +> +> foo +> +<<< +<blockquote> +<p>foo</p> +</blockquote> +>>> Block quotes - 242 +> foo + +> bar +<<< +<blockquote> +<p>foo</p> +</blockquote> +<blockquote> +<p>bar</p> +</blockquote> +>>> Block quotes - 243 +> foo +> bar +<<< +<blockquote> +<p>foo +bar</p> +</blockquote> +>>> Block quotes - 244 +> foo +> +> bar +<<< +<blockquote> +<p>foo</p> +<p>bar</p> +</blockquote> +>>> Block quotes - 245 +foo +> bar +<<< +<p>foo</p> +<blockquote> +<p>bar</p> +</blockquote> +>>> Block quotes - 246 +> aaa +*** +> bbb +<<< +<blockquote> +<p>aaa</p> +</blockquote> +<hr /> +<blockquote> +<p>bbb</p> +</blockquote> +>>> Block quotes - 247 +> bar +baz +<<< +<blockquote> +<p>bar +baz</p> +</blockquote> +>>> Block quotes - 248 +> bar + +baz +<<< +<blockquote> +<p>bar</p> +</blockquote> +<p>baz</p> +>>> Block quotes - 249 +> bar +> +baz +<<< +<blockquote> +<p>bar</p> +</blockquote> +<p>baz</p> +>>> Block quotes - 250 +> > > foo +bar +<<< +<blockquote> +<blockquote> +<blockquote> +<p>foo +bar</p> +</blockquote> +</blockquote> +</blockquote> +>>> Block quotes - 251 +>>> foo +> bar +>>baz +<<< +<blockquote> +<blockquote> +<blockquote> +<p>foo +bar +baz</p> +</blockquote> +</blockquote> +</blockquote> +>>> Block quotes - 252 +> code + +> not code +<<< +<blockquote> +<pre><code>code +</code></pre> +</blockquote> +<blockquote> +<p>not code</p> +</blockquote> diff --git a/pkgs/markdown/test/common_mark/code_spans.unit b/pkgs/markdown/test/common_mark/code_spans.unit new file mode 100644 index 000000000..5ff95dd2a --- /dev/null +++ b/pkgs/markdown/test/common_mark/code_spans.unit @@ -0,0 +1,97 @@ +>>> Code spans - 328 +`foo` +<<< +<p><code>foo</code></p> +>>> Code spans - 329 +`` foo ` bar `` +<<< +<p><code>foo ` bar</code></p> +>>> Code spans - 330 +` `` ` +<<< +<p><code>``</code></p> +>>> Code spans - 331 +` `` ` +<<< +<p><code> `` </code></p> +>>> Code spans - 332 +` a` +<<< +<p><code> a</code></p> +>>> Code spans - 333 +` b ` +<<< +<p><code> b </code></p> +>>> Code spans - 334 +` ` +` ` +<<< +<p><code> </code> +<code> </code></p> +>>> Code spans - 335 +`` +foo +bar +baz +`` +<<< +<p><code>foo bar baz</code></p> +>>> Code spans - 336 +`` +foo +`` +<<< +<p><code>foo </code></p> +>>> Code spans - 337 +`foo bar +baz` +<<< +<p><code>foo bar baz</code></p> +>>> Code spans - 338 +`foo\`bar` +<<< +<p><code>foo\</code>bar`</p> +>>> Code spans - 339 +``foo`bar`` +<<< +<p><code>foo`bar</code></p> +>>> Code spans - 340 +` foo `` bar ` +<<< +<p><code>foo `` bar</code></p> +>>> Code spans - 341 +*foo`*` +<<< +<p>*foo<code>*</code></p> +>>> Code spans - 342 +[not a `link](/foo`) +<<< +<p>[not a <code>link](/foo</code>)</p> +>>> Code spans - 343 +`<a href="`">` +<<< +<p><code><a href="</code>">`</p> +>>> Code spans - 344 +<a href="`">` +<<< +<p><a href="`">`</p> +>>> Code spans - 345 +`<https://foo.bar.`baz>` +<<< +<p><code><https://foo.bar.</code>baz>`</p> +>>> Code spans - 346 +<https://foo.bar.`baz>` +<<< +<p><a href="https://foo.bar.%60baz">https://foo.bar.`baz</a>`</p> +>>> Code spans - 347 +```foo`` +<<< +<p>```foo``</p> +>>> Code spans - 348 +`foo +<<< +<p>`foo</p> +>>> Code spans - 349 +`foo``bar`` +<<< +<p>`foo<code>bar</code></p> diff --git a/pkgs/markdown/test/common_mark/emphasis_and_strong_emphasis.unit b/pkgs/markdown/test/common_mark/emphasis_and_strong_emphasis.unit new file mode 100644 index 000000000..6c8181da6 --- /dev/null +++ b/pkgs/markdown/test/common_mark/emphasis_and_strong_emphasis.unit @@ -0,0 +1,546 @@ +>>> Emphasis and strong emphasis - 350 +*foo bar* +<<< +<p><em>foo bar</em></p> +>>> Emphasis and strong emphasis - 351 +a * foo bar* +<<< +<p>a * foo bar*</p> +>>> Emphasis and strong emphasis - 352 +a*"foo"* +<<< +<p>a*"foo"*</p> +>>> Emphasis and strong emphasis - 353 +* a * +<<< +<p>* a *</p> +>>> Emphasis and strong emphasis - 354 +*$*alpha. + +*£*bravo. + +*€*charlie. +<<< +<p>*$*alpha.</p> +<p><em>£</em>bravo.</p> +<p><em>€</em>charlie.</p> +>>> Emphasis and strong emphasis - 355 +foo*bar* +<<< +<p>foo<em>bar</em></p> +>>> Emphasis and strong emphasis - 356 +5*6*78 +<<< +<p>5<em>6</em>78</p> +>>> Emphasis and strong emphasis - 357 +_foo bar_ +<<< +<p><em>foo bar</em></p> +>>> Emphasis and strong emphasis - 358 +_ foo bar_ +<<< +<p>_ foo bar_</p> +>>> Emphasis and strong emphasis - 359 +a_"foo"_ +<<< +<p>a_"foo"_</p> +>>> Emphasis and strong emphasis - 360 +foo_bar_ +<<< +<p>foo_bar_</p> +>>> Emphasis and strong emphasis - 361 +5_6_78 +<<< +<p>5_6_78</p> +>>> Emphasis and strong emphasis - 362 +пристаням_стремятся_ +<<< +<p>пристаням_стремятся_</p> +>>> Emphasis and strong emphasis - 363 +aa_"bb"_cc +<<< +<p>aa_"bb"_cc</p> +>>> Emphasis and strong emphasis - 364 +foo-_(bar)_ +<<< +<p>foo-<em>(bar)</em></p> +>>> Emphasis and strong emphasis - 365 +_foo* +<<< +<p>_foo*</p> +>>> Emphasis and strong emphasis - 366 +*foo bar * +<<< +<p>*foo bar *</p> +>>> Emphasis and strong emphasis - 367 +*foo bar +* +<<< +<p>*foo bar +*</p> +>>> Emphasis and strong emphasis - 368 +*(*foo) +<<< +<p>*(*foo)</p> +>>> Emphasis and strong emphasis - 369 +*(*foo*)* +<<< +<p><em>(<em>foo</em>)</em></p> +>>> Emphasis and strong emphasis - 370 +*foo*bar +<<< +<p><em>foo</em>bar</p> +>>> Emphasis and strong emphasis - 371 +_foo bar _ +<<< +<p>_foo bar _</p> +>>> Emphasis and strong emphasis - 372 +_(_foo) +<<< +<p>_(_foo)</p> +>>> Emphasis and strong emphasis - 373 +_(_foo_)_ +<<< +<p><em>(<em>foo</em>)</em></p> +>>> Emphasis and strong emphasis - 374 +_foo_bar +<<< +<p>_foo_bar</p> +>>> Emphasis and strong emphasis - 375 +_пристаням_стремятся +<<< +<p>_пристаням_стремятся</p> +>>> Emphasis and strong emphasis - 376 +_foo_bar_baz_ +<<< +<p><em>foo_bar_baz</em></p> +>>> Emphasis and strong emphasis - 377 +_(bar)_. +<<< +<p><em>(bar)</em>.</p> +>>> Emphasis and strong emphasis - 378 +**foo bar** +<<< +<p><strong>foo bar</strong></p> +>>> Emphasis and strong emphasis - 379 +** foo bar** +<<< +<p>** foo bar**</p> +>>> Emphasis and strong emphasis - 380 +a**"foo"** +<<< +<p>a**"foo"**</p> +>>> Emphasis and strong emphasis - 381 +foo**bar** +<<< +<p>foo<strong>bar</strong></p> +>>> Emphasis and strong emphasis - 382 +__foo bar__ +<<< +<p><strong>foo bar</strong></p> +>>> Emphasis and strong emphasis - 383 +__ foo bar__ +<<< +<p>__ foo bar__</p> +>>> Emphasis and strong emphasis - 384 +__ +foo bar__ +<<< +<p>__ +foo bar__</p> +>>> Emphasis and strong emphasis - 385 +a__"foo"__ +<<< +<p>a__"foo"__</p> +>>> Emphasis and strong emphasis - 386 +foo__bar__ +<<< +<p>foo__bar__</p> +>>> Emphasis and strong emphasis - 387 +5__6__78 +<<< +<p>5__6__78</p> +>>> Emphasis and strong emphasis - 388 +пристаням__стремятся__ +<<< +<p>пристаням__стремятся__</p> +>>> Emphasis and strong emphasis - 389 +__foo, __bar__, baz__ +<<< +<p><strong>foo, <strong>bar</strong>, baz</strong></p> +>>> Emphasis and strong emphasis - 390 +foo-__(bar)__ +<<< +<p>foo-<strong>(bar)</strong></p> +>>> Emphasis and strong emphasis - 391 +**foo bar ** +<<< +<p>**foo bar **</p> +>>> Emphasis and strong emphasis - 392 +**(**foo) +<<< +<p>**(**foo)</p> +>>> Emphasis and strong emphasis - 393 +*(**foo**)* +<<< +<p><em>(<strong>foo</strong>)</em></p> +>>> Emphasis and strong emphasis - 394 +**Gomphocarpus (*Gomphocarpus physocarpus*, syn. +*Asclepias physocarpa*)** +<<< +<p><strong>Gomphocarpus (<em>Gomphocarpus physocarpus</em>, syn. +<em>Asclepias physocarpa</em>)</strong></p> +>>> Emphasis and strong emphasis - 395 +**foo "*bar*" foo** +<<< +<p><strong>foo "<em>bar</em>" foo</strong></p> +>>> Emphasis and strong emphasis - 396 +**foo**bar +<<< +<p><strong>foo</strong>bar</p> +>>> Emphasis and strong emphasis - 397 +__foo bar __ +<<< +<p>__foo bar __</p> +>>> Emphasis and strong emphasis - 398 +__(__foo) +<<< +<p>__(__foo)</p> +>>> Emphasis and strong emphasis - 399 +_(__foo__)_ +<<< +<p><em>(<strong>foo</strong>)</em></p> +>>> Emphasis and strong emphasis - 400 +__foo__bar +<<< +<p>__foo__bar</p> +>>> Emphasis and strong emphasis - 401 +__пристаням__стремятся +<<< +<p>__пристаням__стремятся</p> +>>> Emphasis and strong emphasis - 402 +__foo__bar__baz__ +<<< +<p><strong>foo__bar__baz</strong></p> +>>> Emphasis and strong emphasis - 403 +__(bar)__. +<<< +<p><strong>(bar)</strong>.</p> +>>> Emphasis and strong emphasis - 404 +*foo [bar](/url)* +<<< +<p><em>foo <a href="/url">bar</a></em></p> +>>> Emphasis and strong emphasis - 405 +*foo +bar* +<<< +<p><em>foo +bar</em></p> +>>> Emphasis and strong emphasis - 406 +_foo __bar__ baz_ +<<< +<p><em>foo <strong>bar</strong> baz</em></p> +>>> Emphasis and strong emphasis - 407 +_foo _bar_ baz_ +<<< +<p><em>foo <em>bar</em> baz</em></p> +>>> Emphasis and strong emphasis - 408 +__foo_ bar_ +<<< +<p><em><em>foo</em> bar</em></p> +>>> Emphasis and strong emphasis - 409 +*foo *bar** +<<< +<p><em>foo <em>bar</em></em></p> +>>> Emphasis and strong emphasis - 410 +*foo **bar** baz* +<<< +<p><em>foo <strong>bar</strong> baz</em></p> +>>> Emphasis and strong emphasis - 411 +*foo**bar**baz* +<<< +<p><em>foo<strong>bar</strong>baz</em></p> +>>> Emphasis and strong emphasis - 412 +*foo**bar* +<<< +<p><em>foo**bar</em></p> +>>> Emphasis and strong emphasis - 413 +***foo** bar* +<<< +<p><em><strong>foo</strong> bar</em></p> +>>> Emphasis and strong emphasis - 414 +*foo **bar*** +<<< +<p><em>foo <strong>bar</strong></em></p> +>>> Emphasis and strong emphasis - 415 +*foo**bar*** +<<< +<p><em>foo<strong>bar</strong></em></p> +>>> Emphasis and strong emphasis - 416 +foo***bar***baz +<<< +<p>foo<em><strong>bar</strong></em>baz</p> +>>> Emphasis and strong emphasis - 417 +foo******bar*********baz +<<< +<p>foo<strong><strong><strong>bar</strong></strong></strong>***baz</p> +>>> Emphasis and strong emphasis - 418 +*foo **bar *baz* bim** bop* +<<< +<p><em>foo <strong>bar <em>baz</em> bim</strong> bop</em></p> +>>> Emphasis and strong emphasis - 419 +*foo [*bar*](/url)* +<<< +<p><em>foo <a href="/url"><em>bar</em></a></em></p> +>>> Emphasis and strong emphasis - 420 +** is not an empty emphasis +<<< +<p>** is not an empty emphasis</p> +>>> Emphasis and strong emphasis - 421 +**** is not an empty strong emphasis +<<< +<p>**** is not an empty strong emphasis</p> +>>> Emphasis and strong emphasis - 422 +**foo [bar](/url)** +<<< +<p><strong>foo <a href="/url">bar</a></strong></p> +>>> Emphasis and strong emphasis - 423 +**foo +bar** +<<< +<p><strong>foo +bar</strong></p> +>>> Emphasis and strong emphasis - 424 +__foo _bar_ baz__ +<<< +<p><strong>foo <em>bar</em> baz</strong></p> +>>> Emphasis and strong emphasis - 425 +__foo __bar__ baz__ +<<< +<p><strong>foo <strong>bar</strong> baz</strong></p> +>>> Emphasis and strong emphasis - 426 +____foo__ bar__ +<<< +<p><strong><strong>foo</strong> bar</strong></p> +>>> Emphasis and strong emphasis - 427 +**foo **bar**** +<<< +<p><strong>foo <strong>bar</strong></strong></p> +>>> Emphasis and strong emphasis - 428 +**foo *bar* baz** +<<< +<p><strong>foo <em>bar</em> baz</strong></p> +>>> Emphasis and strong emphasis - 429 +**foo*bar*baz** +<<< +<p><strong>foo<em>bar</em>baz</strong></p> +>>> Emphasis and strong emphasis - 430 +***foo* bar** +<<< +<p><strong><em>foo</em> bar</strong></p> +>>> Emphasis and strong emphasis - 431 +**foo *bar*** +<<< +<p><strong>foo <em>bar</em></strong></p> +>>> Emphasis and strong emphasis - 432 +**foo *bar **baz** +bim* bop** +<<< +<p><strong>foo <em>bar <strong>baz</strong> +bim</em> bop</strong></p> +>>> Emphasis and strong emphasis - 433 +**foo [*bar*](/url)** +<<< +<p><strong>foo <a href="/url"><em>bar</em></a></strong></p> +>>> Emphasis and strong emphasis - 434 +__ is not an empty emphasis +<<< +<p>__ is not an empty emphasis</p> +>>> Emphasis and strong emphasis - 435 +____ is not an empty strong emphasis +<<< +<p>____ is not an empty strong emphasis</p> +>>> Emphasis and strong emphasis - 436 +foo *** +<<< +<p>foo ***</p> +>>> Emphasis and strong emphasis - 437 +foo *\** +<<< +<p>foo <em>*</em></p> +>>> Emphasis and strong emphasis - 438 +foo *_* +<<< +<p>foo <em>_</em></p> +>>> Emphasis and strong emphasis - 439 +foo ***** +<<< +<p>foo *****</p> +>>> Emphasis and strong emphasis - 440 +foo **\*** +<<< +<p>foo <strong>*</strong></p> +>>> Emphasis and strong emphasis - 441 +foo **_** +<<< +<p>foo <strong>_</strong></p> +>>> Emphasis and strong emphasis - 442 +**foo* +<<< +<p>*<em>foo</em></p> +>>> Emphasis and strong emphasis - 443 +*foo** +<<< +<p><em>foo</em>*</p> +>>> Emphasis and strong emphasis - 444 +***foo** +<<< +<p>*<strong>foo</strong></p> +>>> Emphasis and strong emphasis - 445 +****foo* +<<< +<p>***<em>foo</em></p> +>>> Emphasis and strong emphasis - 446 +**foo*** +<<< +<p><strong>foo</strong>*</p> +>>> Emphasis and strong emphasis - 447 +*foo**** +<<< +<p><em>foo</em>***</p> +>>> Emphasis and strong emphasis - 448 +foo ___ +<<< +<p>foo ___</p> +>>> Emphasis and strong emphasis - 449 +foo _\__ +<<< +<p>foo <em>_</em></p> +>>> Emphasis and strong emphasis - 450 +foo _*_ +<<< +<p>foo <em>*</em></p> +>>> Emphasis and strong emphasis - 451 +foo _____ +<<< +<p>foo _____</p> +>>> Emphasis and strong emphasis - 452 +foo __\___ +<<< +<p>foo <strong>_</strong></p> +>>> Emphasis and strong emphasis - 453 +foo __*__ +<<< +<p>foo <strong>*</strong></p> +>>> Emphasis and strong emphasis - 454 +__foo_ +<<< +<p>_<em>foo</em></p> +>>> Emphasis and strong emphasis - 455 +_foo__ +<<< +<p><em>foo</em>_</p> +>>> Emphasis and strong emphasis - 456 +___foo__ +<<< +<p>_<strong>foo</strong></p> +>>> Emphasis and strong emphasis - 457 +____foo_ +<<< +<p>___<em>foo</em></p> +>>> Emphasis and strong emphasis - 458 +__foo___ +<<< +<p><strong>foo</strong>_</p> +>>> Emphasis and strong emphasis - 459 +_foo____ +<<< +<p><em>foo</em>___</p> +>>> Emphasis and strong emphasis - 460 +**foo** +<<< +<p><strong>foo</strong></p> +>>> Emphasis and strong emphasis - 461 +*_foo_* +<<< +<p><em><em>foo</em></em></p> +>>> Emphasis and strong emphasis - 462 +__foo__ +<<< +<p><strong>foo</strong></p> +>>> Emphasis and strong emphasis - 463 +_*foo*_ +<<< +<p><em><em>foo</em></em></p> +>>> Emphasis and strong emphasis - 464 +****foo**** +<<< +<p><strong><strong>foo</strong></strong></p> +>>> Emphasis and strong emphasis - 465 +____foo____ +<<< +<p><strong><strong>foo</strong></strong></p> +>>> Emphasis and strong emphasis - 466 +******foo****** +<<< +<p><strong><strong><strong>foo</strong></strong></strong></p> +>>> Emphasis and strong emphasis - 467 +***foo*** +<<< +<p><em><strong>foo</strong></em></p> +>>> Emphasis and strong emphasis - 468 +_____foo_____ +<<< +<p><em><strong><strong>foo</strong></strong></em></p> +>>> Emphasis and strong emphasis - 469 +*foo _bar* baz_ +<<< +<p><em>foo _bar</em> baz_</p> +>>> Emphasis and strong emphasis - 470 +*foo __bar *baz bim__ bam* +<<< +<p><em>foo <strong>bar *baz bim</strong> bam</em></p> +>>> Emphasis and strong emphasis - 471 +**foo **bar baz** +<<< +<p>**foo <strong>bar baz</strong></p> +>>> Emphasis and strong emphasis - 472 +*foo *bar baz* +<<< +<p>*foo <em>bar baz</em></p> +>>> Emphasis and strong emphasis - 473 +*[bar*](/url) +<<< +<p>*<a href="/url">bar*</a></p> +>>> Emphasis and strong emphasis - 474 +_foo [bar_](/url) +<<< +<p>_foo <a href="/url">bar_</a></p> +>>> Emphasis and strong emphasis - 475 +*<img src="foo" title="*"/> +<<< +<p>*<img src="foo" title="*"/></p> +>>> Emphasis and strong emphasis - 476 +**<a href="**"> +<<< +<p>**<a href="**"></p> +>>> Emphasis and strong emphasis - 477 +__<a href="__"> +<<< +<p>__<a href="__"></p> +>>> Emphasis and strong emphasis - 478 +*a `*`* +<<< +<p><em>a <code>*</code></em></p> +>>> Emphasis and strong emphasis - 479 +_a `_`_ +<<< +<p><em>a <code>_</code></em></p> +>>> Emphasis and strong emphasis - 480 +**a<https://foo.bar/?q=**> +<<< +<p>**a<a href="https://foo.bar/?q=**">https://foo.bar/?q=**</a></p> +>>> Emphasis and strong emphasis - 481 +__a<https://foo.bar/?q=__> +<<< +<p>__a<a href="https://foo.bar/?q=__">https://foo.bar/?q=__</a></p> diff --git a/pkgs/markdown/test/common_mark/entity_and_numeric_character_references.unit b/pkgs/markdown/test/common_mark/entity_and_numeric_character_references.unit new file mode 100644 index 000000000..285943590 --- /dev/null +++ b/pkgs/markdown/test/common_mark/entity_and_numeric_character_references.unit @@ -0,0 +1,93 @@ +>>> Entity and numeric character references - 25 +  & © Æ Ď +¾ ℋ ⅆ +∲ ≧̸ +<<< +<p>& © Æ Ď +¾ ℋ ⅆ +∲ ≧̸</p> +>>> Entity and numeric character references - 26 +# Ӓ Ϡ � +<<< +<p># Ӓ Ϡ �</p> +>>> Entity and numeric character references - 27 +" ആ ಫ +<<< +<p>" ആ ಫ</p> +>>> Entity and numeric character references - 28 +  &x; &#; &#x; +� +&#abcdef0; +&ThisIsNotDefined; &hi?; +<<< +<p>&nbsp &x; &#; &#x; +&#87654321; +&#abcdef0; +&ThisIsNotDefined; &hi?;</p> +>>> Entity and numeric character references - 29 +© +<<< +<p>&copy</p> +>>> Entity and numeric character references - 30 +&MadeUpEntity; +<<< +<p>&MadeUpEntity;</p> +>>> Entity and numeric character references - 31 +<a href="öö.html"> +<<< +<a href="öö.html"> +>>> Entity and numeric character references - 32 +[foo](/föö "föö") +<<< +<p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p> +>>> Entity and numeric character references - 33 +[foo] + +[foo]: /föö "föö" +<<< +<p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p> +>>> Entity and numeric character references - 34 +``` föö +foo +``` +<<< +<pre><code class="language-föö">foo +</code></pre> +>>> Entity and numeric character references - 35 +`föö` +<<< +<p><code>f&ouml;&ouml;</code></p> +>>> Entity and numeric character references - 36 + föfö +<<< +<pre><code>f&ouml;f&ouml; +</code></pre> +>>> Entity and numeric character references - 37 +*foo* +*foo* +<<< +<p>*foo* +<em>foo</em></p> +>>> Entity and numeric character references - 38 +* foo + +* foo +<<< +<p>* foo</p> +<ul> +<li>foo</li> +</ul> +>>> Entity and numeric character references - 39 +foo bar +<<< +<p>foo + +bar</p> +>>> Entity and numeric character references - 40 + foo +<<< +<p>foo</p> +>>> Entity and numeric character references - 41 +[a](url "tit") +<<< +<p>[a](url "tit")</p> diff --git a/pkgs/markdown/test/common_mark/fenced_code_blocks.unit b/pkgs/markdown/test/common_mark/fenced_code_blocks.unit new file mode 100644 index 000000000..06dec5865 --- /dev/null +++ b/pkgs/markdown/test/common_mark/fenced_code_blocks.unit @@ -0,0 +1,245 @@ +>>> Fenced code blocks - 119 +``` +< + > +``` +<<< +<pre><code>< + > +</code></pre> +>>> Fenced code blocks - 120 +~~~ +< + > +~~~ +<<< +<pre><code>< + > +</code></pre> +>>> Fenced code blocks - 121 +`` +foo +`` +<<< +<p><code>foo</code></p> +>>> Fenced code blocks - 122 +``` +aaa +~~~ +``` +<<< +<pre><code>aaa +~~~ +</code></pre> +>>> Fenced code blocks - 123 +~~~ +aaa +``` +~~~ +<<< +<pre><code>aaa +``` +</code></pre> +>>> Fenced code blocks - 124 +```` +aaa +``` +`````` +<<< +<pre><code>aaa +``` +</code></pre> +>>> Fenced code blocks - 125 +~~~~ +aaa +~~~ +~~~~ +<<< +<pre><code>aaa +~~~ +</code></pre> +>>> Fenced code blocks - 126 +``` +<<< +<pre><code></code></pre> +>>> Fenced code blocks - 127 +````` + +``` +aaa +<<< +<pre><code> +``` +aaa +</code></pre> +>>> Fenced code blocks - 128 +> ``` +> aaa + +bbb +<<< +<blockquote> +<pre><code>aaa +</code></pre> +</blockquote> +<p>bbb</p> +>>> Fenced code blocks - 129 +``` + + +``` +<<< +<pre><code> + +</code></pre> +>>> Fenced code blocks - 130 +``` +``` +<<< +<pre><code></code></pre> +>>> Fenced code blocks - 131 + ``` + aaa +aaa +``` +<<< +<pre><code>aaa +aaa +</code></pre> +>>> Fenced code blocks - 132 + ``` +aaa + aaa +aaa + ``` +<<< +<pre><code>aaa +aaa +aaa +</code></pre> +>>> Fenced code blocks - 133 + ``` + aaa + aaa + aaa + ``` +<<< +<pre><code>aaa + aaa +aaa +</code></pre> +>>> Fenced code blocks - 134 + ``` + aaa + ``` +<<< +<pre><code>``` +aaa +``` +</code></pre> +>>> Fenced code blocks - 135 +``` +aaa + ``` +<<< +<pre><code>aaa +</code></pre> +>>> Fenced code blocks - 136 + ``` +aaa + ``` +<<< +<pre><code>aaa +</code></pre> +>>> Fenced code blocks - 137 +``` +aaa + ``` +<<< +<pre><code>aaa + ``` +</code></pre> +>>> Fenced code blocks - 138 +``` ``` +aaa +<<< +<p><code> </code> +aaa</p> +>>> Fenced code blocks - 139 +~~~~~~ +aaa +~~~ ~~ +<<< +<pre><code>aaa +~~~ ~~ +</code></pre> +>>> Fenced code blocks - 140 +foo +``` +bar +``` +baz +<<< +<p>foo</p> +<pre><code>bar +</code></pre> +<p>baz</p> +>>> Fenced code blocks - 141 +foo +--- +~~~ +bar +~~~ +# baz +<<< +<h2>foo</h2> +<pre><code>bar +</code></pre> +<h1>baz</h1> +>>> Fenced code blocks - 142 +```ruby +def foo(x) + return 3 +end +``` +<<< +<pre><code class="language-ruby">def foo(x) + return 3 +end +</code></pre> +>>> Fenced code blocks - 143 +~~~~ ruby startline=3 $%@#$ +def foo(x) + return 3 +end +~~~~~~~ +<<< +<pre><code class="language-ruby">def foo(x) + return 3 +end +</code></pre> +>>> Fenced code blocks - 144 +````; +```` +<<< +<pre><code class="language-;"></code></pre> +>>> Fenced code blocks - 145 +``` aa ``` +foo +<<< +<p><code>aa</code> +foo</p> +>>> Fenced code blocks - 146 +~~~ aa ``` ~~~ +foo +~~~ +<<< +<pre><code class="language-aa">foo +</code></pre> +>>> Fenced code blocks - 147 +``` +``` aaa +``` +<<< +<pre><code>``` aaa +</code></pre> diff --git a/pkgs/markdown/test/common_mark/hard_line_breaks.unit b/pkgs/markdown/test/common_mark/hard_line_breaks.unit new file mode 100644 index 000000000..8a3f0be67 --- /dev/null +++ b/pkgs/markdown/test/common_mark/hard_line_breaks.unit @@ -0,0 +1,80 @@ +>>> Hard line breaks - 633 +foo +baz +<<< +<p>foo<br /> +baz</p> +>>> Hard line breaks - 634 +foo\ +baz +<<< +<p>foo<br /> +baz</p> +>>> Hard line breaks - 635 +foo +baz +<<< +<p>foo<br /> +baz</p> +>>> Hard line breaks - 636 +foo + bar +<<< +<p>foo<br /> +bar</p> +>>> Hard line breaks - 637 +foo\ + bar +<<< +<p>foo<br /> +bar</p> +>>> Hard line breaks - 638 +*foo +bar* +<<< +<p><em>foo<br /> +bar</em></p> +>>> Hard line breaks - 639 +*foo\ +bar* +<<< +<p><em>foo<br /> +bar</em></p> +>>> Hard line breaks - 640 +`code +span` +<<< +<p><code>code span</code></p> +>>> Hard line breaks - 641 +`code\ +span` +<<< +<p><code>code\ span</code></p> +>>> Hard line breaks - 642 +<a href="foo +bar"> +<<< +<p><a href="foo +bar"></p> +>>> Hard line breaks - 643 +<a href="foo\ +bar"> +<<< +<p><a href="foo\ +bar"></p> +>>> Hard line breaks - 644 +foo\ +<<< +<p>foo\</p> +>>> Hard line breaks - 645 +foo +<<< +<p>foo</p> +>>> Hard line breaks - 646 +### foo\ +<<< +<h3>foo\</h3> +>>> Hard line breaks - 647 +### foo +<<< +<h3>foo</h3> diff --git a/pkgs/markdown/test/common_mark/html_blocks.unit b/pkgs/markdown/test/common_mark/html_blocks.unit new file mode 100644 index 000000000..3a01cd0a5 --- /dev/null +++ b/pkgs/markdown/test/common_mark/html_blocks.unit @@ -0,0 +1,449 @@ +>>> HTML blocks - 148 +<table><tr><td> +<pre> +**Hello**, + +_world_. +</pre> +</td></tr></table> +<<< +<table><tr><td> +<pre> +**Hello**, +<p><em>world</em>. +</pre></p> +</td></tr></table> +>>> HTML blocks - 149 +<table> + <tr> + <td> + hi + </td> + </tr> +</table> + +okay. +<<< +<table> + <tr> + <td> + hi + </td> + </tr> +</table> +<p>okay.</p> +>>> HTML blocks - 150 + <div> + *hello* + <foo><a> +<<< + <div> + *hello* + <foo><a> +>>> HTML blocks - 151 +</div> +*foo* +<<< +</div> +*foo* +>>> HTML blocks - 152 +<DIV CLASS="foo"> + +*Markdown* + +</DIV> +<<< +<DIV CLASS="foo"> +<p><em>Markdown</em></p> +</DIV> +>>> HTML blocks - 153 +<div id="foo" + class="bar"> +</div> +<<< +<div id="foo" + class="bar"> +</div> +>>> HTML blocks - 154 +<div id="foo" class="bar + baz"> +</div> +<<< +<div id="foo" class="bar + baz"> +</div> +>>> HTML blocks - 155 +<div> +*foo* + +*bar* +<<< +<div> +*foo* +<p><em>bar</em></p> +>>> HTML blocks - 156 +<div id="foo" +*hi* +<<< +<div id="foo" +*hi* +>>> HTML blocks - 157 +<div class +foo +<<< +<div class +foo +>>> HTML blocks - 158 +<div *???-&&&-<--- +*foo* +<<< +<div *???-&&&-<--- +*foo* +>>> HTML blocks - 159 +<div><a href="bar">*foo*</a></div> +<<< +<div><a href="bar">*foo*</a></div> +>>> HTML blocks - 160 +<table><tr><td> +foo +</td></tr></table> +<<< +<table><tr><td> +foo +</td></tr></table> +>>> HTML blocks - 161 +<div></div> +``` c +int x = 33; +``` +<<< +<div></div> +``` c +int x = 33; +``` +>>> HTML blocks - 162 +<a href="foo"> +*bar* +</a> +<<< +<a href="foo"> +*bar* +</a> +>>> HTML blocks - 163 +<Warning> +*bar* +</Warning> +<<< +<Warning> +*bar* +</Warning> +>>> HTML blocks - 164 +<i class="foo"> +*bar* +</i> +<<< +<i class="foo"> +*bar* +</i> +>>> HTML blocks - 165 +</ins> +*bar* +<<< +</ins> +*bar* +>>> HTML blocks - 166 +<del> +*foo* +</del> +<<< +<del> +*foo* +</del> +>>> HTML blocks - 167 +<del> + +*foo* + +</del> +<<< +<del> +<p><em>foo</em></p> +</del> +>>> HTML blocks - 168 +<del>*foo*</del> +<<< +<p><del><em>foo</em></del></p> +>>> HTML blocks - 169 +<pre language="haskell"><code> +import Text.HTML.TagSoup + +main :: IO () +main = print $ parseTags tags +</code></pre> +okay +<<< +<pre language="haskell"><code> +import Text.HTML.TagSoup + +main :: IO () +main = print $ parseTags tags +</code></pre> +<p>okay</p> +>>> HTML blocks - 170 +<script type="text/javascript"> +// JavaScript example + +document.getElementById("demo").innerHTML = "Hello JavaScript!"; +</script> +okay +<<< +<script type="text/javascript"> +// JavaScript example + +document.getElementById("demo").innerHTML = "Hello JavaScript!"; +</script> +<p>okay</p> +>>> HTML blocks - 171 +<textarea> + +*foo* + +_bar_ + +</textarea> +<<< +<textarea> + +*foo* + +_bar_ + +</textarea> +>>> HTML blocks - 172 +<style + type="text/css"> +h1 {color:red;} + +p {color:blue;} +</style> +okay +<<< +<style + type="text/css"> +h1 {color:red;} + +p {color:blue;} +</style> +<p>okay</p> +>>> HTML blocks - 173 +<style + type="text/css"> + +foo +<<< +<style + type="text/css"> + +foo +>>> HTML blocks - 174 +> <div> +> foo + +bar +<<< +<blockquote> +<div> +foo +</blockquote> +<p>bar</p> +>>> HTML blocks - 175 +- <div> +- foo +<<< +<ul> +<li> +<div> +</li> +<li>foo</li> +</ul> +>>> HTML blocks - 176 +<style>p{color:red;}</style> +*foo* +<<< +<style>p{color:red;}</style> +<p><em>foo</em></p> +>>> HTML blocks - 177 +<!-- foo -->*bar* +*baz* +<<< +<!-- foo -->*bar* +<p><em>baz</em></p> +>>> HTML blocks - 178 +<script> +foo +</script>1. *bar* +<<< +<script> +foo +</script>1. *bar* +>>> HTML blocks - 179 +<!-- Foo + +bar + baz --> +okay +<<< +<!-- Foo + +bar + baz --> +<p>okay</p> +>>> HTML blocks - 180 +<?php + + echo '>'; + +?> +okay +<<< +<?php + + echo '>'; + +?> +<p>okay</p> +>>> HTML blocks - 181 +<!DOCTYPE html> +<<< +<!DOCTYPE html> +>>> HTML blocks - 182 +<![CDATA[ +function matchwo(a,b) +{ + if (a < b && a < 0) then { + return 1; + + } else { + + return 0; + } +} +]]> +okay +<<< +<![CDATA[ +function matchwo(a,b) +{ + if (a < b && a < 0) then { + return 1; + + } else { + + return 0; + } +} +]]> +<p>okay</p> +>>> HTML blocks - 183 + <!-- foo --> + + <!-- foo --> +<<< + <!-- foo --> +<pre><code><!-- foo --> +</code></pre> +>>> HTML blocks - 184 + <div> + + <div> +<<< + <div> +<pre><code><div> +</code></pre> +>>> HTML blocks - 185 +Foo +<div> +bar +</div> +<<< +<p>Foo</p> +<div> +bar +</div> +>>> HTML blocks - 186 +<div> +bar +</div> +*foo* +<<< +<div> +bar +</div> +*foo* +>>> HTML blocks - 187 +Foo +<a href="bar"> +baz +<<< +<p>Foo +<a href="bar"> +baz</p> +>>> HTML blocks - 188 +<div> + +*Emphasized* text. + +</div> +<<< +<div> +<p><em>Emphasized</em> text.</p> +</div> +>>> HTML blocks - 189 +<div> +*Emphasized* text. +</div> +<<< +<div> +*Emphasized* text. +</div> +>>> HTML blocks - 190 +<table> + +<tr> + +<td> +Hi +</td> + +</tr> + +</table> +<<< +<table> +<tr> +<td> +Hi +</td> +</tr> +</table> +>>> HTML blocks - 191 +<table> + + <tr> + + <td> + Hi + </td> + + </tr> + +</table> +<<< +<table> + <tr> +<pre><code><td> + Hi +</td> +</code></pre> + </tr> +</table> diff --git a/pkgs/markdown/test/common_mark/images.unit b/pkgs/markdown/test/common_mark/images.unit new file mode 100644 index 000000000..ae42aa2f8 --- /dev/null +++ b/pkgs/markdown/test/common_mark/images.unit @@ -0,0 +1,121 @@ +>>> Images - 572 +![foo](/url "title") +<<< +<p><img src="/url" alt="foo" title="title" /></p> +>>> Images - 573 +![foo *bar*] + +[foo *bar*]: train.jpg "train & tracks" +<<< +<p><img src="train.jpg" alt="foo bar" title="train & tracks" /></p> +>>> Images - 574 +![foo ![bar](/url)](/url2) +<<< +<p><img src="/url2" alt="foo bar" /></p> +>>> Images - 575 +![foo [bar](/url)](/url2) +<<< +<p><img src="/url2" alt="foo bar" /></p> +>>> Images - 576 +![foo *bar*][] + +[foo *bar*]: train.jpg "train & tracks" +<<< +<p><img src="train.jpg" alt="foo bar" title="train & tracks" /></p> +>>> Images - 577 +![foo *bar*][foobar] + +[FOOBAR]: train.jpg "train & tracks" +<<< +<p><img src="train.jpg" alt="foo bar" title="train & tracks" /></p> +>>> Images - 578 +![foo](train.jpg) +<<< +<p><img src="train.jpg" alt="foo" /></p> +>>> Images - 579 +My ![foo bar](/path/to/train.jpg "title" ) +<<< +<p>My <img src="/path/to/train.jpg" alt="foo bar" title="title" /></p> +>>> Images - 580 +![foo](<url>) +<<< +<p><img src="url" alt="foo" /></p> +>>> Images - 581 +![](/url) +<<< +<p><img src="/url" alt="" /></p> +>>> Images - 582 +![foo][bar] + +[bar]: /url +<<< +<p><img src="/url" alt="foo" /></p> +>>> Images - 583 +![foo][bar] + +[BAR]: /url +<<< +<p><img src="/url" alt="foo" /></p> +>>> Images - 584 +![foo][] + +[foo]: /url "title" +<<< +<p><img src="/url" alt="foo" title="title" /></p> +>>> Images - 585 +![*foo* bar][] + +[*foo* bar]: /url "title" +<<< +<p><img src="/url" alt="foo bar" title="title" /></p> +>>> Images - 586 +![Foo][] + +[foo]: /url "title" +<<< +<p><img src="/url" alt="Foo" title="title" /></p> +>>> Images - 587 +![foo] +[] + +[foo]: /url "title" +<<< +<p><img src="/url" alt="foo" title="title" /> +[]</p> +>>> Images - 588 +![foo] + +[foo]: /url "title" +<<< +<p><img src="/url" alt="foo" title="title" /></p> +>>> Images - 589 +![*foo* bar] + +[*foo* bar]: /url "title" +<<< +<p><img src="/url" alt="foo bar" title="title" /></p> +>>> Images - 590 +![[foo]] + +[[foo]]: /url "title" +<<< +<p>![[foo]]</p> +<p>[[foo]]: /url "title"</p> +>>> Images - 591 +![Foo] + +[foo]: /url "title" +<<< +<p><img src="/url" alt="Foo" title="title" /></p> +>>> Images - 592 +!\[foo] + +[foo]: /url "title" +<<< +<p>![foo]</p> +>>> Images - 593 +\![foo] + +[foo]: /url "title" +<<< +<p>!<a href="/url" title="title">foo</a></p> diff --git a/pkgs/markdown/test/common_mark/indented_code_blocks.unit b/pkgs/markdown/test/common_mark/indented_code_blocks.unit new file mode 100644 index 000000000..ce142fee1 --- /dev/null +++ b/pkgs/markdown/test/common_mark/indented_code_blocks.unit @@ -0,0 +1,118 @@ +>>> Indented code blocks - 107 + a simple + indented code block +<<< +<pre><code>a simple + indented code block +</code></pre> +>>> Indented code blocks - 108 + - foo + + bar +<<< +<ul> +<li> +<p>foo</p> +<p>bar</p> +</li> +</ul> +>>> Indented code blocks - 109 +1. foo + + - bar +<<< +<ol> +<li> +<p>foo</p> +<ul> +<li>bar</li> +</ul> +</li> +</ol> +>>> Indented code blocks - 110 + <a/> + *hi* + + - one +<<< +<pre><code><a/> +*hi* + +- one +</code></pre> +>>> Indented code blocks - 111 + chunk1 + + chunk2 + + + + chunk3 +<<< +<pre><code>chunk1 + +chunk2 + + + +chunk3 +</code></pre> +>>> Indented code blocks - 112 + chunk1 + + chunk2 +<<< +<pre><code>chunk1 + + chunk2 +</code></pre> +>>> Indented code blocks - 113 +Foo + bar + +<<< +<p>Foo +bar</p> +>>> Indented code blocks - 114 + foo +bar +<<< +<pre><code>foo +</code></pre> +<p>bar</p> +>>> Indented code blocks - 115 +# Heading + foo +Heading +------ + foo +---- +<<< +<h1>Heading</h1> +<pre><code>foo +</code></pre> +<h2>Heading</h2> +<pre><code>foo +</code></pre> +<hr /> +>>> Indented code blocks - 116 + foo + bar +<<< +<pre><code> foo +bar +</code></pre> +>>> Indented code blocks - 117 + + + foo + + +<<< +<pre><code>foo +</code></pre> +>>> Indented code blocks - 118 + foo +<<< +<pre><code>foo +</code></pre> diff --git a/pkgs/markdown/test/common_mark/inlines.unit b/pkgs/markdown/test/common_mark/inlines.unit new file mode 100644 index 000000000..3d2eebead --- /dev/null +++ b/pkgs/markdown/test/common_mark/inlines.unit @@ -0,0 +1,4 @@ +>>> Inlines - 327 +`hi`lo` +<<< +<p><code>hi</code>lo`</p> diff --git a/pkgs/markdown/test/common_mark/link_reference_definitions.unit b/pkgs/markdown/test/common_mark/link_reference_definitions.unit new file mode 100644 index 000000000..0677259e8 --- /dev/null +++ b/pkgs/markdown/test/common_mark/link_reference_definitions.unit @@ -0,0 +1,202 @@ +>>> Link reference definitions - 192 +[foo]: /url "title" + +[foo] +<<< +<p><a href="/url" title="title">foo</a></p> +>>> Link reference definitions - 193 + [foo]: + /url + 'the title' + +[foo] +<<< +<p><a href="/url" title="the title">foo</a></p> +>>> Link reference definitions - 194 +[Foo*bar\]]:my_(url) 'title (with parens)' + +[Foo*bar\]] +<<< +<p><a href="my_(url)" title="title (with parens)">Foo*bar]</a></p> +>>> Link reference definitions - 195 +[Foo bar]: +<my url> +'title' + +[Foo bar] +<<< +<p><a href="my%20url" title="title">Foo bar</a></p> +>>> Link reference definitions - 196 +[foo]: /url ' +title +line1 +line2 +' + +[foo] +<<< +<p><a href="/url" title=" +title +line1 +line2 +">foo</a></p> +>>> Link reference definitions - 197 +[foo]: /url 'title + +with blank line' + +[foo] +<<< +<p>[foo]: /url 'title</p> +<p>with blank line'</p> +<p>[foo]</p> +>>> Link reference definitions - 198 +[foo]: +/url + +[foo] +<<< +<p><a href="/url">foo</a></p> +>>> Link reference definitions - 199 +[foo]: + +[foo] +<<< +<p>[foo]:</p> +<p>[foo]</p> +>>> Link reference definitions - 200 +[foo]: <> + +[foo] +<<< +<p><a href="">foo</a></p> +>>> Link reference definitions - 201 +[foo]: <bar>(baz) + +[foo] +<<< +<p>[foo]: <bar>(baz)</p> +<p>[foo]</p> +>>> Link reference definitions - 202 +[foo]: /url\bar\*baz "foo\"bar\baz" + +[foo] +<<< +<p><a href="/url%5Cbar*baz" title="foo"bar\baz">foo</a></p> +>>> Link reference definitions - 203 +[foo] + +[foo]: url +<<< +<p><a href="url">foo</a></p> +>>> Link reference definitions - 204 +[foo] + +[foo]: first +[foo]: second +<<< +<p><a href="first">foo</a></p> +>>> Link reference definitions - 205 +[FOO]: /url + +[Foo] +<<< +<p><a href="/url">Foo</a></p> +>>> Link reference definitions - 206 +[ΑΓΩ]: /φου + +[αγω] +<<< +<p><a href="/%CF%86%CE%BF%CF%85">αγω</a></p> +>>> Link reference definitions - 207 +[foo]: /url +<<< + +>>> Link reference definitions - 208 +[ +foo +]: /url +bar +<<< +<p>bar</p> +>>> Link reference definitions - 209 +[foo]: /url "title" ok +<<< +<p>[foo]: /url "title" ok</p> +>>> Link reference definitions - 210 +[foo]: /url +"title" ok +<<< +<p>"title" ok</p> +>>> Link reference definitions - 211 + [foo]: /url "title" + +[foo] +<<< +<pre><code>[foo]: /url "title" +</code></pre> +<p>[foo]</p> +>>> Link reference definitions - 212 +``` +[foo]: /url +``` + +[foo] +<<< +<pre><code>[foo]: /url +</code></pre> +<p>[foo]</p> +>>> Link reference definitions - 213 +Foo +[bar]: /baz + +[bar] +<<< +<p>Foo +[bar]: /baz</p> +<p>[bar]</p> +>>> Link reference definitions - 214 +# [Foo] +[foo]: /url +> bar +<<< +<h1><a href="/url">Foo</a></h1> +<blockquote> +<p>bar</p> +</blockquote> +>>> Link reference definitions - 215 +[foo]: /url +bar +=== +[foo] +<<< +<h1>bar</h1> +<p><a href="/url">foo</a></p> +>>> Link reference definitions - 216 +[foo]: /url +=== +[foo] +<<< +<p>=== +<a href="/url">foo</a></p> +>>> Link reference definitions - 217 +[foo]: /foo-url "foo" +[bar]: /bar-url + "bar" +[baz]: /baz-url + +[foo], +[bar], +[baz] +<<< +<p><a href="/foo-url" title="foo">foo</a>, +<a href="/bar-url" title="bar">bar</a>, +<a href="/baz-url">baz</a></p> +>>> Link reference definitions - 218 +[foo] + +> [foo]: /url +<<< +<p><a href="/url">foo</a></p> +<blockquote> +</blockquote> diff --git a/pkgs/markdown/test/common_mark/links.unit b/pkgs/markdown/test/common_mark/links.unit new file mode 100644 index 000000000..ab399f5b9 --- /dev/null +++ b/pkgs/markdown/test/common_mark/links.unit @@ -0,0 +1,488 @@ +>>> Links - 482 +[link](/uri "title") +<<< +<p><a href="/uri" title="title">link</a></p> +>>> Links - 483 +[link](/uri) +<<< +<p><a href="/uri">link</a></p> +>>> Links - 484 +[](./target.md) +<<< +<p><a href="./target.md"></a></p> +>>> Links - 485 +[link]() +<<< +<p><a href="">link</a></p> +>>> Links - 486 +[link](<>) +<<< +<p><a href="">link</a></p> +>>> Links - 487 +[]() +<<< +<p><a href=""></a></p> +>>> Links - 488 +[link](/my uri) +<<< +<p>[link](/my uri)</p> +>>> Links - 489 +[link](</my uri>) +<<< +<p><a href="/my%20uri">link</a></p> +>>> Links - 490 +[link](foo +bar) +<<< +<p>[link](foo +bar)</p> +>>> Links - 491 +[link](<foo +bar>) +<<< +<p>[link](<foo +bar>)</p> +>>> Links - 492 +[a](<b)c>) +<<< +<p><a href="b)c">a</a></p> +>>> Links - 493 +[link](<foo\>) +<<< +<p>[link](<foo>)</p> +>>> Links - 494 +[a](<b)c +[a](<b)c> +[a](<b>c) +<<< +<p>[a](<b)c +[a](<b)c> +[a](<b>c)</p> +>>> Links - 495 +[link](\(foo\)) +<<< +<p><a href="(foo)">link</a></p> +>>> Links - 496 +[link](foo(and(bar))) +<<< +<p><a href="foo(and(bar))">link</a></p> +>>> Links - 497 +[link](foo(and(bar)) +<<< +<p>[link](foo(and(bar))</p> +>>> Links - 498 +[link](foo\(and\(bar\)) +<<< +<p><a href="foo(and(bar)">link</a></p> +>>> Links - 499 +[link](<foo(and(bar)>) +<<< +<p><a href="foo(and(bar)">link</a></p> +>>> Links - 500 +[link](foo\)\:) +<<< +<p><a href="foo):">link</a></p> +>>> Links - 501 +[link](#fragment) + +[link](https://example.com#fragment) + +[link](https://example.com?foo=3#frag) +<<< +<p><a href="#fragment">link</a></p> +<p><a href="https://example.com#fragment">link</a></p> +<p><a href="https://example.com?foo=3#frag">link</a></p> +>>> Links - 502 +[link](foo\bar) +<<< +<p><a href="foo%5Cbar">link</a></p> +>>> Links - 503 +[link](foo%20bä) +<<< +<p><a href="foo%20b%C3%A4">link</a></p> +>>> Links - 504 +[link]("title") +<<< +<p><a href="%22title%22">link</a></p> +>>> Links - 505 +[link](/url "title") +[link](/url 'title') +[link](/url (title)) +<<< +<p><a href="/url" title="title">link</a> +<a href="/url" title="title">link</a> +<a href="/url" title="title">link</a></p> +>>> Links - 506 +[link](/url "title \""") +<<< +<p><a href="/url" title="title """>link</a></p> +>>> Links - 507 +[link](/url "title") +<<< +<p><a href="/url%C2%A0%22title%22">link</a></p> +>>> Links - 508 +[link](/url "title "and" title") +<<< +<p>[link](/url "title "and" title")</p> +>>> Links - 509 +[link](/url 'title "and" title') +<<< +<p><a href="/url" title="title "and" title">link</a></p> +>>> Links - 510 +[link]( /uri + "title" ) +<<< +<p><a href="/uri" title="title">link</a></p> +>>> Links - 511 +[link] (/uri) +<<< +<p>[link] (/uri)</p> +>>> Links - 512 +[link [foo [bar]]](/uri) +<<< +<p><a href="/uri">link [foo [bar]]</a></p> +>>> Links - 513 +[link] bar](/uri) +<<< +<p>[link] bar](/uri)</p> +>>> Links - 514 +[link [bar](/uri) +<<< +<p>[link <a href="/uri">bar</a></p> +>>> Links - 515 +[link \[bar](/uri) +<<< +<p><a href="/uri">link [bar</a></p> +>>> Links - 516 +[link *foo **bar** `#`*](/uri) +<<< +<p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p> +>>> Links - 517 +[![moon](moon.jpg)](/uri) +<<< +<p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p> +>>> Links - 518 +[foo [bar](/uri)](/uri) +<<< +<p>[foo <a href="/uri">bar</a>](/uri)</p> +>>> Links - 519 +[foo *[bar [baz](/uri)](/uri)*](/uri) +<<< +<p>[foo <em>[bar <a href="/uri">baz</a>](/uri)</em>](/uri)</p> +>>> Links - 520 +![[[foo](uri1)](uri2)](uri3) +<<< +<p><img src="uri3" alt="[foo](uri2)" /></p> +>>> Links - 521 +*[foo*](/uri) +<<< +<p>*<a href="/uri">foo*</a></p> +>>> Links - 522 +[foo *bar](baz*) +<<< +<p><a href="baz*">foo *bar</a></p> +>>> Links - 523 +*foo [bar* baz] +<<< +<p><em>foo [bar</em> baz]</p> +>>> Links - 524 +[foo <bar attr="](baz)"> +<<< +<p>[foo <bar attr="](baz)"></p> +>>> Links - 525 +[foo`](/uri)` +<<< +<p>[foo<code>](/uri)</code></p> +>>> Links - 526 +[foo<https://example.com/?search=](uri)> +<<< +<p>[foo<a href="https://example.com/?search=%5D(uri)">https://example.com/?search=](uri)</a></p> +>>> Links - 527 +[foo][bar] + +[bar]: /url "title" +<<< +<p><a href="/url" title="title">foo</a></p> +>>> Links - 528 +[link [foo [bar]]][ref] + +[ref]: /uri +<<< +<p><a href="/uri">link [foo [bar]]</a></p> +>>> Links - 529 +[link \[bar][ref] + +[ref]: /uri +<<< +<p><a href="/uri">link [bar</a></p> +>>> Links - 530 +[link *foo **bar** `#`*][ref] + +[ref]: /uri +<<< +<p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p> +>>> Links - 531 +[![moon](moon.jpg)][ref] + +[ref]: /uri +<<< +<p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p> +>>> Links - 532 +[foo [bar](/uri)][ref] + +[ref]: /uri +<<< +<p>[foo <a href="/uri">bar</a>]<a href="/uri">ref</a></p> +>>> Links - 533 +[foo *bar [baz][ref]*][ref] + +[ref]: /uri +<<< +<p>[foo <em>bar <a href="/uri">baz</a></em>]<a href="/uri">ref</a></p> +>>> Links - 534 +*[foo*][ref] + +[ref]: /uri +<<< +<p>*<a href="/uri">foo*</a></p> +>>> Links - 535 +[foo *bar][ref]* + +[ref]: /uri +<<< +<p><a href="/uri">foo *bar</a>*</p> +>>> Links - 536 +[foo <bar attr="][ref]"> + +[ref]: /uri +<<< +<p>[foo <bar attr="][ref]"></p> +>>> Links - 537 +[foo`][ref]` + +[ref]: /uri +<<< +<p>[foo<code>][ref]</code></p> +>>> Links - 538 +[foo<https://example.com/?search=][ref]> + +[ref]: /uri +<<< +<p>[foo<a href="https://example.com/?search=%5D%5Bref%5D">https://example.com/?search=][ref]</a></p> +>>> Links - 539 +[foo][BaR] + +[bar]: /url "title" +<<< +<p><a href="/url" title="title">foo</a></p> +>>> Links - 540 +[ẞ] + +[SS]: /url +<<< +<p><a href="/url">ẞ</a></p> +>>> Links - 541 +[Foo + bar]: /url + +[Baz][Foo bar] +<<< +<p><a href="/url">Baz</a></p> +>>> Links - 542 +[foo] [bar] + +[bar]: /url "title" +<<< +<p>[foo] <a href="/url" title="title">bar</a></p> +>>> Links - 543 +[foo] +[bar] + +[bar]: /url "title" +<<< +<p>[foo] +<a href="/url" title="title">bar</a></p> +>>> Links - 544 +[foo]: /url1 + +[foo]: /url2 + +[bar][foo] +<<< +<p><a href="/url1">bar</a></p> +>>> Links - 545 +[bar][foo\!] + +[foo!]: /url +<<< +<p>[bar][foo!]</p> +>>> Links - 546 +[foo][ref[] + +[ref[]: /uri +<<< +<p>[foo][ref[]</p> +<p>[ref[]: /uri</p> +>>> Links - 547 +[foo][ref[bar]] + +[ref[bar]]: /uri +<<< +<p>[foo][ref[bar]]</p> +<p>[ref[bar]]: /uri</p> +>>> Links - 548 +[[[foo]]] + +[[[foo]]]: /url +<<< +<p>[[[foo]]]</p> +<p>[[[foo]]]: /url</p> +>>> Links - 549 +[foo][ref\[] + +[ref\[]: /uri +<<< +<p><a href="/uri">foo</a></p> +>>> Links - 550 +[bar\\]: /uri + +[bar\\] +<<< +<p><a href="/uri">bar\</a></p> +>>> Links - 551 +[] + +[]: /uri +<<< +<p>[]</p> +<p>[]: /uri</p> +>>> Links - 552 +[ + ] + +[ + ]: /uri +<<< +<p>[ +]</p> +<p>[ +]: /uri</p> +>>> Links - 553 +[foo][] + +[foo]: /url "title" +<<< +<p><a href="/url" title="title">foo</a></p> +>>> Links - 554 +[*foo* bar][] + +[*foo* bar]: /url "title" +<<< +<p><a href="/url" title="title"><em>foo</em> bar</a></p> +>>> Links - 555 +[Foo][] + +[foo]: /url "title" +<<< +<p><a href="/url" title="title">Foo</a></p> +>>> Links - 556 +[foo] +[] + +[foo]: /url "title" +<<< +<p><a href="/url" title="title">foo</a> +[]</p> +>>> Links - 557 +[foo] + +[foo]: /url "title" +<<< +<p><a href="/url" title="title">foo</a></p> +>>> Links - 558 +[*foo* bar] + +[*foo* bar]: /url "title" +<<< +<p><a href="/url" title="title"><em>foo</em> bar</a></p> +>>> Links - 559 +[[*foo* bar]] + +[*foo* bar]: /url "title" +<<< +<p>[<a href="/url" title="title"><em>foo</em> bar</a>]</p> +>>> Links - 560 +[[bar [foo] + +[foo]: /url +<<< +<p>[[bar <a href="/url">foo</a></p> +>>> Links - 561 +[Foo] + +[foo]: /url "title" +<<< +<p><a href="/url" title="title">Foo</a></p> +>>> Links - 562 +[foo] bar + +[foo]: /url +<<< +<p><a href="/url">foo</a> bar</p> +>>> Links - 563 +\[foo] + +[foo]: /url "title" +<<< +<p>[foo]</p> +>>> Links - 564 +[foo*]: /url + +*[foo*] +<<< +<p>*<a href="/url">foo*</a></p> +>>> Links - 565 +[foo][bar] + +[foo]: /url1 +[bar]: /url2 +<<< +<p><a href="/url2">foo</a></p> +>>> Links - 566 +[foo][] + +[foo]: /url1 +<<< +<p><a href="/url1">foo</a></p> +>>> Links - 567 +[foo]() + +[foo]: /url1 +<<< +<p><a href="">foo</a></p> +>>> Links - 568 +[foo](not a link) + +[foo]: /url1 +<<< +<p><a href="/url1">foo</a>(not a link)</p> +>>> Links - 569 +[foo][bar][baz] + +[baz]: /url +<<< +<p>[foo]<a href="/url">bar</a></p> +>>> Links - 570 +[foo][bar][baz] + +[baz]: /url1 +[bar]: /url2 +<<< +<p><a href="/url2">foo</a><a href="/url1">baz</a></p> +>>> Links - 571 +[foo][bar][baz] + +[baz]: /url1 +[foo]: /url2 +<<< +<p>[foo]<a href="/url1">bar</a></p> diff --git a/pkgs/markdown/test/common_mark/list_items.unit b/pkgs/markdown/test/common_mark/list_items.unit new file mode 100644 index 000000000..46162a908 --- /dev/null +++ b/pkgs/markdown/test/common_mark/list_items.unit @@ -0,0 +1,586 @@ +>>> List items - 253 +A paragraph +with two lines. + + indented code + +> A block quote. +<<< +<p>A paragraph +with two lines.</p> +<pre><code>indented code +</code></pre> +<blockquote> +<p>A block quote.</p> +</blockquote> +>>> List items - 254 +1. A paragraph + with two lines. + + indented code + + > A block quote. +<<< +<ol> +<li> +<p>A paragraph +with two lines.</p> +<pre><code>indented code +</code></pre> +<blockquote> +<p>A block quote.</p> +</blockquote> +</li> +</ol> +>>> List items - 255 +- one + + two +<<< +<ul> +<li>one</li> +</ul> +<p>two</p> +>>> List items - 256 +- one + + two +<<< +<ul> +<li> +<p>one</p> +<p>two</p> +</li> +</ul> +>>> List items - 257 + - one + + two +<<< +<ul> +<li>one</li> +</ul> +<pre><code> two +</code></pre> +>>> List items - 258 + - one + + two +<<< +<ul> +<li> +<p>one</p> +<p>two</p> +</li> +</ul> +>>> List items - 259 + > > 1. one +>> +>> two +<<< +<blockquote> +<blockquote> +<ol> +<li> +<p>one</p> +<p>two</p> +</li> +</ol> +</blockquote> +</blockquote> +>>> List items - 260 +>>- one +>> + > > two +<<< +<blockquote> +<blockquote> +<ul> +<li>one</li> +</ul> +<p>two</p> +</blockquote> +</blockquote> +>>> List items - 261 +-one + +2.two +<<< +<p>-one</p> +<p>2.two</p> +>>> List items - 262 +- foo + + + bar +<<< +<ul> +<li> +<p>foo</p> +<p>bar</p> +</li> +</ul> +>>> List items - 263 +1. foo + + ``` + bar + ``` + + baz + + > bam +<<< +<ol> +<li> +<p>foo</p> +<pre><code>bar +</code></pre> +<p>baz</p> +<blockquote> +<p>bam</p> +</blockquote> +</li> +</ol> +>>> List items - 264 +- Foo + + bar + + + baz +<<< +<ul> +<li> +<p>Foo</p> +<pre><code>bar + + +baz +</code></pre> +</li> +</ul> +>>> List items - 265 +123456789. ok +<<< +<ol start="123456789"> +<li>ok</li> +</ol> +>>> List items - 266 +1234567890. not ok +<<< +<p>1234567890. not ok</p> +>>> List items - 267 +0. ok +<<< +<ol start="0"> +<li>ok</li> +</ol> +>>> List items - 268 +003. ok +<<< +<ol start="3"> +<li>ok</li> +</ol> +>>> List items - 269 +-1. not ok +<<< +<p>-1. not ok</p> +>>> List items - 270 +- foo + + bar +<<< +<ul> +<li> +<p>foo</p> +<pre><code>bar +</code></pre> +</li> +</ul> +>>> List items - 271 + 10. foo + + bar +<<< +<ol start="10"> +<li> +<p>foo</p> +<pre><code>bar +</code></pre> +</li> +</ol> +>>> List items - 272 + indented code + +paragraph + + more code +<<< +<pre><code>indented code +</code></pre> +<p>paragraph</p> +<pre><code>more code +</code></pre> +>>> List items - 273 +1. indented code + + paragraph + + more code +<<< +<ol> +<li> +<pre><code>indented code +</code></pre> +<p>paragraph</p> +<pre><code>more code +</code></pre> +</li> +</ol> +>>> List items - 274 +1. indented code + + paragraph + + more code +<<< +<ol> +<li> +<pre><code> indented code +</code></pre> +<p>paragraph</p> +<pre><code>more code +</code></pre> +</li> +</ol> +>>> List items - 275 + foo + +bar +<<< +<p>foo</p> +<p>bar</p> +>>> List items - 276 +- foo + + bar +<<< +<ul> +<li>foo</li> +</ul> +<p>bar</p> +>>> List items - 277 +- foo + + bar +<<< +<ul> +<li> +<p>foo</p> +<p>bar</p> +</li> +</ul> +>>> List items - 278 +- + foo +- + ``` + bar + ``` +- + baz +<<< +<ul> +<li>foo</li> +<li> +<pre><code>bar +</code></pre> +</li> +<li> +<pre><code>baz +</code></pre> +</li> +</ul> +>>> List items - 279 +- + foo +<<< +<ul> +<li>foo</li> +</ul> +>>> List items - 280 +- + + foo +<<< +<ul> +<li></li> +</ul> +<p>foo</p> +>>> List items - 281 +- foo +- +- bar +<<< +<ul> +<li>foo</li> +<li></li> +<li>bar</li> +</ul> +>>> List items - 282 +- foo +- +- bar +<<< +<ul> +<li>foo</li> +<li></li> +<li>bar</li> +</ul> +>>> List items - 283 +1. foo +2. +3. bar +<<< +<ol> +<li>foo</li> +<li></li> +<li>bar</li> +</ol> +>>> List items - 284 +* +<<< +<ul> +<li></li> +</ul> +>>> List items - 285 +foo +* + +foo +1. +<<< +<p>foo +*</p> +<p>foo +1.</p> +>>> List items - 286 + 1. A paragraph + with two lines. + + indented code + + > A block quote. +<<< +<ol> +<li> +<p>A paragraph +with two lines.</p> +<pre><code>indented code +</code></pre> +<blockquote> +<p>A block quote.</p> +</blockquote> +</li> +</ol> +>>> List items - 287 + 1. A paragraph + with two lines. + + indented code + + > A block quote. +<<< +<ol> +<li> +<p>A paragraph +with two lines.</p> +<pre><code>indented code +</code></pre> +<blockquote> +<p>A block quote.</p> +</blockquote> +</li> +</ol> +>>> List items - 288 + 1. A paragraph + with two lines. + + indented code + + > A block quote. +<<< +<ol> +<li> +<p>A paragraph +with two lines.</p> +<pre><code>indented code +</code></pre> +<blockquote> +<p>A block quote.</p> +</blockquote> +</li> +</ol> +>>> List items - 289 + 1. A paragraph + with two lines. + + indented code + + > A block quote. +<<< +<pre><code>1. A paragraph + with two lines. + + indented code + + > A block quote. +</code></pre> +>>> List items - 290 + 1. A paragraph +with two lines. + + indented code + + > A block quote. +<<< +<ol> +<li> +<p>A paragraph +with two lines.</p> +<pre><code>indented code +</code></pre> +<blockquote> +<p>A block quote.</p> +</blockquote> +</li> +</ol> +>>> List items - 291 + 1. A paragraph + with two lines. +<<< +<ol> +<li>A paragraph +with two lines.</li> +</ol> +>>> List items - 292 +> 1. > Blockquote +continued here. +<<< +<blockquote> +<ol> +<li> +<blockquote> +<p>Blockquote +continued here.</p> +</blockquote> +</li> +</ol> +</blockquote> +>>> List items - 293 +> 1. > Blockquote +> continued here. +<<< +<blockquote> +<ol> +<li> +<blockquote> +<p>Blockquote +continued here.</p> +</blockquote> +</li> +</ol> +</blockquote> +>>> List items - 294 +- foo + - bar + - baz + - boo +<<< +<ul> +<li>foo +<ul> +<li>bar +<ul> +<li>baz +<ul> +<li>boo</li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +</ul> +>>> List items - 295 +- foo + - bar + - baz + - boo +<<< +<ul> +<li>foo</li> +<li>bar</li> +<li>baz</li> +<li>boo</li> +</ul> +>>> List items - 296 +10) foo + - bar +<<< +<ol start="10"> +<li>foo +<ul> +<li>bar</li> +</ul> +</li> +</ol> +>>> List items - 297 +10) foo + - bar +<<< +<ol start="10"> +<li>foo</li> +</ol> +<ul> +<li>bar</li> +</ul> +>>> List items - 298 +- - foo +<<< +<ul> +<li> +<ul> +<li>foo</li> +</ul> +</li> +</ul> +>>> List items - 299 +1. - 2. foo +<<< +<ol> +<li> +<ul> +<li> +<ol start="2"> +<li>foo</li> +</ol> +</li> +</ul> +</li> +</ol> +>>> List items - 300 +- # Foo +- Bar + --- + baz +<<< +<ul> +<li> +<h1>Foo</h1> +</li> +<li> +<h2>Bar</h2> +baz</li> +</ul> diff --git a/pkgs/markdown/test/common_mark/lists.unit b/pkgs/markdown/test/common_mark/lists.unit new file mode 100644 index 000000000..fce59fe0d --- /dev/null +++ b/pkgs/markdown/test/common_mark/lists.unit @@ -0,0 +1,406 @@ +>>> Lists - 301 +- foo +- bar ++ baz +<<< +<ul> +<li>foo</li> +<li>bar</li> +</ul> +<ul> +<li>baz</li> +</ul> +>>> Lists - 302 +1. foo +2. bar +3) baz +<<< +<ol> +<li>foo</li> +<li>bar</li> +</ol> +<ol start="3"> +<li>baz</li> +</ol> +>>> Lists - 303 +Foo +- bar +- baz +<<< +<p>Foo</p> +<ul> +<li>bar</li> +<li>baz</li> +</ul> +>>> Lists - 304 +The number of windows in my house is +14. The number of doors is 6. +<<< +<p>The number of windows in my house is +14. The number of doors is 6.</p> +>>> Lists - 305 +The number of windows in my house is +1. The number of doors is 6. +<<< +<p>The number of windows in my house is</p> +<ol> +<li>The number of doors is 6.</li> +</ol> +>>> Lists - 306 +- foo + +- bar + + +- baz +<<< +<ul> +<li> +<p>foo</p> +</li> +<li> +<p>bar</p> +</li> +<li> +<p>baz</p> +</li> +</ul> +>>> Lists - 307 +- foo + - bar + - baz + + + bim +<<< +<ul> +<li>foo +<ul> +<li>bar +<ul> +<li> +<p>baz</p> +<p>bim</p> +</li> +</ul> +</li> +</ul> +</li> +</ul> +>>> Lists - 308 +- foo +- bar + +<!-- --> + +- baz +- bim +<<< +<ul> +<li>foo</li> +<li>bar</li> +</ul> +<!-- --> +<ul> +<li>baz</li> +<li>bim</li> +</ul> +>>> Lists - 309 +- foo + + notcode + +- foo + +<!-- --> + + code +<<< +<ul> +<li> +<p>foo</p> +<p>notcode</p> +</li> +<li> +<p>foo</p> +</li> +</ul> +<!-- --> +<pre><code>code +</code></pre> +>>> Lists - 310 +- a + - b + - c + - d + - e + - f +- g +<<< +<ul> +<li>a</li> +<li>b</li> +<li>c</li> +<li>d</li> +<li>e</li> +<li>f</li> +<li>g</li> +</ul> +>>> Lists - 311 +1. a + + 2. b + + 3. c +<<< +<ol> +<li> +<p>a</p> +</li> +<li> +<p>b</p> +</li> +<li> +<p>c</p> +</li> +</ol> +>>> Lists - 312 +- a + - b + - c + - d + - e +<<< +<ul> +<li>a</li> +<li>b</li> +<li>c</li> +<li>d +- e</li> +</ul> +>>> Lists - 313 +1. a + + 2. b + + 3. c +<<< +<ol> +<li> +<p>a</p> +</li> +<li> +<p>b</p> +</li> +</ol> +<pre><code>3. c +</code></pre> +>>> Lists - 314 +- a +- b + +- c +<<< +<ul> +<li> +<p>a</p> +</li> +<li> +<p>b</p> +</li> +<li> +<p>c</p> +</li> +</ul> +>>> Lists - 315 +* a +* + +* c +<<< +<ul> +<li> +<p>a</p> +</li> +<li></li> +<li> +<p>c</p> +</li> +</ul> +>>> Lists - 316 +- a +- b + + c +- d +<<< +<ul> +<li> +<p>a</p> +</li> +<li> +<p>b</p> +<p>c</p> +</li> +<li> +<p>d</p> +</li> +</ul> +>>> Lists - 317 +- a +- b + + [ref]: /url +- d +<<< +<ul> +<li> +<p>a</p> +</li> +<li> +<p>b</p> +</li> +<li> +<p>d</p> +</li> +</ul> +>>> Lists - 318 +- a +- ``` + b + + + ``` +- c +<<< +<ul> +<li>a</li> +<li> +<pre><code>b + + +</code></pre> +</li> +<li>c</li> +</ul> +>>> Lists - 319 +- a + - b + + c +- d +<<< +<ul> +<li>a +<ul> +<li> +<p>b</p> +<p>c</p> +</li> +</ul> +</li> +<li>d</li> +</ul> +>>> Lists - 320 +* a + > b + > +* c +<<< +<ul> +<li>a +<blockquote> +<p>b</p> +</blockquote> +</li> +<li>c</li> +</ul> +>>> Lists - 321 +- a + > b + ``` + c + ``` +- d +<<< +<ul> +<li>a +<blockquote> +<p>b</p> +</blockquote> +<pre><code>c +</code></pre> +</li> +<li>d</li> +</ul> +>>> Lists - 322 +- a +<<< +<ul> +<li>a</li> +</ul> +>>> Lists - 323 +- a + - b +<<< +<ul> +<li>a +<ul> +<li>b</li> +</ul> +</li> +</ul> +>>> Lists - 324 +1. ``` + foo + ``` + + bar +<<< +<ol> +<li> +<pre><code>foo +</code></pre> +<p>bar</p> +</li> +</ol> +>>> Lists - 325 +* foo + * bar + + baz +<<< +<ul> +<li> +<p>foo</p> +<ul> +<li>bar</li> +</ul> +<p>baz</p> +</li> +</ul> +>>> Lists - 326 +- a + - b + - c + +- d + - e + - f +<<< +<ul> +<li> +<p>a</p> +<ul> +<li>b</li> +<li>c</li> +</ul> +</li> +<li> +<p>d</p> +<ul> +<li>e</li> +<li>f</li> +</ul> +</li> +</ul> diff --git a/pkgs/markdown/test/common_mark/paragraphs.unit b/pkgs/markdown/test/common_mark/paragraphs.unit new file mode 100644 index 000000000..a03f4a1dc --- /dev/null +++ b/pkgs/markdown/test/common_mark/paragraphs.unit @@ -0,0 +1,59 @@ +>>> Paragraphs - 219 +aaa + +bbb +<<< +<p>aaa</p> +<p>bbb</p> +>>> Paragraphs - 220 +aaa +bbb + +ccc +ddd +<<< +<p>aaa +bbb</p> +<p>ccc +ddd</p> +>>> Paragraphs - 221 +aaa + + +bbb +<<< +<p>aaa</p> +<p>bbb</p> +>>> Paragraphs - 222 + aaa + bbb +<<< +<p>aaa +bbb</p> +>>> Paragraphs - 223 +aaa + bbb + ccc +<<< +<p>aaa +bbb +ccc</p> +>>> Paragraphs - 224 + aaa +bbb +<<< +<p>aaa +bbb</p> +>>> Paragraphs - 225 + aaa +bbb +<<< +<pre><code>aaa +</code></pre> +<p>bbb</p> +>>> Paragraphs - 226 +aaa +bbb +<<< +<p>aaa<br /> +bbb</p> diff --git a/pkgs/markdown/test/common_mark/precedence.unit b/pkgs/markdown/test/common_mark/precedence.unit new file mode 100644 index 000000000..4359ce94a --- /dev/null +++ b/pkgs/markdown/test/common_mark/precedence.unit @@ -0,0 +1,8 @@ +>>> Precedence - 42 +- `one +- two` +<<< +<ul> +<li>`one</li> +<li>two`</li> +</ul> diff --git a/pkgs/markdown/test/common_mark/raw_html.unit b/pkgs/markdown/test/common_mark/raw_html.unit new file mode 100644 index 000000000..329f96a79 --- /dev/null +++ b/pkgs/markdown/test/common_mark/raw_html.unit @@ -0,0 +1,95 @@ +>>> Raw HTML - 613 +<a><bab><c2c> +<<< +<p><a><bab><c2c></p> +>>> Raw HTML - 614 +<a/><b2/> +<<< +<p><a/><b2/></p> +>>> Raw HTML - 615 +<a /><b2 +data="foo" > +<<< +<p><a /><b2 +data="foo" ></p> +>>> Raw HTML - 616 +<a foo="bar" bam = 'baz <em>"</em>' +_boolean zoop:33=zoop:33 /> +<<< +<p><a foo="bar" bam = 'baz <em>"</em>' +_boolean zoop:33=zoop:33 /></p> +>>> Raw HTML - 617 +Foo <responsive-image src="foo.jpg" /> +<<< +<p>Foo <responsive-image src="foo.jpg" /></p> +>>> Raw HTML - 618 +<33> <__> +<<< +<p><33> <__></p> +>>> Raw HTML - 619 +<a h*#ref="hi"> +<<< +<p><a h*#ref="hi"></p> +>>> Raw HTML - 620 +<a href="hi'> <a href=hi'> +<<< +<p><a href="hi'> <a href=hi'></p> +>>> Raw HTML - 621 +< a>< +foo><bar/ > +<foo bar=baz +bim!bop /> +<<< +<p>< a>< +foo><bar/ > +<foo bar=baz +bim!bop /></p> +>>> Raw HTML - 622 +<a href='bar'title=title> +<<< +<p><a href='bar'title=title></p> +>>> Raw HTML - 623 +</a></foo > +<<< +<p></a></foo ></p> +>>> Raw HTML - 624 +</a href="foo"> +<<< +<p></a href="foo"></p> +>>> Raw HTML - 625 +foo <!-- this is a -- +comment - with hyphens --> +<<< +<p>foo <!-- this is a -- +comment - with hyphens --></p> +>>> Raw HTML - 626 +foo <!--> foo --> + +foo <!---> foo --> +<<< +<p>foo <!--> foo --></p> +<p>foo <!---> foo --></p> +>>> Raw HTML - 627 +foo <?php echo $a; ?> +<<< +<p>foo <?php echo $a; ?></p> +>>> Raw HTML - 628 +foo <!ELEMENT br EMPTY> +<<< +<p>foo <!ELEMENT br EMPTY></p> +>>> Raw HTML - 629 +foo <![CDATA[>&<]]> +<<< +<p>foo <![CDATA[>&<]]></p> +>>> Raw HTML - 630 +foo <a href="ö"> +<<< +<p>foo <a href="ö"></p> +>>> Raw HTML - 631 +foo <a href="\*"> +<<< +<p>foo <a href="\*"></p> +>>> Raw HTML - 632 +<a href="\""> +<<< +<p><a href="""></p> diff --git a/pkgs/markdown/test/common_mark/setext_headings.unit b/pkgs/markdown/test/common_mark/setext_headings.unit new file mode 100644 index 000000000..702c72c0d --- /dev/null +++ b/pkgs/markdown/test/common_mark/setext_headings.unit @@ -0,0 +1,229 @@ +>>> Setext headings - 80 +Foo *bar* +========= + +Foo *bar* +--------- +<<< +<h1>Foo <em>bar</em></h1> +<h2>Foo <em>bar</em></h2> +>>> Setext headings - 81 +Foo *bar +baz* +==== +<<< +<h1>Foo <em>bar +baz</em></h1> +>>> Setext headings - 82 + Foo *bar +baz* +==== +<<< +<h1> Foo <em>bar +baz</em></h1> +>>> Setext headings - 83 +Foo +------------------------- + +Foo += +<<< +<h2>Foo</h2> +<h1>Foo</h1> +>>> Setext headings - 84 + Foo +--- + + Foo +----- + + Foo + === +<<< +<h2> Foo</h2> +<h2> Foo</h2> +<h1> Foo</h1> +>>> Setext headings - 85 + Foo + --- + + Foo +--- +<<< +<pre><code>Foo +--- + +Foo +</code></pre> +<hr /> +>>> Setext headings - 86 +Foo + ---- +<<< +<h2>Foo</h2> +>>> Setext headings - 87 +Foo + --- +<<< +<p>Foo +---</p> +>>> Setext headings - 88 +Foo += = + +Foo +--- - +<<< +<p>Foo += =</p> +<p>Foo</p> +<hr /> +>>> Setext headings - 89 +Foo +----- +<<< +<h2>Foo</h2> +>>> Setext headings - 90 +Foo\ +---- +<<< +<h2>Foo\</h2> +>>> Setext headings - 91 +`Foo +---- +` + +<a title="a lot +--- +of dashes"/> +<<< +<h2>`Foo</h2> +<p>`</p> +<h2><a title="a lot</h2> +<p>of dashes"/></p> +>>> Setext headings - 92 +> Foo +--- +<<< +<blockquote> +<p>Foo</p> +</blockquote> +<hr /> +>>> Setext headings - 93 +> foo +bar +=== +<<< +<blockquote> +<p>foo +bar +===</p> +</blockquote> +>>> Setext headings - 94 +- Foo +--- +<<< +<ul> +<li>Foo</li> +</ul> +<hr /> +>>> Setext headings - 95 +Foo +Bar +--- +<<< +<h2>Foo +Bar</h2> +>>> Setext headings - 96 +--- +Foo +--- +Bar +--- +Baz +<<< +<hr /> +<h2>Foo</h2> +<h2>Bar</h2> +<p>Baz</p> +>>> Setext headings - 97 + +==== +<<< +<p>====</p> +>>> Setext headings - 98 +--- +--- +<<< +<hr /> +<hr /> +>>> Setext headings - 99 +- foo +----- +<<< +<ul> +<li>foo</li> +</ul> +<hr /> +>>> Setext headings - 100 + foo +--- +<<< +<pre><code>foo +</code></pre> +<hr /> +>>> Setext headings - 101 +> foo +----- +<<< +<blockquote> +<p>foo</p> +</blockquote> +<hr /> +>>> Setext headings - 102 +\> foo +------ +<<< +<h2>> foo</h2> +>>> Setext headings - 103 +Foo + +bar +--- +baz +<<< +<p>Foo</p> +<h2>bar</h2> +<p>baz</p> +>>> Setext headings - 104 +Foo +bar + +--- + +baz +<<< +<p>Foo +bar</p> +<hr /> +<p>baz</p> +>>> Setext headings - 105 +Foo +bar +* * * +baz +<<< +<p>Foo +bar</p> +<hr /> +<p>baz</p> +>>> Setext headings - 106 +Foo +bar +\--- +baz +<<< +<p>Foo +bar +--- +baz</p> diff --git a/pkgs/markdown/test/common_mark/soft_line_breaks.unit b/pkgs/markdown/test/common_mark/soft_line_breaks.unit new file mode 100644 index 000000000..88e82f283 --- /dev/null +++ b/pkgs/markdown/test/common_mark/soft_line_breaks.unit @@ -0,0 +1,12 @@ +>>> Soft line breaks - 648 +foo +baz +<<< +<p>foo +baz</p> +>>> Soft line breaks - 649 +foo + baz +<<< +<p>foo +baz</p> diff --git a/pkgs/markdown/test/common_mark/tabs.unit b/pkgs/markdown/test/common_mark/tabs.unit new file mode 100644 index 000000000..1239481d9 --- /dev/null +++ b/pkgs/markdown/test/common_mark/tabs.unit @@ -0,0 +1,87 @@ +>>> Tabs - 1 + foo baz bim +<<< +<pre><code>foo baz bim +</code></pre> +>>> Tabs - 2 + foo baz bim +<<< +<pre><code>foo baz bim +</code></pre> +>>> Tabs - 3 + a a + ὐ a +<<< +<pre><code>a a +ὐ a +</code></pre> +>>> Tabs - 4 + - foo + + bar +<<< +<ul> +<li> +<p>foo</p> +<p>bar</p> +</li> +</ul> +>>> Tabs - 5 +- foo + + bar +<<< +<ul> +<li> +<p>foo</p> +<pre><code> bar +</code></pre> +</li> +</ul> +>>> Tabs - 6 +> foo +<<< +<blockquote> +<pre><code>foo +</code></pre> +</blockquote> +>>> Tabs - 7 +- foo +<<< +<ul> +<li> +<pre><code> foo +</code></pre> +</li> +</ul> +>>> Tabs - 8 + foo + bar +<<< +<pre><code>foo +bar +</code></pre> +>>> Tabs - 9 + - foo + - bar + - baz +<<< +<ul> +<li>foo +<ul> +<li>bar +<ul> +<li>baz</li> +</ul> +</li> +</ul> +</li> +</ul> +>>> Tabs - 10 +# Foo +<<< +<h1>Foo</h1> +>>> Tabs - 11 +* * * +<<< +<hr /> diff --git a/pkgs/markdown/test/common_mark/textual_content.unit b/pkgs/markdown/test/common_mark/textual_content.unit new file mode 100644 index 000000000..0069e0f0f --- /dev/null +++ b/pkgs/markdown/test/common_mark/textual_content.unit @@ -0,0 +1,12 @@ +>>> Textual content - 650 +hello $.;'there +<<< +<p>hello $.;'there</p> +>>> Textual content - 651 +Foo χρῆν +<<< +<p>Foo χρῆν</p> +>>> Textual content - 652 +Multiple spaces +<<< +<p>Multiple spaces</p> diff --git a/pkgs/markdown/test/common_mark/thematic_breaks.unit b/pkgs/markdown/test/common_mark/thematic_breaks.unit new file mode 100644 index 000000000..b4d490fa8 --- /dev/null +++ b/pkgs/markdown/test/common_mark/thematic_breaks.unit @@ -0,0 +1,126 @@ +>>> Thematic breaks - 43 +*** +--- +___ +<<< +<hr /> +<hr /> +<hr /> +>>> Thematic breaks - 44 ++++ +<<< +<p>+++</p> +>>> Thematic breaks - 45 +=== +<<< +<p>===</p> +>>> Thematic breaks - 46 +-- +** +__ +<<< +<p>-- +** +__</p> +>>> Thematic breaks - 47 + *** + *** + *** +<<< +<hr /> +<hr /> +<hr /> +>>> Thematic breaks - 48 + *** +<<< +<pre><code>*** +</code></pre> +>>> Thematic breaks - 49 +Foo + *** +<<< +<p>Foo +***</p> +>>> Thematic breaks - 50 +_____________________________________ +<<< +<hr /> +>>> Thematic breaks - 51 + - - - +<<< +<hr /> +>>> Thematic breaks - 52 + ** * ** * ** * ** +<<< +<hr /> +>>> Thematic breaks - 53 +- - - - +<<< +<hr /> +>>> Thematic breaks - 54 +- - - - +<<< +<hr /> +>>> Thematic breaks - 55 +_ _ _ _ a + +a------ + +---a--- +<<< +<p>_ _ _ _ a</p> +<p>a------</p> +<p>---a---</p> +>>> Thematic breaks - 56 + *-* +<<< +<p><em>-</em></p> +>>> Thematic breaks - 57 +- foo +*** +- bar +<<< +<ul> +<li>foo</li> +</ul> +<hr /> +<ul> +<li>bar</li> +</ul> +>>> Thematic breaks - 58 +Foo +*** +bar +<<< +<p>Foo</p> +<hr /> +<p>bar</p> +>>> Thematic breaks - 59 +Foo +--- +bar +<<< +<h2>Foo</h2> +<p>bar</p> +>>> Thematic breaks - 60 +* Foo +* * * +* Bar +<<< +<ul> +<li>Foo</li> +</ul> +<hr /> +<ul> +<li>Bar</li> +</ul> +>>> Thematic breaks - 61 +- Foo +- * * * +<<< +<ul> +<li>Foo</li> +<li> +<hr /> +</li> +</ul> diff --git a/pkgs/markdown/test/crash_test.dart b/pkgs/markdown/test/crash_test.dart new file mode 100644 index 000000000..a6f427d20 --- /dev/null +++ b/pkgs/markdown/test/crash_test.dart @@ -0,0 +1,226 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:convert'; +import 'dart:io'; +import 'dart:isolate'; + +import 'package:http/http.dart' as http; +import 'package:http/retry.dart' as http; +import 'package:markdown/markdown.dart'; +import 'package:pool/pool.dart'; +import 'package:tar/tar.dart'; +import 'package:test/test.dart'; + +// ignore_for_file: avoid_dynamic_calls + +const extensions = [ + '.md', + '.mkd', + '.mdwn', + '.mdown', + '.mdtxt', + '.mdtext', + '.markdown', + 'README', + 'CHANGELOG', +]; + +void main() async { + // This test is a really dumb and very slow crash-test. + // It downloads the latest package version for each package on pub.dev + // and tries to parse all `*.md` files in the package, counting the number + // of times where the parser throws. + // + // Needless to say, this test is very slow and running it eats a lot of CPU. + // But it's a fairly good way to try a lot of real-world markdown text to see + // if any of the poorly formatted markdown causes the parser to crash. + test( + 'crash test', + () async { + final started = DateTime.now(); + var lastStatus = DateTime(0); + void status(String Function() message) { + if (DateTime.now().difference(lastStatus) > + const Duration(seconds: 30)) { + lastStatus = DateTime.now(); + print(message()); + } + } + + final c = http.RetryClient(http.Client()); + Future<dynamic> getJson(String url) async { + final u = Uri.tryParse(url); + if (u == null) { + return null; + } + try { + final data = await c.read(u); + try { + return jsonDecode(data); + } on FormatException { + return null; + } + } on http.ClientException { + return null; + } on IOException { + return null; + } + } + + final packages = + ((await getJson('https://pub.dev/api/package-names'))['packages'] + as List) + .cast<String>(); + //.take(3).toList(); // useful when testing + print('## Found ${packages.length} packages to scan'); + + var count = 0; + final pool = Pool(50); + final packageVersions = <PackageVersion>[]; + await Future.wait(packages.map((package) async { + await pool.withResource(() async { + final response = await getJson( + 'https://pub.dev/api/packages/$package', + ); + final entry = response['latest'] as Map?; + if (entry != null) { + packageVersions.add(PackageVersion( + package: package, + version: entry['version'] as String, + archiveUrl: entry['archive_url'] as String, + )); + } + count++; + status( + () => 'Listed versions for $count / ${packages.length} packages', + ); + }); + })); + + print('## Found ${packageVersions.length} package versions to scan'); + + count = 0; + final errors = <String>[]; + var skipped = 0; + await Future.wait(packageVersions.map((pv) async { + await pool.withResource(() async { + final archiveUrl = Uri.tryParse(pv.archiveUrl); + if (archiveUrl == null) { + skipped++; + return; + } + late List<int> archive; + try { + archive = await c.readBytes(archiveUrl); + } on http.ClientException { + skipped++; + return; + } on IOException { + skipped++; + return; + } + + final result = await _findMarkdownIssues( + pv.package, + pv.version, + archive, + ); + + // If tar decoding fails. + if (result == null) { + skipped++; + return; + } + + errors.addAll(result); + result.forEach(print); + }); + count++; + status(() => + 'Scanned $count / ${packageVersions.length} (skipped $skipped),' + ' found ${errors.length} issues'); + })); + + await pool.close(); + c.close(); + + print('## Finished scanning'); + print('Scanned ${packageVersions.length} package versions in ' + '${DateTime.now().difference(started)}'); + + if (errors.isNotEmpty) { + print('Found issues:'); + errors.forEach(print); + fail('Found ${errors.length} cases where markdownToHtml threw!'); + } + }, + timeout: const Timeout(Duration(hours: 5)), + tags: 'crash_test', // skipped by default, see: dart_test.yaml + ); +} + +class PackageVersion { + final String package; + final String version; + final String archiveUrl; + + PackageVersion({ + required this.package, + required this.version, + required this.archiveUrl, + }); +} + +/// Scans [gzippedArchive] for markdown files and tries to parse them all. +/// +/// Creates a list of issues that arose when parsing markdown files. The +/// [package] and [version] strings are used to construct nice issues. +/// An issue string may be multi-line, but should be printable. +/// +/// Returns a list of issues, or `null` if decoding and parsing [gzippedArchive] +/// failed. +Future<List<String>?> _findMarkdownIssues( + String package, + String version, + List<int> gzippedArchive, +) async { + return Isolate.run<List<String>?>(() async { + try { + final archive = gzip.decode(gzippedArchive); + final issues = <String>[]; + await TarReader.forEach(Stream.value(archive), (entry) async { + if (extensions.any((ext) => entry.name.endsWith(ext))) { + late String contents; + try { + final bytes = await http.ByteStream(entry.contents).toBytes(); + contents = utf8.decode(bytes); + } on FormatException { + return; // ignore invalid utf8 + } + final start = DateTime.now(); + try { + markdownToHtml( + contents, + extensionSet: ExtensionSet.gitHubWeb, + ); + } catch (err, st) { + issues.add( + 'package:$package-$version/${entry.name}, throws: $err\n$st'); + } + final time = DateTime.now().difference(start); + if (time.inSeconds > 30) { + issues.add( + 'package:$package-$version/${entry.name} took $time to process'); + } + } + }); + return issues; + } on FormatException { + return null; + } + }).timeout(const Duration(minutes: 2), onTimeout: () { + return ['package:$package-$version failed to be processed in 2 minutes']; + }); +} diff --git a/pkgs/markdown/test/document_test.dart b/pkgs/markdown/test/document_test.dart new file mode 100644 index 000000000..3e30697ee --- /dev/null +++ b/pkgs/markdown/test/document_test.dart @@ -0,0 +1,125 @@ +// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:markdown/markdown.dart'; +import 'package:markdown/src/util.dart'; +import 'package:test/test.dart'; + +void main() { + group('Document', () { + test('encodeHtml prevents less than and ampersand escaping', () { + final document = Document(encodeHtml: false); + final result = document.parseInline('< &'); + expect(result, hasLength(1)); + expect( + result[0], + const TypeMatcher<Text>().having((e) => e.text, 'text', equals('< &')), + ); + }); + + group('with encodeHtml enabled', () { + final document = Document(); + + test('encodes HTML in an inline code snippet', () { + final result = + document.parseInline('``<p>Hello <em>Markdown</em></p>``'); + final codeSnippet = result.single as Element; + expect( + codeSnippet.textContent, + equals('<p>Hello <em>Markdown</em></p>'), + ); + }); + + test('encodes HTML in a fenced code block', () { + final lines = '```\n<p>Hello <em>Markdown</em></p>\n```\n'.toLines(); + final result = document.parseLineList(lines); + final codeBlock = result.single as Element; + expect( + codeBlock.textContent, + equals('<p>Hello <em>Markdown</em></p>\n'), + ); + }); + + test('encodes HTML in an indented code block', () { + final lines = ' <p>Hello <em>Markdown</em></p>\n'.toLines(); + final result = document.parseLineList(lines); + final codeBlock = result.single as Element; + expect( + codeBlock.textContent, + equals('<p>Hello <em>Markdown</em></p>\n'), + ); + }); + + test('encodeHtml spaces are preserved in text', () { + // Example to get a <p> tag rendered before a text node. + const contents = 'Sample\n\n<pre>\n A\n B\n</pre>'; + final document = Document(); + final nodes = BlockParser(contents.toLines(), document).parseLines(); + final result = HtmlRenderer().render(nodes); + expect(result, '<p>\n</p>\n<pre>\n A\n B\n</pre>'); + }); + + test('encode double quotes, greater than, and less than when escaped', + () { + const contents = r'\>\"\< Hello'; + final document = Document(); + final nodes = document.parseInline(contents); + expect(nodes, hasLength(1)); + expect( + nodes.single, + const TypeMatcher<Text>().having( + (e) => e.text, + 'text', + '>"< Hello', + ), + ); + }); + }); + + group('with encodeHtml disabled', () { + final document = Document(encodeHtml: false); + + test('leaves HTML alone, in a code snippet', () { + final result = + document.parseInline('```<p>Hello <em>Markdown</em></p>```'); + final codeSnippet = result.single as Element; + expect( + codeSnippet.textContent, + equals('<p>Hello <em>Markdown</em></p>'), + ); + }); + + test('leaves HTML alone, in a fenced code block', () { + final lines = '```\n<p>Hello <em>Markdown</em></p>\n```\n'.toLines(); + final result = document.parseLineList(lines); + final codeBlock = result.single as Element; + expect( + codeBlock.textContent, + equals('<p>Hello <em>Markdown</em></p>\n'), + ); + }); + + test('leaves HTML alone, in an indented code block', () { + final lines = ' <p>Hello <em>Markdown</em></p>\n'.toLines(); + final result = document.parseLineList(lines); + final codeBlock = result.single as Element; + expect( + codeBlock.textContent, + equals('<p>Hello <em>Markdown</em></p>\n'), + ); + }); + + test('leave double quotes, greater than, and less than when escaped', () { + const contents = r'\>\"\< Hello'; + final document = Document(encodeHtml: false); + final nodes = document.parseInline(contents); + expect(nodes, hasLength(1)); + expect( + nodes.single, + const TypeMatcher<Text>().having((e) => e.text, 'text', '>"< Hello'), + ); + }); + }); + }); +} diff --git a/pkgs/markdown/test/extensions/alert_extension.unit b/pkgs/markdown/test/extensions/alert_extension.unit new file mode 100644 index 000000000..9a21f1866 --- /dev/null +++ b/pkgs/markdown/test/extensions/alert_extension.unit @@ -0,0 +1,162 @@ +>>> type note +> [!NoTe] +> Test note alert. +<<< +<div class="markdown-alert markdown-alert-note"> +<p class="markdown-alert-title">Note</p> +<p>Test note alert.</p> +</div> +>>> type tip +> [!TiP] +> Test tip alert. +<<< +<div class="markdown-alert markdown-alert-tip"> +<p class="markdown-alert-title">Tip</p> +<p>Test tip alert.</p> +</div> +>>> type important +> [!ImpoRtanT] +> Test important alert. +<<< +<div class="markdown-alert markdown-alert-important"> +<p class="markdown-alert-title">Important</p> +<p>Test important alert.</p> +</div> +>>> type warning +> [!WarNinG] +> Test warning alert. +<<< +<div class="markdown-alert markdown-alert-warning"> +<p class="markdown-alert-title">Warning</p> +<p>Test warning alert.</p> +</div> +>>> type caution +> [!CauTioN] +> Test caution alert. +<<< +<div class="markdown-alert markdown-alert-caution"> +<p class="markdown-alert-title">Caution</p> +<p>Test caution alert.</p> +</div> +>>> invalid type +> [!foo] +> Test foo alert. +<<< +<blockquote> +<p>[!foo] +Test foo alert.</p> +</blockquote> +>>> contents can both contain/not contain starting quote +> [!NOTE] +Test note alert. +>Test note alert x2. +<<< +<div class="markdown-alert markdown-alert-note"> +<p class="markdown-alert-title">Note</p> +<p>Test note alert. +Test note alert x2.</p> +</div> +>>> spaces everywhere + > [!NOTE] +> Test note alert. + > Test note alert x2. +<<< +<div class="markdown-alert markdown-alert-note"> +<p class="markdown-alert-title">Note</p> +<p>Test note alert. +Test note alert x2.</p> +</div> +>>> title has 3 more spaces then fallback to blockquote +> [!NOTE] +> Test blockquote. +<<< +<blockquote> +<p>[!NOTE] +Test blockquote.</p> +</blockquote> +>>> nested blockquote +> [!NOTE] +>> Test nested blockquote. +<<< +<div class="markdown-alert markdown-alert-note"> +<p class="markdown-alert-title">Note</p> +<blockquote> +<p>Test nested blockquote.</p> +</blockquote> +</div> +>>> escape brackets +> \[!note\] +> Test escape brackets. +<<< +<div class="markdown-alert markdown-alert-note"> +<p class="markdown-alert-title">Note</p> +<p>Test escape brackets.</p> +</div> +>>> terminates properly +> [!note] +> A sample note. + +Additional markdown text. +<<< +<div class="markdown-alert markdown-alert-note"> +<p class="markdown-alert-title">Note</p> +<p>A sample note.</p> +</div> +<p>Additional markdown text.</p> +>>> supports multiple quoted lines +> [!note] +> A sample note +> with two lines. + +Additional markdown text. +<<< +<div class="markdown-alert markdown-alert-note"> +<p class="markdown-alert-title">Note</p> +<p>A sample note +with two lines.</p> +</div> +<p>Additional markdown text.</p> +>>> supports multiple lines +> [!note] +> A sample note + with two lines. + +Additional markdown text. +<<< +<div class="markdown-alert markdown-alert-note"> +<p class="markdown-alert-title">Note</p> +<p>A sample note +with two lines.</p> +</div> +<p>Additional markdown text.</p> +>>> supports continuation lines +> [!note] +> A sample note +with two lines. + +Additional markdown text. +<<< +<div class="markdown-alert markdown-alert-note"> +<p class="markdown-alert-title">Note</p> +<p>A sample note +with two lines.</p> +</div> +<p>Additional markdown text.</p> +>>> crash repro #584.1 +> [!Warning] +> +> Some extensions won't work on dynamic types. +<<< +<div class="markdown-alert markdown-alert-warning"> +<p class="markdown-alert-title">Warning</p> +<p>Some extensions won't work on dynamic types.</p> +</div> +>>> crash repro #584.2 +> [!NOTE] +> +> if you receive the following error: +<<< +<div class="markdown-alert markdown-alert-note"> +<p class="markdown-alert-title">Note</p> +<p>if you receive the following error:</p> +</div> diff --git a/pkgs/markdown/test/extensions/autolink_extension.unit b/pkgs/markdown/test/extensions/autolink_extension.unit new file mode 100644 index 000000000..4a07fdc01 --- /dev/null +++ b/pkgs/markdown/test/extensions/autolink_extension.unit @@ -0,0 +1,10 @@ +>>> not a link +mhttp://www.foo.com +<<< +<p>mhttp://www.foo.com</p> +>>> following a newline +m +http://www.foo.com +<<< +<p>m +<a href="http://www.foo.com">http://www.foo.com</a></p> \ No newline at end of file diff --git a/pkgs/markdown/test/extensions/emojis.unit b/pkgs/markdown/test/extensions/emojis.unit new file mode 100644 index 000000000..00197e50b --- /dev/null +++ b/pkgs/markdown/test/extensions/emojis.unit @@ -0,0 +1,42 @@ +>>> within a paragraph +I love to :smile:. + +<<< +<p>I love to 😄.</p> +>>> within other inline syntax +I *love to :smile:* +<<< +<p>I <em>love to 😄</em></p> +>>> within blockquote +> I love to :smile:. +<<< +<blockquote> +<p>I love to 😄.</p> +</blockquote> +>>> within code block + I love to :smile: +<<< +<pre><code>I love to :smile: +</code></pre> +>>> within a link +I love [to :smile:](http://www.google.com). +<<< +<p>I love <a href="http://www.google.com">to 😄</a>.</p> +>>> within a reference link +I love [to :smile:][]. + +[to :smile:]: http://www.google.com +<<< +<p>I love <a href="http://www.google.com">to 😄</a>.</p> +>>> within inline code +I love to `:smile:`. +<<< +<p>I love to <code>:smile:</code>.</p> +>>> with multiple code points +Yay :australia: +<<< +<p>Yay 🇦🇺</p> +>>> leaves unknown emojis alone +I love :smiles:. +<<< +<p>I love :smiles:.</p> diff --git a/pkgs/markdown/test/extensions/fenced_blockquotes.unit b/pkgs/markdown/test/extensions/fenced_blockquotes.unit new file mode 100644 index 000000000..8124ad4b1 --- /dev/null +++ b/pkgs/markdown/test/extensions/fenced_blockquotes.unit @@ -0,0 +1,70 @@ +>>> simple block quote +>>> +# Foo +bar +baz +>>> + +<<< +<blockquote> +<h1>Foo</h1> +<p>bar +baz</p> +</blockquote> +>>> has blank lines +>>> + +foo + + + + +bar + + +>>> + +<<< +<blockquote> +<p>foo</p> +<p>bar</p> +</blockquote> +>>> with nested block quote +>>> +foo +> bar +>>> + +<<< +<blockquote> +<p>foo</p> +<blockquote> +<p>bar</p> +</blockquote> +</blockquote> +>>> with nested indented clode block +>>> + foo + bar +>>> + +<<< +<blockquote> +<pre><code>foo +bar +</code></pre> +</blockquote> +>>> with nested fenced clode block +>>> +``` +foo +bar +``` +>>> + +<<< +<blockquote> +<pre><code>foo +bar +</code></pre> +</blockquote> \ No newline at end of file diff --git a/pkgs/markdown/test/extensions/fenced_code_blocks.unit b/pkgs/markdown/test/extensions/fenced_code_blocks.unit new file mode 100644 index 000000000..596f49a09 --- /dev/null +++ b/pkgs/markdown/test/extensions/fenced_code_blocks.unit @@ -0,0 +1,52 @@ +>>> without an optional language identifier +``` +code +``` + +<<< +<pre><code>code +</code></pre> +>>> with an optional language identifier +```dart +code +``` + +<<< +<pre><code class="language-dart">code +</code></pre> +>>> escape HTML characters +``` +<&> +``` + +<<< +<pre><code><&> +</code></pre> +>>> Pandoc style without language identifier +~~~~~ +code +~~~~~ + +<<< +<pre><code>code +</code></pre> +>>> Pandoc style with language identifier +~~~~~dart +code +~~~~~ + +<<< +<pre><code class="language-dart">code +</code></pre> +>>> Pandoc style with inner tildes row +~~~~~ +~~~ +code +~~~ +~~~~~ + +<<< +<pre><code>~~~ +code +~~~ +</code></pre> diff --git a/pkgs/markdown/test/extensions/footnote_block.unit b/pkgs/markdown/test/extensions/footnote_block.unit new file mode 100644 index 000000000..ae730bfd0 --- /dev/null +++ b/pkgs/markdown/test/extensions/footnote_block.unit @@ -0,0 +1,288 @@ +>>> footnote reference in footnote definition + +Footnote 1 link[^first]. + +[^first]: footnote reference in footnote definition[^first] + +<<< +<p>Footnote 1 link<sup class="footnote-ref"><a href="#fn-first" id="fnref-first">1</a></sup>.</p> +<section class="footnotes"> +<ol> +<li id="fn-first"> +<p>footnote reference in footnote definition<sup class="footnote-ref"><a href="#fn-first" id="fnref-first-2">1</a></sup> <a href="#fnref-first" class="footnote-backref">↩</a> <a href="#fnref-first-2" class="footnote-backref">↩<sup class="footnote-ref">2</sup></a></p> +</li> +</ol> +</section> +>>> footnote reference cases +[^fifth]: ending with another ']' and different order + +Footnote 1 link[^first]. + +Footnote 2 link[^きゃくちゅう脚注]. + +Footnote 3 link[^p1 p2]. + +Footnote 4 link![^forth]. + +Footnote 5 link![^fifth]]. + +Footnote 6 link![^ sixth ]. + +Footnote 7 link[^きゃくちゅう脚注]. + +[^first]: Here is the footnote definition + +[^きゃくちゅう脚注]: unicode label and duplicated reference. + +[^p1 p2]: p1 p2 + +[^ForTh]: start with '[' and with upper case + +[^sixth]: label-start-with-blank +<<< +<p>Footnote 1 link<sup class="footnote-ref"><a href="#fn-first" id="fnref-first">1</a></sup>.</p> +<p>Footnote 2 link<sup class="footnote-ref"><a href="#fn-%E3%81%8D%E3%82%83%E3%81%8F%E3%81%A1%E3%82%85%E3%81%86%E8%84%9A%E6%B3%A8" id="fnref-%E3%81%8D%E3%82%83%E3%81%8F%E3%81%A1%E3%82%85%E3%81%86%E8%84%9A%E6%B3%A8">2</a></sup>.</p> +<p>Footnote 3 link[^p1 p2].</p> +<p>Footnote 4 link!<sup class="footnote-ref"><a href="#fn-ForTh" id="fnref-ForTh">3</a></sup>.</p> +<p>Footnote 5 link!<sup class="footnote-ref"><a href="#fn-fifth" id="fnref-fifth">4</a></sup>].</p> +<p>Footnote 6 link!<sup class="footnote-ref"><a href="#fn-sixth" id="fnref-sixth">5</a></sup>.</p> +<p>Footnote 7 link<sup class="footnote-ref"><a href="#fn-%E3%81%8D%E3%82%83%E3%81%8F%E3%81%A1%E3%82%85%E3%81%86%E8%84%9A%E6%B3%A8" id="fnref-%E3%81%8D%E3%82%83%E3%81%8F%E3%81%A1%E3%82%85%E3%81%86%E8%84%9A%E6%B3%A8-2">2</a></sup>.</p> +<p>[^p1 p2]: p1 p2</p> +<section class="footnotes"> +<ol> +<li id="fn-first"> +<p>Here is the footnote definition <a href="#fnref-first" class="footnote-backref">↩</a></p> +</li> +<li id="fn-%E3%81%8D%E3%82%83%E3%81%8F%E3%81%A1%E3%82%85%E3%81%86%E8%84%9A%E6%B3%A8"> +<p>unicode label and duplicated reference. <a href="#fnref-%E3%81%8D%E3%82%83%E3%81%8F%E3%81%A1%E3%82%85%E3%81%86%E8%84%9A%E6%B3%A8" class="footnote-backref">↩</a> <a href="#fnref-%E3%81%8D%E3%82%83%E3%81%8F%E3%81%A1%E3%82%85%E3%81%86%E8%84%9A%E6%B3%A8-2" class="footnote-backref">↩<sup class="footnote-ref">2</sup></a></p> +</li> +<li id="fn-ForTh"> +<p>start with '[' and with upper case <a href="#fnref-ForTh" class="footnote-backref">↩</a></p> +</li> +<li id="fn-fifth"> +<p>ending with another ']' and different order <a href="#fnref-fifth" class="footnote-backref">↩</a></p> +</li> +<li id="fn-sixth"> +<p>label-start-with-blank <a href="#fnref-sixth" class="footnote-backref">↩</a></p> +</li> +</ol> +</section> +>>> footnote labels with special chars +empty label[^] and blank label[^ ] + +some[^-] strange[^^] but[^\[] labels[^\[\]] + +[^]: +[^ ]: + +[^-]: valid1 + +[^^]:valid2 + +[^\[]: valid3 + +[^\[\]]: this-is-link-not-footnote +<<< +<p>empty label[^] and blank label[^ ]</p> +<p>some<sup class="footnote-ref"><a href="#fn--" id="fnref--">1</a></sup> strange<sup class="footnote-ref"><a href="#fn-%5E" id="fnref-%5E">2</a></sup> but<sup class="footnote-ref"><a href="#fn-%5C%5B" id="fnref-%5C%5B">3</a></sup> labels<a href="this-is-link-not-footnote">^[]</a></p> +<p>[^]: +[^ ]:</p> +<section class="footnotes"> +<ol> +<li id="fn--"> +<p>valid1 <a href="#fnref--" class="footnote-backref">↩</a></p> +</li> +<li id="fn-%5E"> +<p>valid2 <a href="#fnref-%5E" class="footnote-backref">↩</a></p> +</li> +<li id="fn-%5C%5B"> +<p>valid3 <a href="#fnref-%5C%5B" class="footnote-backref">↩</a></p> +</li> +</ol> +</section> +>>> footnote with paragraph +test footnote[^first]. + +[^first]: Footnote **can have markup** + + and multiple paragraphs. + +"Smartypants, double quotes" and 'single quotes' +<<< +<p>test footnote<sup class="footnote-ref"><a href="#fn-first" id="fnref-first">1</a></sup>.</p> +<p>"Smartypants, double quotes" and 'single quotes'</p> +<section class="footnotes"> +<ol> +<li id="fn-first"> +<p>Footnote <strong>can have markup</strong></p> +<p>and multiple paragraphs. <a href="#fnref-first" class="footnote-backref">↩</a></p> +</li> +</ol> +</section> +>>> footnote adjacent paragraph +Here is a footnote reference,[^1] +[^1]: Here is the footnote. + Subsequent paragraphs +<<< +<p>Here is a footnote reference,<sup class="footnote-ref"><a href="#fn-1" id="fnref-1">1</a></sup></p> +<section class="footnotes"> +<ol> +<li id="fn-1"> +<p>Here is the footnote. +Subsequent paragraphs <a href="#fnref-1" class="footnote-backref">↩</a></p> +</li> +</ol> +</section> +>>> footnote without ref +Here is a footnote reference +[^1]: Here is the footnote. +<<< +<p>Here is a footnote reference</p> +>>> footnote example from github +Here is a simple footnote[^1]. + +A footnote can also have multiple lines[^2]. + +You can also use words, to fit your writing style more closely[^note]. + +[^1]: My reference. +[^2]: Every new line should be prefixed with 2 spaces. + This allows you to have a footnote with multiple lines. +[^note]: + Named footnotes will still render with numbers instead of the text but allow easier identification and linking. + This footnote also has been made with a different syntax using 4 spaces for new lines. +<<< +<p>Here is a simple footnote<sup class="footnote-ref"><a href="#fn-1" id="fnref-1">1</a></sup>.</p> +<p>A footnote can also have multiple lines<sup class="footnote-ref"><a href="#fn-2" id="fnref-2">2</a></sup>.</p> +<p>You can also use words, to fit your writing style more closely<sup class="footnote-ref"><a href="#fn-note" id="fnref-note">3</a></sup>.</p> +<section class="footnotes"> +<ol> +<li id="fn-1"> +<p>My reference. <a href="#fnref-1" class="footnote-backref">↩</a></p> +</li> +<li id="fn-2"> +<p>Every new line should be prefixed with 2 spaces. +This allows you to have a footnote with multiple lines. <a href="#fnref-2" class="footnote-backref">↩</a></p> +</li> +<li id="fn-note"> +<p>Named footnotes will still render with numbers instead of the text but allow easier identification and linking. +This footnote also has been made with a different syntax using 4 spaces for new lines. <a href="#fnref-note" class="footnote-backref">↩</a></p> +</li> +</ol> +</section> +>>> ![^ **image**] without definition should be formatted: unlike github +![^ **image**] +<<< +<p>![^ <strong>image</strong>]</p> +>>> ![^ **image**] with definition should be image: unlike github +![^ **image**] + +[^ **image**]: valid-link +<<< +<p><img src="valid-link" alt="^ image" /></p> +>>> ![^ **image**] with definition should be plain html: unlike github +![^ **image**] + +[^ **image**]: invalid link +<<< +<p>![^ <strong>image</strong>]</p> +<p>[^ <strong>image</strong>]: invalid link</p> +>>> ![ ^**image**] without definition should be formatted +![ ^**image**] +<<< +<p>![ ^<strong>image</strong>]</p> +>>> ![^ ^**image**] without definition should be formatted: unlike github +![^ ^**image**] +<<< +<p>![^ ^<strong>image</strong>]</p> +>>> ![^ ^**image**] with definition should be image: unlike github +![^ ^**image**] + +[^ ^**image**]: valid-link +<<< +<p><img src="valid-link" alt="^ ^image" /></p> +>>> [^ **label**] without definition should be formatted: unlike github +[^ **label**] +<<< +<p>[^ <strong>label</strong>]</p> +>>> [adc][^**link**] without definition should be formatted: unlike github +[adc][^**link**] +<<< +<p>[adc][^<strong>link</strong>]</p> +>>> [adc][^**link**] with definition should be footnotes: +[adc][^**link**] + +[^**link**]: valid-link +<<< +<p>[adc]<sup class="footnote-ref"><a href="#fn-**link**" id="fnref-**link**">1</a></sup></p> +<section class="footnotes"> +<ol> +<li id="fn-**link**"> +<p>valid-link <a href="#fnref-**link**" class="footnote-backref">↩</a></p> +</li> +</ol> +</section> +>>> \[^good] should be text +\[^good] + +[^good]: good +<<< +<p>[^good]</p> +>>>[^ nice] should be link +[^ nice] + +[^ nice ]: good +<<< +<p><a href="good">^ nice</a></p> +>>>[^ nice ] should be text +[^ nice ] + +[^nice ]: good +<<< +<p>[^ nice ]</p> +>>> [^\]] with definition should be link +[^\]] + +[^\]]: good +<<< +<p><a href="good">^]</a></p> +>>> [^a-\nb] with definition should be paragraph +[^a- +b] + +[^a- +b]: good +<<< +<p><a href="good">^a- +b</a></p> +>>> [^a] with error definition should be text +[^a] + +[^a\]: good +<<< +<p>[^a]</p> +>>> [^a] with double definition contain '\]' should be text +[^a] + +[^a\]:]: definition contain '\]' +<<< +<p>[^a]</p> +>>> [^a] with double definition trailing should be footnote +[^a] + +[^a]:]: good +<<< +<p><sup class="footnote-ref"><a href="#fn-a" id="fnref-a">1</a></sup></p> +<section class="footnotes"> +<ol> +<li id="fn-a"> +<p>]: good <a href="#fnref-a" class="footnote-backref">↩</a></p> +</li> +</ol> +</section> +>>> complete image link with definition would be image: unlike github +![^image](example.png) + +[^image]: image footnote +<<< +<p><img src="example.png" alt="^image" /></p> diff --git a/pkgs/markdown/test/extensions/headers_with_ids.unit b/pkgs/markdown/test/extensions/headers_with_ids.unit new file mode 100644 index 000000000..7bad75cc5 --- /dev/null +++ b/pkgs/markdown/test/extensions/headers_with_ids.unit @@ -0,0 +1,41 @@ +>>> simple header +# header + +<<< +<h1 id="header">header</h1> +>>> header that starts with garbage +## 2. header again + +<<< +<h2 id="2-header-again">2. header again</h2> +>>> header with inline syntaxes +### headers **rock** `etc.` + +<<< +<h3 id="headers-rock-etc">headers <strong>rock</strong> <code>etc.</code></h3> +>>> non-unique headers +# header + +## header + +<<< +<h1 id="header">header</h1> +<h2 id="header-2">header</h2> +>>> header starts with inline syntax +# *headers* etc. +<<< +<h1 id="headers-etc"><em>headers</em> etc.</h1> +>>> numbers-only headers (like a changelog) +# 1.2.34 + +## 1.23.4 + +## 1.2.3+4 +<<< +<h1 id="1234">1.2.34</h1> +<h2 id="1234-2">1.23.4</h2> +<h2 id="1234-3">1.2.3+4</h2> +>>> no id +# # +<<< +<h1></h1> diff --git a/pkgs/markdown/test/extensions/inline_html.unit b/pkgs/markdown/test/extensions/inline_html.unit new file mode 100644 index 000000000..1540118e6 --- /dev/null +++ b/pkgs/markdown/test/extensions/inline_html.unit @@ -0,0 +1,17 @@ +>>> within a paragraph +Within a <em class="x">paragraph</EM>. + +<<< +<p>Within a <em class="x">paragraph</EM>.</p> +>>> not HTML +Obviously, 3 < 5 and 7 > 2. +Not HTML: <3>, <_a>, <> + +<<< +<p>Obviously, 3 < 5 and 7 > 2. +Not HTML: <3>, <_a>, <></p> +>>> "markdown" within a tag is not parsed +Text <a href="_foo_">And "_foo_"</a>. + +<<< +<p>Text <a href="_foo_">And "<em>foo</em>"</a>.</p> diff --git a/pkgs/markdown/test/extensions/ordered_list_with_checkboxes.unit b/pkgs/markdown/test/extensions/ordered_list_with_checkboxes.unit new file mode 100644 index 000000000..8503e56e9 --- /dev/null +++ b/pkgs/markdown/test/extensions/ordered_list_with_checkboxes.unit @@ -0,0 +1,79 @@ +>>> checkbox with space +1. [ ] one +2. [ ] two +<<< +<ol class="contains-task-list"> +<li class="task-list-item"><input type="checkbox"></input>one</li> +<li class="task-list-item"><input type="checkbox"></input>two</li> +</ol> +>>> empty checkbox +1. [] one +2. [] two +<<< +<ol> +<li>[] one</li> +<li>[] two</li> +</ol> +>>> checkbox with x +1. [x] one +2. [x] two +<<< +<ol class="contains-task-list"> +<li class="task-list-item"><input type="checkbox" checked="true"></input>one</li> +<li class="task-list-item"><input type="checkbox" checked="true"></input>two</li> +</ol> +>>> checkbox with X +1. [X] one +2. [X] two +<<< +<ol class="contains-task-list"> +<li class="task-list-item"><input type="checkbox" checked="true"></input>one</li> +<li class="task-list-item"><input type="checkbox" checked="true"></input>two</li> +</ol> +>>> mixed checkboxes +1. [ ] one +2. [] two +3. [x] three +4. [X] four +5. five +<<< +<ol class="contains-task-list"> +<li class="task-list-item"><input type="checkbox"></input>one</li> +<li>[] two</li> +<li class="task-list-item"><input type="checkbox" checked="true"></input>three</li> +<li class="task-list-item"><input type="checkbox" checked="true"></input>four</li> +<li>five</li> +</ol> +>>> mixed leading spaces +1. [ ] zero +2. [ ] one +3. [ ] two +4. [ ] three +5. [ ] four +<<< +<ol class="contains-task-list"> +<li class="task-list-item"><input type="checkbox"></input>zero</li> +<li class="task-list-item"><input type="checkbox"></input>one</li> +<li class="task-list-item"><input type="checkbox"></input>two</li> +<li class="task-list-item"><input type="checkbox"></input>three</li> +<li> +<pre><code>[ ] four +</code></pre> +</li> +</ol> +>>> checkbox with empty content +1. [ ] one +2. +3. +4. four +5. [ ] five +6. +<<< +<ol class="contains-task-list"> +<li class="task-list-item"><input type="checkbox"></input>one</li> +<li></li> +<li></li> +<li>four</li> +<li class="task-list-item"><input type="checkbox"></input>five</li> +<li></li> +</ol> \ No newline at end of file diff --git a/pkgs/markdown/test/extensions/setext_headers_with_ids.unit b/pkgs/markdown/test/extensions/setext_headers_with_ids.unit new file mode 100644 index 000000000..b8ef0224a --- /dev/null +++ b/pkgs/markdown/test/extensions/setext_headers_with_ids.unit @@ -0,0 +1,18 @@ +>>> h1 +text +=== + +<<< +<h1 id="text">text</h1> +>>> h2 +text +--- + +<<< +<h2 id="text">text</h2> +>>> header with inline syntax +header *emphasised* +=== + +<<< +<h1 id="header-emphasised">header <em>emphasised</em></h1> diff --git a/pkgs/markdown/test/extensions/strikethrough.unit b/pkgs/markdown/test/extensions/strikethrough.unit new file mode 100644 index 000000000..5222d919f --- /dev/null +++ b/pkgs/markdown/test/extensions/strikethrough.unit @@ -0,0 +1,24 @@ +>>> Missing leading whitespace +word pas~~t~~ word +<<< +<p>word pas<del>t</del> word</p> +>>> Missing trailing whitespace +word ~~p~~ast word +<<< +<p>word <del>p</del>ast word</p> +>>> Middle of word +word p~~as~~t word +<<< +<p>word p<del>as</del>t word</p> +>>> Whitespace after opening +word~~ past~~ word +<<< +<p>word~~ past~~ word</p> +>>> Whitespace before closing +word ~~past ~~word +<<< +<p>word ~~past ~~word</p> +>>> mixed with emphasis and order changes +**~~first~~** ~~**second**~~ +<<< +<p><strong><del>first</del></strong> <del><strong>second</strong></del></p> diff --git a/pkgs/markdown/test/extensions/tables.unit b/pkgs/markdown/test/extensions/tables.unit new file mode 100644 index 000000000..c7a8cae31 --- /dev/null +++ b/pkgs/markdown/test/extensions/tables.unit @@ -0,0 +1,378 @@ +>>> basic table +head | cells +-----|------ +body | cells + +<<< +<table> +<thead> +<tr> +<th>head</th> +<th>cells</th> +</tr> +</thead> +<tbody> +<tr> +<td>body</td> +<td>cells</td> +</tr> +</tbody> +</table> +>>> multiple rows +head | cells +-----|------ +body | cells +more | cells + +<<< +<table> +<thead> +<tr> +<th>head</th> +<th>cells</th> +</tr> +</thead> +<tbody> +<tr> +<td>body</td> +<td>cells</td> +</tr> +<tr> +<td>more</td> +<td>cells</td> +</tr> +</tbody> +</table> +>>> rows wrapped in pipes +| head | cells | +|------|-------| +| body | cells | + +<<< +<table> +<thead> +<tr> +<th>head</th> +<th>cells</th> +</tr> +</thead> +<tbody> +<tr> +<td>body</td> +<td>cells</td> +</tr> +</tbody> +</table> +>>> rows wrapped in pipes, whitespace alignment row +| head | cells | +| -- | --- | +| body | cells | + +<<< +<table> +<thead> +<tr> +<th>head</th> +<th>cells</th> +</tr> +</thead> +<tbody> +<tr> +<td>body</td> +<td>cells</td> +</tr> +</tbody> +</table> +>>> rows wrapped in pipes, tabs in whitespace +| head | cells | +| -- | --- | +| body | cells | + +<<< +<table> +<thead> +<tr> +<th>head</th> +<th>cells</th> +</tr> +</thead> +<tbody> +<tr> +<td>body</td> +<td>cells</td> +</tr> +</tbody> +</table> +>>> cells with inline syntax +head `code` | _cells_ +------------|-------- +*text* | <span>text</span> +<<< +<table> +<thead> +<tr> +<th>head <code>code</code></th> +<th><em>cells</em></th> +</tr> +</thead> +<tbody> +<tr> +<td><em>text</em></td> +<td><span>text</span></td> +</tr> +</tbody> +</table> +>>> cells are parsed before inline syntax +header | _foo | bar_ +-------|------------|--- +text | text +<<< +<table> +<thead> +<tr> +<th>header</th> +<th>_foo</th> +<th>bar_</th> +</tr> +</thead> +<tbody> +<tr> +<td>text</td> +<td>text</td> +<td></td> +</tr> +</tbody> +</table> +>>> cells contain reference links +header | header +-------|-------- +text | [link][here] + +[here]: http://url +<<< +<table> +<thead> +<tr> +<th>header</th> +<th>header</th> +</tr> +</thead> +<tbody> +<tr> +<td>text</td> +<td><a href="http://url">link</a></td> +</tr> +</tbody> +</table> +>>> one column tables +head +-----| +body +<<< +<table> +<thead> +<tr> +<th>head</th> +</tr> +</thead> +<tbody> +<tr> +<td>body</td> +</tr> +</tbody> +</table> +>>> varying cells per row +head | foo | bar +-----|-----|----- +body +row with | two cells +<<< +<table> +<thead> +<tr> +<th>head</th> +<th>foo</th> +<th>bar</th> +</tr> +</thead> +<tbody> +<tr> +<td>body</td> +<td></td> +<td></td> +</tr> +<tr> +<td>row with</td> +<td>two cells</td> +<td></td> +</tr> +</tbody> +</table> +>>> left, center, and right alignment +head | cells | here +:----|:-----:|----: +body | cells | here +too | many | cells | here + +<<< +<table> +<thead> +<tr> +<th align="left">head</th> +<th align="center">cells</th> +<th align="right">here</th> +</tr> +</thead> +<tbody> +<tr> +<td align="left">body</td> +<td align="center">cells</td> +<td align="right">here</td> +</tr> +<tr> +<td align="left">too</td> +<td align="center">many</td> +<td align="right">cells</td> +</tr> +</tbody> +</table> +>>> left, center, and right alignment, with whitespace +head | cells | here + :-- | :---: | ---: +body | cells | here +too | many | cells | here + +<<< +<table> +<thead> +<tr> +<th align="left">head</th> +<th align="center">cells</th> +<th align="right">here</th> +</tr> +</thead> +<tbody> +<tr> +<td align="left">body</td> +<td align="center">cells</td> +<td align="right">here</td> +</tr> +<tr> +<td align="left">too</td> +<td align="center">many</td> +<td align="right">cells</td> +</tr> +</tbody> +</table> +>>> escape pipe +| Name | Character | +| --- | --- | +| Backtick | ` | +| Pipe | \| | + +<<< +<table> +<thead> +<tr> +<th>Name</th> +<th>Character</th> +</tr> +</thead> +<tbody> +<tr> +<td>Backtick</td> +<td>`</td> +</tr> +<tr> +<td>Pipe</td> +<td>|</td> +</tr> +</tbody> +</table> +>>> escape pipe, preserve trailing whitespace +| Name | Character | +| --- | --- | +| Pipe | \| abcdef | + +<<< +<table> +<thead> +<tr> +<th>Name</th> +<th>Character</th> +</tr> +</thead> +<tbody> +<tr> +<td>Pipe</td> +<td>| abcdef</td> +</tr> +</tbody> +</table> +>>> trailing whitespace after final pipe +| Name | Character | +| --- | --- | +| Pipe | abcdef | +<<< +<table> +<thead> +<tr> +<th>Name</th> +<th>Character</th> +</tr> +</thead> +<tbody> +<tr> +<td>Pipe</td> +<td>abcdef</td> +</tr> +</tbody> +</table> +>>> issue #531 +| A | [B](url) | C | +|---|---| +| a | b | c | +<<< +<p>| A | <a href="url">B</a> | C | +|---|---| +| a | b | c |</p> +>>> trailing whitespace after delimiter row +| Name | Value | +| --- | --- | +| Foo | bar | +<<< +<table> +<thead> +<tr> +<th>Name</th> +<th>Value</th> +</tr> +</thead> +<tbody> +<tr> +<td>Foo</td> +<td>bar</td> +</tr> +</tbody> +</table> +>>> can interrupt a paragraph +paragraph +foo | bar +--- | --- +baz | bim +<<< +<p>paragraph</p> +<table> +<thead> +<tr> +<th>foo</th> +<th>bar</th> +</tr> +</thead> +<tbody> +<tr> +<td>baz</td> +<td>bim</td> +</tr> +</tbody> +</table> diff --git a/pkgs/markdown/test/extensions/unordered_list_with_checkboxes.unit b/pkgs/markdown/test/extensions/unordered_list_with_checkboxes.unit new file mode 100644 index 000000000..f33161e2d --- /dev/null +++ b/pkgs/markdown/test/extensions/unordered_list_with_checkboxes.unit @@ -0,0 +1,83 @@ +>>> checkbox with space +* [ ] one +* [ ] two +<<< +<ul class="contains-task-list"> +<li class="task-list-item"><input type="checkbox"></input>one</li> +<li class="task-list-item"><input type="checkbox"></input>two</li> +</ul> +>>> empty checkbox +* [] one +* [] two +<<< +<ul> +<li>[] one</li> +<li>[] two</li> +</ul> +>>> checkbox with x +* [x] one +* [x] two +<<< +<ul class="contains-task-list"> +<li class="task-list-item"><input type="checkbox" checked="true"></input>one</li> +<li class="task-list-item"><input type="checkbox" checked="true"></input>two</li> +</ul> +>>> checkbox with X +* [X] one +* [X] two +<<< +<ul class="contains-task-list"> +<li class="task-list-item"><input type="checkbox" checked="true"></input>one</li> +<li class="task-list-item"><input type="checkbox" checked="true"></input>two</li> +</ul> +>>> mixed checkboxes +* [ ] one +* [] two +* [x] three +* [X] four +* five +<<< +<ul class="contains-task-list"> +<li class="task-list-item"><input type="checkbox"></input>one</li> +<li>[] two</li> +<li class="task-list-item"><input type="checkbox" checked="true"></input>three</li> +<li class="task-list-item"><input type="checkbox" checked="true"></input>four</li> +<li>five</li> +</ul> +>>> mixed leading spaces +*[ ] zero +* [ ] one +* [ ] two +* [ ] three +* [ ] four +* [ ] five +<<< +<p>*[ ] zero</p> +<ul class="contains-task-list"> +<li class="task-list-item"><input type="checkbox"></input>one</li> +<li class="task-list-item"><input type="checkbox"></input>two</li> +<li class="task-list-item"><input type="checkbox"></input>three</li> +<li class="task-list-item"><input type="checkbox"></input>four</li> +<li> +<pre><code>[ ] five +</code></pre> +</li> +</ul> +>>> checkbox list separated with blank lines +- [ ] A + +- [ ] B + +- [ ] +<<< +<ul class="contains-task-list"> +<li class="task-list-item"> +<p><input type="checkbox"></input>A</p> +</li> +<li class="task-list-item"> +<p><input type="checkbox"></input>B</p> +</li> +<li> +<p>[ ]</p> +</li> +</ul> \ No newline at end of file diff --git a/pkgs/markdown/test/gfm/atx_headings.unit b/pkgs/markdown/test/gfm/atx_headings.unit new file mode 100644 index 000000000..5a60cf457 --- /dev/null +++ b/pkgs/markdown/test/gfm/atx_headings.unit @@ -0,0 +1,112 @@ +>>> ATX headings - 32 +# foo +## foo +### foo +#### foo +##### foo +###### foo +<<< +<h1>foo</h1> +<h2>foo</h2> +<h3>foo</h3> +<h4>foo</h4> +<h5>foo</h5> +<h6>foo</h6> +>>> ATX headings - 33 +####### foo +<<< +<p>####### foo</p> +>>> ATX headings - 34 +#5 bolt + +#hashtag +<<< +<p>#5 bolt</p> +<p>#hashtag</p> +>>> ATX headings - 35 +\## foo +<<< +<p>## foo</p> +>>> ATX headings - 36 +# foo *bar* \*baz\* +<<< +<h1>foo <em>bar</em> *baz*</h1> +>>> ATX headings - 37 +# foo +<<< +<h1>foo</h1> +>>> ATX headings - 38 + ### foo + ## foo + # foo +<<< +<h3>foo</h3> +<h2>foo</h2> +<h1>foo</h1> +>>> ATX headings - 39 + # foo +<<< +<pre><code># foo +</code></pre> +>>> ATX headings - 40 +foo + # bar +<<< +<p>foo +# bar</p> +>>> ATX headings - 41 +## foo ## + ### bar ### +<<< +<h2>foo</h2> +<h3>bar</h3> +>>> ATX headings - 42 +# foo ################################## +##### foo ## +<<< +<h1>foo</h1> +<h5>foo</h5> +>>> ATX headings - 43 +### foo ### +<<< +<h3>foo</h3> +>>> ATX headings - 44 +### foo ### b +<<< +<h3>foo ### b</h3> +>>> ATX headings - 45 +# foo# +<<< +<h1>foo#</h1> +>>> ATX headings - 46 +### foo \### +## foo #\## +# foo \# +<<< +<h3>foo ###</h3> +<h2>foo ###</h2> +<h1>foo #</h1> +>>> ATX headings - 47 +**** +## foo +**** +<<< +<hr /> +<h2>foo</h2> +<hr /> +>>> ATX headings - 48 +Foo bar +# baz +Bar foo +<<< +<p>Foo bar</p> +<h1>baz</h1> +<p>Bar foo</p> +>>> ATX headings - 49 +## +# +### ### +<<< +<h2></h2> +<h1></h1> +<h3></h3> diff --git a/pkgs/markdown/test/gfm/autolinks.unit b/pkgs/markdown/test/gfm/autolinks.unit new file mode 100644 index 000000000..6df5296e7 --- /dev/null +++ b/pkgs/markdown/test/gfm/autolinks.unit @@ -0,0 +1,76 @@ +>>> Autolinks - 602 +<http://foo.bar.baz> +<<< +<p><a href="http://foo.bar.baz">http://foo.bar.baz</a></p> +>>> Autolinks - 603 +<http://foo.bar.baz/test?q=hello&id=22&boolean> +<<< +<p><a href="http://foo.bar.baz/test?q=hello&id=22&boolean">http://foo.bar.baz/test?q=hello&id=22&boolean</a></p> +>>> Autolinks - 604 +<irc://foo.bar:2233/baz> +<<< +<p><a href="irc://foo.bar:2233/baz">irc://foo.bar:2233/baz</a></p> +>>> Autolinks - 605 +<MAILTO:FOO@BAR.BAZ> +<<< +<p><a href="MAILTO:FOO@BAR.BAZ">MAILTO:FOO@BAR.BAZ</a></p> +>>> Autolinks - 606 +<a+b+c:d> +<<< +<p><a href="a+b+c:d">a+b+c:d</a></p> +>>> Autolinks - 607 +<made-up-scheme://foo,bar> +<<< +<p><a href="made-up-scheme://foo,bar">made-up-scheme://foo,bar</a></p> +>>> Autolinks - 608 +<http://../> +<<< +<p><a href="http://../">http://../</a></p> +>>> Autolinks - 609 +<localhost:5001/foo> +<<< +<p><a href="localhost:5001/foo">localhost:5001/foo</a></p> +>>> Autolinks - 610 +<http://foo.bar/baz bim> +<<< +<p><http://foo.bar/baz bim></p> +>>> Autolinks - 611 +<http://example.com/\[\> +<<< +<p><a href="http://example.com/%5C%5B%5C">http://example.com/\[\</a></p> +>>> Autolinks - 612 +<foo@bar.example.com> +<<< +<p><a href="mailto:foo@bar.example.com">foo@bar.example.com</a></p> +>>> Autolinks - 613 +<foo+special@Bar.baz-bar0.com> +<<< +<p><a href="mailto:foo+special@Bar.baz-bar0.com">foo+special@Bar.baz-bar0.com</a></p> +>>> Autolinks - 614 +<foo\+@bar.example.com> +<<< +<p><foo+@bar.example.com></p> +>>> Autolinks - 615 +<> +<<< +<p><></p> +>>> Autolinks - 616 +< http://foo.bar > +<<< +<p>< http://foo.bar ></p> +>>> Autolinks - 617 +<m:abc> +<<< +<p><m:abc></p> +>>> Autolinks - 618 +<foo.bar.baz> +<<< +<p><foo.bar.baz></p> +>>> Autolinks - 619 +http://example.com +<<< +<p>http://example.com</p> +>>> Autolinks - 620 +foo@bar.example.com +<<< +<p>foo@bar.example.com</p> diff --git a/pkgs/markdown/test/gfm/autolinks_extension.unit b/pkgs/markdown/test/gfm/autolinks_extension.unit new file mode 100644 index 000000000..ff69a5382 --- /dev/null +++ b/pkgs/markdown/test/gfm/autolinks_extension.unit @@ -0,0 +1,74 @@ +>>> Autolinks (extension) - 621 +www.commonmark.org +<<< +<p><a href="http://www.commonmark.org">www.commonmark.org</a></p> +>>> Autolinks (extension) - 622 +Visit www.commonmark.org/help for more information. +<<< +<p>Visit <a href="http://www.commonmark.org/help">www.commonmark.org/help</a> for more information.</p> +>>> Autolinks (extension) - 623 +Visit www.commonmark.org. + +Visit www.commonmark.org/a.b. +<<< +<p>Visit <a href="http://www.commonmark.org">www.commonmark.org</a>.</p> +<p>Visit <a href="http://www.commonmark.org/a.b">www.commonmark.org/a.b</a>.</p> +>>> Autolinks (extension) - 624 +www.google.com/search?q=Markup+(business) + +www.google.com/search?q=Markup+(business))) + +(www.google.com/search?q=Markup+(business)) + +(www.google.com/search?q=Markup+(business) +<<< +<p><a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a></p> +<p><a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a>))</p> +<p>(<a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a>)</p> +<p>(<a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a></p> +>>> Autolinks (extension) - 625 +www.google.com/search?q=(business))+ok +<<< +<p><a href="http://www.google.com/search?q=(business))+ok">www.google.com/search?q=(business))+ok</a></p> +>>> Autolinks (extension) - 626 +www.google.com/search?q=commonmark&hl=en + +www.google.com/search?q=commonmark&hl; +<<< +<p><a href="http://www.google.com/search?q=commonmark&hl=en">www.google.com/search?q=commonmark&hl=en</a></p> +<p><a href="http://www.google.com/search?q=commonmark">www.google.com/search?q=commonmark</a>&hl;</p> +>>> Autolinks (extension) - 627 +www.commonmark.org/he<lp +<<< +<p><a href="http://www.commonmark.org/he">www.commonmark.org/he</a><lp</p> +>>> Autolinks (extension) - 628 +http://commonmark.org + +(Visit https://encrypted.google.com/search?q=Markup+(business)) + +Anonymous FTP is available at ftp://foo.bar.baz. +<<< +<p><a href="http://commonmark.org">http://commonmark.org</a></p> +<p>(Visit <a href="https://encrypted.google.com/search?q=Markup+(business)">https://encrypted.google.com/search?q=Markup+(business)</a>)</p> +<p>Anonymous FTP is available at <a href="ftp://foo.bar.baz">ftp://foo.bar.baz</a>.</p> +>>> Autolinks (extension) - 629 +foo@bar.baz +<<< +<p><a href="mailto:foo@bar.baz">foo@bar.baz</a></p> +>>> Autolinks (extension) - 630 +hello@mail+xyz.example isn't valid, but hello+xyz@mail.example is. +<<< +<p>hello@mail+xyz.example isn't valid, but <a href="mailto:hello+xyz@mail.example">hello+xyz@mail.example</a> is.</p> +>>> Autolinks (extension) - 631 +a.b-c_d@a.b + +a.b-c_d@a.b. + +a.b-c_d@a.b- + +a.b-c_d@a.b_ +<<< +<p><a href="mailto:a.b-c_d@a.b">a.b-c_d@a.b</a></p> +<p><a href="mailto:a.b-c_d@a.b">a.b-c_d@a.b</a>.</p> +<p>a.b-c_d@a.b-</p> +<p>a.b-c_d@a.b_</p> diff --git a/pkgs/markdown/test/gfm/backslash_escapes.unit b/pkgs/markdown/test/gfm/backslash_escapes.unit new file mode 100644 index 000000000..0e9074ae9 --- /dev/null +++ b/pkgs/markdown/test/gfm/backslash_escapes.unit @@ -0,0 +1,79 @@ +>>> Backslash escapes - 308 +\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~ +<<< +<p>!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~</p> +>>> Backslash escapes - 309 +\ \A\a\ \3\φ\« +<<< +<p>\ \A\a\ \3\φ\«</p> +>>> Backslash escapes - 310 +\*not emphasized* +\<br/> not a tag +\[not a link](/foo) +\`not code` +1\. not a list +\* not a list +\# not a heading +\[foo]: /url "not a reference" +\ö not a character entity +<<< +<p>*not emphasized* +<br/> not a tag +[not a link](/foo) +`not code` +1. not a list +* not a list +# not a heading +[foo]: /url "not a reference" +&ouml; not a character entity</p> +>>> Backslash escapes - 311 +\\*emphasis* +<<< +<p>\<em>emphasis</em></p> +>>> Backslash escapes - 312 +foo\ +bar +<<< +<p>foo<br /> +bar</p> +>>> Backslash escapes - 313 +`` \[\` `` +<<< +<p><code>\[\`</code></p> +>>> Backslash escapes - 314 + \[\] +<<< +<pre><code>\[\] +</code></pre> +>>> Backslash escapes - 315 +~~~ +\[\] +~~~ +<<< +<pre><code>\[\] +</code></pre> +>>> Backslash escapes - 316 +<http://example.com?find=\*> +<<< +<p><a href="http://example.com?find=%5C*">http://example.com?find=\*</a></p> +>>> Backslash escapes - 317 +<a href="/bar\/)"> +<<< +<a href="/bar\/)"> +>>> Backslash escapes - 318 +[foo](/bar\* "ti\*tle") +<<< +<p><a href="/bar*" title="ti*tle">foo</a></p> +>>> Backslash escapes - 319 +[foo] + +[foo]: /bar\* "ti\*tle" +<<< +<p><a href="/bar*" title="ti*tle">foo</a></p> +>>> Backslash escapes - 320 +``` foo\+bar +foo +``` +<<< +<pre><code class="language-foo+bar">foo +</code></pre> diff --git a/pkgs/markdown/test/gfm/blank_lines.unit b/pkgs/markdown/test/gfm/blank_lines.unit new file mode 100644 index 000000000..be24ab7b2 --- /dev/null +++ b/pkgs/markdown/test/gfm/blank_lines.unit @@ -0,0 +1,12 @@ +>>> Blank lines - 197 + + +aaa + + +# aaa + + +<<< +<p>aaa</p> +<h1>aaa</h1> diff --git a/pkgs/markdown/test/gfm/block_quotes.unit b/pkgs/markdown/test/gfm/block_quotes.unit new file mode 100644 index 000000000..50d875775 --- /dev/null +++ b/pkgs/markdown/test/gfm/block_quotes.unit @@ -0,0 +1,239 @@ +>>> Block quotes - 206 +> # Foo +> bar +> baz +<<< +<blockquote> +<h1>Foo</h1> +<p>bar +baz</p> +</blockquote> +>>> Block quotes - 207 +># Foo +>bar +> baz +<<< +<blockquote> +<h1>Foo</h1> +<p>bar +baz</p> +</blockquote> +>>> Block quotes - 208 + > # Foo + > bar + > baz +<<< +<blockquote> +<h1>Foo</h1> +<p>bar +baz</p> +</blockquote> +>>> Block quotes - 209 + > # Foo + > bar + > baz +<<< +<pre><code>> # Foo +> bar +> baz +</code></pre> +>>> Block quotes - 210 +> # Foo +> bar +baz +<<< +<blockquote> +<h1>Foo</h1> +<p>bar +baz</p> +</blockquote> +>>> Block quotes - 211 +> bar +baz +> foo +<<< +<blockquote> +<p>bar +baz +foo</p> +</blockquote> +>>> Block quotes - 212 +> foo +--- +<<< +<blockquote> +<p>foo</p> +</blockquote> +<hr /> +>>> Block quotes - 213 +> - foo +- bar +<<< +<blockquote> +<ul> +<li>foo</li> +</ul> +</blockquote> +<ul> +<li>bar</li> +</ul> +>>> Block quotes - 214 +> foo + bar +<<< +<blockquote> +<pre><code>foo +</code></pre> +</blockquote> +<pre><code>bar +</code></pre> +>>> Block quotes - 215 +> ``` +foo +``` +<<< +<blockquote> +<pre><code></code></pre> +</blockquote> +<p>foo</p> +<pre><code></code></pre> +>>> Block quotes - 216 +> foo + - bar +<<< +<blockquote> +<p>foo +- bar</p> +</blockquote> +>>> Block quotes - 217 +> +<<< +<blockquote> +</blockquote> +>>> Block quotes - 218 +> +> +> +<<< +<blockquote> +</blockquote> +>>> Block quotes - 219 +> +> foo +> +<<< +<blockquote> +<p>foo</p> +</blockquote> +>>> Block quotes - 220 +> foo + +> bar +<<< +<blockquote> +<p>foo</p> +</blockquote> +<blockquote> +<p>bar</p> +</blockquote> +>>> Block quotes - 221 +> foo +> bar +<<< +<blockquote> +<p>foo +bar</p> +</blockquote> +>>> Block quotes - 222 +> foo +> +> bar +<<< +<blockquote> +<p>foo</p> +<p>bar</p> +</blockquote> +>>> Block quotes - 223 +foo +> bar +<<< +<p>foo</p> +<blockquote> +<p>bar</p> +</blockquote> +>>> Block quotes - 224 +> aaa +*** +> bbb +<<< +<blockquote> +<p>aaa</p> +</blockquote> +<hr /> +<blockquote> +<p>bbb</p> +</blockquote> +>>> Block quotes - 225 +> bar +baz +<<< +<blockquote> +<p>bar +baz</p> +</blockquote> +>>> Block quotes - 226 +> bar + +baz +<<< +<blockquote> +<p>bar</p> +</blockquote> +<p>baz</p> +>>> Block quotes - 227 +> bar +> +baz +<<< +<blockquote> +<p>bar</p> +</blockquote> +<p>baz</p> +>>> Block quotes - 228 +> > > foo +bar +<<< +<blockquote> +<blockquote> +<blockquote> +<p>foo +bar</p> +</blockquote> +</blockquote> +</blockquote> +>>> Block quotes - 229 +>>> foo +> bar +>>baz +<<< +<blockquote> +<blockquote> +<blockquote> +<p>foo +bar +baz</p> +</blockquote> +</blockquote> +</blockquote> +>>> Block quotes - 230 +> code + +> not code +<<< +<blockquote> +<pre><code>code +</code></pre> +</blockquote> +<blockquote> +<p>not code</p> +</blockquote> diff --git a/pkgs/markdown/test/gfm/code_spans.unit b/pkgs/markdown/test/gfm/code_spans.unit new file mode 100644 index 000000000..68a4b3aae --- /dev/null +++ b/pkgs/markdown/test/gfm/code_spans.unit @@ -0,0 +1,97 @@ +>>> Code spans - 338 +`foo` +<<< +<p><code>foo</code></p> +>>> Code spans - 339 +`` foo ` bar `` +<<< +<p><code>foo ` bar</code></p> +>>> Code spans - 340 +` `` ` +<<< +<p><code>``</code></p> +>>> Code spans - 341 +` `` ` +<<< +<p><code> `` </code></p> +>>> Code spans - 342 +` a` +<<< +<p><code> a</code></p> +>>> Code spans - 343 +` b ` +<<< +<p><code> b </code></p> +>>> Code spans - 344 +` ` +` ` +<<< +<p><code> </code> +<code> </code></p> +>>> Code spans - 345 +`` +foo +bar +baz +`` +<<< +<p><code>foo bar baz</code></p> +>>> Code spans - 346 +`` +foo +`` +<<< +<p><code>foo </code></p> +>>> Code spans - 347 +`foo bar +baz` +<<< +<p><code>foo bar baz</code></p> +>>> Code spans - 348 +`foo\`bar` +<<< +<p><code>foo\</code>bar`</p> +>>> Code spans - 349 +``foo`bar`` +<<< +<p><code>foo`bar</code></p> +>>> Code spans - 350 +` foo `` bar ` +<<< +<p><code>foo `` bar</code></p> +>>> Code spans - 351 +*foo`*` +<<< +<p>*foo<code>*</code></p> +>>> Code spans - 352 +[not a `link](/foo`) +<<< +<p>[not a <code>link](/foo</code>)</p> +>>> Code spans - 353 +`<a href="`">` +<<< +<p><code><a href="</code>">`</p> +>>> Code spans - 354 +<a href="`">` +<<< +<p><a href="`">`</p> +>>> Code spans - 355 +`<http://foo.bar.`baz>` +<<< +<p><code><http://foo.bar.</code>baz>`</p> +>>> Code spans - 356 +<http://foo.bar.`baz>` +<<< +<p><a href="http://foo.bar.%60baz">http://foo.bar.`baz</a>`</p> +>>> Code spans - 357 +```foo`` +<<< +<p>```foo``</p> +>>> Code spans - 358 +`foo +<<< +<p>`foo</p> +>>> Code spans - 359 +`foo``bar`` +<<< +<p>`foo<code>bar</code></p> diff --git a/pkgs/markdown/test/gfm/disallowed_raw_html_extension.unit b/pkgs/markdown/test/gfm/disallowed_raw_html_extension.unit new file mode 100644 index 000000000..34cc396ff --- /dev/null +++ b/pkgs/markdown/test/gfm/disallowed_raw_html_extension.unit @@ -0,0 +1,11 @@ +>>> Disallowed Raw HTML (extension) - 652 +<strong> <title> <style> <em> + +<blockquote> + <xmp> is disallowed. <XMP> is also disallowed. +</blockquote> +<<< +<p><strong> <title> <style> <em></p> +<blockquote> +<xmp> is disallowed. <XMP> is also disallowed. +</blockquote> diff --git a/pkgs/markdown/test/gfm/emphasis_and_strong_emphasis.unit b/pkgs/markdown/test/gfm/emphasis_and_strong_emphasis.unit new file mode 100644 index 000000000..b6e815514 --- /dev/null +++ b/pkgs/markdown/test/gfm/emphasis_and_strong_emphasis.unit @@ -0,0 +1,536 @@ +>>> Emphasis and strong emphasis - 360 +*foo bar* +<<< +<p><em>foo bar</em></p> +>>> Emphasis and strong emphasis - 361 +a * foo bar* +<<< +<p>a * foo bar*</p> +>>> Emphasis and strong emphasis - 362 +a*"foo"* +<<< +<p>a*"foo"*</p> +>>> Emphasis and strong emphasis - 363 +* a * +<<< +<p>* a *</p> +>>> Emphasis and strong emphasis - 364 +foo*bar* +<<< +<p>foo<em>bar</em></p> +>>> Emphasis and strong emphasis - 365 +5*6*78 +<<< +<p>5<em>6</em>78</p> +>>> Emphasis and strong emphasis - 366 +_foo bar_ +<<< +<p><em>foo bar</em></p> +>>> Emphasis and strong emphasis - 367 +_ foo bar_ +<<< +<p>_ foo bar_</p> +>>> Emphasis and strong emphasis - 368 +a_"foo"_ +<<< +<p>a_"foo"_</p> +>>> Emphasis and strong emphasis - 369 +foo_bar_ +<<< +<p>foo_bar_</p> +>>> Emphasis and strong emphasis - 370 +5_6_78 +<<< +<p>5_6_78</p> +>>> Emphasis and strong emphasis - 371 +пристаням_стремятся_ +<<< +<p>пристаням_стремятся_</p> +>>> Emphasis and strong emphasis - 372 +aa_"bb"_cc +<<< +<p>aa_"bb"_cc</p> +>>> Emphasis and strong emphasis - 373 +foo-_(bar)_ +<<< +<p>foo-<em>(bar)</em></p> +>>> Emphasis and strong emphasis - 374 +_foo* +<<< +<p>_foo*</p> +>>> Emphasis and strong emphasis - 375 +*foo bar * +<<< +<p>*foo bar *</p> +>>> Emphasis and strong emphasis - 376 +*foo bar +* +<<< +<p>*foo bar +*</p> +>>> Emphasis and strong emphasis - 377 +*(*foo) +<<< +<p>*(*foo)</p> +>>> Emphasis and strong emphasis - 378 +*(*foo*)* +<<< +<p><em>(<em>foo</em>)</em></p> +>>> Emphasis and strong emphasis - 379 +*foo*bar +<<< +<p><em>foo</em>bar</p> +>>> Emphasis and strong emphasis - 380 +_foo bar _ +<<< +<p>_foo bar _</p> +>>> Emphasis and strong emphasis - 381 +_(_foo) +<<< +<p>_(_foo)</p> +>>> Emphasis and strong emphasis - 382 +_(_foo_)_ +<<< +<p><em>(<em>foo</em>)</em></p> +>>> Emphasis and strong emphasis - 383 +_foo_bar +<<< +<p>_foo_bar</p> +>>> Emphasis and strong emphasis - 384 +_пристаням_стремятся +<<< +<p>_пристаням_стремятся</p> +>>> Emphasis and strong emphasis - 385 +_foo_bar_baz_ +<<< +<p><em>foo_bar_baz</em></p> +>>> Emphasis and strong emphasis - 386 +_(bar)_. +<<< +<p><em>(bar)</em>.</p> +>>> Emphasis and strong emphasis - 387 +**foo bar** +<<< +<p><strong>foo bar</strong></p> +>>> Emphasis and strong emphasis - 388 +** foo bar** +<<< +<p>** foo bar**</p> +>>> Emphasis and strong emphasis - 389 +a**"foo"** +<<< +<p>a**"foo"**</p> +>>> Emphasis and strong emphasis - 390 +foo**bar** +<<< +<p>foo<strong>bar</strong></p> +>>> Emphasis and strong emphasis - 391 +__foo bar__ +<<< +<p><strong>foo bar</strong></p> +>>> Emphasis and strong emphasis - 392 +__ foo bar__ +<<< +<p>__ foo bar__</p> +>>> Emphasis and strong emphasis - 393 +__ +foo bar__ +<<< +<p>__ +foo bar__</p> +>>> Emphasis and strong emphasis - 394 +a__"foo"__ +<<< +<p>a__"foo"__</p> +>>> Emphasis and strong emphasis - 395 +foo__bar__ +<<< +<p>foo__bar__</p> +>>> Emphasis and strong emphasis - 396 +5__6__78 +<<< +<p>5__6__78</p> +>>> Emphasis and strong emphasis - 397 +пристаням__стремятся__ +<<< +<p>пристаням__стремятся__</p> +>>> Emphasis and strong emphasis - 398 +__foo, __bar__, baz__ +<<< +<p><strong>foo, <strong>bar</strong>, baz</strong></p> +>>> Emphasis and strong emphasis - 399 +foo-__(bar)__ +<<< +<p>foo-<strong>(bar)</strong></p> +>>> Emphasis and strong emphasis - 400 +**foo bar ** +<<< +<p>**foo bar **</p> +>>> Emphasis and strong emphasis - 401 +**(**foo) +<<< +<p>**(**foo)</p> +>>> Emphasis and strong emphasis - 402 +*(**foo**)* +<<< +<p><em>(<strong>foo</strong>)</em></p> +>>> Emphasis and strong emphasis - 403 +**Gomphocarpus (*Gomphocarpus physocarpus*, syn. +*Asclepias physocarpa*)** +<<< +<p><strong>Gomphocarpus (<em>Gomphocarpus physocarpus</em>, syn. +<em>Asclepias physocarpa</em>)</strong></p> +>>> Emphasis and strong emphasis - 404 +**foo "*bar*" foo** +<<< +<p><strong>foo "<em>bar</em>" foo</strong></p> +>>> Emphasis and strong emphasis - 405 +**foo**bar +<<< +<p><strong>foo</strong>bar</p> +>>> Emphasis and strong emphasis - 406 +__foo bar __ +<<< +<p>__foo bar __</p> +>>> Emphasis and strong emphasis - 407 +__(__foo) +<<< +<p>__(__foo)</p> +>>> Emphasis and strong emphasis - 408 +_(__foo__)_ +<<< +<p><em>(<strong>foo</strong>)</em></p> +>>> Emphasis and strong emphasis - 409 +__foo__bar +<<< +<p>__foo__bar</p> +>>> Emphasis and strong emphasis - 410 +__пристаням__стремятся +<<< +<p>__пристаням__стремятся</p> +>>> Emphasis and strong emphasis - 411 +__foo__bar__baz__ +<<< +<p><strong>foo__bar__baz</strong></p> +>>> Emphasis and strong emphasis - 412 +__(bar)__. +<<< +<p><strong>(bar)</strong>.</p> +>>> Emphasis and strong emphasis - 413 +*foo [bar](/url)* +<<< +<p><em>foo <a href="/url">bar</a></em></p> +>>> Emphasis and strong emphasis - 414 +*foo +bar* +<<< +<p><em>foo +bar</em></p> +>>> Emphasis and strong emphasis - 415 +_foo __bar__ baz_ +<<< +<p><em>foo <strong>bar</strong> baz</em></p> +>>> Emphasis and strong emphasis - 416 +_foo _bar_ baz_ +<<< +<p><em>foo <em>bar</em> baz</em></p> +>>> Emphasis and strong emphasis - 417 +__foo_ bar_ +<<< +<p><em><em>foo</em> bar</em></p> +>>> Emphasis and strong emphasis - 418 +*foo *bar** +<<< +<p><em>foo <em>bar</em></em></p> +>>> Emphasis and strong emphasis - 419 +*foo **bar** baz* +<<< +<p><em>foo <strong>bar</strong> baz</em></p> +>>> Emphasis and strong emphasis - 420 +*foo**bar**baz* +<<< +<p><em>foo<strong>bar</strong>baz</em></p> +>>> Emphasis and strong emphasis - 421 +*foo**bar* +<<< +<p><em>foo**bar</em></p> +>>> Emphasis and strong emphasis - 422 +***foo** bar* +<<< +<p><em><strong>foo</strong> bar</em></p> +>>> Emphasis and strong emphasis - 423 +*foo **bar*** +<<< +<p><em>foo <strong>bar</strong></em></p> +>>> Emphasis and strong emphasis - 424 +*foo**bar*** +<<< +<p><em>foo<strong>bar</strong></em></p> +>>> Emphasis and strong emphasis - 425 +foo***bar***baz +<<< +<p>foo<em><strong>bar</strong></em>baz</p> +>>> Emphasis and strong emphasis - 426 +foo******bar*********baz +<<< +<p>foo<strong><strong><strong>bar</strong></strong></strong>***baz</p> +>>> Emphasis and strong emphasis - 427 +*foo **bar *baz* bim** bop* +<<< +<p><em>foo <strong>bar <em>baz</em> bim</strong> bop</em></p> +>>> Emphasis and strong emphasis - 428 +*foo [*bar*](/url)* +<<< +<p><em>foo <a href="/url"><em>bar</em></a></em></p> +>>> Emphasis and strong emphasis - 429 +** is not an empty emphasis +<<< +<p>** is not an empty emphasis</p> +>>> Emphasis and strong emphasis - 430 +**** is not an empty strong emphasis +<<< +<p>**** is not an empty strong emphasis</p> +>>> Emphasis and strong emphasis - 431 +**foo [bar](/url)** +<<< +<p><strong>foo <a href="/url">bar</a></strong></p> +>>> Emphasis and strong emphasis - 432 +**foo +bar** +<<< +<p><strong>foo +bar</strong></p> +>>> Emphasis and strong emphasis - 433 +__foo _bar_ baz__ +<<< +<p><strong>foo <em>bar</em> baz</strong></p> +>>> Emphasis and strong emphasis - 434 +__foo __bar__ baz__ +<<< +<p><strong>foo <strong>bar</strong> baz</strong></p> +>>> Emphasis and strong emphasis - 435 +____foo__ bar__ +<<< +<p><strong><strong>foo</strong> bar</strong></p> +>>> Emphasis and strong emphasis - 436 +**foo **bar**** +<<< +<p><strong>foo <strong>bar</strong></strong></p> +>>> Emphasis and strong emphasis - 437 +**foo *bar* baz** +<<< +<p><strong>foo <em>bar</em> baz</strong></p> +>>> Emphasis and strong emphasis - 438 +**foo*bar*baz** +<<< +<p><strong>foo<em>bar</em>baz</strong></p> +>>> Emphasis and strong emphasis - 439 +***foo* bar** +<<< +<p><strong><em>foo</em> bar</strong></p> +>>> Emphasis and strong emphasis - 440 +**foo *bar*** +<<< +<p><strong>foo <em>bar</em></strong></p> +>>> Emphasis and strong emphasis - 441 +**foo *bar **baz** +bim* bop** +<<< +<p><strong>foo <em>bar <strong>baz</strong> +bim</em> bop</strong></p> +>>> Emphasis and strong emphasis - 442 +**foo [*bar*](/url)** +<<< +<p><strong>foo <a href="/url"><em>bar</em></a></strong></p> +>>> Emphasis and strong emphasis - 443 +__ is not an empty emphasis +<<< +<p>__ is not an empty emphasis</p> +>>> Emphasis and strong emphasis - 444 +____ is not an empty strong emphasis +<<< +<p>____ is not an empty strong emphasis</p> +>>> Emphasis and strong emphasis - 445 +foo *** +<<< +<p>foo ***</p> +>>> Emphasis and strong emphasis - 446 +foo *\** +<<< +<p>foo <em>*</em></p> +>>> Emphasis and strong emphasis - 447 +foo *_* +<<< +<p>foo <em>_</em></p> +>>> Emphasis and strong emphasis - 448 +foo ***** +<<< +<p>foo *****</p> +>>> Emphasis and strong emphasis - 449 +foo **\*** +<<< +<p>foo <strong>*</strong></p> +>>> Emphasis and strong emphasis - 450 +foo **_** +<<< +<p>foo <strong>_</strong></p> +>>> Emphasis and strong emphasis - 451 +**foo* +<<< +<p>*<em>foo</em></p> +>>> Emphasis and strong emphasis - 452 +*foo** +<<< +<p><em>foo</em>*</p> +>>> Emphasis and strong emphasis - 453 +***foo** +<<< +<p>*<strong>foo</strong></p> +>>> Emphasis and strong emphasis - 454 +****foo* +<<< +<p>***<em>foo</em></p> +>>> Emphasis and strong emphasis - 455 +**foo*** +<<< +<p><strong>foo</strong>*</p> +>>> Emphasis and strong emphasis - 456 +*foo**** +<<< +<p><em>foo</em>***</p> +>>> Emphasis and strong emphasis - 457 +foo ___ +<<< +<p>foo ___</p> +>>> Emphasis and strong emphasis - 458 +foo _\__ +<<< +<p>foo <em>_</em></p> +>>> Emphasis and strong emphasis - 459 +foo _*_ +<<< +<p>foo <em>*</em></p> +>>> Emphasis and strong emphasis - 460 +foo _____ +<<< +<p>foo _____</p> +>>> Emphasis and strong emphasis - 461 +foo __\___ +<<< +<p>foo <strong>_</strong></p> +>>> Emphasis and strong emphasis - 462 +foo __*__ +<<< +<p>foo <strong>*</strong></p> +>>> Emphasis and strong emphasis - 463 +__foo_ +<<< +<p>_<em>foo</em></p> +>>> Emphasis and strong emphasis - 464 +_foo__ +<<< +<p><em>foo</em>_</p> +>>> Emphasis and strong emphasis - 465 +___foo__ +<<< +<p>_<strong>foo</strong></p> +>>> Emphasis and strong emphasis - 466 +____foo_ +<<< +<p>___<em>foo</em></p> +>>> Emphasis and strong emphasis - 467 +__foo___ +<<< +<p><strong>foo</strong>_</p> +>>> Emphasis and strong emphasis - 468 +_foo____ +<<< +<p><em>foo</em>___</p> +>>> Emphasis and strong emphasis - 469 +**foo** +<<< +<p><strong>foo</strong></p> +>>> Emphasis and strong emphasis - 470 +*_foo_* +<<< +<p><em><em>foo</em></em></p> +>>> Emphasis and strong emphasis - 471 +__foo__ +<<< +<p><strong>foo</strong></p> +>>> Emphasis and strong emphasis - 472 +_*foo*_ +<<< +<p><em><em>foo</em></em></p> +>>> Emphasis and strong emphasis - 473 +****foo**** +<<< +<p><strong><strong>foo</strong></strong></p> +>>> Emphasis and strong emphasis - 474 +____foo____ +<<< +<p><strong><strong>foo</strong></strong></p> +>>> Emphasis and strong emphasis - 475 +******foo****** +<<< +<p><strong><strong><strong>foo</strong></strong></strong></p> +>>> Emphasis and strong emphasis - 476 +***foo*** +<<< +<p><em><strong>foo</strong></em></p> +>>> Emphasis and strong emphasis - 477 +_____foo_____ +<<< +<p><em><strong><strong>foo</strong></strong></em></p> +>>> Emphasis and strong emphasis - 478 +*foo _bar* baz_ +<<< +<p><em>foo _bar</em> baz_</p> +>>> Emphasis and strong emphasis - 479 +*foo __bar *baz bim__ bam* +<<< +<p><em>foo <strong>bar *baz bim</strong> bam</em></p> +>>> Emphasis and strong emphasis - 480 +**foo **bar baz** +<<< +<p>**foo <strong>bar baz</strong></p> +>>> Emphasis and strong emphasis - 481 +*foo *bar baz* +<<< +<p>*foo <em>bar baz</em></p> +>>> Emphasis and strong emphasis - 482 +*[bar*](/url) +<<< +<p>*<a href="/url">bar*</a></p> +>>> Emphasis and strong emphasis - 483 +_foo [bar_](/url) +<<< +<p>_foo <a href="/url">bar_</a></p> +>>> Emphasis and strong emphasis - 484 +*<img src="foo" title="*"/> +<<< +<p>*<img src="foo" title="*"/></p> +>>> Emphasis and strong emphasis - 485 +**<a href="**"> +<<< +<p>**<a href="**"></p> +>>> Emphasis and strong emphasis - 486 +__<a href="__"> +<<< +<p>__<a href="__"></p> +>>> Emphasis and strong emphasis - 487 +*a `*`* +<<< +<p><em>a <code>*</code></em></p> +>>> Emphasis and strong emphasis - 488 +_a `_`_ +<<< +<p><em>a <code>_</code></em></p> +>>> Emphasis and strong emphasis - 489 +**a<http://foo.bar/?q=**> +<<< +<p>**a<a href="http://foo.bar/?q=**">http://foo.bar/?q=**</a></p> +>>> Emphasis and strong emphasis - 490 +__a<http://foo.bar/?q=__> +<<< +<p>__a<a href="http://foo.bar/?q=__">http://foo.bar/?q=__</a></p> diff --git a/pkgs/markdown/test/gfm/entity_and_numeric_character_references.unit b/pkgs/markdown/test/gfm/entity_and_numeric_character_references.unit new file mode 100644 index 000000000..2a6248e84 --- /dev/null +++ b/pkgs/markdown/test/gfm/entity_and_numeric_character_references.unit @@ -0,0 +1,93 @@ +>>> Entity and numeric character references - 321 +  & © Æ Ď +¾ ℋ ⅆ +∲ ≧̸ +<<< +<p>& © Æ Ď +¾ ℋ ⅆ +∲ ≧̸</p> +>>> Entity and numeric character references - 322 +# Ӓ Ϡ � +<<< +<p># Ӓ Ϡ �</p> +>>> Entity and numeric character references - 323 +" ആ ಫ +<<< +<p>" ആ ಫ</p> +>>> Entity and numeric character references - 324 +  &x; &#; &#x; +� +&#abcdef0; +&ThisIsNotDefined; &hi?; +<<< +<p>&nbsp &x; &#; &#x; +&#987654321; +&#abcdef0; +&ThisIsNotDefined; &hi?;</p> +>>> Entity and numeric character references - 325 +© +<<< +<p>&copy</p> +>>> Entity and numeric character references - 326 +&MadeUpEntity; +<<< +<p>&MadeUpEntity;</p> +>>> Entity and numeric character references - 327 +<a href="öö.html"> +<<< +<a href="öö.html"> +>>> Entity and numeric character references - 328 +[foo](/föö "föö") +<<< +<p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p> +>>> Entity and numeric character references - 329 +[foo] + +[foo]: /föö "föö" +<<< +<p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p> +>>> Entity and numeric character references - 330 +``` föö +foo +``` +<<< +<pre><code class="language-föö">foo +</code></pre> +>>> Entity and numeric character references - 331 +`föö` +<<< +<p><code>f&ouml;&ouml;</code></p> +>>> Entity and numeric character references - 332 + föfö +<<< +<pre><code>f&ouml;f&ouml; +</code></pre> +>>> Entity and numeric character references - 333 +*foo* +*foo* +<<< +<p>*foo* +<em>foo</em></p> +>>> Entity and numeric character references - 334 +* foo + +* foo +<<< +<p>* foo</p> +<ul> +<li>foo</li> +</ul> +>>> Entity and numeric character references - 335 +foo bar +<<< +<p>foo + +bar</p> +>>> Entity and numeric character references - 336 + foo +<<< +<p>foo</p> +>>> Entity and numeric character references - 337 +[a](url "tit") +<<< +<p>[a](url "tit")</p> diff --git a/pkgs/markdown/test/gfm/fenced_code_blocks.unit b/pkgs/markdown/test/gfm/fenced_code_blocks.unit new file mode 100644 index 000000000..f6fa8432a --- /dev/null +++ b/pkgs/markdown/test/gfm/fenced_code_blocks.unit @@ -0,0 +1,245 @@ +>>> Fenced code blocks - 89 +``` +< + > +``` +<<< +<pre><code>< + > +</code></pre> +>>> Fenced code blocks - 90 +~~~ +< + > +~~~ +<<< +<pre><code>< + > +</code></pre> +>>> Fenced code blocks - 91 +`` +foo +`` +<<< +<p><code>foo</code></p> +>>> Fenced code blocks - 92 +``` +aaa +~~~ +``` +<<< +<pre><code>aaa +~~~ +</code></pre> +>>> Fenced code blocks - 93 +~~~ +aaa +``` +~~~ +<<< +<pre><code>aaa +``` +</code></pre> +>>> Fenced code blocks - 94 +```` +aaa +``` +`````` +<<< +<pre><code>aaa +``` +</code></pre> +>>> Fenced code blocks - 95 +~~~~ +aaa +~~~ +~~~~ +<<< +<pre><code>aaa +~~~ +</code></pre> +>>> Fenced code blocks - 96 +``` +<<< +<pre><code></code></pre> +>>> Fenced code blocks - 97 +````` + +``` +aaa +<<< +<pre><code> +``` +aaa +</code></pre> +>>> Fenced code blocks - 98 +> ``` +> aaa + +bbb +<<< +<blockquote> +<pre><code>aaa +</code></pre> +</blockquote> +<p>bbb</p> +>>> Fenced code blocks - 99 +``` + + +``` +<<< +<pre><code> + +</code></pre> +>>> Fenced code blocks - 100 +``` +``` +<<< +<pre><code></code></pre> +>>> Fenced code blocks - 101 + ``` + aaa +aaa +``` +<<< +<pre><code>aaa +aaa +</code></pre> +>>> Fenced code blocks - 102 + ``` +aaa + aaa +aaa + ``` +<<< +<pre><code>aaa +aaa +aaa +</code></pre> +>>> Fenced code blocks - 103 + ``` + aaa + aaa + aaa + ``` +<<< +<pre><code>aaa + aaa +aaa +</code></pre> +>>> Fenced code blocks - 104 + ``` + aaa + ``` +<<< +<pre><code>``` +aaa +``` +</code></pre> +>>> Fenced code blocks - 105 +``` +aaa + ``` +<<< +<pre><code>aaa +</code></pre> +>>> Fenced code blocks - 106 + ``` +aaa + ``` +<<< +<pre><code>aaa +</code></pre> +>>> Fenced code blocks - 107 +``` +aaa + ``` +<<< +<pre><code>aaa + ``` +</code></pre> +>>> Fenced code blocks - 108 +``` ``` +aaa +<<< +<p><code> </code> +aaa</p> +>>> Fenced code blocks - 109 +~~~~~~ +aaa +~~~ ~~ +<<< +<pre><code>aaa +~~~ ~~ +</code></pre> +>>> Fenced code blocks - 110 +foo +``` +bar +``` +baz +<<< +<p>foo</p> +<pre><code>bar +</code></pre> +<p>baz</p> +>>> Fenced code blocks - 111 +foo +--- +~~~ +bar +~~~ +# baz +<<< +<h2>foo</h2> +<pre><code>bar +</code></pre> +<h1>baz</h1> +>>> Fenced code blocks - 112 +```ruby +def foo(x) + return 3 +end +``` +<<< +<pre><code class="language-ruby">def foo(x) + return 3 +end +</code></pre> +>>> Fenced code blocks - 113 +~~~~ ruby startline=3 $%@#$ +def foo(x) + return 3 +end +~~~~~~~ +<<< +<pre><code class="language-ruby">def foo(x) + return 3 +end +</code></pre> +>>> Fenced code blocks - 114 +````; +```` +<<< +<pre><code class="language-;"></code></pre> +>>> Fenced code blocks - 115 +``` aa ``` +foo +<<< +<p><code>aa</code> +foo</p> +>>> Fenced code blocks - 116 +~~~ aa ``` ~~~ +foo +~~~ +<<< +<pre><code class="language-aa">foo +</code></pre> +>>> Fenced code blocks - 117 +``` +``` aaa +``` +<<< +<pre><code>``` aaa +</code></pre> diff --git a/pkgs/markdown/test/gfm/hard_line_breaks.unit b/pkgs/markdown/test/gfm/hard_line_breaks.unit new file mode 100644 index 000000000..e8aa5c062 --- /dev/null +++ b/pkgs/markdown/test/gfm/hard_line_breaks.unit @@ -0,0 +1,80 @@ +>>> Hard line breaks - 653 +foo +baz +<<< +<p>foo<br /> +baz</p> +>>> Hard line breaks - 654 +foo\ +baz +<<< +<p>foo<br /> +baz</p> +>>> Hard line breaks - 655 +foo +baz +<<< +<p>foo<br /> +baz</p> +>>> Hard line breaks - 656 +foo + bar +<<< +<p>foo<br /> +bar</p> +>>> Hard line breaks - 657 +foo\ + bar +<<< +<p>foo<br /> +bar</p> +>>> Hard line breaks - 658 +*foo +bar* +<<< +<p><em>foo<br /> +bar</em></p> +>>> Hard line breaks - 659 +*foo\ +bar* +<<< +<p><em>foo<br /> +bar</em></p> +>>> Hard line breaks - 660 +`code +span` +<<< +<p><code>code span</code></p> +>>> Hard line breaks - 661 +`code\ +span` +<<< +<p><code>code\ span</code></p> +>>> Hard line breaks - 662 +<a href="foo +bar"> +<<< +<p><a href="foo +bar"></p> +>>> Hard line breaks - 663 +<a href="foo\ +bar"> +<<< +<p><a href="foo\ +bar"></p> +>>> Hard line breaks - 664 +foo\ +<<< +<p>foo\</p> +>>> Hard line breaks - 665 +foo +<<< +<p>foo</p> +>>> Hard line breaks - 666 +### foo\ +<<< +<h3>foo\</h3> +>>> Hard line breaks - 667 +### foo +<<< +<h3>foo</h3> diff --git a/pkgs/markdown/test/gfm/html_blocks.unit b/pkgs/markdown/test/gfm/html_blocks.unit new file mode 100644 index 000000000..1af64202e --- /dev/null +++ b/pkgs/markdown/test/gfm/html_blocks.unit @@ -0,0 +1,433 @@ +>>> HTML blocks - 118 +<table><tr><td> +<pre> +**Hello**, + +_world_. +</pre> +</td></tr></table> +<<< +<table><tr><td> +<pre> +**Hello**, +<p><em>world</em>. +</pre></p> +</td></tr></table> +>>> HTML blocks - 119 +<table> + <tr> + <td> + hi + </td> + </tr> +</table> + +okay. +<<< +<table> + <tr> + <td> + hi + </td> + </tr> +</table> +<p>okay.</p> +>>> HTML blocks - 120 + <div> + *hello* + <foo><a> +<<< + <div> + *hello* + <foo><a> +>>> HTML blocks - 121 +</div> +*foo* +<<< +</div> +*foo* +>>> HTML blocks - 122 +<DIV CLASS="foo"> + +*Markdown* + +</DIV> +<<< +<DIV CLASS="foo"> +<p><em>Markdown</em></p> +</DIV> +>>> HTML blocks - 123 +<div id="foo" + class="bar"> +</div> +<<< +<div id="foo" + class="bar"> +</div> +>>> HTML blocks - 124 +<div id="foo" class="bar + baz"> +</div> +<<< +<div id="foo" class="bar + baz"> +</div> +>>> HTML blocks - 125 +<div> +*foo* + +*bar* +<<< +<div> +*foo* +<p><em>bar</em></p> +>>> HTML blocks - 126 +<div id="foo" +*hi* +<<< +<div id="foo" +*hi* +>>> HTML blocks - 127 +<div class +foo +<<< +<div class +foo +>>> HTML blocks - 128 +<div *???-&&&-<--- +*foo* +<<< +<div *???-&&&-<--- +*foo* +>>> HTML blocks - 129 +<div><a href="bar">*foo*</a></div> +<<< +<div><a href="bar">*foo*</a></div> +>>> HTML blocks - 130 +<table><tr><td> +foo +</td></tr></table> +<<< +<table><tr><td> +foo +</td></tr></table> +>>> HTML blocks - 131 +<div></div> +``` c +int x = 33; +``` +<<< +<div></div> +``` c +int x = 33; +``` +>>> HTML blocks - 132 +<a href="foo"> +*bar* +</a> +<<< +<a href="foo"> +*bar* +</a> +>>> HTML blocks - 133 +<Warning> +*bar* +</Warning> +<<< +<Warning> +*bar* +</Warning> +>>> HTML blocks - 134 +<i class="foo"> +*bar* +</i> +<<< +<i class="foo"> +*bar* +</i> +>>> HTML blocks - 135 +</ins> +*bar* +<<< +</ins> +*bar* +>>> HTML blocks - 136 +<del> +*foo* +</del> +<<< +<del> +*foo* +</del> +>>> HTML blocks - 137 +<del> + +*foo* + +</del> +<<< +<del> +<p><em>foo</em></p> +</del> +>>> HTML blocks - 138 +<del>*foo*</del> +<<< +<p><del><em>foo</em></del></p> +>>> HTML blocks - 139 +<pre language="haskell"><code> +import Text.HTML.TagSoup + +main :: IO () +main = print $ parseTags tags +</code></pre> +okay +<<< +<pre language="haskell"><code> +import Text.HTML.TagSoup + +main :: IO () +main = print $ parseTags tags +</code></pre> +<p>okay</p> +>>> HTML blocks - 140 +<script type="text/javascript"> +// JavaScript example + +document.getElementById("demo").innerHTML = "Hello JavaScript!"; +</script> +okay +<<< +<script type="text/javascript"> +// JavaScript example + +document.getElementById("demo").innerHTML = "Hello JavaScript!"; +</script> +<p>okay</p> +>>> HTML blocks - 141 +<style + type="text/css"> +h1 {color:red;} + +p {color:blue;} +</style> +okay +<<< +<style + type="text/css"> +h1 {color:red;} + +p {color:blue;} +</style> +<p>okay</p> +>>> HTML blocks - 142 +<style + type="text/css"> + +foo +<<< +<style + type="text/css"> + +foo +>>> HTML blocks - 143 +> <div> +> foo + +bar +<<< +<blockquote> +<div> +foo +</blockquote> +<p>bar</p> +>>> HTML blocks - 144 +- <div> +- foo +<<< +<ul> +<li> +<div> +</li> +<li>foo</li> +</ul> +>>> HTML blocks - 145 +<style>p{color:red;}</style> +*foo* +<<< +<style>p{color:red;}</style> +<p><em>foo</em></p> +>>> HTML blocks - 146 +<!-- foo -->*bar* +*baz* +<<< +<!-- foo -->*bar* +<p><em>baz</em></p> +>>> HTML blocks - 147 +<script> +foo +</script>1. *bar* +<<< +<script> +foo +</script>1. *bar* +>>> HTML blocks - 148 +<!-- Foo + +bar + baz --> +okay +<<< +<!-- Foo + +bar + baz --> +<p>okay</p> +>>> HTML blocks - 149 +<?php + + echo '>'; + +?> +okay +<<< +<?php + + echo '>'; + +?> +<p>okay</p> +>>> HTML blocks - 150 +<!DOCTYPE html> +<<< +<!DOCTYPE html> +>>> HTML blocks - 151 +<![CDATA[ +function matchwo(a,b) +{ + if (a < b && a < 0) then { + return 1; + + } else { + + return 0; + } +} +]]> +okay +<<< +<![CDATA[ +function matchwo(a,b) +{ + if (a < b && a < 0) then { + return 1; + + } else { + + return 0; + } +} +]]> +<p>okay</p> +>>> HTML blocks - 152 + <!-- foo --> + + <!-- foo --> +<<< + <!-- foo --> +<pre><code><!-- foo --> +</code></pre> +>>> HTML blocks - 153 + <div> + + <div> +<<< + <div> +<pre><code><div> +</code></pre> +>>> HTML blocks - 154 +Foo +<div> +bar +</div> +<<< +<p>Foo</p> +<div> +bar +</div> +>>> HTML blocks - 155 +<div> +bar +</div> +*foo* +<<< +<div> +bar +</div> +*foo* +>>> HTML blocks - 156 +Foo +<a href="bar"> +baz +<<< +<p>Foo +<a href="bar"> +baz</p> +>>> HTML blocks - 157 +<div> + +*Emphasized* text. + +</div> +<<< +<div> +<p><em>Emphasized</em> text.</p> +</div> +>>> HTML blocks - 158 +<div> +*Emphasized* text. +</div> +<<< +<div> +*Emphasized* text. +</div> +>>> HTML blocks - 159 +<table> + +<tr> + +<td> +Hi +</td> + +</tr> + +</table> +<<< +<table> +<tr> +<td> +Hi +</td> +</tr> +</table> +>>> HTML blocks - 160 +<table> + + <tr> + + <td> + Hi + </td> + + </tr> + +</table> +<<< +<table> + <tr> +<pre><code><td> + Hi +</td> +</code></pre> + </tr> +</table> diff --git a/pkgs/markdown/test/gfm/images.unit b/pkgs/markdown/test/gfm/images.unit new file mode 100644 index 000000000..106e1a21f --- /dev/null +++ b/pkgs/markdown/test/gfm/images.unit @@ -0,0 +1,121 @@ +>>> Images - 580 +![foo](/url "title") +<<< +<p><img src="/url" alt="foo" title="title" /></p> +>>> Images - 581 +![foo *bar*] + +[foo *bar*]: train.jpg "train & tracks" +<<< +<p><img src="train.jpg" alt="foo bar" title="train & tracks" /></p> +>>> Images - 582 +![foo ![bar](/url)](/url2) +<<< +<p><img src="/url2" alt="foo bar" /></p> +>>> Images - 583 +![foo [bar](/url)](/url2) +<<< +<p><img src="/url2" alt="foo bar" /></p> +>>> Images - 584 +![foo *bar*][] + +[foo *bar*]: train.jpg "train & tracks" +<<< +<p><img src="train.jpg" alt="foo bar" title="train & tracks" /></p> +>>> Images - 585 +![foo *bar*][foobar] + +[FOOBAR]: train.jpg "train & tracks" +<<< +<p><img src="train.jpg" alt="foo bar" title="train & tracks" /></p> +>>> Images - 586 +![foo](train.jpg) +<<< +<p><img src="train.jpg" alt="foo" /></p> +>>> Images - 587 +My ![foo bar](/path/to/train.jpg "title" ) +<<< +<p>My <img src="/path/to/train.jpg" alt="foo bar" title="title" /></p> +>>> Images - 588 +![foo](<url>) +<<< +<p><img src="url" alt="foo" /></p> +>>> Images - 589 +![](/url) +<<< +<p><img src="/url" alt="" /></p> +>>> Images - 590 +![foo][bar] + +[bar]: /url +<<< +<p><img src="/url" alt="foo" /></p> +>>> Images - 591 +![foo][bar] + +[BAR]: /url +<<< +<p><img src="/url" alt="foo" /></p> +>>> Images - 592 +![foo][] + +[foo]: /url "title" +<<< +<p><img src="/url" alt="foo" title="title" /></p> +>>> Images - 593 +![*foo* bar][] + +[*foo* bar]: /url "title" +<<< +<p><img src="/url" alt="foo bar" title="title" /></p> +>>> Images - 594 +![Foo][] + +[foo]: /url "title" +<<< +<p><img src="/url" alt="Foo" title="title" /></p> +>>> Images - 595 +![foo] +[] + +[foo]: /url "title" +<<< +<p><img src="/url" alt="foo" title="title" /> +[]</p> +>>> Images - 596 +![foo] + +[foo]: /url "title" +<<< +<p><img src="/url" alt="foo" title="title" /></p> +>>> Images - 597 +![*foo* bar] + +[*foo* bar]: /url "title" +<<< +<p><img src="/url" alt="foo bar" title="title" /></p> +>>> Images - 598 +![[foo]] + +[[foo]]: /url "title" +<<< +<p>![[foo]]</p> +<p>[[foo]]: /url "title"</p> +>>> Images - 599 +![Foo] + +[foo]: /url "title" +<<< +<p><img src="/url" alt="Foo" title="title" /></p> +>>> Images - 600 +!\[foo] + +[foo]: /url "title" +<<< +<p>![foo]</p> +>>> Images - 601 +\![foo] + +[foo]: /url "title" +<<< +<p>!<a href="/url" title="title">foo</a></p> diff --git a/pkgs/markdown/test/gfm/indented_code_blocks.unit b/pkgs/markdown/test/gfm/indented_code_blocks.unit new file mode 100644 index 000000000..68fc6d182 --- /dev/null +++ b/pkgs/markdown/test/gfm/indented_code_blocks.unit @@ -0,0 +1,118 @@ +>>> Indented code blocks - 77 + a simple + indented code block +<<< +<pre><code>a simple + indented code block +</code></pre> +>>> Indented code blocks - 78 + - foo + + bar +<<< +<ul> +<li> +<p>foo</p> +<p>bar</p> +</li> +</ul> +>>> Indented code blocks - 79 +1. foo + + - bar +<<< +<ol> +<li> +<p>foo</p> +<ul> +<li>bar</li> +</ul> +</li> +</ol> +>>> Indented code blocks - 80 + <a/> + *hi* + + - one +<<< +<pre><code><a/> +*hi* + +- one +</code></pre> +>>> Indented code blocks - 81 + chunk1 + + chunk2 + + + + chunk3 +<<< +<pre><code>chunk1 + +chunk2 + + + +chunk3 +</code></pre> +>>> Indented code blocks - 82 + chunk1 + + chunk2 +<<< +<pre><code>chunk1 + + chunk2 +</code></pre> +>>> Indented code blocks - 83 +Foo + bar + +<<< +<p>Foo +bar</p> +>>> Indented code blocks - 84 + foo +bar +<<< +<pre><code>foo +</code></pre> +<p>bar</p> +>>> Indented code blocks - 85 +# Heading + foo +Heading +------ + foo +---- +<<< +<h1>Heading</h1> +<pre><code>foo +</code></pre> +<h2>Heading</h2> +<pre><code>foo +</code></pre> +<hr /> +>>> Indented code blocks - 86 + foo + bar +<<< +<pre><code> foo +bar +</code></pre> +>>> Indented code blocks - 87 + + + foo + + +<<< +<pre><code>foo +</code></pre> +>>> Indented code blocks - 88 + foo +<<< +<pre><code>foo +</code></pre> diff --git a/pkgs/markdown/test/gfm/inlines.unit b/pkgs/markdown/test/gfm/inlines.unit new file mode 100644 index 000000000..9e19a33d3 --- /dev/null +++ b/pkgs/markdown/test/gfm/inlines.unit @@ -0,0 +1,4 @@ +>>> Inlines - 307 +`hi`lo` +<<< +<p><code>hi</code>lo`</p> diff --git a/pkgs/markdown/test/gfm/link_reference_definitions.unit b/pkgs/markdown/test/gfm/link_reference_definitions.unit new file mode 100644 index 000000000..b09236fe0 --- /dev/null +++ b/pkgs/markdown/test/gfm/link_reference_definitions.unit @@ -0,0 +1,206 @@ +>>> Link reference definitions - 161 +[foo]: /url "title" + +[foo] +<<< +<p><a href="/url" title="title">foo</a></p> +>>> Link reference definitions - 162 + [foo]: + /url + 'the title' + +[foo] +<<< +<p><a href="/url" title="the title">foo</a></p> +>>> Link reference definitions - 163 +[Foo*bar\]]:my_(url) 'title (with parens)' + +[Foo*bar\]] +<<< +<p><a href="my_(url)" title="title (with parens)">Foo*bar]</a></p> +>>> Link reference definitions - 164 +[Foo bar]: +<my url> +'title' + +[Foo bar] +<<< +<p><a href="my%20url" title="title">Foo bar</a></p> +>>> Link reference definitions - 165 +[foo]: /url ' +title +line1 +line2 +' + +[foo] +<<< +<p><a href="/url" title=" +title +line1 +line2 +">foo</a></p> +>>> Link reference definitions - 166 +[foo]: /url 'title + +with blank line' + +[foo] +<<< +<p>[foo]: /url 'title</p> +<p>with blank line'</p> +<p>[foo]</p> +>>> Link reference definitions - 167 +[foo]: +/url + +[foo] +<<< +<p><a href="/url">foo</a></p> +>>> Link reference definitions - 168 +[foo]: + +[foo] +<<< +<p>[foo]:</p> +<p>[foo]</p> +>>> Link reference definitions - 169 +[foo]: <> + +[foo] +<<< +<p><a href="">foo</a></p> +>>> Link reference definitions - 170 +[foo]: <bar>(baz) + +[foo] +<<< +<p>[foo]: <bar>(baz)</p> +<p>[foo]</p> +>>> Link reference definitions - 171 +[foo]: /url\bar\*baz "foo\"bar\baz" + +[foo] +<<< +<p><a href="/url%5Cbar*baz" title="foo"bar\baz">foo</a></p> +>>> Link reference definitions - 172 +[foo] + +[foo]: url +<<< +<p><a href="url">foo</a></p> +>>> Link reference definitions - 173 +[foo] + +[foo]: first +[foo]: second +<<< +<p><a href="first">foo</a></p> +>>> Link reference definitions - 174 +[FOO]: /url + +[Foo] +<<< +<p><a href="/url">Foo</a></p> +>>> Link reference definitions - 175 +[ΑΓΩ]: /φου + +[αγω] +<<< +<p><a href="/%CF%86%CE%BF%CF%85">αγω</a></p> +>>> Link reference definitions - 176 +[foo]: /url +<<< + +>>> Link reference definitions - 177 +[ +foo +]: /url +bar +<<< +<p>bar</p> +>>> Link reference definitions - 178 +[foo]: /url "title" ok +<<< +<p>[foo]: /url "title" ok</p> +>>> Link reference definitions - 179 +[foo]: /url +"title" ok +<<< +<p>"title" ok</p> +>>> Link reference definitions - 180 + [foo]: /url "title" + +[foo] +<<< +<pre><code>[foo]: /url "title" +</code></pre> +<p>[foo]</p> +>>> Link reference definitions - 181 +``` +[foo]: /url +``` + +[foo] +<<< +<pre><code>[foo]: /url +</code></pre> +<p>[foo]</p> +>>> Link reference definitions - 182 +Foo +[bar]: /baz + +[bar] +<<< +<p>Foo +[bar]: /baz</p> +<p>[bar]</p> +>>> Link reference definitions - 183 +# [Foo] +[foo]: /url +> bar +<<< +<h1><a href="/url">Foo</a></h1> +<blockquote> +<p>bar</p> +</blockquote> +>>> Link reference definitions - 184 +[foo]: /url +bar +=== +[foo] +<<< +<h1>bar</h1> +<p><a href="/url">foo</a></p> +>>> Link reference definitions - 185 +[foo]: /url +=== +[foo] +<<< +<p>=== +<a href="/url">foo</a></p> +>>> Link reference definitions - 186 +[foo]: /foo-url "foo" +[bar]: /bar-url + "bar" +[baz]: /baz-url + +[foo], +[bar], +[baz] +<<< +<p><a href="/foo-url" title="foo">foo</a>, +<a href="/bar-url" title="bar">bar</a>, +<a href="/baz-url">baz</a></p> +>>> Link reference definitions - 187 +[foo] + +> [foo]: /url +<<< +<p><a href="/url">foo</a></p> +<blockquote> +</blockquote> +>>> Link reference definitions - 188 +[foo]: /url +<<< + diff --git a/pkgs/markdown/test/gfm/links.unit b/pkgs/markdown/test/gfm/links.unit new file mode 100644 index 000000000..7288c795e --- /dev/null +++ b/pkgs/markdown/test/gfm/links.unit @@ -0,0 +1,476 @@ +>>> Links - 493 +[link](/uri "title") +<<< +<p><a href="/uri" title="title">link</a></p> +>>> Links - 494 +[link](/uri) +<<< +<p><a href="/uri">link</a></p> +>>> Links - 495 +[link]() +<<< +<p><a href="">link</a></p> +>>> Links - 496 +[link](<>) +<<< +<p><a href="">link</a></p> +>>> Links - 497 +[link](/my uri) +<<< +<p>[link](/my uri)</p> +>>> Links - 498 +[link](</my uri>) +<<< +<p><a href="/my%20uri">link</a></p> +>>> Links - 499 +[link](foo +bar) +<<< +<p>[link](foo +bar)</p> +>>> Links - 500 +[link](<foo +bar>) +<<< +<p>[link](<foo +bar>)</p> +>>> Links - 501 +[a](<b)c>) +<<< +<p><a href="b)c">a</a></p> +>>> Links - 502 +[link](<foo\>) +<<< +<p>[link](<foo>)</p> +>>> Links - 503 +[a](<b)c +[a](<b)c> +[a](<b>c) +<<< +<p>[a](<b)c +[a](<b)c> +[a](<b>c)</p> +>>> Links - 504 +[link](\(foo\)) +<<< +<p><a href="(foo)">link</a></p> +>>> Links - 505 +[link](foo(and(bar))) +<<< +<p><a href="foo(and(bar))">link</a></p> +>>> Links - 506 +[link](foo\(and\(bar\)) +<<< +<p><a href="foo(and(bar)">link</a></p> +>>> Links - 507 +[link](<foo(and(bar)>) +<<< +<p><a href="foo(and(bar)">link</a></p> +>>> Links - 508 +[link](foo\)\:) +<<< +<p><a href="foo):">link</a></p> +>>> Links - 509 +[link](#fragment) + +[link](http://example.com#fragment) + +[link](http://example.com?foo=3#frag) +<<< +<p><a href="#fragment">link</a></p> +<p><a href="http://example.com#fragment">link</a></p> +<p><a href="http://example.com?foo=3#frag">link</a></p> +>>> Links - 510 +[link](foo\bar) +<<< +<p><a href="foo%5Cbar">link</a></p> +>>> Links - 511 +[link](foo%20bä) +<<< +<p><a href="foo%20b%C3%A4">link</a></p> +>>> Links - 512 +[link]("title") +<<< +<p><a href="%22title%22">link</a></p> +>>> Links - 513 +[link](/url "title") +[link](/url 'title') +[link](/url (title)) +<<< +<p><a href="/url" title="title">link</a> +<a href="/url" title="title">link</a> +<a href="/url" title="title">link</a></p> +>>> Links - 514 +[link](/url "title \""") +<<< +<p><a href="/url" title="title """>link</a></p> +>>> Links - 515 +[link](/url "title") +<<< +<p><a href="/url%C2%A0%22title%22">link</a></p> +>>> Links - 516 +[link](/url "title "and" title") +<<< +<p>[link](/url "title "and" title")</p> +>>> Links - 517 +[link](/url 'title "and" title') +<<< +<p><a href="/url" title="title "and" title">link</a></p> +>>> Links - 518 +[link]( /uri + "title" ) +<<< +<p><a href="/uri" title="title">link</a></p> +>>> Links - 519 +[link] (/uri) +<<< +<p>[link] (/uri)</p> +>>> Links - 520 +[link [foo [bar]]](/uri) +<<< +<p><a href="/uri">link [foo [bar]]</a></p> +>>> Links - 521 +[link] bar](/uri) +<<< +<p>[link] bar](/uri)</p> +>>> Links - 522 +[link [bar](/uri) +<<< +<p>[link <a href="/uri">bar</a></p> +>>> Links - 523 +[link \[bar](/uri) +<<< +<p><a href="/uri">link [bar</a></p> +>>> Links - 524 +[link *foo **bar** `#`*](/uri) +<<< +<p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p> +>>> Links - 525 +[![moon](moon.jpg)](/uri) +<<< +<p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p> +>>> Links - 526 +[foo [bar](/uri)](/uri) +<<< +<p>[foo <a href="/uri">bar</a>](/uri)</p> +>>> Links - 527 +[foo *[bar [baz](/uri)](/uri)*](/uri) +<<< +<p>[foo <em>[bar <a href="/uri">baz</a>](/uri)</em>](/uri)</p> +>>> Links - 528 +![[[foo](uri1)](uri2)](uri3) +<<< +<p><img src="uri3" alt="[foo](uri2)" /></p> +>>> Links - 529 +*[foo*](/uri) +<<< +<p>*<a href="/uri">foo*</a></p> +>>> Links - 530 +[foo *bar](baz*) +<<< +<p><a href="baz*">foo *bar</a></p> +>>> Links - 531 +*foo [bar* baz] +<<< +<p><em>foo [bar</em> baz]</p> +>>> Links - 532 +[foo <bar attr="](baz)"> +<<< +<p>[foo <bar attr="](baz)"></p> +>>> Links - 533 +[foo`](/uri)` +<<< +<p>[foo<code>](/uri)</code></p> +>>> Links - 534 +[foo<http://example.com/?search=](uri)> +<<< +<p>[foo<a href="http://example.com/?search=%5D(uri)">http://example.com/?search=](uri)</a></p> +>>> Links - 535 +[foo][bar] + +[bar]: /url "title" +<<< +<p><a href="/url" title="title">foo</a></p> +>>> Links - 536 +[link [foo [bar]]][ref] + +[ref]: /uri +<<< +<p><a href="/uri">link [foo [bar]]</a></p> +>>> Links - 537 +[link \[bar][ref] + +[ref]: /uri +<<< +<p><a href="/uri">link [bar</a></p> +>>> Links - 538 +[link *foo **bar** `#`*][ref] + +[ref]: /uri +<<< +<p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p> +>>> Links - 539 +[![moon](moon.jpg)][ref] + +[ref]: /uri +<<< +<p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p> +>>> Links - 540 +[foo [bar](/uri)][ref] + +[ref]: /uri +<<< +<p>[foo <a href="/uri">bar</a>]<a href="/uri">ref</a></p> +>>> Links - 541 +[foo *bar [baz][ref]*][ref] + +[ref]: /uri +<<< +<p>[foo <em>bar <a href="/uri">baz</a></em>]<a href="/uri">ref</a></p> +>>> Links - 542 +*[foo*][ref] + +[ref]: /uri +<<< +<p>*<a href="/uri">foo*</a></p> +>>> Links - 543 +[foo *bar][ref] + +[ref]: /uri +<<< +<p><a href="/uri">foo *bar</a></p> +>>> Links - 544 +[foo <bar attr="][ref]"> + +[ref]: /uri +<<< +<p>[foo <bar attr="][ref]"></p> +>>> Links - 545 +[foo`][ref]` + +[ref]: /uri +<<< +<p>[foo<code>][ref]</code></p> +>>> Links - 546 +[foo<http://example.com/?search=][ref]> + +[ref]: /uri +<<< +<p>[foo<a href="http://example.com/?search=%5D%5Bref%5D">http://example.com/?search=][ref]</a></p> +>>> Links - 547 +[foo][BaR] + +[bar]: /url "title" +<<< +<p><a href="/url" title="title">foo</a></p> +>>> Links - 548 +[Толпой][Толпой] is a Russian word. + +[ТОЛПОЙ]: /url +<<< +<p><a href="/url">Толпой</a> is a Russian word.</p> +>>> Links - 549 +[Foo + bar]: /url + +[Baz][Foo bar] +<<< +<p><a href="/url">Baz</a></p> +>>> Links - 550 +[foo] [bar] + +[bar]: /url "title" +<<< +<p>[foo] <a href="/url" title="title">bar</a></p> +>>> Links - 551 +[foo] +[bar] + +[bar]: /url "title" +<<< +<p>[foo] +<a href="/url" title="title">bar</a></p> +>>> Links - 552 +[foo]: /url1 + +[foo]: /url2 + +[bar][foo] +<<< +<p><a href="/url1">bar</a></p> +>>> Links - 553 +[bar][foo\!] + +[foo!]: /url +<<< +<p>[bar][foo!]</p> +>>> Links - 554 +[foo][ref[] + +[ref[]: /uri +<<< +<p>[foo][ref[]</p> +<p>[ref[]: /uri</p> +>>> Links - 555 +[foo][ref[bar]] + +[ref[bar]]: /uri +<<< +<p>[foo][ref[bar]]</p> +<p>[ref[bar]]: /uri</p> +>>> Links - 556 +[[[foo]]] + +[[[foo]]]: /url +<<< +<p>[[[foo]]]</p> +<p>[[[foo]]]: /url</p> +>>> Links - 557 +[foo][ref\[] + +[ref\[]: /uri +<<< +<p><a href="/uri">foo</a></p> +>>> Links - 558 +[bar\\]: /uri + +[bar\\] +<<< +<p><a href="/uri">bar\</a></p> +>>> Links - 559 +[] + +[]: /uri +<<< +<p>[]</p> +<p>[]: /uri</p> +>>> Links - 560 +[ + ] + +[ + ]: /uri +<<< +<p>[ +]</p> +<p>[ +]: /uri</p> +>>> Links - 561 +[foo][] + +[foo]: /url "title" +<<< +<p><a href="/url" title="title">foo</a></p> +>>> Links - 562 +[*foo* bar][] + +[*foo* bar]: /url "title" +<<< +<p><a href="/url" title="title"><em>foo</em> bar</a></p> +>>> Links - 563 +[Foo][] + +[foo]: /url "title" +<<< +<p><a href="/url" title="title">Foo</a></p> +>>> Links - 564 +[foo] +[] + +[foo]: /url "title" +<<< +<p><a href="/url" title="title">foo</a> +[]</p> +>>> Links - 565 +[foo] + +[foo]: /url "title" +<<< +<p><a href="/url" title="title">foo</a></p> +>>> Links - 566 +[*foo* bar] + +[*foo* bar]: /url "title" +<<< +<p><a href="/url" title="title"><em>foo</em> bar</a></p> +>>> Links - 567 +[[*foo* bar]] + +[*foo* bar]: /url "title" +<<< +<p>[<a href="/url" title="title"><em>foo</em> bar</a>]</p> +>>> Links - 568 +[[bar [foo] + +[foo]: /url +<<< +<p>[[bar <a href="/url">foo</a></p> +>>> Links - 569 +[Foo] + +[foo]: /url "title" +<<< +<p><a href="/url" title="title">Foo</a></p> +>>> Links - 570 +[foo] bar + +[foo]: /url +<<< +<p><a href="/url">foo</a> bar</p> +>>> Links - 571 +\[foo] + +[foo]: /url "title" +<<< +<p>[foo]</p> +>>> Links - 572 +[foo*]: /url + +*[foo*] +<<< +<p>*<a href="/url">foo*</a></p> +>>> Links - 573 +[foo][bar] + +[foo]: /url1 +[bar]: /url2 +<<< +<p><a href="/url2">foo</a></p> +>>> Links - 574 +[foo][] + +[foo]: /url1 +<<< +<p><a href="/url1">foo</a></p> +>>> Links - 575 +[foo]() + +[foo]: /url1 +<<< +<p><a href="">foo</a></p> +>>> Links - 576 +[foo](not a link) + +[foo]: /url1 +<<< +<p><a href="/url1">foo</a>(not a link)</p> +>>> Links - 577 +[foo][bar][baz] + +[baz]: /url +<<< +<p>[foo]<a href="/url">bar</a></p> +>>> Links - 578 +[foo][bar][baz] + +[baz]: /url1 +[bar]: /url2 +<<< +<p><a href="/url2">foo</a><a href="/url1">baz</a></p> +>>> Links - 579 +[foo][bar][baz] + +[baz]: /url1 +[foo]: /url2 +<<< +<p>[foo]<a href="/url1">bar</a></p> diff --git a/pkgs/markdown/test/gfm/list_items.unit b/pkgs/markdown/test/gfm/list_items.unit new file mode 100644 index 000000000..3954af82f --- /dev/null +++ b/pkgs/markdown/test/gfm/list_items.unit @@ -0,0 +1,586 @@ +>>> List items - 231 +A paragraph +with two lines. + + indented code + +> A block quote. +<<< +<p>A paragraph +with two lines.</p> +<pre><code>indented code +</code></pre> +<blockquote> +<p>A block quote.</p> +</blockquote> +>>> List items - 232 +1. A paragraph + with two lines. + + indented code + + > A block quote. +<<< +<ol> +<li> +<p>A paragraph +with two lines.</p> +<pre><code>indented code +</code></pre> +<blockquote> +<p>A block quote.</p> +</blockquote> +</li> +</ol> +>>> List items - 233 +- one + + two +<<< +<ul> +<li>one</li> +</ul> +<p>two</p> +>>> List items - 234 +- one + + two +<<< +<ul> +<li> +<p>one</p> +<p>two</p> +</li> +</ul> +>>> List items - 235 + - one + + two +<<< +<ul> +<li>one</li> +</ul> +<pre><code> two +</code></pre> +>>> List items - 236 + - one + + two +<<< +<ul> +<li> +<p>one</p> +<p>two</p> +</li> +</ul> +>>> List items - 237 + > > 1. one +>> +>> two +<<< +<blockquote> +<blockquote> +<ol> +<li> +<p>one</p> +<p>two</p> +</li> +</ol> +</blockquote> +</blockquote> +>>> List items - 238 +>>- one +>> + > > two +<<< +<blockquote> +<blockquote> +<ul> +<li>one</li> +</ul> +<p>two</p> +</blockquote> +</blockquote> +>>> List items - 239 +-one + +2.two +<<< +<p>-one</p> +<p>2.two</p> +>>> List items - 240 +- foo + + + bar +<<< +<ul> +<li> +<p>foo</p> +<p>bar</p> +</li> +</ul> +>>> List items - 241 +1. foo + + ``` + bar + ``` + + baz + + > bam +<<< +<ol> +<li> +<p>foo</p> +<pre><code>bar +</code></pre> +<p>baz</p> +<blockquote> +<p>bam</p> +</blockquote> +</li> +</ol> +>>> List items - 242 +- Foo + + bar + + + baz +<<< +<ul> +<li> +<p>Foo</p> +<pre><code>bar + + +baz +</code></pre> +</li> +</ul> +>>> List items - 243 +123456789. ok +<<< +<ol start="123456789"> +<li>ok</li> +</ol> +>>> List items - 244 +1234567890. not ok +<<< +<p>1234567890. not ok</p> +>>> List items - 245 +0. ok +<<< +<ol start="0"> +<li>ok</li> +</ol> +>>> List items - 246 +003. ok +<<< +<ol start="3"> +<li>ok</li> +</ol> +>>> List items - 247 +-1. not ok +<<< +<p>-1. not ok</p> +>>> List items - 248 +- foo + + bar +<<< +<ul> +<li> +<p>foo</p> +<pre><code>bar +</code></pre> +</li> +</ul> +>>> List items - 249 + 10. foo + + bar +<<< +<ol start="10"> +<li> +<p>foo</p> +<pre><code>bar +</code></pre> +</li> +</ol> +>>> List items - 250 + indented code + +paragraph + + more code +<<< +<pre><code>indented code +</code></pre> +<p>paragraph</p> +<pre><code>more code +</code></pre> +>>> List items - 251 +1. indented code + + paragraph + + more code +<<< +<ol> +<li> +<pre><code>indented code +</code></pre> +<p>paragraph</p> +<pre><code>more code +</code></pre> +</li> +</ol> +>>> List items - 252 +1. indented code + + paragraph + + more code +<<< +<ol> +<li> +<pre><code> indented code +</code></pre> +<p>paragraph</p> +<pre><code>more code +</code></pre> +</li> +</ol> +>>> List items - 253 + foo + +bar +<<< +<p>foo</p> +<p>bar</p> +>>> List items - 254 +- foo + + bar +<<< +<ul> +<li>foo</li> +</ul> +<p>bar</p> +>>> List items - 255 +- foo + + bar +<<< +<ul> +<li> +<p>foo</p> +<p>bar</p> +</li> +</ul> +>>> List items - 256 +- + foo +- + ``` + bar + ``` +- + baz +<<< +<ul> +<li>foo</li> +<li> +<pre><code>bar +</code></pre> +</li> +<li> +<pre><code>baz +</code></pre> +</li> +</ul> +>>> List items - 257 +- + foo +<<< +<ul> +<li>foo</li> +</ul> +>>> List items - 258 +- + + foo +<<< +<ul> +<li></li> +</ul> +<p>foo</p> +>>> List items - 259 +- foo +- +- bar +<<< +<ul> +<li>foo</li> +<li></li> +<li>bar</li> +</ul> +>>> List items - 260 +- foo +- +- bar +<<< +<ul> +<li>foo</li> +<li></li> +<li>bar</li> +</ul> +>>> List items - 261 +1. foo +2. +3. bar +<<< +<ol> +<li>foo</li> +<li></li> +<li>bar</li> +</ol> +>>> List items - 262 +* +<<< +<ul> +<li></li> +</ul> +>>> List items - 263 +foo +* + +foo +1. +<<< +<p>foo +*</p> +<p>foo +1.</p> +>>> List items - 264 + 1. A paragraph + with two lines. + + indented code + + > A block quote. +<<< +<ol> +<li> +<p>A paragraph +with two lines.</p> +<pre><code>indented code +</code></pre> +<blockquote> +<p>A block quote.</p> +</blockquote> +</li> +</ol> +>>> List items - 265 + 1. A paragraph + with two lines. + + indented code + + > A block quote. +<<< +<ol> +<li> +<p>A paragraph +with two lines.</p> +<pre><code>indented code +</code></pre> +<blockquote> +<p>A block quote.</p> +</blockquote> +</li> +</ol> +>>> List items - 266 + 1. A paragraph + with two lines. + + indented code + + > A block quote. +<<< +<ol> +<li> +<p>A paragraph +with two lines.</p> +<pre><code>indented code +</code></pre> +<blockquote> +<p>A block quote.</p> +</blockquote> +</li> +</ol> +>>> List items - 267 + 1. A paragraph + with two lines. + + indented code + + > A block quote. +<<< +<pre><code>1. A paragraph + with two lines. + + indented code + + > A block quote. +</code></pre> +>>> List items - 268 + 1. A paragraph +with two lines. + + indented code + + > A block quote. +<<< +<ol> +<li> +<p>A paragraph +with two lines.</p> +<pre><code>indented code +</code></pre> +<blockquote> +<p>A block quote.</p> +</blockquote> +</li> +</ol> +>>> List items - 269 + 1. A paragraph + with two lines. +<<< +<ol> +<li>A paragraph +with two lines.</li> +</ol> +>>> List items - 270 +> 1. > Blockquote +continued here. +<<< +<blockquote> +<ol> +<li> +<blockquote> +<p>Blockquote +continued here.</p> +</blockquote> +</li> +</ol> +</blockquote> +>>> List items - 271 +> 1. > Blockquote +> continued here. +<<< +<blockquote> +<ol> +<li> +<blockquote> +<p>Blockquote +continued here.</p> +</blockquote> +</li> +</ol> +</blockquote> +>>> List items - 272 +- foo + - bar + - baz + - boo +<<< +<ul> +<li>foo +<ul> +<li>bar +<ul> +<li>baz +<ul> +<li>boo</li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +</ul> +>>> List items - 273 +- foo + - bar + - baz + - boo +<<< +<ul> +<li>foo</li> +<li>bar</li> +<li>baz</li> +<li>boo</li> +</ul> +>>> List items - 274 +10) foo + - bar +<<< +<ol start="10"> +<li>foo +<ul> +<li>bar</li> +</ul> +</li> +</ol> +>>> List items - 275 +10) foo + - bar +<<< +<ol start="10"> +<li>foo</li> +</ol> +<ul> +<li>bar</li> +</ul> +>>> List items - 276 +- - foo +<<< +<ul> +<li> +<ul> +<li>foo</li> +</ul> +</li> +</ul> +>>> List items - 277 +1. - 2. foo +<<< +<ol> +<li> +<ul> +<li> +<ol start="2"> +<li>foo</li> +</ol> +</li> +</ul> +</li> +</ol> +>>> List items - 278 +- # Foo +- Bar + --- + baz +<<< +<ul> +<li> +<h1>Foo</h1> +</li> +<li> +<h2>Bar</h2> +baz</li> +</ul> diff --git a/pkgs/markdown/test/gfm/lists.unit b/pkgs/markdown/test/gfm/lists.unit new file mode 100644 index 000000000..e5802db88 --- /dev/null +++ b/pkgs/markdown/test/gfm/lists.unit @@ -0,0 +1,406 @@ +>>> Lists - 281 +- foo +- bar ++ baz +<<< +<ul> +<li>foo</li> +<li>bar</li> +</ul> +<ul> +<li>baz</li> +</ul> +>>> Lists - 282 +1. foo +2. bar +3) baz +<<< +<ol> +<li>foo</li> +<li>bar</li> +</ol> +<ol start="3"> +<li>baz</li> +</ol> +>>> Lists - 283 +Foo +- bar +- baz +<<< +<p>Foo</p> +<ul> +<li>bar</li> +<li>baz</li> +</ul> +>>> Lists - 284 +The number of windows in my house is +14. The number of doors is 6. +<<< +<p>The number of windows in my house is +14. The number of doors is 6.</p> +>>> Lists - 285 +The number of windows in my house is +1. The number of doors is 6. +<<< +<p>The number of windows in my house is</p> +<ol> +<li>The number of doors is 6.</li> +</ol> +>>> Lists - 286 +- foo + +- bar + + +- baz +<<< +<ul> +<li> +<p>foo</p> +</li> +<li> +<p>bar</p> +</li> +<li> +<p>baz</p> +</li> +</ul> +>>> Lists - 287 +- foo + - bar + - baz + + + bim +<<< +<ul> +<li>foo +<ul> +<li>bar +<ul> +<li> +<p>baz</p> +<p>bim</p> +</li> +</ul> +</li> +</ul> +</li> +</ul> +>>> Lists - 288 +- foo +- bar + +<!-- --> + +- baz +- bim +<<< +<ul> +<li>foo</li> +<li>bar</li> +</ul> +<!-- --> +<ul> +<li>baz</li> +<li>bim</li> +</ul> +>>> Lists - 289 +- foo + + notcode + +- foo + +<!-- --> + + code +<<< +<ul> +<li> +<p>foo</p> +<p>notcode</p> +</li> +<li> +<p>foo</p> +</li> +</ul> +<!-- --> +<pre><code>code +</code></pre> +>>> Lists - 290 +- a + - b + - c + - d + - e + - f +- g +<<< +<ul> +<li>a</li> +<li>b</li> +<li>c</li> +<li>d</li> +<li>e</li> +<li>f</li> +<li>g</li> +</ul> +>>> Lists - 291 +1. a + + 2. b + + 3. c +<<< +<ol> +<li> +<p>a</p> +</li> +<li> +<p>b</p> +</li> +<li> +<p>c</p> +</li> +</ol> +>>> Lists - 292 +- a + - b + - c + - d + - e +<<< +<ul> +<li>a</li> +<li>b</li> +<li>c</li> +<li>d +- e</li> +</ul> +>>> Lists - 293 +1. a + + 2. b + + 3. c +<<< +<ol> +<li> +<p>a</p> +</li> +<li> +<p>b</p> +</li> +</ol> +<pre><code>3. c +</code></pre> +>>> Lists - 294 +- a +- b + +- c +<<< +<ul> +<li> +<p>a</p> +</li> +<li> +<p>b</p> +</li> +<li> +<p>c</p> +</li> +</ul> +>>> Lists - 295 +* a +* + +* c +<<< +<ul> +<li> +<p>a</p> +</li> +<li></li> +<li> +<p>c</p> +</li> +</ul> +>>> Lists - 296 +- a +- b + + c +- d +<<< +<ul> +<li> +<p>a</p> +</li> +<li> +<p>b</p> +<p>c</p> +</li> +<li> +<p>d</p> +</li> +</ul> +>>> Lists - 297 +- a +- b + + [ref]: /url +- d +<<< +<ul> +<li> +<p>a</p> +</li> +<li> +<p>b</p> +</li> +<li> +<p>d</p> +</li> +</ul> +>>> Lists - 298 +- a +- ``` + b + + + ``` +- c +<<< +<ul> +<li>a</li> +<li> +<pre><code>b + + +</code></pre> +</li> +<li>c</li> +</ul> +>>> Lists - 299 +- a + - b + + c +- d +<<< +<ul> +<li>a +<ul> +<li> +<p>b</p> +<p>c</p> +</li> +</ul> +</li> +<li>d</li> +</ul> +>>> Lists - 300 +* a + > b + > +* c +<<< +<ul> +<li>a +<blockquote> +<p>b</p> +</blockquote> +</li> +<li>c</li> +</ul> +>>> Lists - 301 +- a + > b + ``` + c + ``` +- d +<<< +<ul> +<li>a +<blockquote> +<p>b</p> +</blockquote> +<pre><code>c +</code></pre> +</li> +<li>d</li> +</ul> +>>> Lists - 302 +- a +<<< +<ul> +<li>a</li> +</ul> +>>> Lists - 303 +- a + - b +<<< +<ul> +<li>a +<ul> +<li>b</li> +</ul> +</li> +</ul> +>>> Lists - 304 +1. ``` + foo + ``` + + bar +<<< +<ol> +<li> +<pre><code>foo +</code></pre> +<p>bar</p> +</li> +</ol> +>>> Lists - 305 +* foo + * bar + + baz +<<< +<ul> +<li> +<p>foo</p> +<ul> +<li>bar</li> +</ul> +<p>baz</p> +</li> +</ul> +>>> Lists - 306 +- a + - b + - c + +- d + - e + - f +<<< +<ul> +<li> +<p>a</p> +<ul> +<li>b</li> +<li>c</li> +</ul> +</li> +<li> +<p>d</p> +<ul> +<li>e</li> +<li>f</li> +</ul> +</li> +</ul> diff --git a/pkgs/markdown/test/gfm/paragraphs.unit b/pkgs/markdown/test/gfm/paragraphs.unit new file mode 100644 index 000000000..a6fc2b15a --- /dev/null +++ b/pkgs/markdown/test/gfm/paragraphs.unit @@ -0,0 +1,59 @@ +>>> Paragraphs - 189 +aaa + +bbb +<<< +<p>aaa</p> +<p>bbb</p> +>>> Paragraphs - 190 +aaa +bbb + +ccc +ddd +<<< +<p>aaa +bbb</p> +<p>ccc +ddd</p> +>>> Paragraphs - 191 +aaa + + +bbb +<<< +<p>aaa</p> +<p>bbb</p> +>>> Paragraphs - 192 + aaa + bbb +<<< +<p>aaa +bbb</p> +>>> Paragraphs - 193 +aaa + bbb + ccc +<<< +<p>aaa +bbb +ccc</p> +>>> Paragraphs - 194 + aaa +bbb +<<< +<p>aaa +bbb</p> +>>> Paragraphs - 195 + aaa +bbb +<<< +<pre><code>aaa +</code></pre> +<p>bbb</p> +>>> Paragraphs - 196 +aaa +bbb +<<< +<p>aaa<br /> +bbb</p> diff --git a/pkgs/markdown/test/gfm/precedence.unit b/pkgs/markdown/test/gfm/precedence.unit new file mode 100644 index 000000000..793a094f7 --- /dev/null +++ b/pkgs/markdown/test/gfm/precedence.unit @@ -0,0 +1,8 @@ +>>> Precedence - 12 +- `one +- two` +<<< +<ul> +<li>`one</li> +<li>two`</li> +</ul> diff --git a/pkgs/markdown/test/gfm/raw_html.unit b/pkgs/markdown/test/gfm/raw_html.unit new file mode 100644 index 000000000..b408353c6 --- /dev/null +++ b/pkgs/markdown/test/gfm/raw_html.unit @@ -0,0 +1,95 @@ +>>> Raw HTML - 632 +<a><bab><c2c> +<<< +<p><a><bab><c2c></p> +>>> Raw HTML - 633 +<a/><b2/> +<<< +<p><a/><b2/></p> +>>> Raw HTML - 634 +<a /><b2 +data="foo" > +<<< +<p><a /><b2 +data="foo" ></p> +>>> Raw HTML - 635 +<a foo="bar" bam = 'baz <em>"</em>' +_boolean zoop:33=zoop:33 /> +<<< +<p><a foo="bar" bam = 'baz <em>"</em>' +_boolean zoop:33=zoop:33 /></p> +>>> Raw HTML - 636 +Foo <responsive-image src="foo.jpg" /> +<<< +<p>Foo <responsive-image src="foo.jpg" /></p> +>>> Raw HTML - 637 +<33> <__> +<<< +<p><33> <__></p> +>>> Raw HTML - 638 +<a h*#ref="hi"> +<<< +<p><a h*#ref="hi"></p> +>>> Raw HTML - 639 +<a href="hi'> <a href=hi'> +<<< +<p><a href="hi'> <a href=hi'></p> +>>> Raw HTML - 640 +< a>< +foo><bar/ > +<foo bar=baz +bim!bop /> +<<< +<p>< a>< +foo><bar/ > +<foo bar=baz +bim!bop /></p> +>>> Raw HTML - 641 +<a href='bar'title=title> +<<< +<p><a href='bar'title=title></p> +>>> Raw HTML - 642 +</a></foo > +<<< +<p></a></foo ></p> +>>> Raw HTML - 643 +</a href="foo"> +<<< +<p></a href="foo"></p> +>>> Raw HTML - 644 +foo <!-- this is a -- +comment - with hyphens --> +<<< +<p>foo <!-- this is a -- +comment - with hyphens --></p> +>>> Raw HTML - 645 +foo <!--> foo --> + +foo <!---> foo --> +<<< +<p>foo <!--> foo --></p> +<p>foo <!---> foo --></p> +>>> Raw HTML - 646 +foo <?php echo $a; ?> +<<< +<p>foo <?php echo $a; ?></p> +>>> Raw HTML - 647 +foo <!ELEMENT br EMPTY> +<<< +<p>foo <!ELEMENT br EMPTY></p> +>>> Raw HTML - 648 +foo <![CDATA[>&<]]> +<<< +<p>foo <![CDATA[>&<]]></p> +>>> Raw HTML - 649 +foo <a href="ö"> +<<< +<p>foo <a href="ö"></p> +>>> Raw HTML - 650 +foo <a href="\*"> +<<< +<p>foo <a href="\*"></p> +>>> Raw HTML - 651 +<a href="\""> +<<< +<p><a href="""></p> diff --git a/pkgs/markdown/test/gfm/setext_headings.unit b/pkgs/markdown/test/gfm/setext_headings.unit new file mode 100644 index 000000000..725a175d5 --- /dev/null +++ b/pkgs/markdown/test/gfm/setext_headings.unit @@ -0,0 +1,229 @@ +>>> Setext headings - 50 +Foo *bar* +========= + +Foo *bar* +--------- +<<< +<h1>Foo <em>bar</em></h1> +<h2>Foo <em>bar</em></h2> +>>> Setext headings - 51 +Foo *bar +baz* +==== +<<< +<h1>Foo <em>bar +baz</em></h1> +>>> Setext headings - 52 + Foo *bar +baz* +==== +<<< +<h1> Foo <em>bar +baz</em></h1> +>>> Setext headings - 53 +Foo +------------------------- + +Foo += +<<< +<h2>Foo</h2> +<h1>Foo</h1> +>>> Setext headings - 54 + Foo +--- + + Foo +----- + + Foo + === +<<< +<h2> Foo</h2> +<h2> Foo</h2> +<h1> Foo</h1> +>>> Setext headings - 55 + Foo + --- + + Foo +--- +<<< +<pre><code>Foo +--- + +Foo +</code></pre> +<hr /> +>>> Setext headings - 56 +Foo + ---- +<<< +<h2>Foo</h2> +>>> Setext headings - 57 +Foo + --- +<<< +<p>Foo +---</p> +>>> Setext headings - 58 +Foo += = + +Foo +--- - +<<< +<p>Foo += =</p> +<p>Foo</p> +<hr /> +>>> Setext headings - 59 +Foo +----- +<<< +<h2>Foo</h2> +>>> Setext headings - 60 +Foo\ +---- +<<< +<h2>Foo\</h2> +>>> Setext headings - 61 +`Foo +---- +` + +<a title="a lot +--- +of dashes"/> +<<< +<h2>`Foo</h2> +<p>`</p> +<h2><a title="a lot</h2> +<p>of dashes"/></p> +>>> Setext headings - 62 +> Foo +--- +<<< +<blockquote> +<p>Foo</p> +</blockquote> +<hr /> +>>> Setext headings - 63 +> foo +bar +=== +<<< +<blockquote> +<p>foo +bar +===</p> +</blockquote> +>>> Setext headings - 64 +- Foo +--- +<<< +<ul> +<li>Foo</li> +</ul> +<hr /> +>>> Setext headings - 65 +Foo +Bar +--- +<<< +<h2>Foo +Bar</h2> +>>> Setext headings - 66 +--- +Foo +--- +Bar +--- +Baz +<<< +<hr /> +<h2>Foo</h2> +<h2>Bar</h2> +<p>Baz</p> +>>> Setext headings - 67 + +==== +<<< +<p>====</p> +>>> Setext headings - 68 +--- +--- +<<< +<hr /> +<hr /> +>>> Setext headings - 69 +- foo +----- +<<< +<ul> +<li>foo</li> +</ul> +<hr /> +>>> Setext headings - 70 + foo +--- +<<< +<pre><code>foo +</code></pre> +<hr /> +>>> Setext headings - 71 +> foo +----- +<<< +<blockquote> +<p>foo</p> +</blockquote> +<hr /> +>>> Setext headings - 72 +\> foo +------ +<<< +<h2>> foo</h2> +>>> Setext headings - 73 +Foo + +bar +--- +baz +<<< +<p>Foo</p> +<h2>bar</h2> +<p>baz</p> +>>> Setext headings - 74 +Foo +bar + +--- + +baz +<<< +<p>Foo +bar</p> +<hr /> +<p>baz</p> +>>> Setext headings - 75 +Foo +bar +* * * +baz +<<< +<p>Foo +bar</p> +<hr /> +<p>baz</p> +>>> Setext headings - 76 +Foo +bar +\--- +baz +<<< +<p>Foo +bar +--- +baz</p> diff --git a/pkgs/markdown/test/gfm/soft_line_breaks.unit b/pkgs/markdown/test/gfm/soft_line_breaks.unit new file mode 100644 index 000000000..2186b0027 --- /dev/null +++ b/pkgs/markdown/test/gfm/soft_line_breaks.unit @@ -0,0 +1,12 @@ +>>> Soft line breaks - 668 +foo +baz +<<< +<p>foo +baz</p> +>>> Soft line breaks - 669 +foo + baz +<<< +<p>foo +baz</p> diff --git a/pkgs/markdown/test/gfm/strikethrough_extension.unit b/pkgs/markdown/test/gfm/strikethrough_extension.unit new file mode 100644 index 000000000..0d6f75f9e --- /dev/null +++ b/pkgs/markdown/test/gfm/strikethrough_extension.unit @@ -0,0 +1,19 @@ +>>> Strikethrough (extension) - 491 +~~Hi~~ Hello, world! +<<< +<p><del>Hi</del> Hello, world!</p> +>>> Strikethrough (extension) - 492 +This ~~has a + +new paragraph~~. +<<< +<p>This ~~has a</p> +<p>new paragraph~~.</p> +>>> single tilde +~Hi~ there. +<<< +<p><del>Hi</del> there.</p> +>>> single tilde with double tilde +~Hi~~ there. +<<< +<p><del>Hi</del>~ there.</p> diff --git a/pkgs/markdown/test/gfm/tables_extension.unit b/pkgs/markdown/test/gfm/tables_extension.unit new file mode 100644 index 000000000..625fca806 --- /dev/null +++ b/pkgs/markdown/test/gfm/tables_extension.unit @@ -0,0 +1,153 @@ +>>> Tables (extension) - 198 +| foo | bar | +| --- | --- | +| baz | bim | +<<< +<table> +<thead> +<tr> +<th>foo</th> +<th>bar</th> +</tr> +</thead> +<tbody> +<tr> +<td>baz</td> +<td>bim</td> +</tr> +</tbody> +</table> +>>> Tables (extension) - 199 +| abc | defghi | +:-: | -----------: +bar | baz +<<< +<table> +<thead> +<tr> +<th align="center">abc</th> +<th align="right">defghi</th> +</tr> +</thead> +<tbody> +<tr> +<td align="center">bar</td> +<td align="right">baz</td> +</tr> +</tbody> +</table> +>>> Tables (extension) - 200 +| f\|oo | +| ------ | +| b `\|` az | +| b **\|** im | +<<< +<table> +<thead> +<tr> +<th>f|oo</th> +</tr> +</thead> +<tbody> +<tr> +<td>b <code>|</code> az</td> +</tr> +<tr> +<td>b <strong>|</strong> im</td> +</tr> +</tbody> +</table> +>>> Tables (extension) - 201 +| abc | def | +| --- | --- | +| bar | baz | +> bar +<<< +<table> +<thead> +<tr> +<th>abc</th> +<th>def</th> +</tr> +</thead> +<tbody> +<tr> +<td>bar</td> +<td>baz</td> +</tr> +</tbody> +</table> +<blockquote> +<p>bar</p> +</blockquote> +>>> Tables (extension) - 202 +| abc | def | +| --- | --- | +| bar | baz | +bar + +bar +<<< +<table> +<thead> +<tr> +<th>abc</th> +<th>def</th> +</tr> +</thead> +<tbody> +<tr> +<td>bar</td> +<td>baz</td> +</tr> +<tr> +<td>bar</td> +<td></td> +</tr> +</tbody> +</table> +<p>bar</p> +>>> Tables (extension) - 203 +| abc | def | +| --- | +| bar | +<<< +<p>| abc | def | +| --- | +| bar |</p> +>>> Tables (extension) - 204 +| abc | def | +| --- | --- | +| bar | +| bar | baz | boo | +<<< +<table> +<thead> +<tr> +<th>abc</th> +<th>def</th> +</tr> +</thead> +<tbody> +<tr> +<td>bar</td> +<td></td> +</tr> +<tr> +<td>bar</td> +<td>baz</td> +</tr> +</tbody> +</table> +>>> Tables (extension) - 205 +| abc | def | +| --- | --- | +<<< +<table> +<thead> +<tr> +<th>abc</th> +<th>def</th> +</tr> +</thead> +</table> diff --git a/pkgs/markdown/test/gfm/tabs.unit b/pkgs/markdown/test/gfm/tabs.unit new file mode 100644 index 000000000..1239481d9 --- /dev/null +++ b/pkgs/markdown/test/gfm/tabs.unit @@ -0,0 +1,87 @@ +>>> Tabs - 1 + foo baz bim +<<< +<pre><code>foo baz bim +</code></pre> +>>> Tabs - 2 + foo baz bim +<<< +<pre><code>foo baz bim +</code></pre> +>>> Tabs - 3 + a a + ὐ a +<<< +<pre><code>a a +ὐ a +</code></pre> +>>> Tabs - 4 + - foo + + bar +<<< +<ul> +<li> +<p>foo</p> +<p>bar</p> +</li> +</ul> +>>> Tabs - 5 +- foo + + bar +<<< +<ul> +<li> +<p>foo</p> +<pre><code> bar +</code></pre> +</li> +</ul> +>>> Tabs - 6 +> foo +<<< +<blockquote> +<pre><code>foo +</code></pre> +</blockquote> +>>> Tabs - 7 +- foo +<<< +<ul> +<li> +<pre><code> foo +</code></pre> +</li> +</ul> +>>> Tabs - 8 + foo + bar +<<< +<pre><code>foo +bar +</code></pre> +>>> Tabs - 9 + - foo + - bar + - baz +<<< +<ul> +<li>foo +<ul> +<li>bar +<ul> +<li>baz</li> +</ul> +</li> +</ul> +</li> +</ul> +>>> Tabs - 10 +# Foo +<<< +<h1>Foo</h1> +>>> Tabs - 11 +* * * +<<< +<hr /> diff --git a/pkgs/markdown/test/gfm/textual_content.unit b/pkgs/markdown/test/gfm/textual_content.unit new file mode 100644 index 000000000..7a1b02c1a --- /dev/null +++ b/pkgs/markdown/test/gfm/textual_content.unit @@ -0,0 +1,12 @@ +>>> Textual content - 670 +hello $.;'there +<<< +<p>hello $.;'there</p> +>>> Textual content - 671 +Foo χρῆν +<<< +<p>Foo χρῆν</p> +>>> Textual content - 672 +Multiple spaces +<<< +<p>Multiple spaces</p> diff --git a/pkgs/markdown/test/gfm/thematic_breaks.unit b/pkgs/markdown/test/gfm/thematic_breaks.unit new file mode 100644 index 000000000..85206c895 --- /dev/null +++ b/pkgs/markdown/test/gfm/thematic_breaks.unit @@ -0,0 +1,126 @@ +>>> Thematic breaks - 13 +*** +--- +___ +<<< +<hr /> +<hr /> +<hr /> +>>> Thematic breaks - 14 ++++ +<<< +<p>+++</p> +>>> Thematic breaks - 15 +=== +<<< +<p>===</p> +>>> Thematic breaks - 16 +-- +** +__ +<<< +<p>-- +** +__</p> +>>> Thematic breaks - 17 + *** + *** + *** +<<< +<hr /> +<hr /> +<hr /> +>>> Thematic breaks - 18 + *** +<<< +<pre><code>*** +</code></pre> +>>> Thematic breaks - 19 +Foo + *** +<<< +<p>Foo +***</p> +>>> Thematic breaks - 20 +_____________________________________ +<<< +<hr /> +>>> Thematic breaks - 21 + - - - +<<< +<hr /> +>>> Thematic breaks - 22 + ** * ** * ** * ** +<<< +<hr /> +>>> Thematic breaks - 23 +- - - - +<<< +<hr /> +>>> Thematic breaks - 24 +- - - - +<<< +<hr /> +>>> Thematic breaks - 25 +_ _ _ _ a + +a------ + +---a--- +<<< +<p>_ _ _ _ a</p> +<p>a------</p> +<p>---a---</p> +>>> Thematic breaks - 26 + *-* +<<< +<p><em>-</em></p> +>>> Thematic breaks - 27 +- foo +*** +- bar +<<< +<ul> +<li>foo</li> +</ul> +<hr /> +<ul> +<li>bar</li> +</ul> +>>> Thematic breaks - 28 +Foo +*** +bar +<<< +<p>Foo</p> +<hr /> +<p>bar</p> +>>> Thematic breaks - 29 +Foo +--- +bar +<<< +<h2>Foo</h2> +<p>bar</p> +>>> Thematic breaks - 30 +* Foo +* * * +* Bar +<<< +<ul> +<li>Foo</li> +</ul> +<hr /> +<ul> +<li>Bar</li> +</ul> +>>> Thematic breaks - 31 +- Foo +- * * * +<<< +<ul> +<li>Foo</li> +<li> +<hr /> +</li> +</ul> diff --git a/pkgs/markdown/test/html_renderer_test.dart b/pkgs/markdown/test/html_renderer_test.dart new file mode 100644 index 000000000..77c33d3d6 --- /dev/null +++ b/pkgs/markdown/test/html_renderer_test.dart @@ -0,0 +1,114 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:markdown/markdown.dart'; +import 'package:test/test.dart'; + +void main() { + group('markdownToHtml', () { + const text = '# Hello **Markdown<em>!</em>**\n***'; + + test('with no syntaxes', () { + final result = markdownToHtml( + text, + withDefaultBlockSyntaxes: false, + withDefaultInlineSyntaxes: false, + encodeHtml: false, + ); + expect(result, equals('# Hello **Markdown<em>!</em>**\n***\n')); + }); + + test('with no default syntaxes but with custom syntaxes', () { + final result = markdownToHtml( + text, + withDefaultBlockSyntaxes: false, + withDefaultInlineSyntaxes: false, + encodeHtml: false, + blockSyntaxes: [const HorizontalRuleSyntax()], + inlineSyntaxes: [ + EmphasisSyntax.asterisk(), + ], + ); + + expect( + result, + equals('# Hello <strong>Markdown<em>!</em></strong>\n<hr />\n'), + ); + }); + + test('with only default block syntaxes', () { + final result = markdownToHtml( + text, + withDefaultInlineSyntaxes: false, + encodeHtml: false, + ); + + expect( + result, + equals('<h1>Hello **Markdown<em>!</em>**</h1>\n<hr />\n'), + ); + }); + + test('with only default inline syntaxes', () { + final result = markdownToHtml( + text, + withDefaultBlockSyntaxes: false, + encodeHtml: false, + ); + + expect( + result, + equals('# Hello <strong>Markdown<em>!</em></strong>\n***\n'), + ); + }); + + test('with no default syntaxes but with encodeHtml enabled', () { + final result = markdownToHtml( + text, + withDefaultBlockSyntaxes: false, + withDefaultInlineSyntaxes: false, + ); + + expect( + result, + equals('# Hello **Markdown<em>!</em>**\n***\n'), + ); + }); + }); + + group('test InlineSyntax caseSensitive parameter', () { + const text = 'one BREAK two'; + + test('with caseSensitive enabled', () { + final result = markdownToHtml( + text, + inlineOnly: true, + inlineSyntaxes: [_BreakSyntax(true)], + ); + + expect(result, equals('one BREAK two')); + }); + + test('with caseSensitive disabled', () { + final result = markdownToHtml( + text, + inlineOnly: true, + inlineSyntaxes: [_BreakSyntax(false)], + ); + + expect(result, equals('one <break /> two')); + }); + }); +} + +class _BreakSyntax extends InlineSyntax { + _BreakSyntax(bool caseSensitive) + : super('break', caseSensitive: caseSensitive); + + @override + bool onMatch(InlineParser parser, Match match) { + parser.addNode(Element.empty('break')); + return true; + } +} diff --git a/pkgs/markdown/test/markdown_test.dart b/pkgs/markdown/test/markdown_test.dart new file mode 100644 index 000000000..feb2d7705 --- /dev/null +++ b/pkgs/markdown/test/markdown_test.dart @@ -0,0 +1,306 @@ +// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@TestOn('vm') +library; + +import 'package:markdown/markdown.dart'; +import 'package:test/test.dart'; + +import 'util.dart'; + +void main() async { + testDirectory('original'); + + // Block syntax extensions. + testFile( + 'extensions/fenced_blockquotes.unit', + blockSyntaxes: [const FencedBlockquoteSyntax()], + ); + testFile( + 'extensions/fenced_code_blocks.unit', + blockSyntaxes: [const FencedCodeBlockSyntax()], + ); + testFile( + 'extensions/headers_with_ids.unit', + blockSyntaxes: [const HeaderWithIdSyntax()], + ); + testFile( + 'extensions/ordered_list_with_checkboxes.unit', + blockSyntaxes: [const OrderedListWithCheckboxSyntax()], + ); + testFile( + 'extensions/setext_headers_with_ids.unit', + blockSyntaxes: [const SetextHeaderWithIdSyntax()], + ); + testFile( + 'extensions/tables.unit', + blockSyntaxes: [const TableSyntax()], + ); + testFile( + 'extensions/unordered_list_with_checkboxes.unit', + blockSyntaxes: [const UnorderedListWithCheckboxSyntax()], + ); + testFile( + 'extensions/alert_extension.unit', + blockSyntaxes: [const AlertBlockSyntax()], + ); + + // Inline syntax extensions + testFile( + 'extensions/autolink_extension.unit', + inlineSyntaxes: [AutolinkExtensionSyntax()], + ); + + testFile( + 'extensions/emojis.unit', + inlineSyntaxes: [EmojiSyntax()], + ); + testFile( + 'extensions/inline_html.unit', + inlineSyntaxes: [InlineHtmlSyntax()], + ); + testFile( + 'extensions/strikethrough.unit', + inlineSyntaxes: [StrikethroughSyntax()], + ); + testFile( + 'extensions/footnote_block.unit', + blockSyntaxes: [const FootnoteDefSyntax()], + ); + + testDirectory('common_mark'); + testDirectory('gfm'); + + group('Corner cases', () { + validateCore('Incorrect Links', ''' +5 Ethernet ([Music]( +''', ''' +<p>5 Ethernet ([Music](</p> +'''); + + validateCore('Incorrect Links - Issue #623 - 1 - Bracketed link 1', ''' +[](< +''', ''' +<p>[](<</p> +'''); + + validateCore('Incorrect Links - Issue #623 - 2 - Bracketed link 2', ''' +[](<> +''', ''' +<p>[](<></p> +'''); + + validateCore('Incorrect Links - Issue #623 - 3 - Bracketed link 3', r''' +[](<\ +''', r''' +<p>[](<\</p> +'''); + + validateCore('Incorrect Links - Issue #623 - 4 - Link title 1', ''' +[](www.example.com " +''', ''' +<p>[](www.example.com "</p> +'''); + + validateCore('Incorrect Links - Issue #623 - 5 - Link title 2', r''' +[](www.example.com "\ +''', r''' +<p>[](www.example.com "\</p> +'''); + + validateCore('Incorrect Links - Issue #623 - 6 - Reference link label', r''' +[][\ +''', r''' +<p>[][\</p> +'''); + + validateCore('Escaping code block language', ''' +```"/><a/href="url">arbitrary_html</a> +``` +''', ''' +<pre><code class="language-"/><a/href="url">arbitrary_html</a>"></code></pre> +'''); + + validateCore('Unicode ellipsis as punctuation', ''' +"Connecting dot **A** to **B.**…" +''', ''' +<p>"Connecting dot <strong>A</strong> to <strong>B.</strong>…"</p> +'''); + }); + + group('Resolver', () { + Node? nyanResolver(String text, [_]) => + text.isEmpty ? null : Text('~=[,,_${text}_,,]:3'); + validateCore( + 'simple link resolver', + ''' +resolve [this] thing +''', + ''' +<p>resolve ~=[,,_this_,,]:3 thing</p> +''', + linkResolver: nyanResolver); + + validateCore( + 'simple image resolver', + ''' +resolve ![this] thing +''', + ''' +<p>resolve ~=[,,_this_,,]:3 thing</p> +''', + imageLinkResolver: nyanResolver); + + validateCore( + 'can resolve link containing inline tags', + ''' +resolve [*star* _underline_] thing +''', + ''' +<p>resolve ~=[,,_*star* _underline__,,]:3 thing</p> +''', + linkResolver: nyanResolver); + + validateCore( + 'link resolver uses un-normalized link label', + ''' +resolve [TH IS] thing +''', + ''' +<p>resolve ~=[,,_TH IS_,,]:3 thing</p> +''', + linkResolver: nyanResolver); + + validateCore( + 'can resolve escaped brackets', + r''' +resolve [\[\]] thing +''', + ''' +<p>resolve ~=[,,_[]_,,]:3 thing</p> +''', + linkResolver: nyanResolver); + + validateCore( + 'can choose to _not_ resolve something, like an empty link', + ''' +resolve [[]] thing +''', + ''' +<p>resolve ~=[,,_[]_,,]:3 thing</p> +''', + linkResolver: nyanResolver); + }); + + group('Custom inline syntax', () { + final nyanSyntax = <InlineSyntax>[TextSyntax('nyan', sub: '~=[,,_,,]:3')]; + validateCore( + 'simple inline syntax', + ''' +nyan''', + '''<p>~=[,,_,,]:3</p> +''', + inlineSyntaxes: nyanSyntax); + + validateCore( + 'dart custom links', + 'links [are<foo>] awesome', + '<p>links <a>are<foo></a> awesome</p>\n', + linkResolver: (String text, [String? _]) => Element.text( + 'a', + text.replaceAll('<', '<'), + ), + ); + + // TODO(amouravski): need more tests here for custom syntaxes, as some + // things are not quite working properly. The regexps are sometime a little + // too greedy, I think. + }); + + group('Inline only', () { + validateCore( + 'simple line', + ''' + This would normally create a paragraph. + ''', + ''' + This would normally create a paragraph. + ''', + inlineOnly: true); + validateCore( + 'strong and em', + ''' + This would _normally_ create a **paragraph**. + ''', + ''' + This would <em>normally</em> create a <strong>paragraph</strong>. + ''', + inlineOnly: true); + validateCore( + 'link', + ''' + This [link](http://www.example.com/) will work normally. + ''', + ''' + This <a href="http://www.example.com/">link</a> will work normally. + ''', + inlineOnly: true); + validateCore( + 'references do not work', + ''' + [This][] shouldn't work, though. + ''', + ''' + [This][] shouldn't work, though. + ''', + inlineOnly: true); + validateCore( + 'less than and ampersand are escaped', + ''' + < & + ''', + ''' + < & + ''', + inlineOnly: true); + validateCore( + 'keeps newlines', + ''' + This paragraph + continues after a newline. + ''', + ''' + This paragraph + continues after a newline. + ''', + inlineOnly: true); + validateCore( + 'ignores block-level markdown syntax', + ''' + 1. This will not be an <ol>. + ''', + ''' + 1. This will not be an <ol>. + ''', + inlineOnly: true); + }); + + group('ExtensionSet', () { + test( + '3 asterisks separated with spaces horizontal rule while it is ' + 'gitHubFlavored', + () { + // Because `gitHubFlavored` will put `UnorderedListWithCheckboxSyntax` + // before `HorizontalRuleSyntax`, the `* * *` will be parsed into an + // empty unordered list if `ListSyntax` does not skip the horizontal + // rule structure. + expect( + markdownToHtml('* * *', extensionSet: ExtensionSet.gitHubFlavored), + '<hr />\n', + ); + }, + ); + }); +} diff --git a/pkgs/markdown/test/original/autolinks.unit b/pkgs/markdown/test/original/autolinks.unit new file mode 100644 index 000000000..d3658e8b8 --- /dev/null +++ b/pkgs/markdown/test/original/autolinks.unit @@ -0,0 +1,10 @@ +>>> basic link +before <http://foo.com/> after + +<<< +<p>before <a href="http://foo.com/">http://foo.com/</a> after</p> +>>> handles ampersand in url +<http://foo.com/?a=1&b=2> + +<<< +<p><a href="http://foo.com/?a=1&b=2">http://foo.com/?a=1&b=2</a></p> diff --git a/pkgs/markdown/test/original/backslash_escapes.unit b/pkgs/markdown/test/original/backslash_escapes.unit new file mode 100644 index 000000000..e3446f32c --- /dev/null +++ b/pkgs/markdown/test/original/backslash_escapes.unit @@ -0,0 +1,38 @@ +>>> Escaped punctuation is indeed escaped. +Punctuations like \! and \" and \# and \$ and \% and \& and \' and \( and \) +and \* and \+ and \, and \- and \. and \/ and \: and \; and \< and \= and \> +and \? and \@ and \[ and \\ and \] and \^ and \_ and \` and \{ and \| and \} +and \~. + +<<< +<p>Punctuations like ! and " and # and $ and % and & and ' and ( and ) +and * and + and , and - and . and / and : and ; and < and = and > +and ? and @ and [ and \ and ] and ^ and _ and ` and { and | and } +and ~.</p> +>>> Inline code blocks can be escaped. +Not \`code`. + +<<< +<p>Not `code`.</p> +>>> Emphasis can be escaped. +\*Both* \_kinds_. + +<<< +<p>*Both* _kinds_.</p> +>>> Links can be escaped. +Escaped brackets: \[foo](bar), and parens: [foo]\(bar). + +<<< +<p>Escaped brackets: [foo](bar), and parens: [foo](bar).</p> +>>> Reference links can be escaped. +Front: \[foo][bar] and back: [foo]\[bar]. + +<<< +<p>Front: [foo][bar] and back: [foo][bar].</p> +>>> Images can be escaped. +Escapes the bang: \![img](img.png), +and escapes the image: !\[img](img.png). + +<<< +<p>Escapes the bang: !<a href="img.png">img</a>, +and escapes the image: ![img](img.png).</p> diff --git a/pkgs/markdown/test/original/block_level_html.unit b/pkgs/markdown/test/original/block_level_html.unit new file mode 100644 index 000000000..ce4076023 --- /dev/null +++ b/pkgs/markdown/test/original/block_level_html.unit @@ -0,0 +1,38 @@ +>>> single line +<table></table> + +<<< +<table></table> +>>> multi-line +<table> + blah +</table> + +<<< +<table> + blah +</table> +>>> blank line ends block +<table> + blah +</table> + +para + +<<< +<table> + blah +</table> +<p>para</p> +>>> HTML can be bogus +<bogus> +blah +</weird> + +para + +<<< +<bogus> +blah +</weird> +<p>para</p> diff --git a/pkgs/markdown/test/original/block_quotes.unit b/pkgs/markdown/test/original/block_quotes.unit new file mode 100644 index 000000000..548bc1aec --- /dev/null +++ b/pkgs/markdown/test/original/block_quotes.unit @@ -0,0 +1,54 @@ +>>> single line +> blah + +<<< +<blockquote> +<p>blah</p> +</blockquote> +>>> with two paragraphs +> first +> +> second + +<<< +<blockquote> +<p>first</p> +<p>second</p> +</blockquote> +>>> nested +> one +>> two +> > > three + +<<< +<blockquote> +<p>one</p> +<blockquote> +<p>two</p> +<blockquote> +<p>three</p> +</blockquote> +</blockquote> +</blockquote> +>>> qoute with lazy continuation +> quote +text +<<< +<blockquote> +<p>quote +text</p> +</blockquote> +>>> quote turns what might be an h2 into an hr +> quote +--- + +<<< +<blockquote> +<p>quote</p> +</blockquote> +<hr /> +>>> issue #495 + > +<<< +<blockquote> +</blockquote> diff --git a/pkgs/markdown/test/original/code_blocks.unit b/pkgs/markdown/test/original/code_blocks.unit new file mode 100644 index 000000000..330a90fbd --- /dev/null +++ b/pkgs/markdown/test/original/code_blocks.unit @@ -0,0 +1,65 @@ +>>> single line + code + +<<< +<pre><code>code +</code></pre> +>>> include leading whitespace after indentation + zero + one + two + three + +<<< +<pre><code>zero + one + two + three +</code></pre> +>>> code blocks separated by newlines form one block + zero + one + + two + + three + +<<< +<pre><code>zero +one + +two + +three +</code></pre> +>>> code blocks separated by two newlines form multiple blocks + zero + one + + + two + + + three + +<<< +<pre><code>zero +one + + +two + + +three +</code></pre> +>>> escape HTML characters + <&> + +<<< +<pre><code><&> +</code></pre> +>>> issue #497 + 'foo' +<<< +<pre><code>'foo' +</code></pre> diff --git a/pkgs/markdown/test/original/emphasis_and_strong.unit b/pkgs/markdown/test/original/emphasis_and_strong.unit new file mode 100644 index 000000000..13a6dd215 --- /dev/null +++ b/pkgs/markdown/test/original/emphasis_and_strong.unit @@ -0,0 +1,83 @@ +>>> single asterisks +before *em* after + +<<< +<p>before <em>em</em> after</p> +>>> single underscores +before _em_ after + +<<< +<p>before <em>em</em> after</p> +>>> double asterisks +before **strong** after + +<<< +<p>before <strong>strong</strong> after</p> +>>> double underscores +before __strong__ after + +<<< +<p>before <strong>strong</strong> after</p> +>>> unmatched asterisk +before *after + +<<< +<p>before *after</p> +>>> unmatched underscore +before _after + +<<< +<p>before _after</p> +>>> multiple spans in one text +a *one* b _two_ c + +<<< +<p>a <em>one</em> b <em>two</em> c</p> +>>> multi-line +before *first +second* after + +<<< +<p>before <em>first +second</em> after</p> +>>> not processed when surrounded by spaces +a * b * c _ d _ e + +<<< +<p>a * b * c _ d _ e</p> +>>> strong then emphasis +**strong***em* + +<<< +<p><strong>strong</strong><em>em</em></p> +>>> emphasis then strong +*em***strong** + +<<< +<p><em>em</em><strong>strong</strong></p> +>>> emphasis inside strong +**strong *em*** + +<<< +<p><strong>strong <em>em</em></strong></p> +>>> mismatched in nested +*a _b* c_ + +<<< +<p><em>a _b</em> c_</p> +>>> in the middle of a word +a_b_c a__b__c a*b*c a**b**c +<<< +<p>a_b_c a__b__c a<em>b</em>c a<strong>b</strong>c</p> +>>> prefixing a word +_a_b __a__b *a*b **a**b +<<< +<p>_a_b __a__b <em>a</em>b <strong>a</strong>b</p> +>>> suffixing a word +a_b_ a__b__ a*b* a**b** +<<< +<p>a_b_ a__b__ a<em>b</em> a<strong>b</strong></p> +>>> spanning words +_a_b c_d_ __a__b c__d__ *a*b c*d* **a**b c**d** +<<< +<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> diff --git a/pkgs/markdown/test/original/fenced_code_block.unit b/pkgs/markdown/test/original/fenced_code_block.unit new file mode 100644 index 000000000..779e747c3 --- /dev/null +++ b/pkgs/markdown/test/original/fenced_code_block.unit @@ -0,0 +1,7 @@ +>>> issue #497 +``` +'foo' +``` +<<< +<pre><code>'foo' +</code></pre> diff --git a/pkgs/markdown/test/original/hard_line_breaks.unit b/pkgs/markdown/test/original/hard_line_breaks.unit new file mode 100644 index 000000000..c8d16262f --- /dev/null +++ b/pkgs/markdown/test/original/hard_line_breaks.unit @@ -0,0 +1,40 @@ +>>> hard line break in a paragraph, using backslash +First line.\ +Second line. + +<<< +<p>First line.<br /> +Second line.</p> +>>> within emphasis, using backslash +*Emphasised\ +text.* + +<<< +<p><em>Emphasised<br /> +text.</em></p> +>>> no escape within code, using backslash +`Some\ +code`. + +<<< +<p><code>Some\ code</code>.</p> +>>> hard line break in a paragraph, using trailing spaces +First line. +Second line. + +<<< +<p>First line. +Second line.</p> +>>> within emphasis, using trailing spaces +*Emphasised +text.* + +<<< +<p><em>Emphasised +text.</em></p> +>>> no escape within code, using trailing spaces +`Some +code`. + +<<< +<p><code>Some code</code>.</p> diff --git a/pkgs/markdown/test/original/headers.unit b/pkgs/markdown/test/original/headers.unit new file mode 100644 index 000000000..928da8be7 --- /dev/null +++ b/pkgs/markdown/test/original/headers.unit @@ -0,0 +1,35 @@ +>>> h1 +# header + +<<< +<h1>header</h1> +>>> h2 +## header + +<<< +<h2>header</h2> +>>> h3 +### header + +<<< +<h3>header</h3> +>>> h4 +#### header + +<<< +<h4>header</h4> +>>> h5 +##### header + +<<< +<h5>header</h5> +>>> h6 +###### header + +<<< +<h6>header</h6> +>>> trailing "#" are removed +# header ###### + +<<< +<h1>header</h1> diff --git a/pkgs/markdown/test/original/horizontal_rules.unit b/pkgs/markdown/test/original/horizontal_rules.unit new file mode 100644 index 000000000..36642e9a3 --- /dev/null +++ b/pkgs/markdown/test/original/horizontal_rules.unit @@ -0,0 +1,20 @@ +>>> from dashes +--- + +<<< +<hr /> +>>> from asterisks +*** + +<<< +<hr /> +>>> from underscores +___ + +<<< +<hr /> +>>> can include up to two spaces +_ _ _ + +<<< +<hr /> diff --git a/pkgs/markdown/test/original/html_block.unit b/pkgs/markdown/test/original/html_block.unit new file mode 100644 index 000000000..f6b92160a --- /dev/null +++ b/pkgs/markdown/test/original/html_block.unit @@ -0,0 +1,11 @@ +>>> issue https://github.com/dart-lang/markdown/issues/547 +<?code-excerpt ?> +```xml +<q> +</q> +``` +<<< +<?code-excerpt ?> +<pre><code class="language-xml"><q> +</q> +</code></pre> \ No newline at end of file diff --git a/pkgs/markdown/test/original/html_encoding.unit b/pkgs/markdown/test/original/html_encoding.unit new file mode 100644 index 000000000..dab904383 --- /dev/null +++ b/pkgs/markdown/test/original/html_encoding.unit @@ -0,0 +1,15 @@ +>>> less than and ampersand are escaped +< & + +<<< +<p>< &</p> +>>> greater than is escaped +not you > + +<<< +<p>not you ></p> +>>> existing entities are untouched +& + +<<< +<p>&</p> diff --git a/pkgs/markdown/test/original/inline_code.unit b/pkgs/markdown/test/original/inline_code.unit new file mode 100644 index 000000000..7315931a6 --- /dev/null +++ b/pkgs/markdown/test/original/inline_code.unit @@ -0,0 +1,87 @@ +>>> simple case +before `source` after + +<<< +<p>before <code>source</code> after</p> +>>> single characters +before `x` and `_` after + +<<< +<p>before <code>x</code> and <code>_</code> after</p> +>>> unmatched backtick +before ` after + +<<< +<p>before ` after</p> +>>> multiple spans in one text +a `one` b `two` c + +<<< +<p>a <code>one</code> b <code>two</code> c</p> +>>> multi-line +before `first +second` after + +<<< +<p>before <code>first second</code> after</p> +>>> simple double backticks +before ``source`` after + +<<< +<p>before <code>source</code> after</p> +>>> even more backticks +before ````source with ``` and```` after + +<<< +<p>before <code>source with ``` and</code> after</p> +>>> double backticks +before ``can `contain` backticks`` after + +<<< +<p>before <code>can `contain` backticks</code> after</p> +>>> double backticks with spaces +before `` `tick` `` after + +<<< +<p>before <code>`tick`</code> after</p> +>>> multiline single backticks with spaces +before `in tick +another` after + +<<< +<p>before <code>in tick another</code> after</p> +>>> multiline double backticks with spaces +before ``in `tick` +another`` after + +<<< +<p>before <code>in `tick` another</code> after</p> +>>> ignore markup inside code +before `*b* _c_` after + +<<< +<p>before <code>*b* _c_</code> after</p> +>>> escape HTML characters +`<&>` + +<<< +<p><code><&></code></p> +>>> escape HTML tags +'*' `<em>` + +<<< +<p>'*' <code><em></code></p> +>>> leave unmatched backticks when first are too long +before ``` tick `` after + +<<< +<p>before ``` tick `` after</p> +>>> leave unmatched backticks when first are too short +before `` tick ``` after + +<<< +<p>before `` tick ``` after</p> +>>> issue #497 +`'foo'` +<<< +<p><code>'foo'</code></p> diff --git a/pkgs/markdown/test/original/inline_images.unit b/pkgs/markdown/test/original/inline_images.unit new file mode 100644 index 000000000..c8180ce91 --- /dev/null +++ b/pkgs/markdown/test/original/inline_images.unit @@ -0,0 +1,29 @@ +>>> image +![](http://foo.com/foo.png) + +<<< +<p><img src="http://foo.com/foo.png" alt="" /></p> +>>> alternate text +![alternate text](http://foo.com/foo.png) + +<<< +<p><img src="http://foo.com/foo.png" alt="alternate text" /></p> +>>> title +![](http://foo.com/foo.png "optional title") + +<<< +<p><img src="http://foo.com/foo.png" alt="" title="optional title" /></p> +>>> invalid alt text +![`alt`](http://foo.com/foo.png) + +<<< +<p><img src="http://foo.com/foo.png" alt="alt" /></p> +>>> XSS +![Uh oh...]("onerror="alert('XSS')) + +<<< +<p><img src="%22onerror=%22alert('XSS')" alt="Uh oh..." /></p> +>>> URL-escaping should be left alone inside the destination +![](https://example/foo%2Fvar) +<<< +<p><img src="https://example/foo%2Fvar" alt="" /></p> \ No newline at end of file diff --git a/pkgs/markdown/test/original/inline_links.unit b/pkgs/markdown/test/original/inline_links.unit new file mode 100644 index 000000000..0a40407d4 --- /dev/null +++ b/pkgs/markdown/test/original/inline_links.unit @@ -0,0 +1,87 @@ +>>> double quotes for title +links [are](http://foo.com "woo") awesome + +<<< +<p>links <a href="http://foo.com" title="woo">are</a> awesome</p> +>>> no title +links [are](http://foo.com) awesome + +<<< +<p>links <a href="http://foo.com">are</a> awesome</p> +>>> can style link contents +links [*are*](http://foo.com) awesome + +<<< +<p>links <a href="http://foo.com"><em>are</em></a> awesome</p> +>>> image inside link +links [![](/are.png)](http://foo.com) awesome + +<<< +<p>links <a href="http://foo.com"><img src="/are.png" alt="" /></a> awesome</p> +>>> image with alt inside link +links [![my alt](/are.png)](http://foo.com) awesome + +<<< +<p>links <a href="http://foo.com"><img src="/are.png" alt="my alt" /></a> awesome</p> +>>> image with title inside link +links [![](/are.png "my title")](http://foo.com) awesome + +<<< +<p>links <a href="http://foo.com"><img src="/are.png" alt="" title="my title" /></a> awesome</p> +>>> no URL +links [are]() awesome + +<<< +<p>links <a href="">are</a> awesome</p> +>>> URL wrapped in angle brackets +links [are](<http://example.com>) awesome + +<<< +<p>links <a href="http://example.com">are</a> awesome</p> +>>> URL wrapped in angle brackets with a title; https://github.com/commonmark/CommonMark/issues/521 +links [are](<http://example.com> "title") awesome + +<<< +<p>links <a href="http://example.com" title="title">are</a> awesome</p> +>>> multi-line link +links [are +awesome](<http://example.com>). + +<<< +<p>links <a href="http://example.com">are +awesome</a>.</p> +>>> multi-line link with a title +links [are](http://foo.com +"woo") awesome + +<<< +<p>links <a href="http://foo.com" title="woo">are</a> awesome</p> +>>> not a real link +links [are] (http://foo.com) awesome + +<<< +<p>links [are] (http://foo.com) awesome</p> +>>> resolver link without a resolver +links [are *awesome*] + +<<< +<p>links [are <em>awesome</em>]</p> +>>> links with escaped parens +[a](\(yes-a-link) +[a](\(yes-a-link\)) +[a](\\(not-a-link\)) +[a](\\(yes-a-link\))) +<<< +<p><a href="(yes-a-link">a</a> +<a href="(yes-a-link)">a</a> +[a](\(not-a-link)) +<a href="(yes-a-link))">a</a></p> +>>> links with unbalanced parentheses +[foo](link(1.png) (what?) +<<< +<p>[foo](link(1.png) (what?)</p> +>>> not an inline link: the title's ending quote is escaped +links [are](<http://example.com> "title\") awesome + +<<< +<p>links [are](<a href="http://example.com">http://example.com</a> "title") awesome</p> \ No newline at end of file diff --git a/pkgs/markdown/test/original/ordered_lists.unit b/pkgs/markdown/test/original/ordered_lists.unit new file mode 100644 index 000000000..8156889b6 --- /dev/null +++ b/pkgs/markdown/test/original/ordered_lists.unit @@ -0,0 +1,49 @@ +>>> ordered list with multiple items +1. one +2. two +10. ten +<<< +<ol> +<li>one</li> +<li>two</li> +<li>ten</li> +</ol> +>>> ordered list with almost nested item +1. one +45. two + 12345. three + +<<< +<ol> +<li>one</li> +<li>two</li> +<li>three</li> +</ol> +>>> nested ordered lists +1. one +2. two + 3. three + 4. four +5. five +<<< +<ol> +<li>one</li> +<li>two +<ol start="3"> +<li>three</li> +<li>four</li> +</ol> +</li> +<li>five</li> +</ol> +>>> new list markers start new lists +1. a +* b + +<<< +<ol> +<li>a</li> +</ol> +<ul> +<li>b</li> +</ul> diff --git a/pkgs/markdown/test/original/paragraphs.unit b/pkgs/markdown/test/original/paragraphs.unit new file mode 100644 index 000000000..a20a55696 --- /dev/null +++ b/pkgs/markdown/test/original/paragraphs.unit @@ -0,0 +1,55 @@ +>>> consecutive lines form a single paragraph +This is the first line. +This is the second line. + +<<< +<p>This is the first line. +This is the second line.</p> +>>> are terminated by a header +para +# header + +<<< +<p>para</p> +<h1>header</h1> +>>> are terminated by a hr +para +___ + +<<< +<p>para</p> +<hr /> +>>> are terminated by an unordered list +para +* list + +<<< +<p>para</p> +<ul> +<li>list</li> +</ul> +>>> are terminated by an ordered list +para +1. list + +<<< +<p>para</p> +<ol> +<li>list</li> +</ol> +>>> take account of windows line endings +line1 + +line2 + + +<<< +<p>line1</p> +<p>line2</p> +>>> cannot be terminated by indented code blocks +para + not code + +<<< +<p>para +not code</p> diff --git a/pkgs/markdown/test/original/reference_images.unit b/pkgs/markdown/test/original/reference_images.unit new file mode 100644 index 000000000..b098d24bd --- /dev/null +++ b/pkgs/markdown/test/original/reference_images.unit @@ -0,0 +1,34 @@ +>>> image +![][foo] + +[foo]: http://foo.com/foo.png + +<<< +<p><img src="http://foo.com/foo.png" alt="" /></p> +>>> alternate text +![alternate text][foo] + +[foo]: http://foo.com/foo.png + +<<< +<p><img src="http://foo.com/foo.png" alt="alternate text" /></p> +>>> title +![][foo] + +[foo]: http://foo.com/foo.png "optional title" + +<<< +<p><img src="http://foo.com/foo.png" alt="" title="optional title" /></p> +>>> invalid alt text +![`alt`][foo] + +[foo]: http://foo.com/foo.png "optional title" + +<<< +<p><img src="http://foo.com/foo.png" alt="alt" title="optional title" /></p> +>>> shortcut reference image +![foo] + +[foo]: http://foo.com/foo.png +<<< +<p><img src="http://foo.com/foo.png" alt="foo" /></p> diff --git a/pkgs/markdown/test/original/reference_links.unit b/pkgs/markdown/test/original/reference_links.unit new file mode 100644 index 000000000..bc3e3369b --- /dev/null +++ b/pkgs/markdown/test/original/reference_links.unit @@ -0,0 +1,100 @@ +>>> double quotes for title +links [are][a] awesome + +[a]: http://foo.com "woo" + +<<< +<p>links <a href="http://foo.com" title="woo">are</a> awesome</p> +>>> single quoted title +links [are][a] awesome + +[a]: http://foo.com 'woo' + +<<< +<p>links <a href="http://foo.com" title="woo">are</a> awesome</p> +>>> parentheses for title +links [are][a] awesome + +[a]: http://foo.com (woo) + +<<< +<p>links <a href="http://foo.com" title="woo">are</a> awesome</p> +>>> no title +links [are][a] awesome + +[a]: http://foo.com + +<<< +<p>links <a href="http://foo.com">are</a> awesome</p> +>>> unknown link becomes plaintext +[not] [known] + +<<< +<p>[not] [known]</p> +>>> can style link contents +links [*are*][a] awesome + +[a]: http://foo.com + +<<< +<p>links <a href="http://foo.com"><em>are</em></a> awesome</p> +>>> inline styles after a bad link are processed +[bad] `code` + +<<< +<p>[bad] <code>code</code></p> +>>> empty reference uses text from link +links [are][] awesome + +[are]: http://foo.com + +<<< +<p>links <a href="http://foo.com">are</a> awesome</p> +>>> references are case-insensitive +links [ARE][] awesome + +[are]: http://foo.com + +<<< +<p>links <a href="http://foo.com">ARE</a> awesome</p> +>>> shortcut reference links +links [are] awesome + +[are]: http://foo.com +<<< +<p>links <a href="http://foo.com">are</a> awesome</p> +>>> reference definitions can span lines +links [are] [awesome] + +[are]: +http://foo.com +[awesome]: +http://bar.com +"Long +Title" +<<< +<p>links <a href="http://foo.com">are</a> <a href="http://bar.com" title="Long +Title">awesome</a></p> +>>> references can be defined in blocks +> links [are] awesome +> +> [are]: http://foo.com +<<< +<blockquote> +<p>links <a href="http://foo.com">are</a> awesome</p> +</blockquote> +>>> reference link regression for github.com/dart-lang/markdown/issues/176 +[![Coverage Status][coverage_status]][coverage_page] + +[coverage_page]:https://coveralls.io/github/yeradis/stay_points.dart?branch=master +[coverage_status]: https://coveralls.io/repos/github/yeradis/stay_points.dart/badge.svg?branch=master +<<< +<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> +>>> compressed reference link label is normalized +Text [foo +bar][]. + +[foo bar]: http://bar.com +<<< +<p>Text <a href="http://bar.com">foo +bar</a>.</p> diff --git a/pkgs/markdown/test/original/setext_headers.unit b/pkgs/markdown/test/original/setext_headers.unit new file mode 100644 index 000000000..f094801e6 --- /dev/null +++ b/pkgs/markdown/test/original/setext_headers.unit @@ -0,0 +1,32 @@ +>>> h1 +text +=== + +<<< +<h1>text</h1> +>>> h2 +text +--- + +<<< +<h2>text</h2> +>>> h1 bar on first line becomes text +=== + +<<< +<p>===</p> +>>> h2 bar on first line becomes list +- + +<<< +<ul> +<li></li> +</ul> +>>> can be multiline +header +on two lines +== + +<<< +<h1>header +on two lines</h1> diff --git a/pkgs/markdown/test/original/strong.unit b/pkgs/markdown/test/original/strong.unit new file mode 100644 index 000000000..e558424aa --- /dev/null +++ b/pkgs/markdown/test/original/strong.unit @@ -0,0 +1,32 @@ +>>> using asterisks +before **strong** after + +<<< +<p>before <strong>strong</strong> after</p> +>>> using underscores +before __strong__ after + +<<< +<p>before <strong>strong</strong> after</p> +>>> unmatched asterisks +before ** after + +<<< +<p>before ** after</p> +>>> unmatched underscores +before __ after + +<<< +<p>before __ after</p> +>>> multiple spans in one text +a **one** b __two__ c + +<<< +<p>a <strong>one</strong> b <strong>two</strong> c</p> +>>> multi-line +before **first +second** after + +<<< +<p>before <strong>first +second</strong> after</p> diff --git a/pkgs/markdown/test/original/unordered_lists.unit b/pkgs/markdown/test/original/unordered_lists.unit new file mode 100644 index 000000000..601777511 --- /dev/null +++ b/pkgs/markdown/test/original/unordered_lists.unit @@ -0,0 +1,151 @@ +>>> asterisk, plus and hyphen +* star +- dash ++ plus + +<<< +<ul> +<li>star</li> +</ul> +<ul> +<li>dash</li> +</ul> +<ul> +<li>plus</li> +</ul> +>>> new markers begin new lists +* a +1. b + +<<< +<ul> +<li>a</li> +</ul> +<ol> +<li>b</li> +</ol> +>>> allow a tab after the marker +* a +1. b + +<<< +<ul> +<li>a</li> +</ul> +<ol> +<li>b</li> +</ol> +>>> wrap items in paragraphs if blank lines separate +* one + +* two + +<<< +<ul> +<li> +<p>one</p> +</li> +<li> +<p>two</p> +</li> +</ul> +>>> force paragraph on item before and after blank lines +* one +* two + +* three + +<<< +<ul> +<li> +<p>one</p> +</li> +<li> +<p>two</p> +</li> +<li> +<p>three</p> +</li> +</ul> +>>> do not force paragraph if item is already block +* > quote + +* # header + +<<< +<ul> +<li> +<blockquote> +<p>quote</p> +</blockquote> +</li> +<li> +<h1>header</h1> +</li> +</ul> +>>> can contain multiple paragraphs +* one + + two + +* three + +<<< +<ul> +<li> +<p>one</p> +<p>two</p> +</li> +<li> +<p>three</p> +</li> +</ul> +>>> can span newlines +* one + two +* three + +<<< +<ul> +<li>one +two</li> +<li>three</li> +</ul> +>>> can nest lists +* one + * nested one + * nested two + +* two + +<<< +<ul> +<li> +<p>one</p> +<ul> +<li>nested one</li> +<li>nested two</li> +</ul> +</li> +<li> +<p>two</p> +</li> +</ul> +>>> list item allows lazy continuations +- list +item + +<<< +<ul> +<li>list +item</li> +</ul> +>>> list item turns what might be an h2 into nothing +- list +--- + +<<< +<ul> +<li>list</li> +</ul> +<hr /> diff --git a/pkgs/markdown/test/util.dart b/pkgs/markdown/test/util.dart new file mode 100644 index 000000000..3d7dc6ad7 --- /dev/null +++ b/pkgs/markdown/test/util.dart @@ -0,0 +1,124 @@ +// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:io/ansi.dart' as ansi; +import 'package:markdown/markdown.dart'; +import 'package:path/path.dart' as p; +import 'package:test/test.dart'; + +import '../tool/expected_output.dart'; + +/// Runs tests defined in "*.unit" files inside directory [name]. +void testDirectory(String name, {ExtensionSet? extensionSet}) { + for (final dataCase in dataCasesUnder(testDirectory: name)) { + final description = + '${dataCase.directory}/${dataCase.file}.unit ${dataCase.description}'; + + final inlineSyntaxes = <InlineSyntax>[]; + final blockSyntaxes = <BlockSyntax>[]; + var enableTagfilter = false; + + if (dataCase.file.endsWith('_extension')) { + final extension = dataCase.file.substring( + 0, + dataCase.file.lastIndexOf('_extension'), + ); + switch (extension) { + case 'autolinks': + inlineSyntaxes.add(AutolinkExtensionSyntax()); + break; + case 'strikethrough': + inlineSyntaxes.add(StrikethroughSyntax()); + break; + case 'tables': + blockSyntaxes.add(const TableSyntax()); + break; + case 'disallowed_raw_html': + enableTagfilter = true; + break; + default: + throw UnimplementedError('Unimplemented extension "$extension"'); + } + } + + validateCore( + description, + dataCase.input, + dataCase.expectedOutput, + extensionSet: extensionSet, + inlineSyntaxes: inlineSyntaxes, + blockSyntaxes: blockSyntaxes, + enableTagfilter: enableTagfilter, + ); + } +} + +void testFile( + String file, { + Iterable<BlockSyntax> blockSyntaxes = const [], + Iterable<InlineSyntax> inlineSyntaxes = const [], +}) { + for (final dataCase + in dataCasesInFile(path: p.join(p.current, 'test', file))) { + final description = + '${dataCase.directory}/${dataCase.file}.unit ${dataCase.description}'; + validateCore( + description, + dataCase.input, + dataCase.expectedOutput, + blockSyntaxes: blockSyntaxes, + inlineSyntaxes: inlineSyntaxes, + ); + } +} + +void validateCore( + String description, + String markdown, + String html, { + Iterable<BlockSyntax> blockSyntaxes = const [], + Iterable<InlineSyntax> inlineSyntaxes = const [], + ExtensionSet? extensionSet, + Resolver? linkResolver, + Resolver? imageLinkResolver, + bool inlineOnly = false, + bool enableTagfilter = false, +}) { + test(description, () { + final result = markdownToHtml( + markdown, + blockSyntaxes: blockSyntaxes, + inlineSyntaxes: inlineSyntaxes, + extensionSet: extensionSet, + linkResolver: linkResolver, + imageLinkResolver: imageLinkResolver, + inlineOnly: inlineOnly, + enableTagfilter: enableTagfilter, + ); + + markdownPrintOnFailure(markdown, html, result); + + expect(result, html); + }); +} + +String whitespaceColor(String input) => input + .replaceAll(' ', ansi.lightBlue.wrap('·')!) + .replaceAll('\t', ansi.backgroundDarkGray.wrap('\t')!); + +void markdownPrintOnFailure(String markdown, String expected, String actual) { + printOnFailure(""" +INPUT: +'''r +${whitespaceColor(markdown)}''' + +EXPECTED: +'''r +${whitespaceColor(expected)}''' + +GOT: +'''r +${whitespaceColor(actual)}''' +"""); +} diff --git a/pkgs/markdown/test/util_test.dart b/pkgs/markdown/test/util_test.dart new file mode 100644 index 000000000..5a2108a5e --- /dev/null +++ b/pkgs/markdown/test/util_test.dart @@ -0,0 +1,86 @@ +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:markdown/markdown.dart'; +import 'package:markdown/src/util.dart'; +import 'package:test/test.dart'; + +void main() { + group('String.toLines()', () { + test('a single line without a line ending', () { + const text = 'Foo'; + final lines = text.toLines(); + + expect(lines.map((e) => e.toMap()), [ + { + 'content': 'Foo', + 'isBlankLine': false, + } + ]); + }); + + test('a single line with a line ending', () { + const text = 'Foo\n'; + final lines = text.toLines(); + + expect(lines.map((e) => e.toMap()), [ + { + 'content': 'Foo', + 'isBlankLine': false, + }, + ]); + }); + + test('multiple lines with a blank line in between', () { + const text = 'Foo\r\n\nBar'; + final lines = text.toLines(); + + expect(lines.map((e) => e.toMap()), [ + { + 'content': 'Foo', + 'isBlankLine': false, + }, + { + 'content': '', + 'isBlankLine': true, + }, + { + 'content': 'Bar', + 'isBlankLine': false, + } + ]); + }); + }); + + group('String.indentation()', () { + test('only spaces', () { + expect(' '.indentation(), 3); + expect(' '.indentation(), 4); + expect(' '.indentation(), 5); + }); + + test('spaces and tabs', () { + expect('\t '.indentation(), 6); + expect(' \t '.indentation(), 5); + expect(' \t'.indentation(), 4); + expect('\t\t '.indentation(), 10); + expect(' \t\t '.indentation(), 9); + expect(' \t\t'.indentation(), 8); + }); + + test('spaces, tabs and non whitespace characters', () { + expect('\t foo'.indentation(), 6); + expect(' \t foo'.indentation(), 5); + expect(' \tfoo'.indentation(), 4); + }); + }); +} + +extension on Line { + Map<String, dynamic> toMap() => { + 'content': content, + 'isBlankLine': isBlankLine, + if (tabRemaining != null) 'tabRemaining': tabRemaining, + }; +} diff --git a/pkgs/markdown/test/version_test.dart b/pkgs/markdown/test/version_test.dart new file mode 100644 index 000000000..93fedcb13 --- /dev/null +++ b/pkgs/markdown/test/version_test.dart @@ -0,0 +1,41 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@TestOn('vm') +library; + +import 'dart:io'; + +import 'package:path/path.dart' as p; +import 'package:test/test.dart'; +import 'package:yaml/yaml.dart'; + +void main() { + test('check versions', () async { + final binary = p.join(p.current, 'bin', 'markdown.dart'); + final dartBin = Platform.executable; + final result = Process.runSync(dartBin, [binary, '--version']); + expect( + result.exitCode, + 0, + reason: 'Exit code expected: 0; actual: ${result.exitCode}\n\n' + 'stdout: ${result.stdout}\n\n' + 'stderr: ${result.stderr}', + ); + + final binVersion = (result.stdout as String).trim(); + + final pubspecFile = p.join(p.current, 'pubspec.yaml'); + + final pubspecContent = + loadYaml(File(pubspecFile).readAsStringSync()) as YamlMap; + + expect( + binVersion, + pubspecContent['version'], + reason: 'The version reported by bin/markdown.dart should match the ' + 'version in pubspec. Run `dart run build_runner build` to update.', + ); + }); +} diff --git a/pkgs/markdown/tool/README.md b/pkgs/markdown/tool/README.md new file mode 100644 index 000000000..ff2f74909 --- /dev/null +++ b/pkgs/markdown/tool/README.md @@ -0,0 +1,48 @@ +# Developer Tools + +This directory contains tools for developers of the Dart markdown package. + +## dartdoc_compare.dart + +When you make a change to the package that might have subtle consequences on +how Markdown is parsed, it would be really great to see how your output compares +to the previous output, on a large collection of Markdown. + +One such collection is the Dartdoc comments of any Dart package, which [dartdoc] +translates into HTML, with the help of this markdown package. You can use the +`dartdoc_compare.dart` script to compare what changes your code will make to +dartdoc's output. Here's how it works: + +1. Clone the [dartdoc git repository]. +2. Get a copy of some Dart code that you would like to use for the comparison. +3. Run the `dartdoc_compare.dart` script like so: + + ``` + $ dart tool/dartdoc_compare.dart \ + --dartdoc-dir=<dartdoc repo> \ + --before=<git SHA of "previous" code> \ + <directory of dart code for comparison> + ``` + +4. The tool will then walk through the following steps: + + 1. cd into the dartdoc directory, change `pubspec.yaml` to depend on your + "before" version of markdown, and run `pub get`. + 2. cd into the directory of dart code, and run `pub get`. + 3. Run dartdoc. + 4. cd back into the dartdoc directory, change `pubspec.yaml` to depend on + your "after" version of markdown (defaults to HEAD), and run `pub get`. + 5. Repeat steps 2 and 3. + 6. Diff the output of steps 3 and 5, and show you how to diff it yourself. + +[dartdoc]: https://pub.dev/packages/dartdoc +[dartdoc git repository]: https://github.com/dart-lang/dartdoc + +## stats.dart + +In an effort to make this package CommonMark-compliant, we have a script that +runs the package through the CommonMark specs. To see help: + +```bash +$ dart tool/stats.dart --help +``` diff --git a/pkgs/markdown/tool/case_folding.txt b/pkgs/markdown/tool/case_folding.txt new file mode 100644 index 000000000..932ace29e --- /dev/null +++ b/pkgs/markdown/tool/case_folding.txt @@ -0,0 +1,1624 @@ +# CaseFolding-14.0.0.txt +# Date: 2021-03-08, 19:35:41 GMT +# © 2021 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# Unicode Character Database +# For documentation, see http://www.unicode.org/reports/tr44/ +# +# Case Folding Properties +# +# This file is a supplement to the UnicodeData file. +# It provides a case folding mapping generated from the Unicode Character Database. +# If all characters are mapped according to the full mapping below, then +# case differences (according to UnicodeData.txt and SpecialCasing.txt) +# are eliminated. +# +# The data supports both implementations that require simple case foldings +# (where string lengths don't change), and implementations that allow full case folding +# (where string lengths may grow). Note that where they can be supported, the +# full case foldings are superior: for example, they allow "MASSE" and "Maße" to match. +# +# All code points not listed in this file map to themselves. +# +# NOTE: case folding does not preserve normalization formats! +# +# For information on case folding, including how to have case folding +# preserve normalization formats, see Section 3.13 Default Case Algorithms in +# The Unicode Standard. +# +# ================================================================================ +# Format +# ================================================================================ +# The entries in this file are in the following machine-readable format: +# +# <code>; <status>; <mapping>; # <name> +# +# The status field is: +# C: common case folding, common mappings shared by both simple and full mappings. +# F: full case folding, mappings that cause strings to grow in length. Multiple characters are separated by spaces. +# S: simple case folding, mappings to single characters where different from F. +# T: special case for uppercase I and dotted uppercase I +# - For non-Turkic languages, this mapping is normally not used. +# - For Turkic languages (tr, az), this mapping can be used instead of the normal mapping for these characters. +# Note that the Turkic mappings do not maintain canonical equivalence without additional processing. +# See the discussions of case mapping in the Unicode Standard for more information. +# +# Usage: +# A. To do a simple case folding, use the mappings with status C + S. +# B. To do a full case folding, use the mappings with status C + F. +# +# The mappings with status T can be used or omitted depending on the desired case-folding +# behavior. (The default option is to exclude them.) +# +# ================================================================= + +# Property: Case_Folding + +# All code points not explicitly listed for Case_Folding +# have the value C for the status field, and the code point itself for the mapping field. + +# ================================================================= +0041; C; 0061; # LATIN CAPITAL LETTER A +0042; C; 0062; # LATIN CAPITAL LETTER B +0043; C; 0063; # LATIN CAPITAL LETTER C +0044; C; 0064; # LATIN CAPITAL LETTER D +0045; C; 0065; # LATIN CAPITAL LETTER E +0046; C; 0066; # LATIN CAPITAL LETTER F +0047; C; 0067; # LATIN CAPITAL LETTER G +0048; C; 0068; # LATIN CAPITAL LETTER H +0049; C; 0069; # LATIN CAPITAL LETTER I +0049; T; 0131; # LATIN CAPITAL LETTER I +004A; C; 006A; # LATIN CAPITAL LETTER J +004B; C; 006B; # LATIN CAPITAL LETTER K +004C; C; 006C; # LATIN CAPITAL LETTER L +004D; C; 006D; # LATIN CAPITAL LETTER M +004E; C; 006E; # LATIN CAPITAL LETTER N +004F; C; 006F; # LATIN CAPITAL LETTER O +0050; C; 0070; # LATIN CAPITAL LETTER P +0051; C; 0071; # LATIN CAPITAL LETTER Q +0052; C; 0072; # LATIN CAPITAL LETTER R +0053; C; 0073; # LATIN CAPITAL LETTER S +0054; C; 0074; # LATIN CAPITAL LETTER T +0055; C; 0075; # LATIN CAPITAL LETTER U +0056; C; 0076; # LATIN CAPITAL LETTER V +0057; C; 0077; # LATIN CAPITAL LETTER W +0058; C; 0078; # LATIN CAPITAL LETTER X +0059; C; 0079; # LATIN CAPITAL LETTER Y +005A; C; 007A; # LATIN CAPITAL LETTER Z +00B5; C; 03BC; # MICRO SIGN +00C0; C; 00E0; # LATIN CAPITAL LETTER A WITH GRAVE +00C1; C; 00E1; # LATIN CAPITAL LETTER A WITH ACUTE +00C2; C; 00E2; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX +00C3; C; 00E3; # LATIN CAPITAL LETTER A WITH TILDE +00C4; C; 00E4; # LATIN CAPITAL LETTER A WITH DIAERESIS +00C5; C; 00E5; # LATIN CAPITAL LETTER A WITH RING ABOVE +00C6; C; 00E6; # LATIN CAPITAL LETTER AE +00C7; C; 00E7; # LATIN CAPITAL LETTER C WITH CEDILLA +00C8; C; 00E8; # LATIN CAPITAL LETTER E WITH GRAVE +00C9; C; 00E9; # LATIN CAPITAL LETTER E WITH ACUTE +00CA; C; 00EA; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX +00CB; C; 00EB; # LATIN CAPITAL LETTER E WITH DIAERESIS +00CC; C; 00EC; # LATIN CAPITAL LETTER I WITH GRAVE +00CD; C; 00ED; # LATIN CAPITAL LETTER I WITH ACUTE +00CE; C; 00EE; # LATIN CAPITAL LETTER I WITH CIRCUMFLEX +00CF; C; 00EF; # LATIN CAPITAL LETTER I WITH DIAERESIS +00D0; C; 00F0; # LATIN CAPITAL LETTER ETH +00D1; C; 00F1; # LATIN CAPITAL LETTER N WITH TILDE +00D2; C; 00F2; # LATIN CAPITAL LETTER O WITH GRAVE +00D3; C; 00F3; # LATIN CAPITAL LETTER O WITH ACUTE +00D4; C; 00F4; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX +00D5; C; 00F5; # LATIN CAPITAL LETTER O WITH TILDE +00D6; C; 00F6; # LATIN CAPITAL LETTER O WITH DIAERESIS +00D8; C; 00F8; # LATIN CAPITAL LETTER O WITH STROKE +00D9; C; 00F9; # LATIN CAPITAL LETTER U WITH GRAVE +00DA; C; 00FA; # LATIN CAPITAL LETTER U WITH ACUTE +00DB; C; 00FB; # LATIN CAPITAL LETTER U WITH CIRCUMFLEX +00DC; C; 00FC; # LATIN CAPITAL LETTER U WITH DIAERESIS +00DD; C; 00FD; # LATIN CAPITAL LETTER Y WITH ACUTE +00DE; C; 00FE; # LATIN CAPITAL LETTER THORN +00DF; F; 0073 0073; # LATIN SMALL LETTER SHARP S +0100; C; 0101; # LATIN CAPITAL LETTER A WITH MACRON +0102; C; 0103; # LATIN CAPITAL LETTER A WITH BREVE +0104; C; 0105; # LATIN CAPITAL LETTER A WITH OGONEK +0106; C; 0107; # LATIN CAPITAL LETTER C WITH ACUTE +0108; C; 0109; # LATIN CAPITAL LETTER C WITH CIRCUMFLEX +010A; C; 010B; # LATIN CAPITAL LETTER C WITH DOT ABOVE +010C; C; 010D; # LATIN CAPITAL LETTER C WITH CARON +010E; C; 010F; # LATIN CAPITAL LETTER D WITH CARON +0110; C; 0111; # LATIN CAPITAL LETTER D WITH STROKE +0112; C; 0113; # LATIN CAPITAL LETTER E WITH MACRON +0114; C; 0115; # LATIN CAPITAL LETTER E WITH BREVE +0116; C; 0117; # LATIN CAPITAL LETTER E WITH DOT ABOVE +0118; C; 0119; # LATIN CAPITAL LETTER E WITH OGONEK +011A; C; 011B; # LATIN CAPITAL LETTER E WITH CARON +011C; C; 011D; # LATIN CAPITAL LETTER G WITH CIRCUMFLEX +011E; C; 011F; # LATIN CAPITAL LETTER G WITH BREVE +0120; C; 0121; # LATIN CAPITAL LETTER G WITH DOT ABOVE +0122; C; 0123; # LATIN CAPITAL LETTER G WITH CEDILLA +0124; C; 0125; # LATIN CAPITAL LETTER H WITH CIRCUMFLEX +0126; C; 0127; # LATIN CAPITAL LETTER H WITH STROKE +0128; C; 0129; # LATIN CAPITAL LETTER I WITH TILDE +012A; C; 012B; # LATIN CAPITAL LETTER I WITH MACRON +012C; C; 012D; # LATIN CAPITAL LETTER I WITH BREVE +012E; C; 012F; # LATIN CAPITAL LETTER I WITH OGONEK +0130; F; 0069 0307; # LATIN CAPITAL LETTER I WITH DOT ABOVE +0130; T; 0069; # LATIN CAPITAL LETTER I WITH DOT ABOVE +0132; C; 0133; # LATIN CAPITAL LIGATURE IJ +0134; C; 0135; # LATIN CAPITAL LETTER J WITH CIRCUMFLEX +0136; C; 0137; # LATIN CAPITAL LETTER K WITH CEDILLA +0139; C; 013A; # LATIN CAPITAL LETTER L WITH ACUTE +013B; C; 013C; # LATIN CAPITAL LETTER L WITH CEDILLA +013D; C; 013E; # LATIN CAPITAL LETTER L WITH CARON +013F; C; 0140; # LATIN CAPITAL LETTER L WITH MIDDLE DOT +0141; C; 0142; # LATIN CAPITAL LETTER L WITH STROKE +0143; C; 0144; # LATIN CAPITAL LETTER N WITH ACUTE +0145; C; 0146; # LATIN CAPITAL LETTER N WITH CEDILLA +0147; C; 0148; # LATIN CAPITAL LETTER N WITH CARON +0149; F; 02BC 006E; # LATIN SMALL LETTER N PRECEDED BY APOSTROPHE +014A; C; 014B; # LATIN CAPITAL LETTER ENG +014C; C; 014D; # LATIN CAPITAL LETTER O WITH MACRON +014E; C; 014F; # LATIN CAPITAL LETTER O WITH BREVE +0150; C; 0151; # LATIN CAPITAL LETTER O WITH DOUBLE ACUTE +0152; C; 0153; # LATIN CAPITAL LIGATURE OE +0154; C; 0155; # LATIN CAPITAL LETTER R WITH ACUTE +0156; C; 0157; # LATIN CAPITAL LETTER R WITH CEDILLA +0158; C; 0159; # LATIN CAPITAL LETTER R WITH CARON +015A; C; 015B; # LATIN CAPITAL LETTER S WITH ACUTE +015C; C; 015D; # LATIN CAPITAL LETTER S WITH CIRCUMFLEX +015E; C; 015F; # LATIN CAPITAL LETTER S WITH CEDILLA +0160; C; 0161; # LATIN CAPITAL LETTER S WITH CARON +0162; C; 0163; # LATIN CAPITAL LETTER T WITH CEDILLA +0164; C; 0165; # LATIN CAPITAL LETTER T WITH CARON +0166; C; 0167; # LATIN CAPITAL LETTER T WITH STROKE +0168; C; 0169; # LATIN CAPITAL LETTER U WITH TILDE +016A; C; 016B; # LATIN CAPITAL LETTER U WITH MACRON +016C; C; 016D; # LATIN CAPITAL LETTER U WITH BREVE +016E; C; 016F; # LATIN CAPITAL LETTER U WITH RING ABOVE +0170; C; 0171; # LATIN CAPITAL LETTER U WITH DOUBLE ACUTE +0172; C; 0173; # LATIN CAPITAL LETTER U WITH OGONEK +0174; C; 0175; # LATIN CAPITAL LETTER W WITH CIRCUMFLEX +0176; C; 0177; # LATIN CAPITAL LETTER Y WITH CIRCUMFLEX +0178; C; 00FF; # LATIN CAPITAL LETTER Y WITH DIAERESIS +0179; C; 017A; # LATIN CAPITAL LETTER Z WITH ACUTE +017B; C; 017C; # LATIN CAPITAL LETTER Z WITH DOT ABOVE +017D; C; 017E; # LATIN CAPITAL LETTER Z WITH CARON +017F; C; 0073; # LATIN SMALL LETTER LONG S +0181; C; 0253; # LATIN CAPITAL LETTER B WITH HOOK +0182; C; 0183; # LATIN CAPITAL LETTER B WITH TOPBAR +0184; C; 0185; # LATIN CAPITAL LETTER TONE SIX +0186; C; 0254; # LATIN CAPITAL LETTER OPEN O +0187; C; 0188; # LATIN CAPITAL LETTER C WITH HOOK +0189; C; 0256; # LATIN CAPITAL LETTER AFRICAN D +018A; C; 0257; # LATIN CAPITAL LETTER D WITH HOOK +018B; C; 018C; # LATIN CAPITAL LETTER D WITH TOPBAR +018E; C; 01DD; # LATIN CAPITAL LETTER REVERSED E +018F; C; 0259; # LATIN CAPITAL LETTER SCHWA +0190; C; 025B; # LATIN CAPITAL LETTER OPEN E +0191; C; 0192; # LATIN CAPITAL LETTER F WITH HOOK +0193; C; 0260; # LATIN CAPITAL LETTER G WITH HOOK +0194; C; 0263; # LATIN CAPITAL LETTER GAMMA +0196; C; 0269; # LATIN CAPITAL LETTER IOTA +0197; C; 0268; # LATIN CAPITAL LETTER I WITH STROKE +0198; C; 0199; # LATIN CAPITAL LETTER K WITH HOOK +019C; C; 026F; # LATIN CAPITAL LETTER TURNED M +019D; C; 0272; # LATIN CAPITAL LETTER N WITH LEFT HOOK +019F; C; 0275; # LATIN CAPITAL LETTER O WITH MIDDLE TILDE +01A0; C; 01A1; # LATIN CAPITAL LETTER O WITH HORN +01A2; C; 01A3; # LATIN CAPITAL LETTER OI +01A4; C; 01A5; # LATIN CAPITAL LETTER P WITH HOOK +01A6; C; 0280; # LATIN LETTER YR +01A7; C; 01A8; # LATIN CAPITAL LETTER TONE TWO +01A9; C; 0283; # LATIN CAPITAL LETTER ESH +01AC; C; 01AD; # LATIN CAPITAL LETTER T WITH HOOK +01AE; C; 0288; # LATIN CAPITAL LETTER T WITH RETROFLEX HOOK +01AF; C; 01B0; # LATIN CAPITAL LETTER U WITH HORN +01B1; C; 028A; # LATIN CAPITAL LETTER UPSILON +01B2; C; 028B; # LATIN CAPITAL LETTER V WITH HOOK +01B3; C; 01B4; # LATIN CAPITAL LETTER Y WITH HOOK +01B5; C; 01B6; # LATIN CAPITAL LETTER Z WITH STROKE +01B7; C; 0292; # LATIN CAPITAL LETTER EZH +01B8; C; 01B9; # LATIN CAPITAL LETTER EZH REVERSED +01BC; C; 01BD; # LATIN CAPITAL LETTER TONE FIVE +01C4; C; 01C6; # LATIN CAPITAL LETTER DZ WITH CARON +01C5; C; 01C6; # LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON +01C7; C; 01C9; # LATIN CAPITAL LETTER LJ +01C8; C; 01C9; # LATIN CAPITAL LETTER L WITH SMALL LETTER J +01CA; C; 01CC; # LATIN CAPITAL LETTER NJ +01CB; C; 01CC; # LATIN CAPITAL LETTER N WITH SMALL LETTER J +01CD; C; 01CE; # LATIN CAPITAL LETTER A WITH CARON +01CF; C; 01D0; # LATIN CAPITAL LETTER I WITH CARON +01D1; C; 01D2; # LATIN CAPITAL LETTER O WITH CARON +01D3; C; 01D4; # LATIN CAPITAL LETTER U WITH CARON +01D5; C; 01D6; # LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON +01D7; C; 01D8; # LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE +01D9; C; 01DA; # LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON +01DB; C; 01DC; # LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE +01DE; C; 01DF; # LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON +01E0; C; 01E1; # LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON +01E2; C; 01E3; # LATIN CAPITAL LETTER AE WITH MACRON +01E4; C; 01E5; # LATIN CAPITAL LETTER G WITH STROKE +01E6; C; 01E7; # LATIN CAPITAL LETTER G WITH CARON +01E8; C; 01E9; # LATIN CAPITAL LETTER K WITH CARON +01EA; C; 01EB; # LATIN CAPITAL LETTER O WITH OGONEK +01EC; C; 01ED; # LATIN CAPITAL LETTER O WITH OGONEK AND MACRON +01EE; C; 01EF; # LATIN CAPITAL LETTER EZH WITH CARON +01F0; F; 006A 030C; # LATIN SMALL LETTER J WITH CARON +01F1; C; 01F3; # LATIN CAPITAL LETTER DZ +01F2; C; 01F3; # LATIN CAPITAL LETTER D WITH SMALL LETTER Z +01F4; C; 01F5; # LATIN CAPITAL LETTER G WITH ACUTE +01F6; C; 0195; # LATIN CAPITAL LETTER HWAIR +01F7; C; 01BF; # LATIN CAPITAL LETTER WYNN +01F8; C; 01F9; # LATIN CAPITAL LETTER N WITH GRAVE +01FA; C; 01FB; # LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE +01FC; C; 01FD; # LATIN CAPITAL LETTER AE WITH ACUTE +01FE; C; 01FF; # LATIN CAPITAL LETTER O WITH STROKE AND ACUTE +0200; C; 0201; # LATIN CAPITAL LETTER A WITH DOUBLE GRAVE +0202; C; 0203; # LATIN CAPITAL LETTER A WITH INVERTED BREVE +0204; C; 0205; # LATIN CAPITAL LETTER E WITH DOUBLE GRAVE +0206; C; 0207; # LATIN CAPITAL LETTER E WITH INVERTED BREVE +0208; C; 0209; # LATIN CAPITAL LETTER I WITH DOUBLE GRAVE +020A; C; 020B; # LATIN CAPITAL LETTER I WITH INVERTED BREVE +020C; C; 020D; # LATIN CAPITAL LETTER O WITH DOUBLE GRAVE +020E; C; 020F; # LATIN CAPITAL LETTER O WITH INVERTED BREVE +0210; C; 0211; # LATIN CAPITAL LETTER R WITH DOUBLE GRAVE +0212; C; 0213; # LATIN CAPITAL LETTER R WITH INVERTED BREVE +0214; C; 0215; # LATIN CAPITAL LETTER U WITH DOUBLE GRAVE +0216; C; 0217; # LATIN CAPITAL LETTER U WITH INVERTED BREVE +0218; C; 0219; # LATIN CAPITAL LETTER S WITH COMMA BELOW +021A; C; 021B; # LATIN CAPITAL LETTER T WITH COMMA BELOW +021C; C; 021D; # LATIN CAPITAL LETTER YOGH +021E; C; 021F; # LATIN CAPITAL LETTER H WITH CARON +0220; C; 019E; # LATIN CAPITAL LETTER N WITH LONG RIGHT LEG +0222; C; 0223; # LATIN CAPITAL LETTER OU +0224; C; 0225; # LATIN CAPITAL LETTER Z WITH HOOK +0226; C; 0227; # LATIN CAPITAL LETTER A WITH DOT ABOVE +0228; C; 0229; # LATIN CAPITAL LETTER E WITH CEDILLA +022A; C; 022B; # LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON +022C; C; 022D; # LATIN CAPITAL LETTER O WITH TILDE AND MACRON +022E; C; 022F; # LATIN CAPITAL LETTER O WITH DOT ABOVE +0230; C; 0231; # LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON +0232; C; 0233; # LATIN CAPITAL LETTER Y WITH MACRON +023A; C; 2C65; # LATIN CAPITAL LETTER A WITH STROKE +023B; C; 023C; # LATIN CAPITAL LETTER C WITH STROKE +023D; C; 019A; # LATIN CAPITAL LETTER L WITH BAR +023E; C; 2C66; # LATIN CAPITAL LETTER T WITH DIAGONAL STROKE +0241; C; 0242; # LATIN CAPITAL LETTER GLOTTAL STOP +0243; C; 0180; # LATIN CAPITAL LETTER B WITH STROKE +0244; C; 0289; # LATIN CAPITAL LETTER U BAR +0245; C; 028C; # LATIN CAPITAL LETTER TURNED V +0246; C; 0247; # LATIN CAPITAL LETTER E WITH STROKE +0248; C; 0249; # LATIN CAPITAL LETTER J WITH STROKE +024A; C; 024B; # LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL +024C; C; 024D; # LATIN CAPITAL LETTER R WITH STROKE +024E; C; 024F; # LATIN CAPITAL LETTER Y WITH STROKE +0345; C; 03B9; # COMBINING GREEK YPOGEGRAMMENI +0370; C; 0371; # GREEK CAPITAL LETTER HETA +0372; C; 0373; # GREEK CAPITAL LETTER ARCHAIC SAMPI +0376; C; 0377; # GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA +037F; C; 03F3; # GREEK CAPITAL LETTER YOT +0386; C; 03AC; # GREEK CAPITAL LETTER ALPHA WITH TONOS +0388; C; 03AD; # GREEK CAPITAL LETTER EPSILON WITH TONOS +0389; C; 03AE; # GREEK CAPITAL LETTER ETA WITH TONOS +038A; C; 03AF; # GREEK CAPITAL LETTER IOTA WITH TONOS +038C; C; 03CC; # GREEK CAPITAL LETTER OMICRON WITH TONOS +038E; C; 03CD; # GREEK CAPITAL LETTER UPSILON WITH TONOS +038F; C; 03CE; # GREEK CAPITAL LETTER OMEGA WITH TONOS +0390; F; 03B9 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS +0391; C; 03B1; # GREEK CAPITAL LETTER ALPHA +0392; C; 03B2; # GREEK CAPITAL LETTER BETA +0393; C; 03B3; # GREEK CAPITAL LETTER GAMMA +0394; C; 03B4; # GREEK CAPITAL LETTER DELTA +0395; C; 03B5; # GREEK CAPITAL LETTER EPSILON +0396; C; 03B6; # GREEK CAPITAL LETTER ZETA +0397; C; 03B7; # GREEK CAPITAL LETTER ETA +0398; C; 03B8; # GREEK CAPITAL LETTER THETA +0399; C; 03B9; # GREEK CAPITAL LETTER IOTA +039A; C; 03BA; # GREEK CAPITAL LETTER KAPPA +039B; C; 03BB; # GREEK CAPITAL LETTER LAMDA +039C; C; 03BC; # GREEK CAPITAL LETTER MU +039D; C; 03BD; # GREEK CAPITAL LETTER NU +039E; C; 03BE; # GREEK CAPITAL LETTER XI +039F; C; 03BF; # GREEK CAPITAL LETTER OMICRON +03A0; C; 03C0; # GREEK CAPITAL LETTER PI +03A1; C; 03C1; # GREEK CAPITAL LETTER RHO +03A3; C; 03C3; # GREEK CAPITAL LETTER SIGMA +03A4; C; 03C4; # GREEK CAPITAL LETTER TAU +03A5; C; 03C5; # GREEK CAPITAL LETTER UPSILON +03A6; C; 03C6; # GREEK CAPITAL LETTER PHI +03A7; C; 03C7; # GREEK CAPITAL LETTER CHI +03A8; C; 03C8; # GREEK CAPITAL LETTER PSI +03A9; C; 03C9; # GREEK CAPITAL LETTER OMEGA +03AA; C; 03CA; # GREEK CAPITAL LETTER IOTA WITH DIALYTIKA +03AB; C; 03CB; # GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA +03B0; F; 03C5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS +03C2; C; 03C3; # GREEK SMALL LETTER FINAL SIGMA +03CF; C; 03D7; # GREEK CAPITAL KAI SYMBOL +03D0; C; 03B2; # GREEK BETA SYMBOL +03D1; C; 03B8; # GREEK THETA SYMBOL +03D5; C; 03C6; # GREEK PHI SYMBOL +03D6; C; 03C0; # GREEK PI SYMBOL +03D8; C; 03D9; # GREEK LETTER ARCHAIC KOPPA +03DA; C; 03DB; # GREEK LETTER STIGMA +03DC; C; 03DD; # GREEK LETTER DIGAMMA +03DE; C; 03DF; # GREEK LETTER KOPPA +03E0; C; 03E1; # GREEK LETTER SAMPI +03E2; C; 03E3; # COPTIC CAPITAL LETTER SHEI +03E4; C; 03E5; # COPTIC CAPITAL LETTER FEI +03E6; C; 03E7; # COPTIC CAPITAL LETTER KHEI +03E8; C; 03E9; # COPTIC CAPITAL LETTER HORI +03EA; C; 03EB; # COPTIC CAPITAL LETTER GANGIA +03EC; C; 03ED; # COPTIC CAPITAL LETTER SHIMA +03EE; C; 03EF; # COPTIC CAPITAL LETTER DEI +03F0; C; 03BA; # GREEK KAPPA SYMBOL +03F1; C; 03C1; # GREEK RHO SYMBOL +03F4; C; 03B8; # GREEK CAPITAL THETA SYMBOL +03F5; C; 03B5; # GREEK LUNATE EPSILON SYMBOL +03F7; C; 03F8; # GREEK CAPITAL LETTER SHO +03F9; C; 03F2; # GREEK CAPITAL LUNATE SIGMA SYMBOL +03FA; C; 03FB; # GREEK CAPITAL LETTER SAN +03FD; C; 037B; # GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL +03FE; C; 037C; # GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL +03FF; C; 037D; # GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL +0400; C; 0450; # CYRILLIC CAPITAL LETTER IE WITH GRAVE +0401; C; 0451; # CYRILLIC CAPITAL LETTER IO +0402; C; 0452; # CYRILLIC CAPITAL LETTER DJE +0403; C; 0453; # CYRILLIC CAPITAL LETTER GJE +0404; C; 0454; # CYRILLIC CAPITAL LETTER UKRAINIAN IE +0405; C; 0455; # CYRILLIC CAPITAL LETTER DZE +0406; C; 0456; # CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I +0407; C; 0457; # CYRILLIC CAPITAL LETTER YI +0408; C; 0458; # CYRILLIC CAPITAL LETTER JE +0409; C; 0459; # CYRILLIC CAPITAL LETTER LJE +040A; C; 045A; # CYRILLIC CAPITAL LETTER NJE +040B; C; 045B; # CYRILLIC CAPITAL LETTER TSHE +040C; C; 045C; # CYRILLIC CAPITAL LETTER KJE +040D; C; 045D; # CYRILLIC CAPITAL LETTER I WITH GRAVE +040E; C; 045E; # CYRILLIC CAPITAL LETTER SHORT U +040F; C; 045F; # CYRILLIC CAPITAL LETTER DZHE +0410; C; 0430; # CYRILLIC CAPITAL LETTER A +0411; C; 0431; # CYRILLIC CAPITAL LETTER BE +0412; C; 0432; # CYRILLIC CAPITAL LETTER VE +0413; C; 0433; # CYRILLIC CAPITAL LETTER GHE +0414; C; 0434; # CYRILLIC CAPITAL LETTER DE +0415; C; 0435; # CYRILLIC CAPITAL LETTER IE +0416; C; 0436; # CYRILLIC CAPITAL LETTER ZHE +0417; C; 0437; # CYRILLIC CAPITAL LETTER ZE +0418; C; 0438; # CYRILLIC CAPITAL LETTER I +0419; C; 0439; # CYRILLIC CAPITAL LETTER SHORT I +041A; C; 043A; # CYRILLIC CAPITAL LETTER KA +041B; C; 043B; # CYRILLIC CAPITAL LETTER EL +041C; C; 043C; # CYRILLIC CAPITAL LETTER EM +041D; C; 043D; # CYRILLIC CAPITAL LETTER EN +041E; C; 043E; # CYRILLIC CAPITAL LETTER O +041F; C; 043F; # CYRILLIC CAPITAL LETTER PE +0420; C; 0440; # CYRILLIC CAPITAL LETTER ER +0421; C; 0441; # CYRILLIC CAPITAL LETTER ES +0422; C; 0442; # CYRILLIC CAPITAL LETTER TE +0423; C; 0443; # CYRILLIC CAPITAL LETTER U +0424; C; 0444; # CYRILLIC CAPITAL LETTER EF +0425; C; 0445; # CYRILLIC CAPITAL LETTER HA +0426; C; 0446; # CYRILLIC CAPITAL LETTER TSE +0427; C; 0447; # CYRILLIC CAPITAL LETTER CHE +0428; C; 0448; # CYRILLIC CAPITAL LETTER SHA +0429; C; 0449; # CYRILLIC CAPITAL LETTER SHCHA +042A; C; 044A; # CYRILLIC CAPITAL LETTER HARD SIGN +042B; C; 044B; # CYRILLIC CAPITAL LETTER YERU +042C; C; 044C; # CYRILLIC CAPITAL LETTER SOFT SIGN +042D; C; 044D; # CYRILLIC CAPITAL LETTER E +042E; C; 044E; # CYRILLIC CAPITAL LETTER YU +042F; C; 044F; # CYRILLIC CAPITAL LETTER YA +0460; C; 0461; # CYRILLIC CAPITAL LETTER OMEGA +0462; C; 0463; # CYRILLIC CAPITAL LETTER YAT +0464; C; 0465; # CYRILLIC CAPITAL LETTER IOTIFIED E +0466; C; 0467; # CYRILLIC CAPITAL LETTER LITTLE YUS +0468; C; 0469; # CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS +046A; C; 046B; # CYRILLIC CAPITAL LETTER BIG YUS +046C; C; 046D; # CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS +046E; C; 046F; # CYRILLIC CAPITAL LETTER KSI +0470; C; 0471; # CYRILLIC CAPITAL LETTER PSI +0472; C; 0473; # CYRILLIC CAPITAL LETTER FITA +0474; C; 0475; # CYRILLIC CAPITAL LETTER IZHITSA +0476; C; 0477; # CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT +0478; C; 0479; # CYRILLIC CAPITAL LETTER UK +047A; C; 047B; # CYRILLIC CAPITAL LETTER ROUND OMEGA +047C; C; 047D; # CYRILLIC CAPITAL LETTER OMEGA WITH TITLO +047E; C; 047F; # CYRILLIC CAPITAL LETTER OT +0480; C; 0481; # CYRILLIC CAPITAL LETTER KOPPA +048A; C; 048B; # CYRILLIC CAPITAL LETTER SHORT I WITH TAIL +048C; C; 048D; # CYRILLIC CAPITAL LETTER SEMISOFT SIGN +048E; C; 048F; # CYRILLIC CAPITAL LETTER ER WITH TICK +0490; C; 0491; # CYRILLIC CAPITAL LETTER GHE WITH UPTURN +0492; C; 0493; # CYRILLIC CAPITAL LETTER GHE WITH STROKE +0494; C; 0495; # CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK +0496; C; 0497; # CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER +0498; C; 0499; # CYRILLIC CAPITAL LETTER ZE WITH DESCENDER +049A; C; 049B; # CYRILLIC CAPITAL LETTER KA WITH DESCENDER +049C; C; 049D; # CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE +049E; C; 049F; # CYRILLIC CAPITAL LETTER KA WITH STROKE +04A0; C; 04A1; # CYRILLIC CAPITAL LETTER BASHKIR KA +04A2; C; 04A3; # CYRILLIC CAPITAL LETTER EN WITH DESCENDER +04A4; C; 04A5; # CYRILLIC CAPITAL LIGATURE EN GHE +04A6; C; 04A7; # CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK +04A8; C; 04A9; # CYRILLIC CAPITAL LETTER ABKHASIAN HA +04AA; C; 04AB; # CYRILLIC CAPITAL LETTER ES WITH DESCENDER +04AC; C; 04AD; # CYRILLIC CAPITAL LETTER TE WITH DESCENDER +04AE; C; 04AF; # CYRILLIC CAPITAL LETTER STRAIGHT U +04B0; C; 04B1; # CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE +04B2; C; 04B3; # CYRILLIC CAPITAL LETTER HA WITH DESCENDER +04B4; C; 04B5; # CYRILLIC CAPITAL LIGATURE TE TSE +04B6; C; 04B7; # CYRILLIC CAPITAL LETTER CHE WITH DESCENDER +04B8; C; 04B9; # CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE +04BA; C; 04BB; # CYRILLIC CAPITAL LETTER SHHA +04BC; C; 04BD; # CYRILLIC CAPITAL LETTER ABKHASIAN CHE +04BE; C; 04BF; # CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER +04C0; C; 04CF; # CYRILLIC LETTER PALOCHKA +04C1; C; 04C2; # CYRILLIC CAPITAL LETTER ZHE WITH BREVE +04C3; C; 04C4; # CYRILLIC CAPITAL LETTER KA WITH HOOK +04C5; C; 04C6; # CYRILLIC CAPITAL LETTER EL WITH TAIL +04C7; C; 04C8; # CYRILLIC CAPITAL LETTER EN WITH HOOK +04C9; C; 04CA; # CYRILLIC CAPITAL LETTER EN WITH TAIL +04CB; C; 04CC; # CYRILLIC CAPITAL LETTER KHAKASSIAN CHE +04CD; C; 04CE; # CYRILLIC CAPITAL LETTER EM WITH TAIL +04D0; C; 04D1; # CYRILLIC CAPITAL LETTER A WITH BREVE +04D2; C; 04D3; # CYRILLIC CAPITAL LETTER A WITH DIAERESIS +04D4; C; 04D5; # CYRILLIC CAPITAL LIGATURE A IE +04D6; C; 04D7; # CYRILLIC CAPITAL LETTER IE WITH BREVE +04D8; C; 04D9; # CYRILLIC CAPITAL LETTER SCHWA +04DA; C; 04DB; # CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS +04DC; C; 04DD; # CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS +04DE; C; 04DF; # CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS +04E0; C; 04E1; # CYRILLIC CAPITAL LETTER ABKHASIAN DZE +04E2; C; 04E3; # CYRILLIC CAPITAL LETTER I WITH MACRON +04E4; C; 04E5; # CYRILLIC CAPITAL LETTER I WITH DIAERESIS +04E6; C; 04E7; # CYRILLIC CAPITAL LETTER O WITH DIAERESIS +04E8; C; 04E9; # CYRILLIC CAPITAL LETTER BARRED O +04EA; C; 04EB; # CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS +04EC; C; 04ED; # CYRILLIC CAPITAL LETTER E WITH DIAERESIS +04EE; C; 04EF; # CYRILLIC CAPITAL LETTER U WITH MACRON +04F0; C; 04F1; # CYRILLIC CAPITAL LETTER U WITH DIAERESIS +04F2; C; 04F3; # CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE +04F4; C; 04F5; # CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS +04F6; C; 04F7; # CYRILLIC CAPITAL LETTER GHE WITH DESCENDER +04F8; C; 04F9; # CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS +04FA; C; 04FB; # CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK +04FC; C; 04FD; # CYRILLIC CAPITAL LETTER HA WITH HOOK +04FE; C; 04FF; # CYRILLIC CAPITAL LETTER HA WITH STROKE +0500; C; 0501; # CYRILLIC CAPITAL LETTER KOMI DE +0502; C; 0503; # CYRILLIC CAPITAL LETTER KOMI DJE +0504; C; 0505; # CYRILLIC CAPITAL LETTER KOMI ZJE +0506; C; 0507; # CYRILLIC CAPITAL LETTER KOMI DZJE +0508; C; 0509; # CYRILLIC CAPITAL LETTER KOMI LJE +050A; C; 050B; # CYRILLIC CAPITAL LETTER KOMI NJE +050C; C; 050D; # CYRILLIC CAPITAL LETTER KOMI SJE +050E; C; 050F; # CYRILLIC CAPITAL LETTER KOMI TJE +0510; C; 0511; # CYRILLIC CAPITAL LETTER REVERSED ZE +0512; C; 0513; # CYRILLIC CAPITAL LETTER EL WITH HOOK +0514; C; 0515; # CYRILLIC CAPITAL LETTER LHA +0516; C; 0517; # CYRILLIC CAPITAL LETTER RHA +0518; C; 0519; # CYRILLIC CAPITAL LETTER YAE +051A; C; 051B; # CYRILLIC CAPITAL LETTER QA +051C; C; 051D; # CYRILLIC CAPITAL LETTER WE +051E; C; 051F; # CYRILLIC CAPITAL LETTER ALEUT KA +0520; C; 0521; # CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK +0522; C; 0523; # CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK +0524; C; 0525; # CYRILLIC CAPITAL LETTER PE WITH DESCENDER +0526; C; 0527; # CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER +0528; C; 0529; # CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK +052A; C; 052B; # CYRILLIC CAPITAL LETTER DZZHE +052C; C; 052D; # CYRILLIC CAPITAL LETTER DCHE +052E; C; 052F; # CYRILLIC CAPITAL LETTER EL WITH DESCENDER +0531; C; 0561; # ARMENIAN CAPITAL LETTER AYB +0532; C; 0562; # ARMENIAN CAPITAL LETTER BEN +0533; C; 0563; # ARMENIAN CAPITAL LETTER GIM +0534; C; 0564; # ARMENIAN CAPITAL LETTER DA +0535; C; 0565; # ARMENIAN CAPITAL LETTER ECH +0536; C; 0566; # ARMENIAN CAPITAL LETTER ZA +0537; C; 0567; # ARMENIAN CAPITAL LETTER EH +0538; C; 0568; # ARMENIAN CAPITAL LETTER ET +0539; C; 0569; # ARMENIAN CAPITAL LETTER TO +053A; C; 056A; # ARMENIAN CAPITAL LETTER ZHE +053B; C; 056B; # ARMENIAN CAPITAL LETTER INI +053C; C; 056C; # ARMENIAN CAPITAL LETTER LIWN +053D; C; 056D; # ARMENIAN CAPITAL LETTER XEH +053E; C; 056E; # ARMENIAN CAPITAL LETTER CA +053F; C; 056F; # ARMENIAN CAPITAL LETTER KEN +0540; C; 0570; # ARMENIAN CAPITAL LETTER HO +0541; C; 0571; # ARMENIAN CAPITAL LETTER JA +0542; C; 0572; # ARMENIAN CAPITAL LETTER GHAD +0543; C; 0573; # ARMENIAN CAPITAL LETTER CHEH +0544; C; 0574; # ARMENIAN CAPITAL LETTER MEN +0545; C; 0575; # ARMENIAN CAPITAL LETTER YI +0546; C; 0576; # ARMENIAN CAPITAL LETTER NOW +0547; C; 0577; # ARMENIAN CAPITAL LETTER SHA +0548; C; 0578; # ARMENIAN CAPITAL LETTER VO +0549; C; 0579; # ARMENIAN CAPITAL LETTER CHA +054A; C; 057A; # ARMENIAN CAPITAL LETTER PEH +054B; C; 057B; # ARMENIAN CAPITAL LETTER JHEH +054C; C; 057C; # ARMENIAN CAPITAL LETTER RA +054D; C; 057D; # ARMENIAN CAPITAL LETTER SEH +054E; C; 057E; # ARMENIAN CAPITAL LETTER VEW +054F; C; 057F; # ARMENIAN CAPITAL LETTER TIWN +0550; C; 0580; # ARMENIAN CAPITAL LETTER REH +0551; C; 0581; # ARMENIAN CAPITAL LETTER CO +0552; C; 0582; # ARMENIAN CAPITAL LETTER YIWN +0553; C; 0583; # ARMENIAN CAPITAL LETTER PIWR +0554; C; 0584; # ARMENIAN CAPITAL LETTER KEH +0555; C; 0585; # ARMENIAN CAPITAL LETTER OH +0556; C; 0586; # ARMENIAN CAPITAL LETTER FEH +0587; F; 0565 0582; # ARMENIAN SMALL LIGATURE ECH YIWN +10A0; C; 2D00; # GEORGIAN CAPITAL LETTER AN +10A1; C; 2D01; # GEORGIAN CAPITAL LETTER BAN +10A2; C; 2D02; # GEORGIAN CAPITAL LETTER GAN +10A3; C; 2D03; # GEORGIAN CAPITAL LETTER DON +10A4; C; 2D04; # GEORGIAN CAPITAL LETTER EN +10A5; C; 2D05; # GEORGIAN CAPITAL LETTER VIN +10A6; C; 2D06; # GEORGIAN CAPITAL LETTER ZEN +10A7; C; 2D07; # GEORGIAN CAPITAL LETTER TAN +10A8; C; 2D08; # GEORGIAN CAPITAL LETTER IN +10A9; C; 2D09; # GEORGIAN CAPITAL LETTER KAN +10AA; C; 2D0A; # GEORGIAN CAPITAL LETTER LAS +10AB; C; 2D0B; # GEORGIAN CAPITAL LETTER MAN +10AC; C; 2D0C; # GEORGIAN CAPITAL LETTER NAR +10AD; C; 2D0D; # GEORGIAN CAPITAL LETTER ON +10AE; C; 2D0E; # GEORGIAN CAPITAL LETTER PAR +10AF; C; 2D0F; # GEORGIAN CAPITAL LETTER ZHAR +10B0; C; 2D10; # GEORGIAN CAPITAL LETTER RAE +10B1; C; 2D11; # GEORGIAN CAPITAL LETTER SAN +10B2; C; 2D12; # GEORGIAN CAPITAL LETTER TAR +10B3; C; 2D13; # GEORGIAN CAPITAL LETTER UN +10B4; C; 2D14; # GEORGIAN CAPITAL LETTER PHAR +10B5; C; 2D15; # GEORGIAN CAPITAL LETTER KHAR +10B6; C; 2D16; # GEORGIAN CAPITAL LETTER GHAN +10B7; C; 2D17; # GEORGIAN CAPITAL LETTER QAR +10B8; C; 2D18; # GEORGIAN CAPITAL LETTER SHIN +10B9; C; 2D19; # GEORGIAN CAPITAL LETTER CHIN +10BA; C; 2D1A; # GEORGIAN CAPITAL LETTER CAN +10BB; C; 2D1B; # GEORGIAN CAPITAL LETTER JIL +10BC; C; 2D1C; # GEORGIAN CAPITAL LETTER CIL +10BD; C; 2D1D; # GEORGIAN CAPITAL LETTER CHAR +10BE; C; 2D1E; # GEORGIAN CAPITAL LETTER XAN +10BF; C; 2D1F; # GEORGIAN CAPITAL LETTER JHAN +10C0; C; 2D20; # GEORGIAN CAPITAL LETTER HAE +10C1; C; 2D21; # GEORGIAN CAPITAL LETTER HE +10C2; C; 2D22; # GEORGIAN CAPITAL LETTER HIE +10C3; C; 2D23; # GEORGIAN CAPITAL LETTER WE +10C4; C; 2D24; # GEORGIAN CAPITAL LETTER HAR +10C5; C; 2D25; # GEORGIAN CAPITAL LETTER HOE +10C7; C; 2D27; # GEORGIAN CAPITAL LETTER YN +10CD; C; 2D2D; # GEORGIAN CAPITAL LETTER AEN +13F8; C; 13F0; # CHEROKEE SMALL LETTER YE +13F9; C; 13F1; # CHEROKEE SMALL LETTER YI +13FA; C; 13F2; # CHEROKEE SMALL LETTER YO +13FB; C; 13F3; # CHEROKEE SMALL LETTER YU +13FC; C; 13F4; # CHEROKEE SMALL LETTER YV +13FD; C; 13F5; # CHEROKEE SMALL LETTER MV +1C80; C; 0432; # CYRILLIC SMALL LETTER ROUNDED VE +1C81; C; 0434; # CYRILLIC SMALL LETTER LONG-LEGGED DE +1C82; C; 043E; # CYRILLIC SMALL LETTER NARROW O +1C83; C; 0441; # CYRILLIC SMALL LETTER WIDE ES +1C84; C; 0442; # CYRILLIC SMALL LETTER TALL TE +1C85; C; 0442; # CYRILLIC SMALL LETTER THREE-LEGGED TE +1C86; C; 044A; # CYRILLIC SMALL LETTER TALL HARD SIGN +1C87; C; 0463; # CYRILLIC SMALL LETTER TALL YAT +1C88; C; A64B; # CYRILLIC SMALL LETTER UNBLENDED UK +1C90; C; 10D0; # GEORGIAN MTAVRULI CAPITAL LETTER AN +1C91; C; 10D1; # GEORGIAN MTAVRULI CAPITAL LETTER BAN +1C92; C; 10D2; # GEORGIAN MTAVRULI CAPITAL LETTER GAN +1C93; C; 10D3; # GEORGIAN MTAVRULI CAPITAL LETTER DON +1C94; C; 10D4; # GEORGIAN MTAVRULI CAPITAL LETTER EN +1C95; C; 10D5; # GEORGIAN MTAVRULI CAPITAL LETTER VIN +1C96; C; 10D6; # GEORGIAN MTAVRULI CAPITAL LETTER ZEN +1C97; C; 10D7; # GEORGIAN MTAVRULI CAPITAL LETTER TAN +1C98; C; 10D8; # GEORGIAN MTAVRULI CAPITAL LETTER IN +1C99; C; 10D9; # GEORGIAN MTAVRULI CAPITAL LETTER KAN +1C9A; C; 10DA; # GEORGIAN MTAVRULI CAPITAL LETTER LAS +1C9B; C; 10DB; # GEORGIAN MTAVRULI CAPITAL LETTER MAN +1C9C; C; 10DC; # GEORGIAN MTAVRULI CAPITAL LETTER NAR +1C9D; C; 10DD; # GEORGIAN MTAVRULI CAPITAL LETTER ON +1C9E; C; 10DE; # GEORGIAN MTAVRULI CAPITAL LETTER PAR +1C9F; C; 10DF; # GEORGIAN MTAVRULI CAPITAL LETTER ZHAR +1CA0; C; 10E0; # GEORGIAN MTAVRULI CAPITAL LETTER RAE +1CA1; C; 10E1; # GEORGIAN MTAVRULI CAPITAL LETTER SAN +1CA2; C; 10E2; # GEORGIAN MTAVRULI CAPITAL LETTER TAR +1CA3; C; 10E3; # GEORGIAN MTAVRULI CAPITAL LETTER UN +1CA4; C; 10E4; # GEORGIAN MTAVRULI CAPITAL LETTER PHAR +1CA5; C; 10E5; # GEORGIAN MTAVRULI CAPITAL LETTER KHAR +1CA6; C; 10E6; # GEORGIAN MTAVRULI CAPITAL LETTER GHAN +1CA7; C; 10E7; # GEORGIAN MTAVRULI CAPITAL LETTER QAR +1CA8; C; 10E8; # GEORGIAN MTAVRULI CAPITAL LETTER SHIN +1CA9; C; 10E9; # GEORGIAN MTAVRULI CAPITAL LETTER CHIN +1CAA; C; 10EA; # GEORGIAN MTAVRULI CAPITAL LETTER CAN +1CAB; C; 10EB; # GEORGIAN MTAVRULI CAPITAL LETTER JIL +1CAC; C; 10EC; # GEORGIAN MTAVRULI CAPITAL LETTER CIL +1CAD; C; 10ED; # GEORGIAN MTAVRULI CAPITAL LETTER CHAR +1CAE; C; 10EE; # GEORGIAN MTAVRULI CAPITAL LETTER XAN +1CAF; C; 10EF; # GEORGIAN MTAVRULI CAPITAL LETTER JHAN +1CB0; C; 10F0; # GEORGIAN MTAVRULI CAPITAL LETTER HAE +1CB1; C; 10F1; # GEORGIAN MTAVRULI CAPITAL LETTER HE +1CB2; C; 10F2; # GEORGIAN MTAVRULI CAPITAL LETTER HIE +1CB3; C; 10F3; # GEORGIAN MTAVRULI CAPITAL LETTER WE +1CB4; C; 10F4; # GEORGIAN MTAVRULI CAPITAL LETTER HAR +1CB5; C; 10F5; # GEORGIAN MTAVRULI CAPITAL LETTER HOE +1CB6; C; 10F6; # GEORGIAN MTAVRULI CAPITAL LETTER FI +1CB7; C; 10F7; # GEORGIAN MTAVRULI CAPITAL LETTER YN +1CB8; C; 10F8; # GEORGIAN MTAVRULI CAPITAL LETTER ELIFI +1CB9; C; 10F9; # GEORGIAN MTAVRULI CAPITAL LETTER TURNED GAN +1CBA; C; 10FA; # GEORGIAN MTAVRULI CAPITAL LETTER AIN +1CBD; C; 10FD; # GEORGIAN MTAVRULI CAPITAL LETTER AEN +1CBE; C; 10FE; # GEORGIAN MTAVRULI CAPITAL LETTER HARD SIGN +1CBF; C; 10FF; # GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN +1E00; C; 1E01; # LATIN CAPITAL LETTER A WITH RING BELOW +1E02; C; 1E03; # LATIN CAPITAL LETTER B WITH DOT ABOVE +1E04; C; 1E05; # LATIN CAPITAL LETTER B WITH DOT BELOW +1E06; C; 1E07; # LATIN CAPITAL LETTER B WITH LINE BELOW +1E08; C; 1E09; # LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE +1E0A; C; 1E0B; # LATIN CAPITAL LETTER D WITH DOT ABOVE +1E0C; C; 1E0D; # LATIN CAPITAL LETTER D WITH DOT BELOW +1E0E; C; 1E0F; # LATIN CAPITAL LETTER D WITH LINE BELOW +1E10; C; 1E11; # LATIN CAPITAL LETTER D WITH CEDILLA +1E12; C; 1E13; # LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW +1E14; C; 1E15; # LATIN CAPITAL LETTER E WITH MACRON AND GRAVE +1E16; C; 1E17; # LATIN CAPITAL LETTER E WITH MACRON AND ACUTE +1E18; C; 1E19; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW +1E1A; C; 1E1B; # LATIN CAPITAL LETTER E WITH TILDE BELOW +1E1C; C; 1E1D; # LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE +1E1E; C; 1E1F; # LATIN CAPITAL LETTER F WITH DOT ABOVE +1E20; C; 1E21; # LATIN CAPITAL LETTER G WITH MACRON +1E22; C; 1E23; # LATIN CAPITAL LETTER H WITH DOT ABOVE +1E24; C; 1E25; # LATIN CAPITAL LETTER H WITH DOT BELOW +1E26; C; 1E27; # LATIN CAPITAL LETTER H WITH DIAERESIS +1E28; C; 1E29; # LATIN CAPITAL LETTER H WITH CEDILLA +1E2A; C; 1E2B; # LATIN CAPITAL LETTER H WITH BREVE BELOW +1E2C; C; 1E2D; # LATIN CAPITAL LETTER I WITH TILDE BELOW +1E2E; C; 1E2F; # LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE +1E30; C; 1E31; # LATIN CAPITAL LETTER K WITH ACUTE +1E32; C; 1E33; # LATIN CAPITAL LETTER K WITH DOT BELOW +1E34; C; 1E35; # LATIN CAPITAL LETTER K WITH LINE BELOW +1E36; C; 1E37; # LATIN CAPITAL LETTER L WITH DOT BELOW +1E38; C; 1E39; # LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON +1E3A; C; 1E3B; # LATIN CAPITAL LETTER L WITH LINE BELOW +1E3C; C; 1E3D; # LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW +1E3E; C; 1E3F; # LATIN CAPITAL LETTER M WITH ACUTE +1E40; C; 1E41; # LATIN CAPITAL LETTER M WITH DOT ABOVE +1E42; C; 1E43; # LATIN CAPITAL LETTER M WITH DOT BELOW +1E44; C; 1E45; # LATIN CAPITAL LETTER N WITH DOT ABOVE +1E46; C; 1E47; # LATIN CAPITAL LETTER N WITH DOT BELOW +1E48; C; 1E49; # LATIN CAPITAL LETTER N WITH LINE BELOW +1E4A; C; 1E4B; # LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW +1E4C; C; 1E4D; # LATIN CAPITAL LETTER O WITH TILDE AND ACUTE +1E4E; C; 1E4F; # LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS +1E50; C; 1E51; # LATIN CAPITAL LETTER O WITH MACRON AND GRAVE +1E52; C; 1E53; # LATIN CAPITAL LETTER O WITH MACRON AND ACUTE +1E54; C; 1E55; # LATIN CAPITAL LETTER P WITH ACUTE +1E56; C; 1E57; # LATIN CAPITAL LETTER P WITH DOT ABOVE +1E58; C; 1E59; # LATIN CAPITAL LETTER R WITH DOT ABOVE +1E5A; C; 1E5B; # LATIN CAPITAL LETTER R WITH DOT BELOW +1E5C; C; 1E5D; # LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON +1E5E; C; 1E5F; # LATIN CAPITAL LETTER R WITH LINE BELOW +1E60; C; 1E61; # LATIN CAPITAL LETTER S WITH DOT ABOVE +1E62; C; 1E63; # LATIN CAPITAL LETTER S WITH DOT BELOW +1E64; C; 1E65; # LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE +1E66; C; 1E67; # LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE +1E68; C; 1E69; # LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE +1E6A; C; 1E6B; # LATIN CAPITAL LETTER T WITH DOT ABOVE +1E6C; C; 1E6D; # LATIN CAPITAL LETTER T WITH DOT BELOW +1E6E; C; 1E6F; # LATIN CAPITAL LETTER T WITH LINE BELOW +1E70; C; 1E71; # LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW +1E72; C; 1E73; # LATIN CAPITAL LETTER U WITH DIAERESIS BELOW +1E74; C; 1E75; # LATIN CAPITAL LETTER U WITH TILDE BELOW +1E76; C; 1E77; # LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW +1E78; C; 1E79; # LATIN CAPITAL LETTER U WITH TILDE AND ACUTE +1E7A; C; 1E7B; # LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS +1E7C; C; 1E7D; # LATIN CAPITAL LETTER V WITH TILDE +1E7E; C; 1E7F; # LATIN CAPITAL LETTER V WITH DOT BELOW +1E80; C; 1E81; # LATIN CAPITAL LETTER W WITH GRAVE +1E82; C; 1E83; # LATIN CAPITAL LETTER W WITH ACUTE +1E84; C; 1E85; # LATIN CAPITAL LETTER W WITH DIAERESIS +1E86; C; 1E87; # LATIN CAPITAL LETTER W WITH DOT ABOVE +1E88; C; 1E89; # LATIN CAPITAL LETTER W WITH DOT BELOW +1E8A; C; 1E8B; # LATIN CAPITAL LETTER X WITH DOT ABOVE +1E8C; C; 1E8D; # LATIN CAPITAL LETTER X WITH DIAERESIS +1E8E; C; 1E8F; # LATIN CAPITAL LETTER Y WITH DOT ABOVE +1E90; C; 1E91; # LATIN CAPITAL LETTER Z WITH CIRCUMFLEX +1E92; C; 1E93; # LATIN CAPITAL LETTER Z WITH DOT BELOW +1E94; C; 1E95; # LATIN CAPITAL LETTER Z WITH LINE BELOW +1E96; F; 0068 0331; # LATIN SMALL LETTER H WITH LINE BELOW +1E97; F; 0074 0308; # LATIN SMALL LETTER T WITH DIAERESIS +1E98; F; 0077 030A; # LATIN SMALL LETTER W WITH RING ABOVE +1E99; F; 0079 030A; # LATIN SMALL LETTER Y WITH RING ABOVE +1E9A; F; 0061 02BE; # LATIN SMALL LETTER A WITH RIGHT HALF RING +1E9B; C; 1E61; # LATIN SMALL LETTER LONG S WITH DOT ABOVE +1E9E; F; 0073 0073; # LATIN CAPITAL LETTER SHARP S +1E9E; S; 00DF; # LATIN CAPITAL LETTER SHARP S +1EA0; C; 1EA1; # LATIN CAPITAL LETTER A WITH DOT BELOW +1EA2; C; 1EA3; # LATIN CAPITAL LETTER A WITH HOOK ABOVE +1EA4; C; 1EA5; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE +1EA6; C; 1EA7; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE +1EA8; C; 1EA9; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE +1EAA; C; 1EAB; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE +1EAC; C; 1EAD; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW +1EAE; C; 1EAF; # LATIN CAPITAL LETTER A WITH BREVE AND ACUTE +1EB0; C; 1EB1; # LATIN CAPITAL LETTER A WITH BREVE AND GRAVE +1EB2; C; 1EB3; # LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE +1EB4; C; 1EB5; # LATIN CAPITAL LETTER A WITH BREVE AND TILDE +1EB6; C; 1EB7; # LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW +1EB8; C; 1EB9; # LATIN CAPITAL LETTER E WITH DOT BELOW +1EBA; C; 1EBB; # LATIN CAPITAL LETTER E WITH HOOK ABOVE +1EBC; C; 1EBD; # LATIN CAPITAL LETTER E WITH TILDE +1EBE; C; 1EBF; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE +1EC0; C; 1EC1; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE +1EC2; C; 1EC3; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE +1EC4; C; 1EC5; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE +1EC6; C; 1EC7; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW +1EC8; C; 1EC9; # LATIN CAPITAL LETTER I WITH HOOK ABOVE +1ECA; C; 1ECB; # LATIN CAPITAL LETTER I WITH DOT BELOW +1ECC; C; 1ECD; # LATIN CAPITAL LETTER O WITH DOT BELOW +1ECE; C; 1ECF; # LATIN CAPITAL LETTER O WITH HOOK ABOVE +1ED0; C; 1ED1; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE +1ED2; C; 1ED3; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE +1ED4; C; 1ED5; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE +1ED6; C; 1ED7; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE +1ED8; C; 1ED9; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW +1EDA; C; 1EDB; # LATIN CAPITAL LETTER O WITH HORN AND ACUTE +1EDC; C; 1EDD; # LATIN CAPITAL LETTER O WITH HORN AND GRAVE +1EDE; C; 1EDF; # LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE +1EE0; C; 1EE1; # LATIN CAPITAL LETTER O WITH HORN AND TILDE +1EE2; C; 1EE3; # LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW +1EE4; C; 1EE5; # LATIN CAPITAL LETTER U WITH DOT BELOW +1EE6; C; 1EE7; # LATIN CAPITAL LETTER U WITH HOOK ABOVE +1EE8; C; 1EE9; # LATIN CAPITAL LETTER U WITH HORN AND ACUTE +1EEA; C; 1EEB; # LATIN CAPITAL LETTER U WITH HORN AND GRAVE +1EEC; C; 1EED; # LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE +1EEE; C; 1EEF; # LATIN CAPITAL LETTER U WITH HORN AND TILDE +1EF0; C; 1EF1; # LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW +1EF2; C; 1EF3; # LATIN CAPITAL LETTER Y WITH GRAVE +1EF4; C; 1EF5; # LATIN CAPITAL LETTER Y WITH DOT BELOW +1EF6; C; 1EF7; # LATIN CAPITAL LETTER Y WITH HOOK ABOVE +1EF8; C; 1EF9; # LATIN CAPITAL LETTER Y WITH TILDE +1EFA; C; 1EFB; # LATIN CAPITAL LETTER MIDDLE-WELSH LL +1EFC; C; 1EFD; # LATIN CAPITAL LETTER MIDDLE-WELSH V +1EFE; C; 1EFF; # LATIN CAPITAL LETTER Y WITH LOOP +1F08; C; 1F00; # GREEK CAPITAL LETTER ALPHA WITH PSILI +1F09; C; 1F01; # GREEK CAPITAL LETTER ALPHA WITH DASIA +1F0A; C; 1F02; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA +1F0B; C; 1F03; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA +1F0C; C; 1F04; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA +1F0D; C; 1F05; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA +1F0E; C; 1F06; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI +1F0F; C; 1F07; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI +1F18; C; 1F10; # GREEK CAPITAL LETTER EPSILON WITH PSILI +1F19; C; 1F11; # GREEK CAPITAL LETTER EPSILON WITH DASIA +1F1A; C; 1F12; # GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA +1F1B; C; 1F13; # GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA +1F1C; C; 1F14; # GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA +1F1D; C; 1F15; # GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA +1F28; C; 1F20; # GREEK CAPITAL LETTER ETA WITH PSILI +1F29; C; 1F21; # GREEK CAPITAL LETTER ETA WITH DASIA +1F2A; C; 1F22; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA +1F2B; C; 1F23; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA +1F2C; C; 1F24; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA +1F2D; C; 1F25; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA +1F2E; C; 1F26; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI +1F2F; C; 1F27; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI +1F38; C; 1F30; # GREEK CAPITAL LETTER IOTA WITH PSILI +1F39; C; 1F31; # GREEK CAPITAL LETTER IOTA WITH DASIA +1F3A; C; 1F32; # GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA +1F3B; C; 1F33; # GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA +1F3C; C; 1F34; # GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA +1F3D; C; 1F35; # GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA +1F3E; C; 1F36; # GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI +1F3F; C; 1F37; # GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI +1F48; C; 1F40; # GREEK CAPITAL LETTER OMICRON WITH PSILI +1F49; C; 1F41; # GREEK CAPITAL LETTER OMICRON WITH DASIA +1F4A; C; 1F42; # GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA +1F4B; C; 1F43; # GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA +1F4C; C; 1F44; # GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA +1F4D; C; 1F45; # GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA +1F50; F; 03C5 0313; # GREEK SMALL LETTER UPSILON WITH PSILI +1F52; F; 03C5 0313 0300; # GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA +1F54; F; 03C5 0313 0301; # GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA +1F56; F; 03C5 0313 0342; # GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI +1F59; C; 1F51; # GREEK CAPITAL LETTER UPSILON WITH DASIA +1F5B; C; 1F53; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA +1F5D; C; 1F55; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA +1F5F; C; 1F57; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI +1F68; C; 1F60; # GREEK CAPITAL LETTER OMEGA WITH PSILI +1F69; C; 1F61; # GREEK CAPITAL LETTER OMEGA WITH DASIA +1F6A; C; 1F62; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA +1F6B; C; 1F63; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA +1F6C; C; 1F64; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA +1F6D; C; 1F65; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA +1F6E; C; 1F66; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI +1F6F; C; 1F67; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI +1F80; F; 1F00 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI +1F81; F; 1F01 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI +1F82; F; 1F02 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1F83; F; 1F03 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1F84; F; 1F04 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1F85; F; 1F05 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1F86; F; 1F06 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1F87; F; 1F07 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1F88; F; 1F00 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI +1F88; S; 1F80; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI +1F89; F; 1F01 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI +1F89; S; 1F81; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI +1F8A; F; 1F02 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F8A; S; 1F82; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F8B; F; 1F03 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F8B; S; 1F83; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F8C; F; 1F04 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F8C; S; 1F84; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F8D; F; 1F05 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F8D; S; 1F85; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F8E; F; 1F06 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F8E; S; 1F86; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F8F; F; 1F07 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1F8F; S; 1F87; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1F90; F; 1F20 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI +1F91; F; 1F21 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI +1F92; F; 1F22 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1F93; F; 1F23 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1F94; F; 1F24 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1F95; F; 1F25 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1F96; F; 1F26 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1F97; F; 1F27 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1F98; F; 1F20 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI +1F98; S; 1F90; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI +1F99; F; 1F21 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI +1F99; S; 1F91; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI +1F9A; F; 1F22 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F9A; S; 1F92; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F9B; F; 1F23 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F9B; S; 1F93; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F9C; F; 1F24 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F9C; S; 1F94; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F9D; F; 1F25 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F9D; S; 1F95; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F9E; F; 1F26 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F9E; S; 1F96; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F9F; F; 1F27 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1F9F; S; 1F97; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1FA0; F; 1F60 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI +1FA1; F; 1F61 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI +1FA2; F; 1F62 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1FA3; F; 1F63 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1FA4; F; 1F64 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1FA5; F; 1F65 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1FA6; F; 1F66 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1FA7; F; 1F67 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1FA8; F; 1F60 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI +1FA8; S; 1FA0; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI +1FA9; F; 1F61 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI +1FA9; S; 1FA1; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI +1FAA; F; 1F62 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1FAA; S; 1FA2; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1FAB; F; 1F63 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1FAB; S; 1FA3; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1FAC; F; 1F64 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1FAC; S; 1FA4; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1FAD; F; 1F65 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1FAD; S; 1FA5; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1FAE; F; 1F66 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1FAE; S; 1FA6; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1FAF; F; 1F67 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1FAF; S; 1FA7; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1FB2; F; 1F70 03B9; # GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI +1FB3; F; 03B1 03B9; # GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI +1FB4; F; 03AC 03B9; # GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI +1FB6; F; 03B1 0342; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI +1FB7; F; 03B1 0342 03B9; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI +1FB8; C; 1FB0; # GREEK CAPITAL LETTER ALPHA WITH VRACHY +1FB9; C; 1FB1; # GREEK CAPITAL LETTER ALPHA WITH MACRON +1FBA; C; 1F70; # GREEK CAPITAL LETTER ALPHA WITH VARIA +1FBB; C; 1F71; # GREEK CAPITAL LETTER ALPHA WITH OXIA +1FBC; F; 03B1 03B9; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI +1FBC; S; 1FB3; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI +1FBE; C; 03B9; # GREEK PROSGEGRAMMENI +1FC2; F; 1F74 03B9; # GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI +1FC3; F; 03B7 03B9; # GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI +1FC4; F; 03AE 03B9; # GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI +1FC6; F; 03B7 0342; # GREEK SMALL LETTER ETA WITH PERISPOMENI +1FC7; F; 03B7 0342 03B9; # GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI +1FC8; C; 1F72; # GREEK CAPITAL LETTER EPSILON WITH VARIA +1FC9; C; 1F73; # GREEK CAPITAL LETTER EPSILON WITH OXIA +1FCA; C; 1F74; # GREEK CAPITAL LETTER ETA WITH VARIA +1FCB; C; 1F75; # GREEK CAPITAL LETTER ETA WITH OXIA +1FCC; F; 03B7 03B9; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI +1FCC; S; 1FC3; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI +1FD2; F; 03B9 0308 0300; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA +1FD3; F; 03B9 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA +1FD6; F; 03B9 0342; # GREEK SMALL LETTER IOTA WITH PERISPOMENI +1FD7; F; 03B9 0308 0342; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI +1FD8; C; 1FD0; # GREEK CAPITAL LETTER IOTA WITH VRACHY +1FD9; C; 1FD1; # GREEK CAPITAL LETTER IOTA WITH MACRON +1FDA; C; 1F76; # GREEK CAPITAL LETTER IOTA WITH VARIA +1FDB; C; 1F77; # GREEK CAPITAL LETTER IOTA WITH OXIA +1FE2; F; 03C5 0308 0300; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA +1FE3; F; 03C5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA +1FE4; F; 03C1 0313; # GREEK SMALL LETTER RHO WITH PSILI +1FE6; F; 03C5 0342; # GREEK SMALL LETTER UPSILON WITH PERISPOMENI +1FE7; F; 03C5 0308 0342; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI +1FE8; C; 1FE0; # GREEK CAPITAL LETTER UPSILON WITH VRACHY +1FE9; C; 1FE1; # GREEK CAPITAL LETTER UPSILON WITH MACRON +1FEA; C; 1F7A; # GREEK CAPITAL LETTER UPSILON WITH VARIA +1FEB; C; 1F7B; # GREEK CAPITAL LETTER UPSILON WITH OXIA +1FEC; C; 1FE5; # GREEK CAPITAL LETTER RHO WITH DASIA +1FF2; F; 1F7C 03B9; # GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI +1FF3; F; 03C9 03B9; # GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI +1FF4; F; 03CE 03B9; # GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI +1FF6; F; 03C9 0342; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI +1FF7; F; 03C9 0342 03B9; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI +1FF8; C; 1F78; # GREEK CAPITAL LETTER OMICRON WITH VARIA +1FF9; C; 1F79; # GREEK CAPITAL LETTER OMICRON WITH OXIA +1FFA; C; 1F7C; # GREEK CAPITAL LETTER OMEGA WITH VARIA +1FFB; C; 1F7D; # GREEK CAPITAL LETTER OMEGA WITH OXIA +1FFC; F; 03C9 03B9; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI +1FFC; S; 1FF3; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI +2126; C; 03C9; # OHM SIGN +212A; C; 006B; # KELVIN SIGN +212B; C; 00E5; # ANGSTROM SIGN +2132; C; 214E; # TURNED CAPITAL F +2160; C; 2170; # ROMAN NUMERAL ONE +2161; C; 2171; # ROMAN NUMERAL TWO +2162; C; 2172; # ROMAN NUMERAL THREE +2163; C; 2173; # ROMAN NUMERAL FOUR +2164; C; 2174; # ROMAN NUMERAL FIVE +2165; C; 2175; # ROMAN NUMERAL SIX +2166; C; 2176; # ROMAN NUMERAL SEVEN +2167; C; 2177; # ROMAN NUMERAL EIGHT +2168; C; 2178; # ROMAN NUMERAL NINE +2169; C; 2179; # ROMAN NUMERAL TEN +216A; C; 217A; # ROMAN NUMERAL ELEVEN +216B; C; 217B; # ROMAN NUMERAL TWELVE +216C; C; 217C; # ROMAN NUMERAL FIFTY +216D; C; 217D; # ROMAN NUMERAL ONE HUNDRED +216E; C; 217E; # ROMAN NUMERAL FIVE HUNDRED +216F; C; 217F; # ROMAN NUMERAL ONE THOUSAND +2183; C; 2184; # ROMAN NUMERAL REVERSED ONE HUNDRED +24B6; C; 24D0; # CIRCLED LATIN CAPITAL LETTER A +24B7; C; 24D1; # CIRCLED LATIN CAPITAL LETTER B +24B8; C; 24D2; # CIRCLED LATIN CAPITAL LETTER C +24B9; C; 24D3; # CIRCLED LATIN CAPITAL LETTER D +24BA; C; 24D4; # CIRCLED LATIN CAPITAL LETTER E +24BB; C; 24D5; # CIRCLED LATIN CAPITAL LETTER F +24BC; C; 24D6; # CIRCLED LATIN CAPITAL LETTER G +24BD; C; 24D7; # CIRCLED LATIN CAPITAL LETTER H +24BE; C; 24D8; # CIRCLED LATIN CAPITAL LETTER I +24BF; C; 24D9; # CIRCLED LATIN CAPITAL LETTER J +24C0; C; 24DA; # CIRCLED LATIN CAPITAL LETTER K +24C1; C; 24DB; # CIRCLED LATIN CAPITAL LETTER L +24C2; C; 24DC; # CIRCLED LATIN CAPITAL LETTER M +24C3; C; 24DD; # CIRCLED LATIN CAPITAL LETTER N +24C4; C; 24DE; # CIRCLED LATIN CAPITAL LETTER O +24C5; C; 24DF; # CIRCLED LATIN CAPITAL LETTER P +24C6; C; 24E0; # CIRCLED LATIN CAPITAL LETTER Q +24C7; C; 24E1; # CIRCLED LATIN CAPITAL LETTER R +24C8; C; 24E2; # CIRCLED LATIN CAPITAL LETTER S +24C9; C; 24E3; # CIRCLED LATIN CAPITAL LETTER T +24CA; C; 24E4; # CIRCLED LATIN CAPITAL LETTER U +24CB; C; 24E5; # CIRCLED LATIN CAPITAL LETTER V +24CC; C; 24E6; # CIRCLED LATIN CAPITAL LETTER W +24CD; C; 24E7; # CIRCLED LATIN CAPITAL LETTER X +24CE; C; 24E8; # CIRCLED LATIN CAPITAL LETTER Y +24CF; C; 24E9; # CIRCLED LATIN CAPITAL LETTER Z +2C00; C; 2C30; # GLAGOLITIC CAPITAL LETTER AZU +2C01; C; 2C31; # GLAGOLITIC CAPITAL LETTER BUKY +2C02; C; 2C32; # GLAGOLITIC CAPITAL LETTER VEDE +2C03; C; 2C33; # GLAGOLITIC CAPITAL LETTER GLAGOLI +2C04; C; 2C34; # GLAGOLITIC CAPITAL LETTER DOBRO +2C05; C; 2C35; # GLAGOLITIC CAPITAL LETTER YESTU +2C06; C; 2C36; # GLAGOLITIC CAPITAL LETTER ZHIVETE +2C07; C; 2C37; # GLAGOLITIC CAPITAL LETTER DZELO +2C08; C; 2C38; # GLAGOLITIC CAPITAL LETTER ZEMLJA +2C09; C; 2C39; # GLAGOLITIC CAPITAL LETTER IZHE +2C0A; C; 2C3A; # GLAGOLITIC CAPITAL LETTER INITIAL IZHE +2C0B; C; 2C3B; # GLAGOLITIC CAPITAL LETTER I +2C0C; C; 2C3C; # GLAGOLITIC CAPITAL LETTER DJERVI +2C0D; C; 2C3D; # GLAGOLITIC CAPITAL LETTER KAKO +2C0E; C; 2C3E; # GLAGOLITIC CAPITAL LETTER LJUDIJE +2C0F; C; 2C3F; # GLAGOLITIC CAPITAL LETTER MYSLITE +2C10; C; 2C40; # GLAGOLITIC CAPITAL LETTER NASHI +2C11; C; 2C41; # GLAGOLITIC CAPITAL LETTER ONU +2C12; C; 2C42; # GLAGOLITIC CAPITAL LETTER POKOJI +2C13; C; 2C43; # GLAGOLITIC CAPITAL LETTER RITSI +2C14; C; 2C44; # GLAGOLITIC CAPITAL LETTER SLOVO +2C15; C; 2C45; # GLAGOLITIC CAPITAL LETTER TVRIDO +2C16; C; 2C46; # GLAGOLITIC CAPITAL LETTER UKU +2C17; C; 2C47; # GLAGOLITIC CAPITAL LETTER FRITU +2C18; C; 2C48; # GLAGOLITIC CAPITAL LETTER HERU +2C19; C; 2C49; # GLAGOLITIC CAPITAL LETTER OTU +2C1A; C; 2C4A; # GLAGOLITIC CAPITAL LETTER PE +2C1B; C; 2C4B; # GLAGOLITIC CAPITAL LETTER SHTA +2C1C; C; 2C4C; # GLAGOLITIC CAPITAL LETTER TSI +2C1D; C; 2C4D; # GLAGOLITIC CAPITAL LETTER CHRIVI +2C1E; C; 2C4E; # GLAGOLITIC CAPITAL LETTER SHA +2C1F; C; 2C4F; # GLAGOLITIC CAPITAL LETTER YERU +2C20; C; 2C50; # GLAGOLITIC CAPITAL LETTER YERI +2C21; C; 2C51; # GLAGOLITIC CAPITAL LETTER YATI +2C22; C; 2C52; # GLAGOLITIC CAPITAL LETTER SPIDERY HA +2C23; C; 2C53; # GLAGOLITIC CAPITAL LETTER YU +2C24; C; 2C54; # GLAGOLITIC CAPITAL LETTER SMALL YUS +2C25; C; 2C55; # GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL +2C26; C; 2C56; # GLAGOLITIC CAPITAL LETTER YO +2C27; C; 2C57; # GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS +2C28; C; 2C58; # GLAGOLITIC CAPITAL LETTER BIG YUS +2C29; C; 2C59; # GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS +2C2A; C; 2C5A; # GLAGOLITIC CAPITAL LETTER FITA +2C2B; C; 2C5B; # GLAGOLITIC CAPITAL LETTER IZHITSA +2C2C; C; 2C5C; # GLAGOLITIC CAPITAL LETTER SHTAPIC +2C2D; C; 2C5D; # GLAGOLITIC CAPITAL LETTER TROKUTASTI A +2C2E; C; 2C5E; # GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE +2C2F; C; 2C5F; # GLAGOLITIC CAPITAL LETTER CAUDATE CHRIVI +2C60; C; 2C61; # LATIN CAPITAL LETTER L WITH DOUBLE BAR +2C62; C; 026B; # LATIN CAPITAL LETTER L WITH MIDDLE TILDE +2C63; C; 1D7D; # LATIN CAPITAL LETTER P WITH STROKE +2C64; C; 027D; # LATIN CAPITAL LETTER R WITH TAIL +2C67; C; 2C68; # LATIN CAPITAL LETTER H WITH DESCENDER +2C69; C; 2C6A; # LATIN CAPITAL LETTER K WITH DESCENDER +2C6B; C; 2C6C; # LATIN CAPITAL LETTER Z WITH DESCENDER +2C6D; C; 0251; # LATIN CAPITAL LETTER ALPHA +2C6E; C; 0271; # LATIN CAPITAL LETTER M WITH HOOK +2C6F; C; 0250; # LATIN CAPITAL LETTER TURNED A +2C70; C; 0252; # LATIN CAPITAL LETTER TURNED ALPHA +2C72; C; 2C73; # LATIN CAPITAL LETTER W WITH HOOK +2C75; C; 2C76; # LATIN CAPITAL LETTER HALF H +2C7E; C; 023F; # LATIN CAPITAL LETTER S WITH SWASH TAIL +2C7F; C; 0240; # LATIN CAPITAL LETTER Z WITH SWASH TAIL +2C80; C; 2C81; # COPTIC CAPITAL LETTER ALFA +2C82; C; 2C83; # COPTIC CAPITAL LETTER VIDA +2C84; C; 2C85; # COPTIC CAPITAL LETTER GAMMA +2C86; C; 2C87; # COPTIC CAPITAL LETTER DALDA +2C88; C; 2C89; # COPTIC CAPITAL LETTER EIE +2C8A; C; 2C8B; # COPTIC CAPITAL LETTER SOU +2C8C; C; 2C8D; # COPTIC CAPITAL LETTER ZATA +2C8E; C; 2C8F; # COPTIC CAPITAL LETTER HATE +2C90; C; 2C91; # COPTIC CAPITAL LETTER THETHE +2C92; C; 2C93; # COPTIC CAPITAL LETTER IAUDA +2C94; C; 2C95; # COPTIC CAPITAL LETTER KAPA +2C96; C; 2C97; # COPTIC CAPITAL LETTER LAULA +2C98; C; 2C99; # COPTIC CAPITAL LETTER MI +2C9A; C; 2C9B; # COPTIC CAPITAL LETTER NI +2C9C; C; 2C9D; # COPTIC CAPITAL LETTER KSI +2C9E; C; 2C9F; # COPTIC CAPITAL LETTER O +2CA0; C; 2CA1; # COPTIC CAPITAL LETTER PI +2CA2; C; 2CA3; # COPTIC CAPITAL LETTER RO +2CA4; C; 2CA5; # COPTIC CAPITAL LETTER SIMA +2CA6; C; 2CA7; # COPTIC CAPITAL LETTER TAU +2CA8; C; 2CA9; # COPTIC CAPITAL LETTER UA +2CAA; C; 2CAB; # COPTIC CAPITAL LETTER FI +2CAC; C; 2CAD; # COPTIC CAPITAL LETTER KHI +2CAE; C; 2CAF; # COPTIC CAPITAL LETTER PSI +2CB0; C; 2CB1; # COPTIC CAPITAL LETTER OOU +2CB2; C; 2CB3; # COPTIC CAPITAL LETTER DIALECT-P ALEF +2CB4; C; 2CB5; # COPTIC CAPITAL LETTER OLD COPTIC AIN +2CB6; C; 2CB7; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE +2CB8; C; 2CB9; # COPTIC CAPITAL LETTER DIALECT-P KAPA +2CBA; C; 2CBB; # COPTIC CAPITAL LETTER DIALECT-P NI +2CBC; C; 2CBD; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI +2CBE; C; 2CBF; # COPTIC CAPITAL LETTER OLD COPTIC OOU +2CC0; C; 2CC1; # COPTIC CAPITAL LETTER SAMPI +2CC2; C; 2CC3; # COPTIC CAPITAL LETTER CROSSED SHEI +2CC4; C; 2CC5; # COPTIC CAPITAL LETTER OLD COPTIC SHEI +2CC6; C; 2CC7; # COPTIC CAPITAL LETTER OLD COPTIC ESH +2CC8; C; 2CC9; # COPTIC CAPITAL LETTER AKHMIMIC KHEI +2CCA; C; 2CCB; # COPTIC CAPITAL LETTER DIALECT-P HORI +2CCC; C; 2CCD; # COPTIC CAPITAL LETTER OLD COPTIC HORI +2CCE; C; 2CCF; # COPTIC CAPITAL LETTER OLD COPTIC HA +2CD0; C; 2CD1; # COPTIC CAPITAL LETTER L-SHAPED HA +2CD2; C; 2CD3; # COPTIC CAPITAL LETTER OLD COPTIC HEI +2CD4; C; 2CD5; # COPTIC CAPITAL LETTER OLD COPTIC HAT +2CD6; C; 2CD7; # COPTIC CAPITAL LETTER OLD COPTIC GANGIA +2CD8; C; 2CD9; # COPTIC CAPITAL LETTER OLD COPTIC DJA +2CDA; C; 2CDB; # COPTIC CAPITAL LETTER OLD COPTIC SHIMA +2CDC; C; 2CDD; # COPTIC CAPITAL LETTER OLD NUBIAN SHIMA +2CDE; C; 2CDF; # COPTIC CAPITAL LETTER OLD NUBIAN NGI +2CE0; C; 2CE1; # COPTIC CAPITAL LETTER OLD NUBIAN NYI +2CE2; C; 2CE3; # COPTIC CAPITAL LETTER OLD NUBIAN WAU +2CEB; C; 2CEC; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI +2CED; C; 2CEE; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIA +2CF2; C; 2CF3; # COPTIC CAPITAL LETTER BOHAIRIC KHEI +A640; C; A641; # CYRILLIC CAPITAL LETTER ZEMLYA +A642; C; A643; # CYRILLIC CAPITAL LETTER DZELO +A644; C; A645; # CYRILLIC CAPITAL LETTER REVERSED DZE +A646; C; A647; # CYRILLIC CAPITAL LETTER IOTA +A648; C; A649; # CYRILLIC CAPITAL LETTER DJERV +A64A; C; A64B; # CYRILLIC CAPITAL LETTER MONOGRAPH UK +A64C; C; A64D; # CYRILLIC CAPITAL LETTER BROAD OMEGA +A64E; C; A64F; # CYRILLIC CAPITAL LETTER NEUTRAL YER +A650; C; A651; # CYRILLIC CAPITAL LETTER YERU WITH BACK YER +A652; C; A653; # CYRILLIC CAPITAL LETTER IOTIFIED YAT +A654; C; A655; # CYRILLIC CAPITAL LETTER REVERSED YU +A656; C; A657; # CYRILLIC CAPITAL LETTER IOTIFIED A +A658; C; A659; # CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS +A65A; C; A65B; # CYRILLIC CAPITAL LETTER BLENDED YUS +A65C; C; A65D; # CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS +A65E; C; A65F; # CYRILLIC CAPITAL LETTER YN +A660; C; A661; # CYRILLIC CAPITAL LETTER REVERSED TSE +A662; C; A663; # CYRILLIC CAPITAL LETTER SOFT DE +A664; C; A665; # CYRILLIC CAPITAL LETTER SOFT EL +A666; C; A667; # CYRILLIC CAPITAL LETTER SOFT EM +A668; C; A669; # CYRILLIC CAPITAL LETTER MONOCULAR O +A66A; C; A66B; # CYRILLIC CAPITAL LETTER BINOCULAR O +A66C; C; A66D; # CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O +A680; C; A681; # CYRILLIC CAPITAL LETTER DWE +A682; C; A683; # CYRILLIC CAPITAL LETTER DZWE +A684; C; A685; # CYRILLIC CAPITAL LETTER ZHWE +A686; C; A687; # CYRILLIC CAPITAL LETTER CCHE +A688; C; A689; # CYRILLIC CAPITAL LETTER DZZE +A68A; C; A68B; # CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK +A68C; C; A68D; # CYRILLIC CAPITAL LETTER TWE +A68E; C; A68F; # CYRILLIC CAPITAL LETTER TSWE +A690; C; A691; # CYRILLIC CAPITAL LETTER TSSE +A692; C; A693; # CYRILLIC CAPITAL LETTER TCHE +A694; C; A695; # CYRILLIC CAPITAL LETTER HWE +A696; C; A697; # CYRILLIC CAPITAL LETTER SHWE +A698; C; A699; # CYRILLIC CAPITAL LETTER DOUBLE O +A69A; C; A69B; # CYRILLIC CAPITAL LETTER CROSSED O +A722; C; A723; # LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF +A724; C; A725; # LATIN CAPITAL LETTER EGYPTOLOGICAL AIN +A726; C; A727; # LATIN CAPITAL LETTER HENG +A728; C; A729; # LATIN CAPITAL LETTER TZ +A72A; C; A72B; # LATIN CAPITAL LETTER TRESILLO +A72C; C; A72D; # LATIN CAPITAL LETTER CUATRILLO +A72E; C; A72F; # LATIN CAPITAL LETTER CUATRILLO WITH COMMA +A732; C; A733; # LATIN CAPITAL LETTER AA +A734; C; A735; # LATIN CAPITAL LETTER AO +A736; C; A737; # LATIN CAPITAL LETTER AU +A738; C; A739; # LATIN CAPITAL LETTER AV +A73A; C; A73B; # LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR +A73C; C; A73D; # LATIN CAPITAL LETTER AY +A73E; C; A73F; # LATIN CAPITAL LETTER REVERSED C WITH DOT +A740; C; A741; # LATIN CAPITAL LETTER K WITH STROKE +A742; C; A743; # LATIN CAPITAL LETTER K WITH DIAGONAL STROKE +A744; C; A745; # LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE +A746; C; A747; # LATIN CAPITAL LETTER BROKEN L +A748; C; A749; # LATIN CAPITAL LETTER L WITH HIGH STROKE +A74A; C; A74B; # LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY +A74C; C; A74D; # LATIN CAPITAL LETTER O WITH LOOP +A74E; C; A74F; # LATIN CAPITAL LETTER OO +A750; C; A751; # LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER +A752; C; A753; # LATIN CAPITAL LETTER P WITH FLOURISH +A754; C; A755; # LATIN CAPITAL LETTER P WITH SQUIRREL TAIL +A756; C; A757; # LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER +A758; C; A759; # LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE +A75A; C; A75B; # LATIN CAPITAL LETTER R ROTUNDA +A75C; C; A75D; # LATIN CAPITAL LETTER RUM ROTUNDA +A75E; C; A75F; # LATIN CAPITAL LETTER V WITH DIAGONAL STROKE +A760; C; A761; # LATIN CAPITAL LETTER VY +A762; C; A763; # LATIN CAPITAL LETTER VISIGOTHIC Z +A764; C; A765; # LATIN CAPITAL LETTER THORN WITH STROKE +A766; C; A767; # LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER +A768; C; A769; # LATIN CAPITAL LETTER VEND +A76A; C; A76B; # LATIN CAPITAL LETTER ET +A76C; C; A76D; # LATIN CAPITAL LETTER IS +A76E; C; A76F; # LATIN CAPITAL LETTER CON +A779; C; A77A; # LATIN CAPITAL LETTER INSULAR D +A77B; C; A77C; # LATIN CAPITAL LETTER INSULAR F +A77D; C; 1D79; # LATIN CAPITAL LETTER INSULAR G +A77E; C; A77F; # LATIN CAPITAL LETTER TURNED INSULAR G +A780; C; A781; # LATIN CAPITAL LETTER TURNED L +A782; C; A783; # LATIN CAPITAL LETTER INSULAR R +A784; C; A785; # LATIN CAPITAL LETTER INSULAR S +A786; C; A787; # LATIN CAPITAL LETTER INSULAR T +A78B; C; A78C; # LATIN CAPITAL LETTER SALTILLO +A78D; C; 0265; # LATIN CAPITAL LETTER TURNED H +A790; C; A791; # LATIN CAPITAL LETTER N WITH DESCENDER +A792; C; A793; # LATIN CAPITAL LETTER C WITH BAR +A796; C; A797; # LATIN CAPITAL LETTER B WITH FLOURISH +A798; C; A799; # LATIN CAPITAL LETTER F WITH STROKE +A79A; C; A79B; # LATIN CAPITAL LETTER VOLAPUK AE +A79C; C; A79D; # LATIN CAPITAL LETTER VOLAPUK OE +A79E; C; A79F; # LATIN CAPITAL LETTER VOLAPUK UE +A7A0; C; A7A1; # LATIN CAPITAL LETTER G WITH OBLIQUE STROKE +A7A2; C; A7A3; # LATIN CAPITAL LETTER K WITH OBLIQUE STROKE +A7A4; C; A7A5; # LATIN CAPITAL LETTER N WITH OBLIQUE STROKE +A7A6; C; A7A7; # LATIN CAPITAL LETTER R WITH OBLIQUE STROKE +A7A8; C; A7A9; # LATIN CAPITAL LETTER S WITH OBLIQUE STROKE +A7AA; C; 0266; # LATIN CAPITAL LETTER H WITH HOOK +A7AB; C; 025C; # LATIN CAPITAL LETTER REVERSED OPEN E +A7AC; C; 0261; # LATIN CAPITAL LETTER SCRIPT G +A7AD; C; 026C; # LATIN CAPITAL LETTER L WITH BELT +A7AE; C; 026A; # LATIN CAPITAL LETTER SMALL CAPITAL I +A7B0; C; 029E; # LATIN CAPITAL LETTER TURNED K +A7B1; C; 0287; # LATIN CAPITAL LETTER TURNED T +A7B2; C; 029D; # LATIN CAPITAL LETTER J WITH CROSSED-TAIL +A7B3; C; AB53; # LATIN CAPITAL LETTER CHI +A7B4; C; A7B5; # LATIN CAPITAL LETTER BETA +A7B6; C; A7B7; # LATIN CAPITAL LETTER OMEGA +A7B8; C; A7B9; # LATIN CAPITAL LETTER U WITH STROKE +A7BA; C; A7BB; # LATIN CAPITAL LETTER GLOTTAL A +A7BC; C; A7BD; # LATIN CAPITAL LETTER GLOTTAL I +A7BE; C; A7BF; # LATIN CAPITAL LETTER GLOTTAL U +A7C0; C; A7C1; # LATIN CAPITAL LETTER OLD POLISH O +A7C2; C; A7C3; # LATIN CAPITAL LETTER ANGLICANA W +A7C4; C; A794; # LATIN CAPITAL LETTER C WITH PALATAL HOOK +A7C5; C; 0282; # LATIN CAPITAL LETTER S WITH HOOK +A7C6; C; 1D8E; # LATIN CAPITAL LETTER Z WITH PALATAL HOOK +A7C7; C; A7C8; # LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY +A7C9; C; A7CA; # LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY +A7D0; C; A7D1; # LATIN CAPITAL LETTER CLOSED INSULAR G +A7D6; C; A7D7; # LATIN CAPITAL LETTER MIDDLE SCOTS S +A7D8; C; A7D9; # LATIN CAPITAL LETTER SIGMOID S +A7F5; C; A7F6; # LATIN CAPITAL LETTER REVERSED HALF H +AB70; C; 13A0; # CHEROKEE SMALL LETTER A +AB71; C; 13A1; # CHEROKEE SMALL LETTER E +AB72; C; 13A2; # CHEROKEE SMALL LETTER I +AB73; C; 13A3; # CHEROKEE SMALL LETTER O +AB74; C; 13A4; # CHEROKEE SMALL LETTER U +AB75; C; 13A5; # CHEROKEE SMALL LETTER V +AB76; C; 13A6; # CHEROKEE SMALL LETTER GA +AB77; C; 13A7; # CHEROKEE SMALL LETTER KA +AB78; C; 13A8; # CHEROKEE SMALL LETTER GE +AB79; C; 13A9; # CHEROKEE SMALL LETTER GI +AB7A; C; 13AA; # CHEROKEE SMALL LETTER GO +AB7B; C; 13AB; # CHEROKEE SMALL LETTER GU +AB7C; C; 13AC; # CHEROKEE SMALL LETTER GV +AB7D; C; 13AD; # CHEROKEE SMALL LETTER HA +AB7E; C; 13AE; # CHEROKEE SMALL LETTER HE +AB7F; C; 13AF; # CHEROKEE SMALL LETTER HI +AB80; C; 13B0; # CHEROKEE SMALL LETTER HO +AB81; C; 13B1; # CHEROKEE SMALL LETTER HU +AB82; C; 13B2; # CHEROKEE SMALL LETTER HV +AB83; C; 13B3; # CHEROKEE SMALL LETTER LA +AB84; C; 13B4; # CHEROKEE SMALL LETTER LE +AB85; C; 13B5; # CHEROKEE SMALL LETTER LI +AB86; C; 13B6; # CHEROKEE SMALL LETTER LO +AB87; C; 13B7; # CHEROKEE SMALL LETTER LU +AB88; C; 13B8; # CHEROKEE SMALL LETTER LV +AB89; C; 13B9; # CHEROKEE SMALL LETTER MA +AB8A; C; 13BA; # CHEROKEE SMALL LETTER ME +AB8B; C; 13BB; # CHEROKEE SMALL LETTER MI +AB8C; C; 13BC; # CHEROKEE SMALL LETTER MO +AB8D; C; 13BD; # CHEROKEE SMALL LETTER MU +AB8E; C; 13BE; # CHEROKEE SMALL LETTER NA +AB8F; C; 13BF; # CHEROKEE SMALL LETTER HNA +AB90; C; 13C0; # CHEROKEE SMALL LETTER NAH +AB91; C; 13C1; # CHEROKEE SMALL LETTER NE +AB92; C; 13C2; # CHEROKEE SMALL LETTER NI +AB93; C; 13C3; # CHEROKEE SMALL LETTER NO +AB94; C; 13C4; # CHEROKEE SMALL LETTER NU +AB95; C; 13C5; # CHEROKEE SMALL LETTER NV +AB96; C; 13C6; # CHEROKEE SMALL LETTER QUA +AB97; C; 13C7; # CHEROKEE SMALL LETTER QUE +AB98; C; 13C8; # CHEROKEE SMALL LETTER QUI +AB99; C; 13C9; # CHEROKEE SMALL LETTER QUO +AB9A; C; 13CA; # CHEROKEE SMALL LETTER QUU +AB9B; C; 13CB; # CHEROKEE SMALL LETTER QUV +AB9C; C; 13CC; # CHEROKEE SMALL LETTER SA +AB9D; C; 13CD; # CHEROKEE SMALL LETTER S +AB9E; C; 13CE; # CHEROKEE SMALL LETTER SE +AB9F; C; 13CF; # CHEROKEE SMALL LETTER SI +ABA0; C; 13D0; # CHEROKEE SMALL LETTER SO +ABA1; C; 13D1; # CHEROKEE SMALL LETTER SU +ABA2; C; 13D2; # CHEROKEE SMALL LETTER SV +ABA3; C; 13D3; # CHEROKEE SMALL LETTER DA +ABA4; C; 13D4; # CHEROKEE SMALL LETTER TA +ABA5; C; 13D5; # CHEROKEE SMALL LETTER DE +ABA6; C; 13D6; # CHEROKEE SMALL LETTER TE +ABA7; C; 13D7; # CHEROKEE SMALL LETTER DI +ABA8; C; 13D8; # CHEROKEE SMALL LETTER TI +ABA9; C; 13D9; # CHEROKEE SMALL LETTER DO +ABAA; C; 13DA; # CHEROKEE SMALL LETTER DU +ABAB; C; 13DB; # CHEROKEE SMALL LETTER DV +ABAC; C; 13DC; # CHEROKEE SMALL LETTER DLA +ABAD; C; 13DD; # CHEROKEE SMALL LETTER TLA +ABAE; C; 13DE; # CHEROKEE SMALL LETTER TLE +ABAF; C; 13DF; # CHEROKEE SMALL LETTER TLI +ABB0; C; 13E0; # CHEROKEE SMALL LETTER TLO +ABB1; C; 13E1; # CHEROKEE SMALL LETTER TLU +ABB2; C; 13E2; # CHEROKEE SMALL LETTER TLV +ABB3; C; 13E3; # CHEROKEE SMALL LETTER TSA +ABB4; C; 13E4; # CHEROKEE SMALL LETTER TSE +ABB5; C; 13E5; # CHEROKEE SMALL LETTER TSI +ABB6; C; 13E6; # CHEROKEE SMALL LETTER TSO +ABB7; C; 13E7; # CHEROKEE SMALL LETTER TSU +ABB8; C; 13E8; # CHEROKEE SMALL LETTER TSV +ABB9; C; 13E9; # CHEROKEE SMALL LETTER WA +ABBA; C; 13EA; # CHEROKEE SMALL LETTER WE +ABBB; C; 13EB; # CHEROKEE SMALL LETTER WI +ABBC; C; 13EC; # CHEROKEE SMALL LETTER WO +ABBD; C; 13ED; # CHEROKEE SMALL LETTER WU +ABBE; C; 13EE; # CHEROKEE SMALL LETTER WV +ABBF; C; 13EF; # CHEROKEE SMALL LETTER YA +FB00; F; 0066 0066; # LATIN SMALL LIGATURE FF +FB01; F; 0066 0069; # LATIN SMALL LIGATURE FI +FB02; F; 0066 006C; # LATIN SMALL LIGATURE FL +FB03; F; 0066 0066 0069; # LATIN SMALL LIGATURE FFI +FB04; F; 0066 0066 006C; # LATIN SMALL LIGATURE FFL +FB05; F; 0073 0074; # LATIN SMALL LIGATURE LONG S T +FB06; F; 0073 0074; # LATIN SMALL LIGATURE ST +FB13; F; 0574 0576; # ARMENIAN SMALL LIGATURE MEN NOW +FB14; F; 0574 0565; # ARMENIAN SMALL LIGATURE MEN ECH +FB15; F; 0574 056B; # ARMENIAN SMALL LIGATURE MEN INI +FB16; F; 057E 0576; # ARMENIAN SMALL LIGATURE VEW NOW +FB17; F; 0574 056D; # ARMENIAN SMALL LIGATURE MEN XEH +FF21; C; FF41; # FULLWIDTH LATIN CAPITAL LETTER A +FF22; C; FF42; # FULLWIDTH LATIN CAPITAL LETTER B +FF23; C; FF43; # FULLWIDTH LATIN CAPITAL LETTER C +FF24; C; FF44; # FULLWIDTH LATIN CAPITAL LETTER D +FF25; C; FF45; # FULLWIDTH LATIN CAPITAL LETTER E +FF26; C; FF46; # FULLWIDTH LATIN CAPITAL LETTER F +FF27; C; FF47; # FULLWIDTH LATIN CAPITAL LETTER G +FF28; C; FF48; # FULLWIDTH LATIN CAPITAL LETTER H +FF29; C; FF49; # FULLWIDTH LATIN CAPITAL LETTER I +FF2A; C; FF4A; # FULLWIDTH LATIN CAPITAL LETTER J +FF2B; C; FF4B; # FULLWIDTH LATIN CAPITAL LETTER K +FF2C; C; FF4C; # FULLWIDTH LATIN CAPITAL LETTER L +FF2D; C; FF4D; # FULLWIDTH LATIN CAPITAL LETTER M +FF2E; C; FF4E; # FULLWIDTH LATIN CAPITAL LETTER N +FF2F; C; FF4F; # FULLWIDTH LATIN CAPITAL LETTER O +FF30; C; FF50; # FULLWIDTH LATIN CAPITAL LETTER P +FF31; C; FF51; # FULLWIDTH LATIN CAPITAL LETTER Q +FF32; C; FF52; # FULLWIDTH LATIN CAPITAL LETTER R +FF33; C; FF53; # FULLWIDTH LATIN CAPITAL LETTER S +FF34; C; FF54; # FULLWIDTH LATIN CAPITAL LETTER T +FF35; C; FF55; # FULLWIDTH LATIN CAPITAL LETTER U +FF36; C; FF56; # FULLWIDTH LATIN CAPITAL LETTER V +FF37; C; FF57; # FULLWIDTH LATIN CAPITAL LETTER W +FF38; C; FF58; # FULLWIDTH LATIN CAPITAL LETTER X +FF39; C; FF59; # FULLWIDTH LATIN CAPITAL LETTER Y +FF3A; C; FF5A; # FULLWIDTH LATIN CAPITAL LETTER Z +10400; C; 10428; # DESERET CAPITAL LETTER LONG I +10401; C; 10429; # DESERET CAPITAL LETTER LONG E +10402; C; 1042A; # DESERET CAPITAL LETTER LONG A +10403; C; 1042B; # DESERET CAPITAL LETTER LONG AH +10404; C; 1042C; # DESERET CAPITAL LETTER LONG O +10405; C; 1042D; # DESERET CAPITAL LETTER LONG OO +10406; C; 1042E; # DESERET CAPITAL LETTER SHORT I +10407; C; 1042F; # DESERET CAPITAL LETTER SHORT E +10408; C; 10430; # DESERET CAPITAL LETTER SHORT A +10409; C; 10431; # DESERET CAPITAL LETTER SHORT AH +1040A; C; 10432; # DESERET CAPITAL LETTER SHORT O +1040B; C; 10433; # DESERET CAPITAL LETTER SHORT OO +1040C; C; 10434; # DESERET CAPITAL LETTER AY +1040D; C; 10435; # DESERET CAPITAL LETTER OW +1040E; C; 10436; # DESERET CAPITAL LETTER WU +1040F; C; 10437; # DESERET CAPITAL LETTER YEE +10410; C; 10438; # DESERET CAPITAL LETTER H +10411; C; 10439; # DESERET CAPITAL LETTER PEE +10412; C; 1043A; # DESERET CAPITAL LETTER BEE +10413; C; 1043B; # DESERET CAPITAL LETTER TEE +10414; C; 1043C; # DESERET CAPITAL LETTER DEE +10415; C; 1043D; # DESERET CAPITAL LETTER CHEE +10416; C; 1043E; # DESERET CAPITAL LETTER JEE +10417; C; 1043F; # DESERET CAPITAL LETTER KAY +10418; C; 10440; # DESERET CAPITAL LETTER GAY +10419; C; 10441; # DESERET CAPITAL LETTER EF +1041A; C; 10442; # DESERET CAPITAL LETTER VEE +1041B; C; 10443; # DESERET CAPITAL LETTER ETH +1041C; C; 10444; # DESERET CAPITAL LETTER THEE +1041D; C; 10445; # DESERET CAPITAL LETTER ES +1041E; C; 10446; # DESERET CAPITAL LETTER ZEE +1041F; C; 10447; # DESERET CAPITAL LETTER ESH +10420; C; 10448; # DESERET CAPITAL LETTER ZHEE +10421; C; 10449; # DESERET CAPITAL LETTER ER +10422; C; 1044A; # DESERET CAPITAL LETTER EL +10423; C; 1044B; # DESERET CAPITAL LETTER EM +10424; C; 1044C; # DESERET CAPITAL LETTER EN +10425; C; 1044D; # DESERET CAPITAL LETTER ENG +10426; C; 1044E; # DESERET CAPITAL LETTER OI +10427; C; 1044F; # DESERET CAPITAL LETTER EW +104B0; C; 104D8; # OSAGE CAPITAL LETTER A +104B1; C; 104D9; # OSAGE CAPITAL LETTER AI +104B2; C; 104DA; # OSAGE CAPITAL LETTER AIN +104B3; C; 104DB; # OSAGE CAPITAL LETTER AH +104B4; C; 104DC; # OSAGE CAPITAL LETTER BRA +104B5; C; 104DD; # OSAGE CAPITAL LETTER CHA +104B6; C; 104DE; # OSAGE CAPITAL LETTER EHCHA +104B7; C; 104DF; # OSAGE CAPITAL LETTER E +104B8; C; 104E0; # OSAGE CAPITAL LETTER EIN +104B9; C; 104E1; # OSAGE CAPITAL LETTER HA +104BA; C; 104E2; # OSAGE CAPITAL LETTER HYA +104BB; C; 104E3; # OSAGE CAPITAL LETTER I +104BC; C; 104E4; # OSAGE CAPITAL LETTER KA +104BD; C; 104E5; # OSAGE CAPITAL LETTER EHKA +104BE; C; 104E6; # OSAGE CAPITAL LETTER KYA +104BF; C; 104E7; # OSAGE CAPITAL LETTER LA +104C0; C; 104E8; # OSAGE CAPITAL LETTER MA +104C1; C; 104E9; # OSAGE CAPITAL LETTER NA +104C2; C; 104EA; # OSAGE CAPITAL LETTER O +104C3; C; 104EB; # OSAGE CAPITAL LETTER OIN +104C4; C; 104EC; # OSAGE CAPITAL LETTER PA +104C5; C; 104ED; # OSAGE CAPITAL LETTER EHPA +104C6; C; 104EE; # OSAGE CAPITAL LETTER SA +104C7; C; 104EF; # OSAGE CAPITAL LETTER SHA +104C8; C; 104F0; # OSAGE CAPITAL LETTER TA +104C9; C; 104F1; # OSAGE CAPITAL LETTER EHTA +104CA; C; 104F2; # OSAGE CAPITAL LETTER TSA +104CB; C; 104F3; # OSAGE CAPITAL LETTER EHTSA +104CC; C; 104F4; # OSAGE CAPITAL LETTER TSHA +104CD; C; 104F5; # OSAGE CAPITAL LETTER DHA +104CE; C; 104F6; # OSAGE CAPITAL LETTER U +104CF; C; 104F7; # OSAGE CAPITAL LETTER WA +104D0; C; 104F8; # OSAGE CAPITAL LETTER KHA +104D1; C; 104F9; # OSAGE CAPITAL LETTER GHA +104D2; C; 104FA; # OSAGE CAPITAL LETTER ZA +104D3; C; 104FB; # OSAGE CAPITAL LETTER ZHA +10570; C; 10597; # VITHKUQI CAPITAL LETTER A +10571; C; 10598; # VITHKUQI CAPITAL LETTER BBE +10572; C; 10599; # VITHKUQI CAPITAL LETTER BE +10573; C; 1059A; # VITHKUQI CAPITAL LETTER CE +10574; C; 1059B; # VITHKUQI CAPITAL LETTER CHE +10575; C; 1059C; # VITHKUQI CAPITAL LETTER DE +10576; C; 1059D; # VITHKUQI CAPITAL LETTER DHE +10577; C; 1059E; # VITHKUQI CAPITAL LETTER EI +10578; C; 1059F; # VITHKUQI CAPITAL LETTER E +10579; C; 105A0; # VITHKUQI CAPITAL LETTER FE +1057A; C; 105A1; # VITHKUQI CAPITAL LETTER GA +1057C; C; 105A3; # VITHKUQI CAPITAL LETTER HA +1057D; C; 105A4; # VITHKUQI CAPITAL LETTER HHA +1057E; C; 105A5; # VITHKUQI CAPITAL LETTER I +1057F; C; 105A6; # VITHKUQI CAPITAL LETTER IJE +10580; C; 105A7; # VITHKUQI CAPITAL LETTER JE +10581; C; 105A8; # VITHKUQI CAPITAL LETTER KA +10582; C; 105A9; # VITHKUQI CAPITAL LETTER LA +10583; C; 105AA; # VITHKUQI CAPITAL LETTER LLA +10584; C; 105AB; # VITHKUQI CAPITAL LETTER ME +10585; C; 105AC; # VITHKUQI CAPITAL LETTER NE +10586; C; 105AD; # VITHKUQI CAPITAL LETTER NJE +10587; C; 105AE; # VITHKUQI CAPITAL LETTER O +10588; C; 105AF; # VITHKUQI CAPITAL LETTER PE +10589; C; 105B0; # VITHKUQI CAPITAL LETTER QA +1058A; C; 105B1; # VITHKUQI CAPITAL LETTER RE +1058C; C; 105B3; # VITHKUQI CAPITAL LETTER SE +1058D; C; 105B4; # VITHKUQI CAPITAL LETTER SHE +1058E; C; 105B5; # VITHKUQI CAPITAL LETTER TE +1058F; C; 105B6; # VITHKUQI CAPITAL LETTER THE +10590; C; 105B7; # VITHKUQI CAPITAL LETTER U +10591; C; 105B8; # VITHKUQI CAPITAL LETTER VE +10592; C; 105B9; # VITHKUQI CAPITAL LETTER XE +10594; C; 105BB; # VITHKUQI CAPITAL LETTER Y +10595; C; 105BC; # VITHKUQI CAPITAL LETTER ZE +10C80; C; 10CC0; # OLD HUNGARIAN CAPITAL LETTER A +10C81; C; 10CC1; # OLD HUNGARIAN CAPITAL LETTER AA +10C82; C; 10CC2; # OLD HUNGARIAN CAPITAL LETTER EB +10C83; C; 10CC3; # OLD HUNGARIAN CAPITAL LETTER AMB +10C84; C; 10CC4; # OLD HUNGARIAN CAPITAL LETTER EC +10C85; C; 10CC5; # OLD HUNGARIAN CAPITAL LETTER ENC +10C86; C; 10CC6; # OLD HUNGARIAN CAPITAL LETTER ECS +10C87; C; 10CC7; # OLD HUNGARIAN CAPITAL LETTER ED +10C88; C; 10CC8; # OLD HUNGARIAN CAPITAL LETTER AND +10C89; C; 10CC9; # OLD HUNGARIAN CAPITAL LETTER E +10C8A; C; 10CCA; # OLD HUNGARIAN CAPITAL LETTER CLOSE E +10C8B; C; 10CCB; # OLD HUNGARIAN CAPITAL LETTER EE +10C8C; C; 10CCC; # OLD HUNGARIAN CAPITAL LETTER EF +10C8D; C; 10CCD; # OLD HUNGARIAN CAPITAL LETTER EG +10C8E; C; 10CCE; # OLD HUNGARIAN CAPITAL LETTER EGY +10C8F; C; 10CCF; # OLD HUNGARIAN CAPITAL LETTER EH +10C90; C; 10CD0; # OLD HUNGARIAN CAPITAL LETTER I +10C91; C; 10CD1; # OLD HUNGARIAN CAPITAL LETTER II +10C92; C; 10CD2; # OLD HUNGARIAN CAPITAL LETTER EJ +10C93; C; 10CD3; # OLD HUNGARIAN CAPITAL LETTER EK +10C94; C; 10CD4; # OLD HUNGARIAN CAPITAL LETTER AK +10C95; C; 10CD5; # OLD HUNGARIAN CAPITAL LETTER UNK +10C96; C; 10CD6; # OLD HUNGARIAN CAPITAL LETTER EL +10C97; C; 10CD7; # OLD HUNGARIAN CAPITAL LETTER ELY +10C98; C; 10CD8; # OLD HUNGARIAN CAPITAL LETTER EM +10C99; C; 10CD9; # OLD HUNGARIAN CAPITAL LETTER EN +10C9A; C; 10CDA; # OLD HUNGARIAN CAPITAL LETTER ENY +10C9B; C; 10CDB; # OLD HUNGARIAN CAPITAL LETTER O +10C9C; C; 10CDC; # OLD HUNGARIAN CAPITAL LETTER OO +10C9D; C; 10CDD; # OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG OE +10C9E; C; 10CDE; # OLD HUNGARIAN CAPITAL LETTER RUDIMENTA OE +10C9F; C; 10CDF; # OLD HUNGARIAN CAPITAL LETTER OEE +10CA0; C; 10CE0; # OLD HUNGARIAN CAPITAL LETTER EP +10CA1; C; 10CE1; # OLD HUNGARIAN CAPITAL LETTER EMP +10CA2; C; 10CE2; # OLD HUNGARIAN CAPITAL LETTER ER +10CA3; C; 10CE3; # OLD HUNGARIAN CAPITAL LETTER SHORT ER +10CA4; C; 10CE4; # OLD HUNGARIAN CAPITAL LETTER ES +10CA5; C; 10CE5; # OLD HUNGARIAN CAPITAL LETTER ESZ +10CA6; C; 10CE6; # OLD HUNGARIAN CAPITAL LETTER ET +10CA7; C; 10CE7; # OLD HUNGARIAN CAPITAL LETTER ENT +10CA8; C; 10CE8; # OLD HUNGARIAN CAPITAL LETTER ETY +10CA9; C; 10CE9; # OLD HUNGARIAN CAPITAL LETTER ECH +10CAA; C; 10CEA; # OLD HUNGARIAN CAPITAL LETTER U +10CAB; C; 10CEB; # OLD HUNGARIAN CAPITAL LETTER UU +10CAC; C; 10CEC; # OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG UE +10CAD; C; 10CED; # OLD HUNGARIAN CAPITAL LETTER RUDIMENTA UE +10CAE; C; 10CEE; # OLD HUNGARIAN CAPITAL LETTER EV +10CAF; C; 10CEF; # OLD HUNGARIAN CAPITAL LETTER EZ +10CB0; C; 10CF0; # OLD HUNGARIAN CAPITAL LETTER EZS +10CB1; C; 10CF1; # OLD HUNGARIAN CAPITAL LETTER ENT-SHAPED SIGN +10CB2; C; 10CF2; # OLD HUNGARIAN CAPITAL LETTER US +118A0; C; 118C0; # WARANG CITI CAPITAL LETTER NGAA +118A1; C; 118C1; # WARANG CITI CAPITAL LETTER A +118A2; C; 118C2; # WARANG CITI CAPITAL LETTER WI +118A3; C; 118C3; # WARANG CITI CAPITAL LETTER YU +118A4; C; 118C4; # WARANG CITI CAPITAL LETTER YA +118A5; C; 118C5; # WARANG CITI CAPITAL LETTER YO +118A6; C; 118C6; # WARANG CITI CAPITAL LETTER II +118A7; C; 118C7; # WARANG CITI CAPITAL LETTER UU +118A8; C; 118C8; # WARANG CITI CAPITAL LETTER E +118A9; C; 118C9; # WARANG CITI CAPITAL LETTER O +118AA; C; 118CA; # WARANG CITI CAPITAL LETTER ANG +118AB; C; 118CB; # WARANG CITI CAPITAL LETTER GA +118AC; C; 118CC; # WARANG CITI CAPITAL LETTER KO +118AD; C; 118CD; # WARANG CITI CAPITAL LETTER ENY +118AE; C; 118CE; # WARANG CITI CAPITAL LETTER YUJ +118AF; C; 118CF; # WARANG CITI CAPITAL LETTER UC +118B0; C; 118D0; # WARANG CITI CAPITAL LETTER ENN +118B1; C; 118D1; # WARANG CITI CAPITAL LETTER ODD +118B2; C; 118D2; # WARANG CITI CAPITAL LETTER TTE +118B3; C; 118D3; # WARANG CITI CAPITAL LETTER NUNG +118B4; C; 118D4; # WARANG CITI CAPITAL LETTER DA +118B5; C; 118D5; # WARANG CITI CAPITAL LETTER AT +118B6; C; 118D6; # WARANG CITI CAPITAL LETTER AM +118B7; C; 118D7; # WARANG CITI CAPITAL LETTER BU +118B8; C; 118D8; # WARANG CITI CAPITAL LETTER PU +118B9; C; 118D9; # WARANG CITI CAPITAL LETTER HIYO +118BA; C; 118DA; # WARANG CITI CAPITAL LETTER HOLO +118BB; C; 118DB; # WARANG CITI CAPITAL LETTER HORR +118BC; C; 118DC; # WARANG CITI CAPITAL LETTER HAR +118BD; C; 118DD; # WARANG CITI CAPITAL LETTER SSUU +118BE; C; 118DE; # WARANG CITI CAPITAL LETTER SII +118BF; C; 118DF; # WARANG CITI CAPITAL LETTER VIYO +16E40; C; 16E60; # MEDEFAIDRIN CAPITAL LETTER M +16E41; C; 16E61; # MEDEFAIDRIN CAPITAL LETTER S +16E42; C; 16E62; # MEDEFAIDRIN CAPITAL LETTER V +16E43; C; 16E63; # MEDEFAIDRIN CAPITAL LETTER W +16E44; C; 16E64; # MEDEFAIDRIN CAPITAL LETTER ATIU +16E45; C; 16E65; # MEDEFAIDRIN CAPITAL LETTER Z +16E46; C; 16E66; # MEDEFAIDRIN CAPITAL LETTER KP +16E47; C; 16E67; # MEDEFAIDRIN CAPITAL LETTER P +16E48; C; 16E68; # MEDEFAIDRIN CAPITAL LETTER T +16E49; C; 16E69; # MEDEFAIDRIN CAPITAL LETTER G +16E4A; C; 16E6A; # MEDEFAIDRIN CAPITAL LETTER F +16E4B; C; 16E6B; # MEDEFAIDRIN CAPITAL LETTER I +16E4C; C; 16E6C; # MEDEFAIDRIN CAPITAL LETTER K +16E4D; C; 16E6D; # MEDEFAIDRIN CAPITAL LETTER A +16E4E; C; 16E6E; # MEDEFAIDRIN CAPITAL LETTER J +16E4F; C; 16E6F; # MEDEFAIDRIN CAPITAL LETTER E +16E50; C; 16E70; # MEDEFAIDRIN CAPITAL LETTER B +16E51; C; 16E71; # MEDEFAIDRIN CAPITAL LETTER C +16E52; C; 16E72; # MEDEFAIDRIN CAPITAL LETTER U +16E53; C; 16E73; # MEDEFAIDRIN CAPITAL LETTER YU +16E54; C; 16E74; # MEDEFAIDRIN CAPITAL LETTER L +16E55; C; 16E75; # MEDEFAIDRIN CAPITAL LETTER Q +16E56; C; 16E76; # MEDEFAIDRIN CAPITAL LETTER HP +16E57; C; 16E77; # MEDEFAIDRIN CAPITAL LETTER NY +16E58; C; 16E78; # MEDEFAIDRIN CAPITAL LETTER X +16E59; C; 16E79; # MEDEFAIDRIN CAPITAL LETTER D +16E5A; C; 16E7A; # MEDEFAIDRIN CAPITAL LETTER OE +16E5B; C; 16E7B; # MEDEFAIDRIN CAPITAL LETTER N +16E5C; C; 16E7C; # MEDEFAIDRIN CAPITAL LETTER R +16E5D; C; 16E7D; # MEDEFAIDRIN CAPITAL LETTER O +16E5E; C; 16E7E; # MEDEFAIDRIN CAPITAL LETTER AI +16E5F; C; 16E7F; # MEDEFAIDRIN CAPITAL LETTER Y +1E900; C; 1E922; # ADLAM CAPITAL LETTER ALIF +1E901; C; 1E923; # ADLAM CAPITAL LETTER DAALI +1E902; C; 1E924; # ADLAM CAPITAL LETTER LAAM +1E903; C; 1E925; # ADLAM CAPITAL LETTER MIIM +1E904; C; 1E926; # ADLAM CAPITAL LETTER BA +1E905; C; 1E927; # ADLAM CAPITAL LETTER SINNYIIYHE +1E906; C; 1E928; # ADLAM CAPITAL LETTER PE +1E907; C; 1E929; # ADLAM CAPITAL LETTER BHE +1E908; C; 1E92A; # ADLAM CAPITAL LETTER RA +1E909; C; 1E92B; # ADLAM CAPITAL LETTER E +1E90A; C; 1E92C; # ADLAM CAPITAL LETTER FA +1E90B; C; 1E92D; # ADLAM CAPITAL LETTER I +1E90C; C; 1E92E; # ADLAM CAPITAL LETTER O +1E90D; C; 1E92F; # ADLAM CAPITAL LETTER DHA +1E90E; C; 1E930; # ADLAM CAPITAL LETTER YHE +1E90F; C; 1E931; # ADLAM CAPITAL LETTER WAW +1E910; C; 1E932; # ADLAM CAPITAL LETTER NUN +1E911; C; 1E933; # ADLAM CAPITAL LETTER KAF +1E912; C; 1E934; # ADLAM CAPITAL LETTER YA +1E913; C; 1E935; # ADLAM CAPITAL LETTER U +1E914; C; 1E936; # ADLAM CAPITAL LETTER JIIM +1E915; C; 1E937; # ADLAM CAPITAL LETTER CHI +1E916; C; 1E938; # ADLAM CAPITAL LETTER HA +1E917; C; 1E939; # ADLAM CAPITAL LETTER QAAF +1E918; C; 1E93A; # ADLAM CAPITAL LETTER GA +1E919; C; 1E93B; # ADLAM CAPITAL LETTER NYA +1E91A; C; 1E93C; # ADLAM CAPITAL LETTER TU +1E91B; C; 1E93D; # ADLAM CAPITAL LETTER NHA +1E91C; C; 1E93E; # ADLAM CAPITAL LETTER VA +1E91D; C; 1E93F; # ADLAM CAPITAL LETTER KHA +1E91E; C; 1E940; # ADLAM CAPITAL LETTER GBE +1E91F; C; 1E941; # ADLAM CAPITAL LETTER ZAL +1E920; C; 1E942; # ADLAM CAPITAL LETTER KPO +1E921; C; 1E943; # ADLAM CAPITAL LETTER SHA +# +# EOF diff --git a/pkgs/markdown/tool/common_mark_stats.json b/pkgs/markdown/tool/common_mark_stats.json new file mode 100644 index 000000000..2e0ba8fc4 --- /dev/null +++ b/pkgs/markdown/tool/common_mark_stats.json @@ -0,0 +1,706 @@ +{ + "ATX headings": { + "62": "strict", + "63": "strict", + "64": "strict", + "65": "strict", + "66": "strict", + "67": "strict", + "68": "strict", + "69": "strict", + "70": "strict", + "71": "strict", + "72": "strict", + "73": "strict", + "74": "strict", + "75": "strict", + "76": "strict", + "77": "strict", + "78": "strict", + "79": "strict" + }, + "Autolinks": { + "594": "strict", + "595": "strict", + "596": "strict", + "597": "strict", + "598": "strict", + "599": "strict", + "600": "strict", + "601": "strict", + "602": "strict", + "603": "strict", + "604": "strict", + "605": "strict", + "606": "strict", + "607": "strict", + "608": "strict", + "609": "strict", + "610": "strict", + "611": "strict", + "612": "strict" + }, + "Backslash escapes": { + "12": "strict", + "13": "strict", + "14": "strict", + "15": "strict", + "16": "strict", + "17": "strict", + "18": "strict", + "19": "strict", + "20": "strict", + "21": "strict", + "22": "strict", + "23": "strict", + "24": "strict" + }, + "Blank lines": { + "227": "strict" + }, + "Block quotes": { + "228": "strict", + "229": "strict", + "230": "strict", + "231": "strict", + "232": "strict", + "233": "strict", + "234": "strict", + "235": "strict", + "236": "strict", + "237": "strict", + "238": "strict", + "239": "strict", + "240": "strict", + "241": "strict", + "242": "strict", + "243": "strict", + "244": "strict", + "245": "strict", + "246": "strict", + "247": "strict", + "248": "strict", + "249": "strict", + "250": "strict", + "251": "strict", + "252": "strict" + }, + "Code spans": { + "328": "strict", + "329": "strict", + "330": "strict", + "331": "strict", + "332": "strict", + "333": "strict", + "334": "strict", + "335": "strict", + "336": "strict", + "337": "strict", + "338": "strict", + "339": "strict", + "340": "strict", + "341": "strict", + "342": "strict", + "343": "strict", + "344": "strict", + "345": "strict", + "346": "strict", + "347": "strict", + "348": "strict", + "349": "strict" + }, + "Emphasis and strong emphasis": { + "350": "strict", + "351": "strict", + "352": "strict", + "353": "strict", + "354": "fail", + "355": "strict", + "356": "strict", + "357": "strict", + "358": "strict", + "359": "strict", + "360": "strict", + "361": "strict", + "362": "strict", + "363": "strict", + "364": "strict", + "365": "strict", + "366": "strict", + "367": "strict", + "368": "strict", + "369": "strict", + "370": "strict", + "371": "strict", + "372": "strict", + "373": "strict", + "374": "strict", + "375": "strict", + "376": "strict", + "377": "strict", + "378": "strict", + "379": "strict", + "380": "strict", + "381": "strict", + "382": "strict", + "383": "strict", + "384": "strict", + "385": "strict", + "386": "strict", + "387": "strict", + "388": "strict", + "389": "strict", + "390": "strict", + "391": "strict", + "392": "strict", + "393": "strict", + "394": "strict", + "395": "strict", + "396": "strict", + "397": "strict", + "398": "strict", + "399": "strict", + "400": "strict", + "401": "strict", + "402": "strict", + "403": "strict", + "404": "strict", + "405": "strict", + "406": "strict", + "407": "strict", + "408": "strict", + "409": "strict", + "410": "strict", + "411": "strict", + "412": "strict", + "413": "strict", + "414": "strict", + "415": "strict", + "416": "strict", + "417": "strict", + "418": "strict", + "419": "strict", + "420": "strict", + "421": "strict", + "422": "strict", + "423": "strict", + "424": "strict", + "425": "strict", + "426": "strict", + "427": "strict", + "428": "strict", + "429": "strict", + "430": "strict", + "431": "strict", + "432": "strict", + "433": "strict", + "434": "strict", + "435": "strict", + "436": "strict", + "437": "strict", + "438": "strict", + "439": "strict", + "440": "strict", + "441": "strict", + "442": "strict", + "443": "strict", + "444": "strict", + "445": "strict", + "446": "strict", + "447": "strict", + "448": "strict", + "449": "strict", + "450": "strict", + "451": "strict", + "452": "strict", + "453": "strict", + "454": "strict", + "455": "strict", + "456": "strict", + "457": "strict", + "458": "strict", + "459": "strict", + "460": "strict", + "461": "strict", + "462": "strict", + "463": "strict", + "464": "strict", + "465": "strict", + "466": "strict", + "467": "strict", + "468": "strict", + "469": "strict", + "470": "strict", + "471": "strict", + "472": "strict", + "473": "strict", + "474": "strict", + "475": "strict", + "476": "strict", + "477": "strict", + "478": "strict", + "479": "strict", + "480": "strict", + "481": "strict" + }, + "Entity and numeric character references": { + "25": "loose", + "26": "strict", + "27": "strict", + "28": "strict", + "29": "strict", + "30": "strict", + "31": "strict", + "32": "strict", + "33": "strict", + "34": "strict", + "35": "strict", + "36": "strict", + "37": "strict", + "38": "strict", + "39": "strict", + "40": "loose", + "41": "strict" + }, + "Fenced code blocks": { + "119": "strict", + "120": "strict", + "121": "strict", + "122": "strict", + "123": "strict", + "124": "strict", + "125": "strict", + "126": "strict", + "127": "strict", + "128": "strict", + "129": "strict", + "130": "strict", + "131": "strict", + "132": "strict", + "133": "strict", + "134": "strict", + "135": "strict", + "136": "strict", + "137": "strict", + "138": "strict", + "139": "strict", + "140": "strict", + "141": "strict", + "142": "strict", + "143": "strict", + "144": "strict", + "145": "strict", + "146": "strict", + "147": "strict" + }, + "Hard line breaks": { + "633": "strict", + "634": "strict", + "635": "strict", + "636": "strict", + "637": "strict", + "638": "strict", + "639": "strict", + "640": "strict", + "641": "strict", + "642": "strict", + "643": "strict", + "644": "strict", + "645": "strict", + "646": "strict", + "647": "strict" + }, + "HTML blocks": { + "148": "strict", + "149": "strict", + "150": "strict", + "151": "strict", + "152": "strict", + "153": "strict", + "154": "strict", + "155": "strict", + "156": "strict", + "157": "strict", + "158": "strict", + "159": "strict", + "160": "strict", + "161": "strict", + "162": "strict", + "163": "strict", + "164": "strict", + "165": "strict", + "166": "strict", + "167": "strict", + "168": "strict", + "169": "strict", + "170": "strict", + "171": "strict", + "172": "strict", + "173": "strict", + "174": "strict", + "175": "strict", + "176": "strict", + "177": "strict", + "178": "strict", + "179": "strict", + "180": "strict", + "181": "strict", + "182": "strict", + "183": "strict", + "184": "strict", + "185": "strict", + "186": "strict", + "187": "strict", + "188": "strict", + "189": "strict", + "190": "strict", + "191": "strict" + }, + "Images": { + "572": "strict", + "573": "strict", + "574": "strict", + "575": "strict", + "576": "strict", + "577": "strict", + "578": "strict", + "579": "strict", + "580": "strict", + "581": "strict", + "582": "strict", + "583": "strict", + "584": "strict", + "585": "strict", + "586": "strict", + "587": "strict", + "588": "strict", + "589": "strict", + "590": "strict", + "591": "strict", + "592": "strict", + "593": "strict" + }, + "Indented code blocks": { + "107": "strict", + "108": "strict", + "109": "strict", + "110": "strict", + "111": "strict", + "112": "strict", + "113": "strict", + "114": "strict", + "115": "strict", + "116": "strict", + "117": "strict", + "118": "strict" + }, + "Inlines": { + "327": "strict" + }, + "Link reference definitions": { + "192": "strict", + "193": "strict", + "194": "strict", + "195": "strict", + "196": "strict", + "197": "strict", + "198": "strict", + "199": "strict", + "200": "strict", + "201": "strict", + "202": "strict", + "203": "strict", + "204": "strict", + "205": "strict", + "206": "strict", + "207": "loose", + "208": "strict", + "209": "strict", + "210": "strict", + "211": "strict", + "212": "strict", + "213": "strict", + "214": "strict", + "215": "strict", + "216": "strict", + "217": "strict", + "218": "strict" + }, + "Links": { + "482": "strict", + "483": "strict", + "484": "strict", + "485": "strict", + "486": "strict", + "487": "strict", + "488": "strict", + "489": "strict", + "490": "strict", + "491": "strict", + "492": "strict", + "493": "strict", + "494": "strict", + "495": "strict", + "496": "strict", + "497": "strict", + "498": "strict", + "499": "strict", + "500": "strict", + "501": "strict", + "502": "strict", + "503": "strict", + "504": "strict", + "505": "strict", + "506": "strict", + "507": "strict", + "508": "strict", + "509": "strict", + "510": "strict", + "511": "strict", + "512": "strict", + "513": "strict", + "514": "strict", + "515": "strict", + "516": "strict", + "517": "strict", + "518": "strict", + "519": "strict", + "520": "strict", + "521": "strict", + "522": "strict", + "523": "strict", + "524": "strict", + "525": "strict", + "526": "strict", + "527": "strict", + "528": "strict", + "529": "strict", + "530": "strict", + "531": "strict", + "532": "strict", + "533": "strict", + "534": "strict", + "535": "strict", + "536": "strict", + "537": "strict", + "538": "strict", + "539": "strict", + "540": "strict", + "541": "strict", + "542": "strict", + "543": "strict", + "544": "strict", + "545": "strict", + "546": "strict", + "547": "strict", + "548": "strict", + "549": "strict", + "550": "strict", + "551": "strict", + "552": "strict", + "553": "strict", + "554": "strict", + "555": "strict", + "556": "strict", + "557": "strict", + "558": "strict", + "559": "strict", + "560": "strict", + "561": "strict", + "562": "strict", + "563": "strict", + "564": "strict", + "565": "strict", + "566": "strict", + "567": "strict", + "568": "strict", + "569": "strict", + "570": "strict", + "571": "strict" + }, + "List items": { + "253": "strict", + "254": "strict", + "255": "strict", + "256": "strict", + "257": "strict", + "258": "strict", + "259": "strict", + "260": "strict", + "261": "strict", + "262": "strict", + "263": "strict", + "264": "strict", + "265": "strict", + "266": "strict", + "267": "strict", + "268": "strict", + "269": "strict", + "270": "strict", + "271": "strict", + "272": "strict", + "273": "strict", + "274": "strict", + "275": "strict", + "276": "strict", + "277": "strict", + "278": "strict", + "279": "strict", + "280": "strict", + "281": "strict", + "282": "strict", + "283": "strict", + "284": "strict", + "285": "strict", + "286": "strict", + "287": "strict", + "288": "strict", + "289": "strict", + "290": "strict", + "291": "strict", + "292": "strict", + "293": "strict", + "294": "strict", + "295": "strict", + "296": "strict", + "297": "strict", + "298": "strict", + "299": "strict", + "300": "strict" + }, + "Lists": { + "301": "strict", + "302": "strict", + "303": "strict", + "304": "strict", + "305": "strict", + "306": "strict", + "307": "strict", + "308": "strict", + "309": "strict", + "310": "strict", + "311": "strict", + "312": "strict", + "313": "strict", + "314": "strict", + "315": "strict", + "316": "strict", + "317": "strict", + "318": "strict", + "319": "strict", + "320": "strict", + "321": "strict", + "322": "strict", + "323": "strict", + "324": "strict", + "325": "strict", + "326": "strict" + }, + "Paragraphs": { + "219": "strict", + "220": "strict", + "221": "strict", + "222": "strict", + "223": "strict", + "224": "strict", + "225": "strict", + "226": "strict" + }, + "Precedence": { + "42": "strict" + }, + "Raw HTML": { + "613": "strict", + "614": "strict", + "615": "strict", + "616": "strict", + "617": "strict", + "618": "strict", + "619": "strict", + "620": "strict", + "621": "strict", + "622": "strict", + "623": "strict", + "624": "strict", + "625": "loose", + "626": "loose", + "627": "strict", + "628": "strict", + "629": "strict", + "630": "strict", + "631": "strict", + "632": "strict" + }, + "Setext headings": { + "80": "strict", + "81": "strict", + "82": "loose", + "83": "strict", + "84": "loose", + "85": "strict", + "86": "strict", + "87": "strict", + "88": "strict", + "89": "strict", + "90": "strict", + "91": "strict", + "92": "strict", + "93": "strict", + "94": "strict", + "95": "strict", + "96": "strict", + "97": "strict", + "98": "strict", + "99": "strict", + "100": "strict", + "101": "strict", + "102": "strict", + "103": "strict", + "104": "strict", + "105": "strict", + "106": "strict" + }, + "Soft line breaks": { + "648": "strict", + "649": "strict" + }, + "Tabs": { + "1": "strict", + "2": "strict", + "3": "strict", + "4": "strict", + "5": "strict", + "6": "loose", + "7": "strict", + "8": "strict", + "9": "strict", + "10": "strict", + "11": "strict" + }, + "Textual content": { + "650": "strict", + "651": "strict", + "652": "strict" + }, + "Thematic breaks": { + "43": "strict", + "44": "strict", + "45": "strict", + "46": "strict", + "47": "strict", + "48": "strict", + "49": "strict", + "50": "strict", + "51": "strict", + "52": "strict", + "53": "strict", + "54": "strict", + "55": "strict", + "56": "strict", + "57": "strict", + "58": "strict", + "59": "strict", + "60": "strict", + "61": "strict" + } +} diff --git a/pkgs/markdown/tool/common_mark_stats.txt b/pkgs/markdown/tool/common_mark_stats.txt new file mode 100644 index 000000000..db3b891ec --- /dev/null +++ b/pkgs/markdown/tool/common_mark_stats.txt @@ -0,0 +1,28 @@ + 18 of 18 – 100.0% ATX headings + 19 of 19 – 100.0% Autolinks + 13 of 13 – 100.0% Backslash escapes + 1 of 1 – 100.0% Blank lines + 25 of 25 – 100.0% Block quotes + 22 of 22 – 100.0% Code spans + 131 of 132 – 99.2% Emphasis and strong emphasis + 17 of 17 – 100.0% Entity and numeric character references + 29 of 29 – 100.0% Fenced code blocks + 15 of 15 – 100.0% Hard line breaks + 44 of 44 – 100.0% HTML blocks + 22 of 22 – 100.0% Images + 12 of 12 – 100.0% Indented code blocks + 1 of 1 – 100.0% Inlines + 27 of 27 – 100.0% Link reference definitions + 90 of 90 – 100.0% Links + 48 of 48 – 100.0% List items + 26 of 26 – 100.0% Lists + 8 of 8 – 100.0% Paragraphs + 1 of 1 – 100.0% Precedence + 20 of 20 – 100.0% Raw HTML + 27 of 27 – 100.0% Setext headings + 2 of 2 – 100.0% Soft line breaks + 11 of 11 – 100.0% Tabs + 3 of 3 – 100.0% Textual content + 19 of 19 – 100.0% Thematic breaks + 651 of 652 – 99.8% TOTAL + 643 of 651 – 98.8% TOTAL Strict diff --git a/pkgs/markdown/tool/common_mark_tests.json b/pkgs/markdown/tool/common_mark_tests.json new file mode 100644 index 000000000..1f89e66f2 --- /dev/null +++ b/pkgs/markdown/tool/common_mark_tests.json @@ -0,0 +1,5218 @@ +[ + { + "markdown": "\tfoo\tbaz\t\tbim\n", + "html": "<pre><code>foo\tbaz\t\tbim\n</code></pre>\n", + "example": 1, + "start_line": 355, + "end_line": 360, + "section": "Tabs" + }, + { + "markdown": " \tfoo\tbaz\t\tbim\n", + "html": "<pre><code>foo\tbaz\t\tbim\n</code></pre>\n", + "example": 2, + "start_line": 362, + "end_line": 367, + "section": "Tabs" + }, + { + "markdown": " a\ta\n ὐ\ta\n", + "html": "<pre><code>a\ta\nὐ\ta\n</code></pre>\n", + "example": 3, + "start_line": 369, + "end_line": 376, + "section": "Tabs" + }, + { + "markdown": " - foo\n\n\tbar\n", + "html": "<ul>\n<li>\n<p>foo</p>\n<p>bar</p>\n</li>\n</ul>\n", + "example": 4, + "start_line": 382, + "end_line": 393, + "section": "Tabs" + }, + { + "markdown": "- foo\n\n\t\tbar\n", + "html": "<ul>\n<li>\n<p>foo</p>\n<pre><code> bar\n</code></pre>\n</li>\n</ul>\n", + "example": 5, + "start_line": 395, + "end_line": 407, + "section": "Tabs" + }, + { + "markdown": ">\t\tfoo\n", + "html": "<blockquote>\n<pre><code> foo\n</code></pre>\n</blockquote>\n", + "example": 6, + "start_line": 418, + "end_line": 425, + "section": "Tabs" + }, + { + "markdown": "-\t\tfoo\n", + "html": "<ul>\n<li>\n<pre><code> foo\n</code></pre>\n</li>\n</ul>\n", + "example": 7, + "start_line": 427, + "end_line": 436, + "section": "Tabs" + }, + { + "markdown": " foo\n\tbar\n", + "html": "<pre><code>foo\nbar\n</code></pre>\n", + "example": 8, + "start_line": 439, + "end_line": 446, + "section": "Tabs" + }, + { + "markdown": " - foo\n - bar\n\t - baz\n", + "html": "<ul>\n<li>foo\n<ul>\n<li>bar\n<ul>\n<li>baz</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n", + "example": 9, + "start_line": 448, + "end_line": 464, + "section": "Tabs" + }, + { + "markdown": "#\tFoo\n", + "html": "<h1>Foo</h1>\n", + "example": 10, + "start_line": 466, + "end_line": 470, + "section": "Tabs" + }, + { + "markdown": "*\t*\t*\t\n", + "html": "<hr />\n", + "example": 11, + "start_line": 472, + "end_line": 476, + "section": "Tabs" + }, + { + "markdown": "\\!\\\"\\#\\$\\%\\&\\'\\(\\)\\*\\+\\,\\-\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\\\\\]\\^\\_\\`\\{\\|\\}\\~\n", + "html": "<p>!"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~</p>\n", + "example": 12, + "start_line": 489, + "end_line": 493, + "section": "Backslash escapes" + }, + { + "markdown": "\\\t\\A\\a\\ \\3\\φ\\«\n", + "html": "<p>\\\t\\A\\a\\ \\3\\φ\\«</p>\n", + "example": 13, + "start_line": 499, + "end_line": 503, + "section": "Backslash escapes" + }, + { + "markdown": "\\*not emphasized*\n\\<br/> not a tag\n\\[not a link](/foo)\n\\`not code`\n1\\. not a list\n\\* not a list\n\\# not a heading\n\\[foo]: /url \"not a reference\"\n\\ö not a character entity\n", + "html": "<p>*not emphasized*\n<br/> not a tag\n[not a link](/foo)\n`not code`\n1. not a list\n* not a list\n# not a heading\n[foo]: /url "not a reference"\n&ouml; not a character entity</p>\n", + "example": 14, + "start_line": 509, + "end_line": 529, + "section": "Backslash escapes" + }, + { + "markdown": "\\\\*emphasis*\n", + "html": "<p>\\<em>emphasis</em></p>\n", + "example": 15, + "start_line": 534, + "end_line": 538, + "section": "Backslash escapes" + }, + { + "markdown": "foo\\\nbar\n", + "html": "<p>foo<br />\nbar</p>\n", + "example": 16, + "start_line": 543, + "end_line": 549, + "section": "Backslash escapes" + }, + { + "markdown": "`` \\[\\` ``\n", + "html": "<p><code>\\[\\`</code></p>\n", + "example": 17, + "start_line": 555, + "end_line": 559, + "section": "Backslash escapes" + }, + { + "markdown": " \\[\\]\n", + "html": "<pre><code>\\[\\]\n</code></pre>\n", + "example": 18, + "start_line": 562, + "end_line": 567, + "section": "Backslash escapes" + }, + { + "markdown": "~~~\n\\[\\]\n~~~\n", + "html": "<pre><code>\\[\\]\n</code></pre>\n", + "example": 19, + "start_line": 570, + "end_line": 577, + "section": "Backslash escapes" + }, + { + "markdown": "<https://example.com?find=\\*>\n", + "html": "<p><a href=\"https://example.com?find=%5C*\">https://example.com?find=\\*</a></p>\n", + "example": 20, + "start_line": 580, + "end_line": 584, + "section": "Backslash escapes" + }, + { + "markdown": "<a href=\"/bar\\/)\">\n", + "html": "<a href=\"/bar\\/)\">\n", + "example": 21, + "start_line": 587, + "end_line": 591, + "section": "Backslash escapes" + }, + { + "markdown": "[foo](/bar\\* \"ti\\*tle\")\n", + "html": "<p><a href=\"/bar*\" title=\"ti*tle\">foo</a></p>\n", + "example": 22, + "start_line": 597, + "end_line": 601, + "section": "Backslash escapes" + }, + { + "markdown": "[foo]\n\n[foo]: /bar\\* \"ti\\*tle\"\n", + "html": "<p><a href=\"/bar*\" title=\"ti*tle\">foo</a></p>\n", + "example": 23, + "start_line": 604, + "end_line": 610, + "section": "Backslash escapes" + }, + { + "markdown": "``` foo\\+bar\nfoo\n```\n", + "html": "<pre><code class=\"language-foo+bar\">foo\n</code></pre>\n", + "example": 24, + "start_line": 613, + "end_line": 620, + "section": "Backslash escapes" + }, + { + "markdown": "  & © Æ Ď\n¾ ℋ ⅆ\n∲ ≧̸\n", + "html": "<p>  & © Æ Ď\n¾ ℋ ⅆ\n∲ ≧̸</p>\n", + "example": 25, + "start_line": 649, + "end_line": 657, + "section": "Entity and numeric character references" + }, + { + "markdown": "# Ӓ Ϡ �\n", + "html": "<p># Ӓ Ϡ �</p>\n", + "example": 26, + "start_line": 668, + "end_line": 672, + "section": "Entity and numeric character references" + }, + { + "markdown": "" ആ ಫ\n", + "html": "<p>" ആ ಫ</p>\n", + "example": 27, + "start_line": 681, + "end_line": 685, + "section": "Entity and numeric character references" + }, + { + "markdown": "  &x; &#; &#x;\n�\n&#abcdef0;\n&ThisIsNotDefined; &hi?;\n", + "html": "<p>&nbsp &x; &#; &#x;\n&#87654321;\n&#abcdef0;\n&ThisIsNotDefined; &hi?;</p>\n", + "example": 28, + "start_line": 690, + "end_line": 700, + "section": "Entity and numeric character references" + }, + { + "markdown": "©\n", + "html": "<p>&copy</p>\n", + "example": 29, + "start_line": 707, + "end_line": 711, + "section": "Entity and numeric character references" + }, + { + "markdown": "&MadeUpEntity;\n", + "html": "<p>&MadeUpEntity;</p>\n", + "example": 30, + "start_line": 717, + "end_line": 721, + "section": "Entity and numeric character references" + }, + { + "markdown": "<a href=\"öö.html\">\n", + "html": "<a href=\"öö.html\">\n", + "example": 31, + "start_line": 728, + "end_line": 732, + "section": "Entity and numeric character references" + }, + { + "markdown": "[foo](/föö \"föö\")\n", + "html": "<p><a href=\"/f%C3%B6%C3%B6\" title=\"föö\">foo</a></p>\n", + "example": 32, + "start_line": 735, + "end_line": 739, + "section": "Entity and numeric character references" + }, + { + "markdown": "[foo]\n\n[foo]: /föö \"föö\"\n", + "html": "<p><a href=\"/f%C3%B6%C3%B6\" title=\"föö\">foo</a></p>\n", + "example": 33, + "start_line": 742, + "end_line": 748, + "section": "Entity and numeric character references" + }, + { + "markdown": "``` föö\nfoo\n```\n", + "html": "<pre><code class=\"language-föö\">foo\n</code></pre>\n", + "example": 34, + "start_line": 751, + "end_line": 758, + "section": "Entity and numeric character references" + }, + { + "markdown": "`föö`\n", + "html": "<p><code>f&ouml;&ouml;</code></p>\n", + "example": 35, + "start_line": 764, + "end_line": 768, + "section": "Entity and numeric character references" + }, + { + "markdown": " föfö\n", + "html": "<pre><code>f&ouml;f&ouml;\n</code></pre>\n", + "example": 36, + "start_line": 771, + "end_line": 776, + "section": "Entity and numeric character references" + }, + { + "markdown": "*foo*\n*foo*\n", + "html": "<p>*foo*\n<em>foo</em></p>\n", + "example": 37, + "start_line": 783, + "end_line": 789, + "section": "Entity and numeric character references" + }, + { + "markdown": "* foo\n\n* foo\n", + "html": "<p>* foo</p>\n<ul>\n<li>foo</li>\n</ul>\n", + "example": 38, + "start_line": 791, + "end_line": 800, + "section": "Entity and numeric character references" + }, + { + "markdown": "foo bar\n", + "html": "<p>foo\n\nbar</p>\n", + "example": 39, + "start_line": 802, + "end_line": 808, + "section": "Entity and numeric character references" + }, + { + "markdown": " foo\n", + "html": "<p>\tfoo</p>\n", + "example": 40, + "start_line": 810, + "end_line": 814, + "section": "Entity and numeric character references" + }, + { + "markdown": "[a](url "tit")\n", + "html": "<p>[a](url "tit")</p>\n", + "example": 41, + "start_line": 817, + "end_line": 821, + "section": "Entity and numeric character references" + }, + { + "markdown": "- `one\n- two`\n", + "html": "<ul>\n<li>`one</li>\n<li>two`</li>\n</ul>\n", + "example": 42, + "start_line": 840, + "end_line": 848, + "section": "Precedence" + }, + { + "markdown": "***\n---\n___\n", + "html": "<hr />\n<hr />\n<hr />\n", + "example": 43, + "start_line": 879, + "end_line": 887, + "section": "Thematic breaks" + }, + { + "markdown": "+++\n", + "html": "<p>+++</p>\n", + "example": 44, + "start_line": 892, + "end_line": 896, + "section": "Thematic breaks" + }, + { + "markdown": "===\n", + "html": "<p>===</p>\n", + "example": 45, + "start_line": 899, + "end_line": 903, + "section": "Thematic breaks" + }, + { + "markdown": "--\n**\n__\n", + "html": "<p>--\n**\n__</p>\n", + "example": 46, + "start_line": 908, + "end_line": 916, + "section": "Thematic breaks" + }, + { + "markdown": " ***\n ***\n ***\n", + "html": "<hr />\n<hr />\n<hr />\n", + "example": 47, + "start_line": 921, + "end_line": 929, + "section": "Thematic breaks" + }, + { + "markdown": " ***\n", + "html": "<pre><code>***\n</code></pre>\n", + "example": 48, + "start_line": 934, + "end_line": 939, + "section": "Thematic breaks" + }, + { + "markdown": "Foo\n ***\n", + "html": "<p>Foo\n***</p>\n", + "example": 49, + "start_line": 942, + "end_line": 948, + "section": "Thematic breaks" + }, + { + "markdown": "_____________________________________\n", + "html": "<hr />\n", + "example": 50, + "start_line": 953, + "end_line": 957, + "section": "Thematic breaks" + }, + { + "markdown": " - - -\n", + "html": "<hr />\n", + "example": 51, + "start_line": 962, + "end_line": 966, + "section": "Thematic breaks" + }, + { + "markdown": " ** * ** * ** * **\n", + "html": "<hr />\n", + "example": 52, + "start_line": 969, + "end_line": 973, + "section": "Thematic breaks" + }, + { + "markdown": "- - - -\n", + "html": "<hr />\n", + "example": 53, + "start_line": 976, + "end_line": 980, + "section": "Thematic breaks" + }, + { + "markdown": "- - - - \n", + "html": "<hr />\n", + "example": 54, + "start_line": 985, + "end_line": 989, + "section": "Thematic breaks" + }, + { + "markdown": "_ _ _ _ a\n\na------\n\n---a---\n", + "html": "<p>_ _ _ _ a</p>\n<p>a------</p>\n<p>---a---</p>\n", + "example": 55, + "start_line": 994, + "end_line": 1004, + "section": "Thematic breaks" + }, + { + "markdown": " *-*\n", + "html": "<p><em>-</em></p>\n", + "example": 56, + "start_line": 1010, + "end_line": 1014, + "section": "Thematic breaks" + }, + { + "markdown": "- foo\n***\n- bar\n", + "html": "<ul>\n<li>foo</li>\n</ul>\n<hr />\n<ul>\n<li>bar</li>\n</ul>\n", + "example": 57, + "start_line": 1019, + "end_line": 1031, + "section": "Thematic breaks" + }, + { + "markdown": "Foo\n***\nbar\n", + "html": "<p>Foo</p>\n<hr />\n<p>bar</p>\n", + "example": 58, + "start_line": 1036, + "end_line": 1044, + "section": "Thematic breaks" + }, + { + "markdown": "Foo\n---\nbar\n", + "html": "<h2>Foo</h2>\n<p>bar</p>\n", + "example": 59, + "start_line": 1053, + "end_line": 1060, + "section": "Thematic breaks" + }, + { + "markdown": "* Foo\n* * *\n* Bar\n", + "html": "<ul>\n<li>Foo</li>\n</ul>\n<hr />\n<ul>\n<li>Bar</li>\n</ul>\n", + "example": 60, + "start_line": 1066, + "end_line": 1078, + "section": "Thematic breaks" + }, + { + "markdown": "- Foo\n- * * *\n", + "html": "<ul>\n<li>Foo</li>\n<li>\n<hr />\n</li>\n</ul>\n", + "example": 61, + "start_line": 1083, + "end_line": 1093, + "section": "Thematic breaks" + }, + { + "markdown": "# foo\n## foo\n### foo\n#### foo\n##### foo\n###### foo\n", + "html": "<h1>foo</h1>\n<h2>foo</h2>\n<h3>foo</h3>\n<h4>foo</h4>\n<h5>foo</h5>\n<h6>foo</h6>\n", + "example": 62, + "start_line": 1112, + "end_line": 1126, + "section": "ATX headings" + }, + { + "markdown": "####### foo\n", + "html": "<p>####### foo</p>\n", + "example": 63, + "start_line": 1131, + "end_line": 1135, + "section": "ATX headings" + }, + { + "markdown": "#5 bolt\n\n#hashtag\n", + "html": "<p>#5 bolt</p>\n<p>#hashtag</p>\n", + "example": 64, + "start_line": 1146, + "end_line": 1153, + "section": "ATX headings" + }, + { + "markdown": "\\## foo\n", + "html": "<p>## foo</p>\n", + "example": 65, + "start_line": 1158, + "end_line": 1162, + "section": "ATX headings" + }, + { + "markdown": "# foo *bar* \\*baz\\*\n", + "html": "<h1>foo <em>bar</em> *baz*</h1>\n", + "example": 66, + "start_line": 1167, + "end_line": 1171, + "section": "ATX headings" + }, + { + "markdown": "# foo \n", + "html": "<h1>foo</h1>\n", + "example": 67, + "start_line": 1176, + "end_line": 1180, + "section": "ATX headings" + }, + { + "markdown": " ### foo\n ## foo\n # foo\n", + "html": "<h3>foo</h3>\n<h2>foo</h2>\n<h1>foo</h1>\n", + "example": 68, + "start_line": 1185, + "end_line": 1193, + "section": "ATX headings" + }, + { + "markdown": " # foo\n", + "html": "<pre><code># foo\n</code></pre>\n", + "example": 69, + "start_line": 1198, + "end_line": 1203, + "section": "ATX headings" + }, + { + "markdown": "foo\n # bar\n", + "html": "<p>foo\n# bar</p>\n", + "example": 70, + "start_line": 1206, + "end_line": 1212, + "section": "ATX headings" + }, + { + "markdown": "## foo ##\n ### bar ###\n", + "html": "<h2>foo</h2>\n<h3>bar</h3>\n", + "example": 71, + "start_line": 1217, + "end_line": 1223, + "section": "ATX headings" + }, + { + "markdown": "# foo ##################################\n##### foo ##\n", + "html": "<h1>foo</h1>\n<h5>foo</h5>\n", + "example": 72, + "start_line": 1228, + "end_line": 1234, + "section": "ATX headings" + }, + { + "markdown": "### foo ### \n", + "html": "<h3>foo</h3>\n", + "example": 73, + "start_line": 1239, + "end_line": 1243, + "section": "ATX headings" + }, + { + "markdown": "### foo ### b\n", + "html": "<h3>foo ### b</h3>\n", + "example": 74, + "start_line": 1250, + "end_line": 1254, + "section": "ATX headings" + }, + { + "markdown": "# foo#\n", + "html": "<h1>foo#</h1>\n", + "example": 75, + "start_line": 1259, + "end_line": 1263, + "section": "ATX headings" + }, + { + "markdown": "### foo \\###\n## foo #\\##\n# foo \\#\n", + "html": "<h3>foo ###</h3>\n<h2>foo ###</h2>\n<h1>foo #</h1>\n", + "example": 76, + "start_line": 1269, + "end_line": 1277, + "section": "ATX headings" + }, + { + "markdown": "****\n## foo\n****\n", + "html": "<hr />\n<h2>foo</h2>\n<hr />\n", + "example": 77, + "start_line": 1283, + "end_line": 1291, + "section": "ATX headings" + }, + { + "markdown": "Foo bar\n# baz\nBar foo\n", + "html": "<p>Foo bar</p>\n<h1>baz</h1>\n<p>Bar foo</p>\n", + "example": 78, + "start_line": 1294, + "end_line": 1302, + "section": "ATX headings" + }, + { + "markdown": "## \n#\n### ###\n", + "html": "<h2></h2>\n<h1></h1>\n<h3></h3>\n", + "example": 79, + "start_line": 1307, + "end_line": 1315, + "section": "ATX headings" + }, + { + "markdown": "Foo *bar*\n=========\n\nFoo *bar*\n---------\n", + "html": "<h1>Foo <em>bar</em></h1>\n<h2>Foo <em>bar</em></h2>\n", + "example": 80, + "start_line": 1347, + "end_line": 1356, + "section": "Setext headings" + }, + { + "markdown": "Foo *bar\nbaz*\n====\n", + "html": "<h1>Foo <em>bar\nbaz</em></h1>\n", + "example": 81, + "start_line": 1361, + "end_line": 1368, + "section": "Setext headings" + }, + { + "markdown": " Foo *bar\nbaz*\t\n====\n", + "html": "<h1>Foo <em>bar\nbaz</em></h1>\n", + "example": 82, + "start_line": 1375, + "end_line": 1382, + "section": "Setext headings" + }, + { + "markdown": "Foo\n-------------------------\n\nFoo\n=\n", + "html": "<h2>Foo</h2>\n<h1>Foo</h1>\n", + "example": 83, + "start_line": 1387, + "end_line": 1396, + "section": "Setext headings" + }, + { + "markdown": " Foo\n---\n\n Foo\n-----\n\n Foo\n ===\n", + "html": "<h2>Foo</h2>\n<h2>Foo</h2>\n<h1>Foo</h1>\n", + "example": 84, + "start_line": 1402, + "end_line": 1415, + "section": "Setext headings" + }, + { + "markdown": " Foo\n ---\n\n Foo\n---\n", + "html": "<pre><code>Foo\n---\n\nFoo\n</code></pre>\n<hr />\n", + "example": 85, + "start_line": 1420, + "end_line": 1433, + "section": "Setext headings" + }, + { + "markdown": "Foo\n ---- \n", + "html": "<h2>Foo</h2>\n", + "example": 86, + "start_line": 1439, + "end_line": 1444, + "section": "Setext headings" + }, + { + "markdown": "Foo\n ---\n", + "html": "<p>Foo\n---</p>\n", + "example": 87, + "start_line": 1449, + "end_line": 1455, + "section": "Setext headings" + }, + { + "markdown": "Foo\n= =\n\nFoo\n--- -\n", + "html": "<p>Foo\n= =</p>\n<p>Foo</p>\n<hr />\n", + "example": 88, + "start_line": 1460, + "end_line": 1471, + "section": "Setext headings" + }, + { + "markdown": "Foo \n-----\n", + "html": "<h2>Foo</h2>\n", + "example": 89, + "start_line": 1476, + "end_line": 1481, + "section": "Setext headings" + }, + { + "markdown": "Foo\\\n----\n", + "html": "<h2>Foo\\</h2>\n", + "example": 90, + "start_line": 1486, + "end_line": 1491, + "section": "Setext headings" + }, + { + "markdown": "`Foo\n----\n`\n\n<a title=\"a lot\n---\nof dashes\"/>\n", + "html": "<h2>`Foo</h2>\n<p>`</p>\n<h2><a title="a lot</h2>\n<p>of dashes"/></p>\n", + "example": 91, + "start_line": 1497, + "end_line": 1510, + "section": "Setext headings" + }, + { + "markdown": "> Foo\n---\n", + "html": "<blockquote>\n<p>Foo</p>\n</blockquote>\n<hr />\n", + "example": 92, + "start_line": 1516, + "end_line": 1524, + "section": "Setext headings" + }, + { + "markdown": "> foo\nbar\n===\n", + "html": "<blockquote>\n<p>foo\nbar\n===</p>\n</blockquote>\n", + "example": 93, + "start_line": 1527, + "end_line": 1537, + "section": "Setext headings" + }, + { + "markdown": "- Foo\n---\n", + "html": "<ul>\n<li>Foo</li>\n</ul>\n<hr />\n", + "example": 94, + "start_line": 1540, + "end_line": 1548, + "section": "Setext headings" + }, + { + "markdown": "Foo\nBar\n---\n", + "html": "<h2>Foo\nBar</h2>\n", + "example": 95, + "start_line": 1555, + "end_line": 1562, + "section": "Setext headings" + }, + { + "markdown": "---\nFoo\n---\nBar\n---\nBaz\n", + "html": "<hr />\n<h2>Foo</h2>\n<h2>Bar</h2>\n<p>Baz</p>\n", + "example": 96, + "start_line": 1568, + "end_line": 1580, + "section": "Setext headings" + }, + { + "markdown": "\n====\n", + "html": "<p>====</p>\n", + "example": 97, + "start_line": 1585, + "end_line": 1590, + "section": "Setext headings" + }, + { + "markdown": "---\n---\n", + "html": "<hr />\n<hr />\n", + "example": 98, + "start_line": 1597, + "end_line": 1603, + "section": "Setext headings" + }, + { + "markdown": "- foo\n-----\n", + "html": "<ul>\n<li>foo</li>\n</ul>\n<hr />\n", + "example": 99, + "start_line": 1606, + "end_line": 1614, + "section": "Setext headings" + }, + { + "markdown": " foo\n---\n", + "html": "<pre><code>foo\n</code></pre>\n<hr />\n", + "example": 100, + "start_line": 1617, + "end_line": 1624, + "section": "Setext headings" + }, + { + "markdown": "> foo\n-----\n", + "html": "<blockquote>\n<p>foo</p>\n</blockquote>\n<hr />\n", + "example": 101, + "start_line": 1627, + "end_line": 1635, + "section": "Setext headings" + }, + { + "markdown": "\\> foo\n------\n", + "html": "<h2>> foo</h2>\n", + "example": 102, + "start_line": 1641, + "end_line": 1646, + "section": "Setext headings" + }, + { + "markdown": "Foo\n\nbar\n---\nbaz\n", + "html": "<p>Foo</p>\n<h2>bar</h2>\n<p>baz</p>\n", + "example": 103, + "start_line": 1672, + "end_line": 1682, + "section": "Setext headings" + }, + { + "markdown": "Foo\nbar\n\n---\n\nbaz\n", + "html": "<p>Foo\nbar</p>\n<hr />\n<p>baz</p>\n", + "example": 104, + "start_line": 1688, + "end_line": 1700, + "section": "Setext headings" + }, + { + "markdown": "Foo\nbar\n* * *\nbaz\n", + "html": "<p>Foo\nbar</p>\n<hr />\n<p>baz</p>\n", + "example": 105, + "start_line": 1706, + "end_line": 1716, + "section": "Setext headings" + }, + { + "markdown": "Foo\nbar\n\\---\nbaz\n", + "html": "<p>Foo\nbar\n---\nbaz</p>\n", + "example": 106, + "start_line": 1721, + "end_line": 1731, + "section": "Setext headings" + }, + { + "markdown": " a simple\n indented code block\n", + "html": "<pre><code>a simple\n indented code block\n</code></pre>\n", + "example": 107, + "start_line": 1749, + "end_line": 1756, + "section": "Indented code blocks" + }, + { + "markdown": " - foo\n\n bar\n", + "html": "<ul>\n<li>\n<p>foo</p>\n<p>bar</p>\n</li>\n</ul>\n", + "example": 108, + "start_line": 1763, + "end_line": 1774, + "section": "Indented code blocks" + }, + { + "markdown": "1. foo\n\n - bar\n", + "html": "<ol>\n<li>\n<p>foo</p>\n<ul>\n<li>bar</li>\n</ul>\n</li>\n</ol>\n", + "example": 109, + "start_line": 1777, + "end_line": 1790, + "section": "Indented code blocks" + }, + { + "markdown": " <a/>\n *hi*\n\n - one\n", + "html": "<pre><code><a/>\n*hi*\n\n- one\n</code></pre>\n", + "example": 110, + "start_line": 1797, + "end_line": 1808, + "section": "Indented code blocks" + }, + { + "markdown": " chunk1\n\n chunk2\n \n \n \n chunk3\n", + "html": "<pre><code>chunk1\n\nchunk2\n\n\n\nchunk3\n</code></pre>\n", + "example": 111, + "start_line": 1813, + "end_line": 1830, + "section": "Indented code blocks" + }, + { + "markdown": " chunk1\n \n chunk2\n", + "html": "<pre><code>chunk1\n \n chunk2\n</code></pre>\n", + "example": 112, + "start_line": 1836, + "end_line": 1845, + "section": "Indented code blocks" + }, + { + "markdown": "Foo\n bar\n\n", + "html": "<p>Foo\nbar</p>\n", + "example": 113, + "start_line": 1851, + "end_line": 1858, + "section": "Indented code blocks" + }, + { + "markdown": " foo\nbar\n", + "html": "<pre><code>foo\n</code></pre>\n<p>bar</p>\n", + "example": 114, + "start_line": 1865, + "end_line": 1872, + "section": "Indented code blocks" + }, + { + "markdown": "# Heading\n foo\nHeading\n------\n foo\n----\n", + "html": "<h1>Heading</h1>\n<pre><code>foo\n</code></pre>\n<h2>Heading</h2>\n<pre><code>foo\n</code></pre>\n<hr />\n", + "example": 115, + "start_line": 1878, + "end_line": 1893, + "section": "Indented code blocks" + }, + { + "markdown": " foo\n bar\n", + "html": "<pre><code> foo\nbar\n</code></pre>\n", + "example": 116, + "start_line": 1898, + "end_line": 1905, + "section": "Indented code blocks" + }, + { + "markdown": "\n \n foo\n \n\n", + "html": "<pre><code>foo\n</code></pre>\n", + "example": 117, + "start_line": 1911, + "end_line": 1920, + "section": "Indented code blocks" + }, + { + "markdown": " foo \n", + "html": "<pre><code>foo \n</code></pre>\n", + "example": 118, + "start_line": 1925, + "end_line": 1930, + "section": "Indented code blocks" + }, + { + "markdown": "```\n<\n >\n```\n", + "html": "<pre><code><\n >\n</code></pre>\n", + "example": 119, + "start_line": 1980, + "end_line": 1989, + "section": "Fenced code blocks" + }, + { + "markdown": "~~~\n<\n >\n~~~\n", + "html": "<pre><code><\n >\n</code></pre>\n", + "example": 120, + "start_line": 1994, + "end_line": 2003, + "section": "Fenced code blocks" + }, + { + "markdown": "``\nfoo\n``\n", + "html": "<p><code>foo</code></p>\n", + "example": 121, + "start_line": 2007, + "end_line": 2013, + "section": "Fenced code blocks" + }, + { + "markdown": "```\naaa\n~~~\n```\n", + "html": "<pre><code>aaa\n~~~\n</code></pre>\n", + "example": 122, + "start_line": 2018, + "end_line": 2027, + "section": "Fenced code blocks" + }, + { + "markdown": "~~~\naaa\n```\n~~~\n", + "html": "<pre><code>aaa\n```\n</code></pre>\n", + "example": 123, + "start_line": 2030, + "end_line": 2039, + "section": "Fenced code blocks" + }, + { + "markdown": "````\naaa\n```\n``````\n", + "html": "<pre><code>aaa\n```\n</code></pre>\n", + "example": 124, + "start_line": 2044, + "end_line": 2053, + "section": "Fenced code blocks" + }, + { + "markdown": "~~~~\naaa\n~~~\n~~~~\n", + "html": "<pre><code>aaa\n~~~\n</code></pre>\n", + "example": 125, + "start_line": 2056, + "end_line": 2065, + "section": "Fenced code blocks" + }, + { + "markdown": "```\n", + "html": "<pre><code></code></pre>\n", + "example": 126, + "start_line": 2071, + "end_line": 2075, + "section": "Fenced code blocks" + }, + { + "markdown": "`````\n\n```\naaa\n", + "html": "<pre><code>\n```\naaa\n</code></pre>\n", + "example": 127, + "start_line": 2078, + "end_line": 2088, + "section": "Fenced code blocks" + }, + { + "markdown": "> ```\n> aaa\n\nbbb\n", + "html": "<blockquote>\n<pre><code>aaa\n</code></pre>\n</blockquote>\n<p>bbb</p>\n", + "example": 128, + "start_line": 2091, + "end_line": 2102, + "section": "Fenced code blocks" + }, + { + "markdown": "```\n\n \n```\n", + "html": "<pre><code>\n \n</code></pre>\n", + "example": 129, + "start_line": 2107, + "end_line": 2116, + "section": "Fenced code blocks" + }, + { + "markdown": "```\n```\n", + "html": "<pre><code></code></pre>\n", + "example": 130, + "start_line": 2121, + "end_line": 2126, + "section": "Fenced code blocks" + }, + { + "markdown": " ```\n aaa\naaa\n```\n", + "html": "<pre><code>aaa\naaa\n</code></pre>\n", + "example": 131, + "start_line": 2133, + "end_line": 2142, + "section": "Fenced code blocks" + }, + { + "markdown": " ```\naaa\n aaa\naaa\n ```\n", + "html": "<pre><code>aaa\naaa\naaa\n</code></pre>\n", + "example": 132, + "start_line": 2145, + "end_line": 2156, + "section": "Fenced code blocks" + }, + { + "markdown": " ```\n aaa\n aaa\n aaa\n ```\n", + "html": "<pre><code>aaa\n aaa\naaa\n</code></pre>\n", + "example": 133, + "start_line": 2159, + "end_line": 2170, + "section": "Fenced code blocks" + }, + { + "markdown": " ```\n aaa\n ```\n", + "html": "<pre><code>```\naaa\n```\n</code></pre>\n", + "example": 134, + "start_line": 2175, + "end_line": 2184, + "section": "Fenced code blocks" + }, + { + "markdown": "```\naaa\n ```\n", + "html": "<pre><code>aaa\n</code></pre>\n", + "example": 135, + "start_line": 2190, + "end_line": 2197, + "section": "Fenced code blocks" + }, + { + "markdown": " ```\naaa\n ```\n", + "html": "<pre><code>aaa\n</code></pre>\n", + "example": 136, + "start_line": 2200, + "end_line": 2207, + "section": "Fenced code blocks" + }, + { + "markdown": "```\naaa\n ```\n", + "html": "<pre><code>aaa\n ```\n</code></pre>\n", + "example": 137, + "start_line": 2212, + "end_line": 2220, + "section": "Fenced code blocks" + }, + { + "markdown": "``` ```\naaa\n", + "html": "<p><code> </code>\naaa</p>\n", + "example": 138, + "start_line": 2226, + "end_line": 2232, + "section": "Fenced code blocks" + }, + { + "markdown": "~~~~~~\naaa\n~~~ ~~\n", + "html": "<pre><code>aaa\n~~~ ~~\n</code></pre>\n", + "example": 139, + "start_line": 2235, + "end_line": 2243, + "section": "Fenced code blocks" + }, + { + "markdown": "foo\n```\nbar\n```\nbaz\n", + "html": "<p>foo</p>\n<pre><code>bar\n</code></pre>\n<p>baz</p>\n", + "example": 140, + "start_line": 2249, + "end_line": 2260, + "section": "Fenced code blocks" + }, + { + "markdown": "foo\n---\n~~~\nbar\n~~~\n# baz\n", + "html": "<h2>foo</h2>\n<pre><code>bar\n</code></pre>\n<h1>baz</h1>\n", + "example": 141, + "start_line": 2266, + "end_line": 2278, + "section": "Fenced code blocks" + }, + { + "markdown": "```ruby\ndef foo(x)\n return 3\nend\n```\n", + "html": "<pre><code class=\"language-ruby\">def foo(x)\n return 3\nend\n</code></pre>\n", + "example": 142, + "start_line": 2288, + "end_line": 2299, + "section": "Fenced code blocks" + }, + { + "markdown": "~~~~ ruby startline=3 $%@#$\ndef foo(x)\n return 3\nend\n~~~~~~~\n", + "html": "<pre><code class=\"language-ruby\">def foo(x)\n return 3\nend\n</code></pre>\n", + "example": 143, + "start_line": 2302, + "end_line": 2313, + "section": "Fenced code blocks" + }, + { + "markdown": "````;\n````\n", + "html": "<pre><code class=\"language-;\"></code></pre>\n", + "example": 144, + "start_line": 2316, + "end_line": 2321, + "section": "Fenced code blocks" + }, + { + "markdown": "``` aa ```\nfoo\n", + "html": "<p><code>aa</code>\nfoo</p>\n", + "example": 145, + "start_line": 2326, + "end_line": 2332, + "section": "Fenced code blocks" + }, + { + "markdown": "~~~ aa ``` ~~~\nfoo\n~~~\n", + "html": "<pre><code class=\"language-aa\">foo\n</code></pre>\n", + "example": 146, + "start_line": 2337, + "end_line": 2344, + "section": "Fenced code blocks" + }, + { + "markdown": "```\n``` aaa\n```\n", + "html": "<pre><code>``` aaa\n</code></pre>\n", + "example": 147, + "start_line": 2349, + "end_line": 2356, + "section": "Fenced code blocks" + }, + { + "markdown": "<table><tr><td>\n<pre>\n**Hello**,\n\n_world_.\n</pre>\n</td></tr></table>\n", + "html": "<table><tr><td>\n<pre>\n**Hello**,\n<p><em>world</em>.\n</pre></p>\n</td></tr></table>\n", + "example": 148, + "start_line": 2428, + "end_line": 2443, + "section": "HTML blocks" + }, + { + "markdown": "<table>\n <tr>\n <td>\n hi\n </td>\n </tr>\n</table>\n\nokay.\n", + "html": "<table>\n <tr>\n <td>\n hi\n </td>\n </tr>\n</table>\n<p>okay.</p>\n", + "example": 149, + "start_line": 2457, + "end_line": 2476, + "section": "HTML blocks" + }, + { + "markdown": " <div>\n *hello*\n <foo><a>\n", + "html": " <div>\n *hello*\n <foo><a>\n", + "example": 150, + "start_line": 2479, + "end_line": 2487, + "section": "HTML blocks" + }, + { + "markdown": "</div>\n*foo*\n", + "html": "</div>\n*foo*\n", + "example": 151, + "start_line": 2492, + "end_line": 2498, + "section": "HTML blocks" + }, + { + "markdown": "<DIV CLASS=\"foo\">\n\n*Markdown*\n\n</DIV>\n", + "html": "<DIV CLASS=\"foo\">\n<p><em>Markdown</em></p>\n</DIV>\n", + "example": 152, + "start_line": 2503, + "end_line": 2513, + "section": "HTML blocks" + }, + { + "markdown": "<div id=\"foo\"\n class=\"bar\">\n</div>\n", + "html": "<div id=\"foo\"\n class=\"bar\">\n</div>\n", + "example": 153, + "start_line": 2519, + "end_line": 2527, + "section": "HTML blocks" + }, + { + "markdown": "<div id=\"foo\" class=\"bar\n baz\">\n</div>\n", + "html": "<div id=\"foo\" class=\"bar\n baz\">\n</div>\n", + "example": 154, + "start_line": 2530, + "end_line": 2538, + "section": "HTML blocks" + }, + { + "markdown": "<div>\n*foo*\n\n*bar*\n", + "html": "<div>\n*foo*\n<p><em>bar</em></p>\n", + "example": 155, + "start_line": 2542, + "end_line": 2551, + "section": "HTML blocks" + }, + { + "markdown": "<div id=\"foo\"\n*hi*\n", + "html": "<div id=\"foo\"\n*hi*\n", + "example": 156, + "start_line": 2558, + "end_line": 2564, + "section": "HTML blocks" + }, + { + "markdown": "<div class\nfoo\n", + "html": "<div class\nfoo\n", + "example": 157, + "start_line": 2567, + "end_line": 2573, + "section": "HTML blocks" + }, + { + "markdown": "<div *???-&&&-<---\n*foo*\n", + "html": "<div *???-&&&-<---\n*foo*\n", + "example": 158, + "start_line": 2579, + "end_line": 2585, + "section": "HTML blocks" + }, + { + "markdown": "<div><a href=\"bar\">*foo*</a></div>\n", + "html": "<div><a href=\"bar\">*foo*</a></div>\n", + "example": 159, + "start_line": 2591, + "end_line": 2595, + "section": "HTML blocks" + }, + { + "markdown": "<table><tr><td>\nfoo\n</td></tr></table>\n", + "html": "<table><tr><td>\nfoo\n</td></tr></table>\n", + "example": 160, + "start_line": 2598, + "end_line": 2606, + "section": "HTML blocks" + }, + { + "markdown": "<div></div>\n``` c\nint x = 33;\n```\n", + "html": "<div></div>\n``` c\nint x = 33;\n```\n", + "example": 161, + "start_line": 2615, + "end_line": 2625, + "section": "HTML blocks" + }, + { + "markdown": "<a href=\"foo\">\n*bar*\n</a>\n", + "html": "<a href=\"foo\">\n*bar*\n</a>\n", + "example": 162, + "start_line": 2632, + "end_line": 2640, + "section": "HTML blocks" + }, + { + "markdown": "<Warning>\n*bar*\n</Warning>\n", + "html": "<Warning>\n*bar*\n</Warning>\n", + "example": 163, + "start_line": 2645, + "end_line": 2653, + "section": "HTML blocks" + }, + { + "markdown": "<i class=\"foo\">\n*bar*\n</i>\n", + "html": "<i class=\"foo\">\n*bar*\n</i>\n", + "example": 164, + "start_line": 2656, + "end_line": 2664, + "section": "HTML blocks" + }, + { + "markdown": "</ins>\n*bar*\n", + "html": "</ins>\n*bar*\n", + "example": 165, + "start_line": 2667, + "end_line": 2673, + "section": "HTML blocks" + }, + { + "markdown": "<del>\n*foo*\n</del>\n", + "html": "<del>\n*foo*\n</del>\n", + "example": 166, + "start_line": 2682, + "end_line": 2690, + "section": "HTML blocks" + }, + { + "markdown": "<del>\n\n*foo*\n\n</del>\n", + "html": "<del>\n<p><em>foo</em></p>\n</del>\n", + "example": 167, + "start_line": 2697, + "end_line": 2707, + "section": "HTML blocks" + }, + { + "markdown": "<del>*foo*</del>\n", + "html": "<p><del><em>foo</em></del></p>\n", + "example": 168, + "start_line": 2715, + "end_line": 2719, + "section": "HTML blocks" + }, + { + "markdown": "<pre language=\"haskell\"><code>\nimport Text.HTML.TagSoup\n\nmain :: IO ()\nmain = print $ parseTags tags\n</code></pre>\nokay\n", + "html": "<pre language=\"haskell\"><code>\nimport Text.HTML.TagSoup\n\nmain :: IO ()\nmain = print $ parseTags tags\n</code></pre>\n<p>okay</p>\n", + "example": 169, + "start_line": 2731, + "end_line": 2747, + "section": "HTML blocks" + }, + { + "markdown": "<script type=\"text/javascript\">\n// JavaScript example\n\ndocument.getElementById(\"demo\").innerHTML = \"Hello JavaScript!\";\n</script>\nokay\n", + "html": "<script type=\"text/javascript\">\n// JavaScript example\n\ndocument.getElementById(\"demo\").innerHTML = \"Hello JavaScript!\";\n</script>\n<p>okay</p>\n", + "example": 170, + "start_line": 2752, + "end_line": 2766, + "section": "HTML blocks" + }, + { + "markdown": "<textarea>\n\n*foo*\n\n_bar_\n\n</textarea>\n", + "html": "<textarea>\n\n*foo*\n\n_bar_\n\n</textarea>\n", + "example": 171, + "start_line": 2771, + "end_line": 2787, + "section": "HTML blocks" + }, + { + "markdown": "<style\n type=\"text/css\">\nh1 {color:red;}\n\np {color:blue;}\n</style>\nokay\n", + "html": "<style\n type=\"text/css\">\nh1 {color:red;}\n\np {color:blue;}\n</style>\n<p>okay</p>\n", + "example": 172, + "start_line": 2791, + "end_line": 2807, + "section": "HTML blocks" + }, + { + "markdown": "<style\n type=\"text/css\">\n\nfoo\n", + "html": "<style\n type=\"text/css\">\n\nfoo\n", + "example": 173, + "start_line": 2814, + "end_line": 2824, + "section": "HTML blocks" + }, + { + "markdown": "> <div>\n> foo\n\nbar\n", + "html": "<blockquote>\n<div>\nfoo\n</blockquote>\n<p>bar</p>\n", + "example": 174, + "start_line": 2827, + "end_line": 2838, + "section": "HTML blocks" + }, + { + "markdown": "- <div>\n- foo\n", + "html": "<ul>\n<li>\n<div>\n</li>\n<li>foo</li>\n</ul>\n", + "example": 175, + "start_line": 2841, + "end_line": 2851, + "section": "HTML blocks" + }, + { + "markdown": "<style>p{color:red;}</style>\n*foo*\n", + "html": "<style>p{color:red;}</style>\n<p><em>foo</em></p>\n", + "example": 176, + "start_line": 2856, + "end_line": 2862, + "section": "HTML blocks" + }, + { + "markdown": "<!-- foo -->*bar*\n*baz*\n", + "html": "<!-- foo -->*bar*\n<p><em>baz</em></p>\n", + "example": 177, + "start_line": 2865, + "end_line": 2871, + "section": "HTML blocks" + }, + { + "markdown": "<script>\nfoo\n</script>1. *bar*\n", + "html": "<script>\nfoo\n</script>1. *bar*\n", + "example": 178, + "start_line": 2877, + "end_line": 2885, + "section": "HTML blocks" + }, + { + "markdown": "<!-- Foo\n\nbar\n baz -->\nokay\n", + "html": "<!-- Foo\n\nbar\n baz -->\n<p>okay</p>\n", + "example": 179, + "start_line": 2890, + "end_line": 2902, + "section": "HTML blocks" + }, + { + "markdown": "<?php\n\n echo '>';\n\n?>\nokay\n", + "html": "<?php\n\n echo '>';\n\n?>\n<p>okay</p>\n", + "example": 180, + "start_line": 2908, + "end_line": 2922, + "section": "HTML blocks" + }, + { + "markdown": "<!DOCTYPE html>\n", + "html": "<!DOCTYPE html>\n", + "example": 181, + "start_line": 2927, + "end_line": 2931, + "section": "HTML blocks" + }, + { + "markdown": "<![CDATA[\nfunction matchwo(a,b)\n{\n if (a < b && a < 0) then {\n return 1;\n\n } else {\n\n return 0;\n }\n}\n]]>\nokay\n", + "html": "<![CDATA[\nfunction matchwo(a,b)\n{\n if (a < b && a < 0) then {\n return 1;\n\n } else {\n\n return 0;\n }\n}\n]]>\n<p>okay</p>\n", + "example": 182, + "start_line": 2936, + "end_line": 2964, + "section": "HTML blocks" + }, + { + "markdown": " <!-- foo -->\n\n <!-- foo -->\n", + "html": " <!-- foo -->\n<pre><code><!-- foo -->\n</code></pre>\n", + "example": 183, + "start_line": 2970, + "end_line": 2978, + "section": "HTML blocks" + }, + { + "markdown": " <div>\n\n <div>\n", + "html": " <div>\n<pre><code><div>\n</code></pre>\n", + "example": 184, + "start_line": 2981, + "end_line": 2989, + "section": "HTML blocks" + }, + { + "markdown": "Foo\n<div>\nbar\n</div>\n", + "html": "<p>Foo</p>\n<div>\nbar\n</div>\n", + "example": 185, + "start_line": 2995, + "end_line": 3005, + "section": "HTML blocks" + }, + { + "markdown": "<div>\nbar\n</div>\n*foo*\n", + "html": "<div>\nbar\n</div>\n*foo*\n", + "example": 186, + "start_line": 3012, + "end_line": 3022, + "section": "HTML blocks" + }, + { + "markdown": "Foo\n<a href=\"bar\">\nbaz\n", + "html": "<p>Foo\n<a href=\"bar\">\nbaz</p>\n", + "example": 187, + "start_line": 3027, + "end_line": 3035, + "section": "HTML blocks" + }, + { + "markdown": "<div>\n\n*Emphasized* text.\n\n</div>\n", + "html": "<div>\n<p><em>Emphasized</em> text.</p>\n</div>\n", + "example": 188, + "start_line": 3068, + "end_line": 3078, + "section": "HTML blocks" + }, + { + "markdown": "<div>\n*Emphasized* text.\n</div>\n", + "html": "<div>\n*Emphasized* text.\n</div>\n", + "example": 189, + "start_line": 3081, + "end_line": 3089, + "section": "HTML blocks" + }, + { + "markdown": "<table>\n\n<tr>\n\n<td>\nHi\n</td>\n\n</tr>\n\n</table>\n", + "html": "<table>\n<tr>\n<td>\nHi\n</td>\n</tr>\n</table>\n", + "example": 190, + "start_line": 3103, + "end_line": 3123, + "section": "HTML blocks" + }, + { + "markdown": "<table>\n\n <tr>\n\n <td>\n Hi\n </td>\n\n </tr>\n\n</table>\n", + "html": "<table>\n <tr>\n<pre><code><td>\n Hi\n</td>\n</code></pre>\n </tr>\n</table>\n", + "example": 191, + "start_line": 3130, + "end_line": 3151, + "section": "HTML blocks" + }, + { + "markdown": "[foo]: /url \"title\"\n\n[foo]\n", + "html": "<p><a href=\"/url\" title=\"title\">foo</a></p>\n", + "example": 192, + "start_line": 3179, + "end_line": 3185, + "section": "Link reference definitions" + }, + { + "markdown": " [foo]: \n /url \n 'the title' \n\n[foo]\n", + "html": "<p><a href=\"/url\" title=\"the title\">foo</a></p>\n", + "example": 193, + "start_line": 3188, + "end_line": 3196, + "section": "Link reference definitions" + }, + { + "markdown": "[Foo*bar\\]]:my_(url) 'title (with parens)'\n\n[Foo*bar\\]]\n", + "html": "<p><a href=\"my_(url)\" title=\"title (with parens)\">Foo*bar]</a></p>\n", + "example": 194, + "start_line": 3199, + "end_line": 3205, + "section": "Link reference definitions" + }, + { + "markdown": "[Foo bar]:\n<my url>\n'title'\n\n[Foo bar]\n", + "html": "<p><a href=\"my%20url\" title=\"title\">Foo bar</a></p>\n", + "example": 195, + "start_line": 3208, + "end_line": 3216, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url '\ntitle\nline1\nline2\n'\n\n[foo]\n", + "html": "<p><a href=\"/url\" title=\"\ntitle\nline1\nline2\n\">foo</a></p>\n", + "example": 196, + "start_line": 3221, + "end_line": 3235, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url 'title\n\nwith blank line'\n\n[foo]\n", + "html": "<p>[foo]: /url 'title</p>\n<p>with blank line'</p>\n<p>[foo]</p>\n", + "example": 197, + "start_line": 3240, + "end_line": 3250, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]:\n/url\n\n[foo]\n", + "html": "<p><a href=\"/url\">foo</a></p>\n", + "example": 198, + "start_line": 3255, + "end_line": 3262, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]:\n\n[foo]\n", + "html": "<p>[foo]:</p>\n<p>[foo]</p>\n", + "example": 199, + "start_line": 3267, + "end_line": 3274, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: <>\n\n[foo]\n", + "html": "<p><a href=\"\">foo</a></p>\n", + "example": 200, + "start_line": 3279, + "end_line": 3285, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: <bar>(baz)\n\n[foo]\n", + "html": "<p>[foo]: <bar>(baz)</p>\n<p>[foo]</p>\n", + "example": 201, + "start_line": 3290, + "end_line": 3297, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url\\bar\\*baz \"foo\\\"bar\\baz\"\n\n[foo]\n", + "html": "<p><a href=\"/url%5Cbar*baz\" title=\"foo"bar\\baz\">foo</a></p>\n", + "example": 202, + "start_line": 3303, + "end_line": 3309, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]\n\n[foo]: url\n", + "html": "<p><a href=\"url\">foo</a></p>\n", + "example": 203, + "start_line": 3314, + "end_line": 3320, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]\n\n[foo]: first\n[foo]: second\n", + "html": "<p><a href=\"first\">foo</a></p>\n", + "example": 204, + "start_line": 3326, + "end_line": 3333, + "section": "Link reference definitions" + }, + { + "markdown": "[FOO]: /url\n\n[Foo]\n", + "html": "<p><a href=\"/url\">Foo</a></p>\n", + "example": 205, + "start_line": 3339, + "end_line": 3345, + "section": "Link reference definitions" + }, + { + "markdown": "[ΑΓΩ]: /φου\n\n[αγω]\n", + "html": "<p><a href=\"/%CF%86%CE%BF%CF%85\">αγω</a></p>\n", + "example": 206, + "start_line": 3348, + "end_line": 3354, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url\n", + "html": "", + "example": 207, + "start_line": 3363, + "end_line": 3366, + "section": "Link reference definitions" + }, + { + "markdown": "[\nfoo\n]: /url\nbar\n", + "html": "<p>bar</p>\n", + "example": 208, + "start_line": 3371, + "end_line": 3378, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url \"title\" ok\n", + "html": "<p>[foo]: /url "title" ok</p>\n", + "example": 209, + "start_line": 3384, + "end_line": 3388, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url\n\"title\" ok\n", + "html": "<p>"title" ok</p>\n", + "example": 210, + "start_line": 3393, + "end_line": 3398, + "section": "Link reference definitions" + }, + { + "markdown": " [foo]: /url \"title\"\n\n[foo]\n", + "html": "<pre><code>[foo]: /url "title"\n</code></pre>\n<p>[foo]</p>\n", + "example": 211, + "start_line": 3404, + "end_line": 3412, + "section": "Link reference definitions" + }, + { + "markdown": "```\n[foo]: /url\n```\n\n[foo]\n", + "html": "<pre><code>[foo]: /url\n</code></pre>\n<p>[foo]</p>\n", + "example": 212, + "start_line": 3418, + "end_line": 3428, + "section": "Link reference definitions" + }, + { + "markdown": "Foo\n[bar]: /baz\n\n[bar]\n", + "html": "<p>Foo\n[bar]: /baz</p>\n<p>[bar]</p>\n", + "example": 213, + "start_line": 3433, + "end_line": 3442, + "section": "Link reference definitions" + }, + { + "markdown": "# [Foo]\n[foo]: /url\n> bar\n", + "html": "<h1><a href=\"/url\">Foo</a></h1>\n<blockquote>\n<p>bar</p>\n</blockquote>\n", + "example": 214, + "start_line": 3448, + "end_line": 3457, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url\nbar\n===\n[foo]\n", + "html": "<h1>bar</h1>\n<p><a href=\"/url\">foo</a></p>\n", + "example": 215, + "start_line": 3459, + "end_line": 3467, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url\n===\n[foo]\n", + "html": "<p>===\n<a href=\"/url\">foo</a></p>\n", + "example": 216, + "start_line": 3469, + "end_line": 3476, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /foo-url \"foo\"\n[bar]: /bar-url\n \"bar\"\n[baz]: /baz-url\n\n[foo],\n[bar],\n[baz]\n", + "html": "<p><a href=\"/foo-url\" title=\"foo\">foo</a>,\n<a href=\"/bar-url\" title=\"bar\">bar</a>,\n<a href=\"/baz-url\">baz</a></p>\n", + "example": 217, + "start_line": 3482, + "end_line": 3495, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]\n\n> [foo]: /url\n", + "html": "<p><a href=\"/url\">foo</a></p>\n<blockquote>\n</blockquote>\n", + "example": 218, + "start_line": 3503, + "end_line": 3511, + "section": "Link reference definitions" + }, + { + "markdown": "aaa\n\nbbb\n", + "html": "<p>aaa</p>\n<p>bbb</p>\n", + "example": 219, + "start_line": 3525, + "end_line": 3532, + "section": "Paragraphs" + }, + { + "markdown": "aaa\nbbb\n\nccc\nddd\n", + "html": "<p>aaa\nbbb</p>\n<p>ccc\nddd</p>\n", + "example": 220, + "start_line": 3537, + "end_line": 3548, + "section": "Paragraphs" + }, + { + "markdown": "aaa\n\n\nbbb\n", + "html": "<p>aaa</p>\n<p>bbb</p>\n", + "example": 221, + "start_line": 3553, + "end_line": 3561, + "section": "Paragraphs" + }, + { + "markdown": " aaa\n bbb\n", + "html": "<p>aaa\nbbb</p>\n", + "example": 222, + "start_line": 3566, + "end_line": 3572, + "section": "Paragraphs" + }, + { + "markdown": "aaa\n bbb\n ccc\n", + "html": "<p>aaa\nbbb\nccc</p>\n", + "example": 223, + "start_line": 3578, + "end_line": 3586, + "section": "Paragraphs" + }, + { + "markdown": " aaa\nbbb\n", + "html": "<p>aaa\nbbb</p>\n", + "example": 224, + "start_line": 3592, + "end_line": 3598, + "section": "Paragraphs" + }, + { + "markdown": " aaa\nbbb\n", + "html": "<pre><code>aaa\n</code></pre>\n<p>bbb</p>\n", + "example": 225, + "start_line": 3601, + "end_line": 3608, + "section": "Paragraphs" + }, + { + "markdown": "aaa \nbbb \n", + "html": "<p>aaa<br />\nbbb</p>\n", + "example": 226, + "start_line": 3615, + "end_line": 3621, + "section": "Paragraphs" + }, + { + "markdown": " \n\naaa\n \n\n# aaa\n\n \n", + "html": "<p>aaa</p>\n<h1>aaa</h1>\n", + "example": 227, + "start_line": 3632, + "end_line": 3644, + "section": "Blank lines" + }, + { + "markdown": "> # Foo\n> bar\n> baz\n", + "html": "<blockquote>\n<h1>Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>\n", + "example": 228, + "start_line": 3700, + "end_line": 3710, + "section": "Block quotes" + }, + { + "markdown": "># Foo\n>bar\n> baz\n", + "html": "<blockquote>\n<h1>Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>\n", + "example": 229, + "start_line": 3715, + "end_line": 3725, + "section": "Block quotes" + }, + { + "markdown": " > # Foo\n > bar\n > baz\n", + "html": "<blockquote>\n<h1>Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>\n", + "example": 230, + "start_line": 3730, + "end_line": 3740, + "section": "Block quotes" + }, + { + "markdown": " > # Foo\n > bar\n > baz\n", + "html": "<pre><code>> # Foo\n> bar\n> baz\n</code></pre>\n", + "example": 231, + "start_line": 3745, + "end_line": 3754, + "section": "Block quotes" + }, + { + "markdown": "> # Foo\n> bar\nbaz\n", + "html": "<blockquote>\n<h1>Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>\n", + "example": 232, + "start_line": 3760, + "end_line": 3770, + "section": "Block quotes" + }, + { + "markdown": "> bar\nbaz\n> foo\n", + "html": "<blockquote>\n<p>bar\nbaz\nfoo</p>\n</blockquote>\n", + "example": 233, + "start_line": 3776, + "end_line": 3786, + "section": "Block quotes" + }, + { + "markdown": "> foo\n---\n", + "html": "<blockquote>\n<p>foo</p>\n</blockquote>\n<hr />\n", + "example": 234, + "start_line": 3800, + "end_line": 3808, + "section": "Block quotes" + }, + { + "markdown": "> - foo\n- bar\n", + "html": "<blockquote>\n<ul>\n<li>foo</li>\n</ul>\n</blockquote>\n<ul>\n<li>bar</li>\n</ul>\n", + "example": 235, + "start_line": 3820, + "end_line": 3832, + "section": "Block quotes" + }, + { + "markdown": "> foo\n bar\n", + "html": "<blockquote>\n<pre><code>foo\n</code></pre>\n</blockquote>\n<pre><code>bar\n</code></pre>\n", + "example": 236, + "start_line": 3838, + "end_line": 3848, + "section": "Block quotes" + }, + { + "markdown": "> ```\nfoo\n```\n", + "html": "<blockquote>\n<pre><code></code></pre>\n</blockquote>\n<p>foo</p>\n<pre><code></code></pre>\n", + "example": 237, + "start_line": 3851, + "end_line": 3861, + "section": "Block quotes" + }, + { + "markdown": "> foo\n - bar\n", + "html": "<blockquote>\n<p>foo\n- bar</p>\n</blockquote>\n", + "example": 238, + "start_line": 3867, + "end_line": 3875, + "section": "Block quotes" + }, + { + "markdown": ">\n", + "html": "<blockquote>\n</blockquote>\n", + "example": 239, + "start_line": 3891, + "end_line": 3896, + "section": "Block quotes" + }, + { + "markdown": ">\n> \n> \n", + "html": "<blockquote>\n</blockquote>\n", + "example": 240, + "start_line": 3899, + "end_line": 3906, + "section": "Block quotes" + }, + { + "markdown": ">\n> foo\n> \n", + "html": "<blockquote>\n<p>foo</p>\n</blockquote>\n", + "example": 241, + "start_line": 3911, + "end_line": 3919, + "section": "Block quotes" + }, + { + "markdown": "> foo\n\n> bar\n", + "html": "<blockquote>\n<p>foo</p>\n</blockquote>\n<blockquote>\n<p>bar</p>\n</blockquote>\n", + "example": 242, + "start_line": 3924, + "end_line": 3935, + "section": "Block quotes" + }, + { + "markdown": "> foo\n> bar\n", + "html": "<blockquote>\n<p>foo\nbar</p>\n</blockquote>\n", + "example": 243, + "start_line": 3946, + "end_line": 3954, + "section": "Block quotes" + }, + { + "markdown": "> foo\n>\n> bar\n", + "html": "<blockquote>\n<p>foo</p>\n<p>bar</p>\n</blockquote>\n", + "example": 244, + "start_line": 3959, + "end_line": 3968, + "section": "Block quotes" + }, + { + "markdown": "foo\n> bar\n", + "html": "<p>foo</p>\n<blockquote>\n<p>bar</p>\n</blockquote>\n", + "example": 245, + "start_line": 3973, + "end_line": 3981, + "section": "Block quotes" + }, + { + "markdown": "> aaa\n***\n> bbb\n", + "html": "<blockquote>\n<p>aaa</p>\n</blockquote>\n<hr />\n<blockquote>\n<p>bbb</p>\n</blockquote>\n", + "example": 246, + "start_line": 3987, + "end_line": 3999, + "section": "Block quotes" + }, + { + "markdown": "> bar\nbaz\n", + "html": "<blockquote>\n<p>bar\nbaz</p>\n</blockquote>\n", + "example": 247, + "start_line": 4005, + "end_line": 4013, + "section": "Block quotes" + }, + { + "markdown": "> bar\n\nbaz\n", + "html": "<blockquote>\n<p>bar</p>\n</blockquote>\n<p>baz</p>\n", + "example": 248, + "start_line": 4016, + "end_line": 4025, + "section": "Block quotes" + }, + { + "markdown": "> bar\n>\nbaz\n", + "html": "<blockquote>\n<p>bar</p>\n</blockquote>\n<p>baz</p>\n", + "example": 249, + "start_line": 4028, + "end_line": 4037, + "section": "Block quotes" + }, + { + "markdown": "> > > foo\nbar\n", + "html": "<blockquote>\n<blockquote>\n<blockquote>\n<p>foo\nbar</p>\n</blockquote>\n</blockquote>\n</blockquote>\n", + "example": 250, + "start_line": 4044, + "end_line": 4056, + "section": "Block quotes" + }, + { + "markdown": ">>> foo\n> bar\n>>baz\n", + "html": "<blockquote>\n<blockquote>\n<blockquote>\n<p>foo\nbar\nbaz</p>\n</blockquote>\n</blockquote>\n</blockquote>\n", + "example": 251, + "start_line": 4059, + "end_line": 4073, + "section": "Block quotes" + }, + { + "markdown": "> code\n\n> not code\n", + "html": "<blockquote>\n<pre><code>code\n</code></pre>\n</blockquote>\n<blockquote>\n<p>not code</p>\n</blockquote>\n", + "example": 252, + "start_line": 4081, + "end_line": 4093, + "section": "Block quotes" + }, + { + "markdown": "A paragraph\nwith two lines.\n\n indented code\n\n> A block quote.\n", + "html": "<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n", + "example": 253, + "start_line": 4135, + "end_line": 4150, + "section": "List items" + }, + { + "markdown": "1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n", + "html": "<ol>\n<li>\n<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n</li>\n</ol>\n", + "example": 254, + "start_line": 4157, + "end_line": 4176, + "section": "List items" + }, + { + "markdown": "- one\n\n two\n", + "html": "<ul>\n<li>one</li>\n</ul>\n<p>two</p>\n", + "example": 255, + "start_line": 4190, + "end_line": 4199, + "section": "List items" + }, + { + "markdown": "- one\n\n two\n", + "html": "<ul>\n<li>\n<p>one</p>\n<p>two</p>\n</li>\n</ul>\n", + "example": 256, + "start_line": 4202, + "end_line": 4213, + "section": "List items" + }, + { + "markdown": " - one\n\n two\n", + "html": "<ul>\n<li>one</li>\n</ul>\n<pre><code> two\n</code></pre>\n", + "example": 257, + "start_line": 4216, + "end_line": 4226, + "section": "List items" + }, + { + "markdown": " - one\n\n two\n", + "html": "<ul>\n<li>\n<p>one</p>\n<p>two</p>\n</li>\n</ul>\n", + "example": 258, + "start_line": 4229, + "end_line": 4240, + "section": "List items" + }, + { + "markdown": " > > 1. one\n>>\n>> two\n", + "html": "<blockquote>\n<blockquote>\n<ol>\n<li>\n<p>one</p>\n<p>two</p>\n</li>\n</ol>\n</blockquote>\n</blockquote>\n", + "example": 259, + "start_line": 4251, + "end_line": 4266, + "section": "List items" + }, + { + "markdown": ">>- one\n>>\n > > two\n", + "html": "<blockquote>\n<blockquote>\n<ul>\n<li>one</li>\n</ul>\n<p>two</p>\n</blockquote>\n</blockquote>\n", + "example": 260, + "start_line": 4278, + "end_line": 4291, + "section": "List items" + }, + { + "markdown": "-one\n\n2.two\n", + "html": "<p>-one</p>\n<p>2.two</p>\n", + "example": 261, + "start_line": 4297, + "end_line": 4304, + "section": "List items" + }, + { + "markdown": "- foo\n\n\n bar\n", + "html": "<ul>\n<li>\n<p>foo</p>\n<p>bar</p>\n</li>\n</ul>\n", + "example": 262, + "start_line": 4310, + "end_line": 4322, + "section": "List items" + }, + { + "markdown": "1. foo\n\n ```\n bar\n ```\n\n baz\n\n > bam\n", + "html": "<ol>\n<li>\n<p>foo</p>\n<pre><code>bar\n</code></pre>\n<p>baz</p>\n<blockquote>\n<p>bam</p>\n</blockquote>\n</li>\n</ol>\n", + "example": 263, + "start_line": 4327, + "end_line": 4349, + "section": "List items" + }, + { + "markdown": "- Foo\n\n bar\n\n\n baz\n", + "html": "<ul>\n<li>\n<p>Foo</p>\n<pre><code>bar\n\n\nbaz\n</code></pre>\n</li>\n</ul>\n", + "example": 264, + "start_line": 4355, + "end_line": 4373, + "section": "List items" + }, + { + "markdown": "123456789. ok\n", + "html": "<ol start=\"123456789\">\n<li>ok</li>\n</ol>\n", + "example": 265, + "start_line": 4377, + "end_line": 4383, + "section": "List items" + }, + { + "markdown": "1234567890. not ok\n", + "html": "<p>1234567890. not ok</p>\n", + "example": 266, + "start_line": 4386, + "end_line": 4390, + "section": "List items" + }, + { + "markdown": "0. ok\n", + "html": "<ol start=\"0\">\n<li>ok</li>\n</ol>\n", + "example": 267, + "start_line": 4395, + "end_line": 4401, + "section": "List items" + }, + { + "markdown": "003. ok\n", + "html": "<ol start=\"3\">\n<li>ok</li>\n</ol>\n", + "example": 268, + "start_line": 4404, + "end_line": 4410, + "section": "List items" + }, + { + "markdown": "-1. not ok\n", + "html": "<p>-1. not ok</p>\n", + "example": 269, + "start_line": 4415, + "end_line": 4419, + "section": "List items" + }, + { + "markdown": "- foo\n\n bar\n", + "html": "<ul>\n<li>\n<p>foo</p>\n<pre><code>bar\n</code></pre>\n</li>\n</ul>\n", + "example": 270, + "start_line": 4438, + "end_line": 4450, + "section": "List items" + }, + { + "markdown": " 10. foo\n\n bar\n", + "html": "<ol start=\"10\">\n<li>\n<p>foo</p>\n<pre><code>bar\n</code></pre>\n</li>\n</ol>\n", + "example": 271, + "start_line": 4455, + "end_line": 4467, + "section": "List items" + }, + { + "markdown": " indented code\n\nparagraph\n\n more code\n", + "html": "<pre><code>indented code\n</code></pre>\n<p>paragraph</p>\n<pre><code>more code\n</code></pre>\n", + "example": 272, + "start_line": 4474, + "end_line": 4486, + "section": "List items" + }, + { + "markdown": "1. indented code\n\n paragraph\n\n more code\n", + "html": "<ol>\n<li>\n<pre><code>indented code\n</code></pre>\n<p>paragraph</p>\n<pre><code>more code\n</code></pre>\n</li>\n</ol>\n", + "example": 273, + "start_line": 4489, + "end_line": 4505, + "section": "List items" + }, + { + "markdown": "1. indented code\n\n paragraph\n\n more code\n", + "html": "<ol>\n<li>\n<pre><code> indented code\n</code></pre>\n<p>paragraph</p>\n<pre><code>more code\n</code></pre>\n</li>\n</ol>\n", + "example": 274, + "start_line": 4511, + "end_line": 4527, + "section": "List items" + }, + { + "markdown": " foo\n\nbar\n", + "html": "<p>foo</p>\n<p>bar</p>\n", + "example": 275, + "start_line": 4538, + "end_line": 4545, + "section": "List items" + }, + { + "markdown": "- foo\n\n bar\n", + "html": "<ul>\n<li>foo</li>\n</ul>\n<p>bar</p>\n", + "example": 276, + "start_line": 4548, + "end_line": 4557, + "section": "List items" + }, + { + "markdown": "- foo\n\n bar\n", + "html": "<ul>\n<li>\n<p>foo</p>\n<p>bar</p>\n</li>\n</ul>\n", + "example": 277, + "start_line": 4565, + "end_line": 4576, + "section": "List items" + }, + { + "markdown": "-\n foo\n-\n ```\n bar\n ```\n-\n baz\n", + "html": "<ul>\n<li>foo</li>\n<li>\n<pre><code>bar\n</code></pre>\n</li>\n<li>\n<pre><code>baz\n</code></pre>\n</li>\n</ul>\n", + "example": 278, + "start_line": 4592, + "end_line": 4613, + "section": "List items" + }, + { + "markdown": "- \n foo\n", + "html": "<ul>\n<li>foo</li>\n</ul>\n", + "example": 279, + "start_line": 4618, + "end_line": 4625, + "section": "List items" + }, + { + "markdown": "-\n\n foo\n", + "html": "<ul>\n<li></li>\n</ul>\n<p>foo</p>\n", + "example": 280, + "start_line": 4632, + "end_line": 4641, + "section": "List items" + }, + { + "markdown": "- foo\n-\n- bar\n", + "html": "<ul>\n<li>foo</li>\n<li></li>\n<li>bar</li>\n</ul>\n", + "example": 281, + "start_line": 4646, + "end_line": 4656, + "section": "List items" + }, + { + "markdown": "- foo\n- \n- bar\n", + "html": "<ul>\n<li>foo</li>\n<li></li>\n<li>bar</li>\n</ul>\n", + "example": 282, + "start_line": 4661, + "end_line": 4671, + "section": "List items" + }, + { + "markdown": "1. foo\n2.\n3. bar\n", + "html": "<ol>\n<li>foo</li>\n<li></li>\n<li>bar</li>\n</ol>\n", + "example": 283, + "start_line": 4676, + "end_line": 4686, + "section": "List items" + }, + { + "markdown": "*\n", + "html": "<ul>\n<li></li>\n</ul>\n", + "example": 284, + "start_line": 4691, + "end_line": 4697, + "section": "List items" + }, + { + "markdown": "foo\n*\n\nfoo\n1.\n", + "html": "<p>foo\n*</p>\n<p>foo\n1.</p>\n", + "example": 285, + "start_line": 4701, + "end_line": 4712, + "section": "List items" + }, + { + "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n", + "html": "<ol>\n<li>\n<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n</li>\n</ol>\n", + "example": 286, + "start_line": 4723, + "end_line": 4742, + "section": "List items" + }, + { + "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n", + "html": "<ol>\n<li>\n<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n</li>\n</ol>\n", + "example": 287, + "start_line": 4747, + "end_line": 4766, + "section": "List items" + }, + { + "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n", + "html": "<ol>\n<li>\n<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n</li>\n</ol>\n", + "example": 288, + "start_line": 4771, + "end_line": 4790, + "section": "List items" + }, + { + "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n", + "html": "<pre><code>1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n</code></pre>\n", + "example": 289, + "start_line": 4795, + "end_line": 4810, + "section": "List items" + }, + { + "markdown": " 1. A paragraph\nwith two lines.\n\n indented code\n\n > A block quote.\n", + "html": "<ol>\n<li>\n<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n</li>\n</ol>\n", + "example": 290, + "start_line": 4825, + "end_line": 4844, + "section": "List items" + }, + { + "markdown": " 1. A paragraph\n with two lines.\n", + "html": "<ol>\n<li>A paragraph\nwith two lines.</li>\n</ol>\n", + "example": 291, + "start_line": 4849, + "end_line": 4857, + "section": "List items" + }, + { + "markdown": "> 1. > Blockquote\ncontinued here.\n", + "html": "<blockquote>\n<ol>\n<li>\n<blockquote>\n<p>Blockquote\ncontinued here.</p>\n</blockquote>\n</li>\n</ol>\n</blockquote>\n", + "example": 292, + "start_line": 4862, + "end_line": 4876, + "section": "List items" + }, + { + "markdown": "> 1. > Blockquote\n> continued here.\n", + "html": "<blockquote>\n<ol>\n<li>\n<blockquote>\n<p>Blockquote\ncontinued here.</p>\n</blockquote>\n</li>\n</ol>\n</blockquote>\n", + "example": 293, + "start_line": 4879, + "end_line": 4893, + "section": "List items" + }, + { + "markdown": "- foo\n - bar\n - baz\n - boo\n", + "html": "<ul>\n<li>foo\n<ul>\n<li>bar\n<ul>\n<li>baz\n<ul>\n<li>boo</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n", + "example": 294, + "start_line": 4907, + "end_line": 4928, + "section": "List items" + }, + { + "markdown": "- foo\n - bar\n - baz\n - boo\n", + "html": "<ul>\n<li>foo</li>\n<li>bar</li>\n<li>baz</li>\n<li>boo</li>\n</ul>\n", + "example": 295, + "start_line": 4933, + "end_line": 4945, + "section": "List items" + }, + { + "markdown": "10) foo\n - bar\n", + "html": "<ol start=\"10\">\n<li>foo\n<ul>\n<li>bar</li>\n</ul>\n</li>\n</ol>\n", + "example": 296, + "start_line": 4950, + "end_line": 4961, + "section": "List items" + }, + { + "markdown": "10) foo\n - bar\n", + "html": "<ol start=\"10\">\n<li>foo</li>\n</ol>\n<ul>\n<li>bar</li>\n</ul>\n", + "example": 297, + "start_line": 4966, + "end_line": 4976, + "section": "List items" + }, + { + "markdown": "- - foo\n", + "html": "<ul>\n<li>\n<ul>\n<li>foo</li>\n</ul>\n</li>\n</ul>\n", + "example": 298, + "start_line": 4981, + "end_line": 4991, + "section": "List items" + }, + { + "markdown": "1. - 2. foo\n", + "html": "<ol>\n<li>\n<ul>\n<li>\n<ol start=\"2\">\n<li>foo</li>\n</ol>\n</li>\n</ul>\n</li>\n</ol>\n", + "example": 299, + "start_line": 4994, + "end_line": 5008, + "section": "List items" + }, + { + "markdown": "- # Foo\n- Bar\n ---\n baz\n", + "html": "<ul>\n<li>\n<h1>Foo</h1>\n</li>\n<li>\n<h2>Bar</h2>\nbaz</li>\n</ul>\n", + "example": 300, + "start_line": 5013, + "end_line": 5027, + "section": "List items" + }, + { + "markdown": "- foo\n- bar\n+ baz\n", + "html": "<ul>\n<li>foo</li>\n<li>bar</li>\n</ul>\n<ul>\n<li>baz</li>\n</ul>\n", + "example": 301, + "start_line": 5249, + "end_line": 5261, + "section": "Lists" + }, + { + "markdown": "1. foo\n2. bar\n3) baz\n", + "html": "<ol>\n<li>foo</li>\n<li>bar</li>\n</ol>\n<ol start=\"3\">\n<li>baz</li>\n</ol>\n", + "example": 302, + "start_line": 5264, + "end_line": 5276, + "section": "Lists" + }, + { + "markdown": "Foo\n- bar\n- baz\n", + "html": "<p>Foo</p>\n<ul>\n<li>bar</li>\n<li>baz</li>\n</ul>\n", + "example": 303, + "start_line": 5283, + "end_line": 5293, + "section": "Lists" + }, + { + "markdown": "The number of windows in my house is\n14. The number of doors is 6.\n", + "html": "<p>The number of windows in my house is\n14. The number of doors is 6.</p>\n", + "example": 304, + "start_line": 5360, + "end_line": 5366, + "section": "Lists" + }, + { + "markdown": "The number of windows in my house is\n1. The number of doors is 6.\n", + "html": "<p>The number of windows in my house is</p>\n<ol>\n<li>The number of doors is 6.</li>\n</ol>\n", + "example": 305, + "start_line": 5370, + "end_line": 5378, + "section": "Lists" + }, + { + "markdown": "- foo\n\n- bar\n\n\n- baz\n", + "html": "<ul>\n<li>\n<p>foo</p>\n</li>\n<li>\n<p>bar</p>\n</li>\n<li>\n<p>baz</p>\n</li>\n</ul>\n", + "example": 306, + "start_line": 5384, + "end_line": 5403, + "section": "Lists" + }, + { + "markdown": "- foo\n - bar\n - baz\n\n\n bim\n", + "html": "<ul>\n<li>foo\n<ul>\n<li>bar\n<ul>\n<li>\n<p>baz</p>\n<p>bim</p>\n</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n", + "example": 307, + "start_line": 5405, + "end_line": 5427, + "section": "Lists" + }, + { + "markdown": "- foo\n- bar\n\n<!-- -->\n\n- baz\n- bim\n", + "html": "<ul>\n<li>foo</li>\n<li>bar</li>\n</ul>\n<!-- -->\n<ul>\n<li>baz</li>\n<li>bim</li>\n</ul>\n", + "example": 308, + "start_line": 5435, + "end_line": 5453, + "section": "Lists" + }, + { + "markdown": "- foo\n\n notcode\n\n- foo\n\n<!-- -->\n\n code\n", + "html": "<ul>\n<li>\n<p>foo</p>\n<p>notcode</p>\n</li>\n<li>\n<p>foo</p>\n</li>\n</ul>\n<!-- -->\n<pre><code>code\n</code></pre>\n", + "example": 309, + "start_line": 5456, + "end_line": 5479, + "section": "Lists" + }, + { + "markdown": "- a\n - b\n - c\n - d\n - e\n - f\n- g\n", + "html": "<ul>\n<li>a</li>\n<li>b</li>\n<li>c</li>\n<li>d</li>\n<li>e</li>\n<li>f</li>\n<li>g</li>\n</ul>\n", + "example": 310, + "start_line": 5487, + "end_line": 5505, + "section": "Lists" + }, + { + "markdown": "1. a\n\n 2. b\n\n 3. c\n", + "html": "<ol>\n<li>\n<p>a</p>\n</li>\n<li>\n<p>b</p>\n</li>\n<li>\n<p>c</p>\n</li>\n</ol>\n", + "example": 311, + "start_line": 5508, + "end_line": 5526, + "section": "Lists" + }, + { + "markdown": "- a\n - b\n - c\n - d\n - e\n", + "html": "<ul>\n<li>a</li>\n<li>b</li>\n<li>c</li>\n<li>d\n- e</li>\n</ul>\n", + "example": 312, + "start_line": 5532, + "end_line": 5546, + "section": "Lists" + }, + { + "markdown": "1. a\n\n 2. b\n\n 3. c\n", + "html": "<ol>\n<li>\n<p>a</p>\n</li>\n<li>\n<p>b</p>\n</li>\n</ol>\n<pre><code>3. c\n</code></pre>\n", + "example": 313, + "start_line": 5552, + "end_line": 5569, + "section": "Lists" + }, + { + "markdown": "- a\n- b\n\n- c\n", + "html": "<ul>\n<li>\n<p>a</p>\n</li>\n<li>\n<p>b</p>\n</li>\n<li>\n<p>c</p>\n</li>\n</ul>\n", + "example": 314, + "start_line": 5575, + "end_line": 5592, + "section": "Lists" + }, + { + "markdown": "* a\n*\n\n* c\n", + "html": "<ul>\n<li>\n<p>a</p>\n</li>\n<li></li>\n<li>\n<p>c</p>\n</li>\n</ul>\n", + "example": 315, + "start_line": 5597, + "end_line": 5612, + "section": "Lists" + }, + { + "markdown": "- a\n- b\n\n c\n- d\n", + "html": "<ul>\n<li>\n<p>a</p>\n</li>\n<li>\n<p>b</p>\n<p>c</p>\n</li>\n<li>\n<p>d</p>\n</li>\n</ul>\n", + "example": 316, + "start_line": 5619, + "end_line": 5638, + "section": "Lists" + }, + { + "markdown": "- a\n- b\n\n [ref]: /url\n- d\n", + "html": "<ul>\n<li>\n<p>a</p>\n</li>\n<li>\n<p>b</p>\n</li>\n<li>\n<p>d</p>\n</li>\n</ul>\n", + "example": 317, + "start_line": 5641, + "end_line": 5659, + "section": "Lists" + }, + { + "markdown": "- a\n- ```\n b\n\n\n ```\n- c\n", + "html": "<ul>\n<li>a</li>\n<li>\n<pre><code>b\n\n\n</code></pre>\n</li>\n<li>c</li>\n</ul>\n", + "example": 318, + "start_line": 5664, + "end_line": 5683, + "section": "Lists" + }, + { + "markdown": "- a\n - b\n\n c\n- d\n", + "html": "<ul>\n<li>a\n<ul>\n<li>\n<p>b</p>\n<p>c</p>\n</li>\n</ul>\n</li>\n<li>d</li>\n</ul>\n", + "example": 319, + "start_line": 5690, + "end_line": 5708, + "section": "Lists" + }, + { + "markdown": "* a\n > b\n >\n* c\n", + "html": "<ul>\n<li>a\n<blockquote>\n<p>b</p>\n</blockquote>\n</li>\n<li>c</li>\n</ul>\n", + "example": 320, + "start_line": 5714, + "end_line": 5728, + "section": "Lists" + }, + { + "markdown": "- a\n > b\n ```\n c\n ```\n- d\n", + "html": "<ul>\n<li>a\n<blockquote>\n<p>b</p>\n</blockquote>\n<pre><code>c\n</code></pre>\n</li>\n<li>d</li>\n</ul>\n", + "example": 321, + "start_line": 5734, + "end_line": 5752, + "section": "Lists" + }, + { + "markdown": "- a\n", + "html": "<ul>\n<li>a</li>\n</ul>\n", + "example": 322, + "start_line": 5757, + "end_line": 5763, + "section": "Lists" + }, + { + "markdown": "- a\n - b\n", + "html": "<ul>\n<li>a\n<ul>\n<li>b</li>\n</ul>\n</li>\n</ul>\n", + "example": 323, + "start_line": 5766, + "end_line": 5777, + "section": "Lists" + }, + { + "markdown": "1. ```\n foo\n ```\n\n bar\n", + "html": "<ol>\n<li>\n<pre><code>foo\n</code></pre>\n<p>bar</p>\n</li>\n</ol>\n", + "example": 324, + "start_line": 5783, + "end_line": 5797, + "section": "Lists" + }, + { + "markdown": "* foo\n * bar\n\n baz\n", + "html": "<ul>\n<li>\n<p>foo</p>\n<ul>\n<li>bar</li>\n</ul>\n<p>baz</p>\n</li>\n</ul>\n", + "example": 325, + "start_line": 5802, + "end_line": 5817, + "section": "Lists" + }, + { + "markdown": "- a\n - b\n - c\n\n- d\n - e\n - f\n", + "html": "<ul>\n<li>\n<p>a</p>\n<ul>\n<li>b</li>\n<li>c</li>\n</ul>\n</li>\n<li>\n<p>d</p>\n<ul>\n<li>e</li>\n<li>f</li>\n</ul>\n</li>\n</ul>\n", + "example": 326, + "start_line": 5820, + "end_line": 5845, + "section": "Lists" + }, + { + "markdown": "`hi`lo`\n", + "html": "<p><code>hi</code>lo`</p>\n", + "example": 327, + "start_line": 5854, + "end_line": 5858, + "section": "Inlines" + }, + { + "markdown": "`foo`\n", + "html": "<p><code>foo</code></p>\n", + "example": 328, + "start_line": 5886, + "end_line": 5890, + "section": "Code spans" + }, + { + "markdown": "`` foo ` bar ``\n", + "html": "<p><code>foo ` bar</code></p>\n", + "example": 329, + "start_line": 5897, + "end_line": 5901, + "section": "Code spans" + }, + { + "markdown": "` `` `\n", + "html": "<p><code>``</code></p>\n", + "example": 330, + "start_line": 5907, + "end_line": 5911, + "section": "Code spans" + }, + { + "markdown": "` `` `\n", + "html": "<p><code> `` </code></p>\n", + "example": 331, + "start_line": 5915, + "end_line": 5919, + "section": "Code spans" + }, + { + "markdown": "` a`\n", + "html": "<p><code> a</code></p>\n", + "example": 332, + "start_line": 5924, + "end_line": 5928, + "section": "Code spans" + }, + { + "markdown": "` b `\n", + "html": "<p><code> b </code></p>\n", + "example": 333, + "start_line": 5933, + "end_line": 5937, + "section": "Code spans" + }, + { + "markdown": "` `\n` `\n", + "html": "<p><code> </code>\n<code> </code></p>\n", + "example": 334, + "start_line": 5941, + "end_line": 5947, + "section": "Code spans" + }, + { + "markdown": "``\nfoo\nbar \nbaz\n``\n", + "html": "<p><code>foo bar baz</code></p>\n", + "example": 335, + "start_line": 5952, + "end_line": 5960, + "section": "Code spans" + }, + { + "markdown": "``\nfoo \n``\n", + "html": "<p><code>foo </code></p>\n", + "example": 336, + "start_line": 5962, + "end_line": 5968, + "section": "Code spans" + }, + { + "markdown": "`foo bar \nbaz`\n", + "html": "<p><code>foo bar baz</code></p>\n", + "example": 337, + "start_line": 5973, + "end_line": 5978, + "section": "Code spans" + }, + { + "markdown": "`foo\\`bar`\n", + "html": "<p><code>foo\\</code>bar`</p>\n", + "example": 338, + "start_line": 5990, + "end_line": 5994, + "section": "Code spans" + }, + { + "markdown": "``foo`bar``\n", + "html": "<p><code>foo`bar</code></p>\n", + "example": 339, + "start_line": 6001, + "end_line": 6005, + "section": "Code spans" + }, + { + "markdown": "` foo `` bar `\n", + "html": "<p><code>foo `` bar</code></p>\n", + "example": 340, + "start_line": 6007, + "end_line": 6011, + "section": "Code spans" + }, + { + "markdown": "*foo`*`\n", + "html": "<p>*foo<code>*</code></p>\n", + "example": 341, + "start_line": 6019, + "end_line": 6023, + "section": "Code spans" + }, + { + "markdown": "[not a `link](/foo`)\n", + "html": "<p>[not a <code>link](/foo</code>)</p>\n", + "example": 342, + "start_line": 6028, + "end_line": 6032, + "section": "Code spans" + }, + { + "markdown": "`<a href=\"`\">`\n", + "html": "<p><code><a href="</code>">`</p>\n", + "example": 343, + "start_line": 6038, + "end_line": 6042, + "section": "Code spans" + }, + { + "markdown": "<a href=\"`\">`\n", + "html": "<p><a href=\"`\">`</p>\n", + "example": 344, + "start_line": 6047, + "end_line": 6051, + "section": "Code spans" + }, + { + "markdown": "`<https://foo.bar.`baz>`\n", + "html": "<p><code><https://foo.bar.</code>baz>`</p>\n", + "example": 345, + "start_line": 6056, + "end_line": 6060, + "section": "Code spans" + }, + { + "markdown": "<https://foo.bar.`baz>`\n", + "html": "<p><a href=\"https://foo.bar.%60baz\">https://foo.bar.`baz</a>`</p>\n", + "example": 346, + "start_line": 6065, + "end_line": 6069, + "section": "Code spans" + }, + { + "markdown": "```foo``\n", + "html": "<p>```foo``</p>\n", + "example": 347, + "start_line": 6075, + "end_line": 6079, + "section": "Code spans" + }, + { + "markdown": "`foo\n", + "html": "<p>`foo</p>\n", + "example": 348, + "start_line": 6082, + "end_line": 6086, + "section": "Code spans" + }, + { + "markdown": "`foo``bar``\n", + "html": "<p>`foo<code>bar</code></p>\n", + "example": 349, + "start_line": 6091, + "end_line": 6095, + "section": "Code spans" + }, + { + "markdown": "*foo bar*\n", + "html": "<p><em>foo bar</em></p>\n", + "example": 350, + "start_line": 6308, + "end_line": 6312, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "a * foo bar*\n", + "html": "<p>a * foo bar*</p>\n", + "example": 351, + "start_line": 6318, + "end_line": 6322, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "a*\"foo\"*\n", + "html": "<p>a*"foo"*</p>\n", + "example": 352, + "start_line": 6329, + "end_line": 6333, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "* a *\n", + "html": "<p>* a *</p>\n", + "example": 353, + "start_line": 6338, + "end_line": 6342, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*$*alpha.\n\n*£*bravo.\n\n*€*charlie.\n", + "html": "<p>*$*alpha.</p>\n<p>*£*bravo.</p>\n<p>*€*charlie.</p>\n", + "example": 354, + "start_line": 6347, + "end_line": 6357, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo*bar*\n", + "html": "<p>foo<em>bar</em></p>\n", + "example": 355, + "start_line": 6362, + "end_line": 6366, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "5*6*78\n", + "html": "<p>5<em>6</em>78</p>\n", + "example": 356, + "start_line": 6369, + "end_line": 6373, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo bar_\n", + "html": "<p><em>foo bar</em></p>\n", + "example": 357, + "start_line": 6378, + "end_line": 6382, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_ foo bar_\n", + "html": "<p>_ foo bar_</p>\n", + "example": 358, + "start_line": 6388, + "end_line": 6392, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "a_\"foo\"_\n", + "html": "<p>a_"foo"_</p>\n", + "example": 359, + "start_line": 6398, + "end_line": 6402, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo_bar_\n", + "html": "<p>foo_bar_</p>\n", + "example": 360, + "start_line": 6407, + "end_line": 6411, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "5_6_78\n", + "html": "<p>5_6_78</p>\n", + "example": 361, + "start_line": 6414, + "end_line": 6418, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "пристаням_стремятся_\n", + "html": "<p>пристаням_стремятся_</p>\n", + "example": 362, + "start_line": 6421, + "end_line": 6425, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "aa_\"bb\"_cc\n", + "html": "<p>aa_"bb"_cc</p>\n", + "example": 363, + "start_line": 6431, + "end_line": 6435, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo-_(bar)_\n", + "html": "<p>foo-<em>(bar)</em></p>\n", + "example": 364, + "start_line": 6442, + "end_line": 6446, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo*\n", + "html": "<p>_foo*</p>\n", + "example": 365, + "start_line": 6454, + "end_line": 6458, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo bar *\n", + "html": "<p>*foo bar *</p>\n", + "example": 366, + "start_line": 6464, + "end_line": 6468, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo bar\n*\n", + "html": "<p>*foo bar\n*</p>\n", + "example": 367, + "start_line": 6473, + "end_line": 6479, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*(*foo)\n", + "html": "<p>*(*foo)</p>\n", + "example": 368, + "start_line": 6486, + "end_line": 6490, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*(*foo*)*\n", + "html": "<p><em>(<em>foo</em>)</em></p>\n", + "example": 369, + "start_line": 6496, + "end_line": 6500, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo*bar\n", + "html": "<p><em>foo</em>bar</p>\n", + "example": 370, + "start_line": 6505, + "end_line": 6509, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo bar _\n", + "html": "<p>_foo bar _</p>\n", + "example": 371, + "start_line": 6518, + "end_line": 6522, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_(_foo)\n", + "html": "<p>_(_foo)</p>\n", + "example": 372, + "start_line": 6528, + "end_line": 6532, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_(_foo_)_\n", + "html": "<p><em>(<em>foo</em>)</em></p>\n", + "example": 373, + "start_line": 6537, + "end_line": 6541, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo_bar\n", + "html": "<p>_foo_bar</p>\n", + "example": 374, + "start_line": 6546, + "end_line": 6550, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_пристаням_стремятся\n", + "html": "<p>_пристаням_стремятся</p>\n", + "example": 375, + "start_line": 6553, + "end_line": 6557, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo_bar_baz_\n", + "html": "<p><em>foo_bar_baz</em></p>\n", + "example": 376, + "start_line": 6560, + "end_line": 6564, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_(bar)_.\n", + "html": "<p><em>(bar)</em>.</p>\n", + "example": 377, + "start_line": 6571, + "end_line": 6575, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo bar**\n", + "html": "<p><strong>foo bar</strong></p>\n", + "example": 378, + "start_line": 6580, + "end_line": 6584, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "** foo bar**\n", + "html": "<p>** foo bar**</p>\n", + "example": 379, + "start_line": 6590, + "end_line": 6594, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "a**\"foo\"**\n", + "html": "<p>a**"foo"**</p>\n", + "example": 380, + "start_line": 6601, + "end_line": 6605, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo**bar**\n", + "html": "<p>foo<strong>bar</strong></p>\n", + "example": 381, + "start_line": 6610, + "end_line": 6614, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo bar__\n", + "html": "<p><strong>foo bar</strong></p>\n", + "example": 382, + "start_line": 6619, + "end_line": 6623, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__ foo bar__\n", + "html": "<p>__ foo bar__</p>\n", + "example": 383, + "start_line": 6629, + "end_line": 6633, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__\nfoo bar__\n", + "html": "<p>__\nfoo bar__</p>\n", + "example": 384, + "start_line": 6637, + "end_line": 6643, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "a__\"foo\"__\n", + "html": "<p>a__"foo"__</p>\n", + "example": 385, + "start_line": 6649, + "end_line": 6653, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo__bar__\n", + "html": "<p>foo__bar__</p>\n", + "example": 386, + "start_line": 6658, + "end_line": 6662, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "5__6__78\n", + "html": "<p>5__6__78</p>\n", + "example": 387, + "start_line": 6665, + "end_line": 6669, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "пристаням__стремятся__\n", + "html": "<p>пристаням__стремятся__</p>\n", + "example": 388, + "start_line": 6672, + "end_line": 6676, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo, __bar__, baz__\n", + "html": "<p><strong>foo, <strong>bar</strong>, baz</strong></p>\n", + "example": 389, + "start_line": 6679, + "end_line": 6683, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo-__(bar)__\n", + "html": "<p>foo-<strong>(bar)</strong></p>\n", + "example": 390, + "start_line": 6690, + "end_line": 6694, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo bar **\n", + "html": "<p>**foo bar **</p>\n", + "example": 391, + "start_line": 6703, + "end_line": 6707, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**(**foo)\n", + "html": "<p>**(**foo)</p>\n", + "example": 392, + "start_line": 6716, + "end_line": 6720, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*(**foo**)*\n", + "html": "<p><em>(<strong>foo</strong>)</em></p>\n", + "example": 393, + "start_line": 6726, + "end_line": 6730, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**Gomphocarpus (*Gomphocarpus physocarpus*, syn.\n*Asclepias physocarpa*)**\n", + "html": "<p><strong>Gomphocarpus (<em>Gomphocarpus physocarpus</em>, syn.\n<em>Asclepias physocarpa</em>)</strong></p>\n", + "example": 394, + "start_line": 6733, + "end_line": 6739, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo \"*bar*\" foo**\n", + "html": "<p><strong>foo "<em>bar</em>" foo</strong></p>\n", + "example": 395, + "start_line": 6742, + "end_line": 6746, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo**bar\n", + "html": "<p><strong>foo</strong>bar</p>\n", + "example": 396, + "start_line": 6751, + "end_line": 6755, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo bar __\n", + "html": "<p>__foo bar __</p>\n", + "example": 397, + "start_line": 6763, + "end_line": 6767, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__(__foo)\n", + "html": "<p>__(__foo)</p>\n", + "example": 398, + "start_line": 6773, + "end_line": 6777, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_(__foo__)_\n", + "html": "<p><em>(<strong>foo</strong>)</em></p>\n", + "example": 399, + "start_line": 6783, + "end_line": 6787, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo__bar\n", + "html": "<p>__foo__bar</p>\n", + "example": 400, + "start_line": 6792, + "end_line": 6796, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__пристаням__стремятся\n", + "html": "<p>__пристаням__стремятся</p>\n", + "example": 401, + "start_line": 6799, + "end_line": 6803, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo__bar__baz__\n", + "html": "<p><strong>foo__bar__baz</strong></p>\n", + "example": 402, + "start_line": 6806, + "end_line": 6810, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__(bar)__.\n", + "html": "<p><strong>(bar)</strong>.</p>\n", + "example": 403, + "start_line": 6817, + "end_line": 6821, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo [bar](/url)*\n", + "html": "<p><em>foo <a href=\"/url\">bar</a></em></p>\n", + "example": 404, + "start_line": 6829, + "end_line": 6833, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo\nbar*\n", + "html": "<p><em>foo\nbar</em></p>\n", + "example": 405, + "start_line": 6836, + "end_line": 6842, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo __bar__ baz_\n", + "html": "<p><em>foo <strong>bar</strong> baz</em></p>\n", + "example": 406, + "start_line": 6848, + "end_line": 6852, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo _bar_ baz_\n", + "html": "<p><em>foo <em>bar</em> baz</em></p>\n", + "example": 407, + "start_line": 6855, + "end_line": 6859, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo_ bar_\n", + "html": "<p><em><em>foo</em> bar</em></p>\n", + "example": 408, + "start_line": 6862, + "end_line": 6866, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo *bar**\n", + "html": "<p><em>foo <em>bar</em></em></p>\n", + "example": 409, + "start_line": 6869, + "end_line": 6873, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo **bar** baz*\n", + "html": "<p><em>foo <strong>bar</strong> baz</em></p>\n", + "example": 410, + "start_line": 6876, + "end_line": 6880, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo**bar**baz*\n", + "html": "<p><em>foo<strong>bar</strong>baz</em></p>\n", + "example": 411, + "start_line": 6882, + "end_line": 6886, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo**bar*\n", + "html": "<p><em>foo**bar</em></p>\n", + "example": 412, + "start_line": 6906, + "end_line": 6910, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "***foo** bar*\n", + "html": "<p><em><strong>foo</strong> bar</em></p>\n", + "example": 413, + "start_line": 6919, + "end_line": 6923, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo **bar***\n", + "html": "<p><em>foo <strong>bar</strong></em></p>\n", + "example": 414, + "start_line": 6926, + "end_line": 6930, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo**bar***\n", + "html": "<p><em>foo<strong>bar</strong></em></p>\n", + "example": 415, + "start_line": 6933, + "end_line": 6937, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo***bar***baz\n", + "html": "<p>foo<em><strong>bar</strong></em>baz</p>\n", + "example": 416, + "start_line": 6944, + "end_line": 6948, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo******bar*********baz\n", + "html": "<p>foo<strong><strong><strong>bar</strong></strong></strong>***baz</p>\n", + "example": 417, + "start_line": 6950, + "end_line": 6954, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo **bar *baz* bim** bop*\n", + "html": "<p><em>foo <strong>bar <em>baz</em> bim</strong> bop</em></p>\n", + "example": 418, + "start_line": 6959, + "end_line": 6963, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo [*bar*](/url)*\n", + "html": "<p><em>foo <a href=\"/url\"><em>bar</em></a></em></p>\n", + "example": 419, + "start_line": 6966, + "end_line": 6970, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "** is not an empty emphasis\n", + "html": "<p>** is not an empty emphasis</p>\n", + "example": 420, + "start_line": 6975, + "end_line": 6979, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**** is not an empty strong emphasis\n", + "html": "<p>**** is not an empty strong emphasis</p>\n", + "example": 421, + "start_line": 6982, + "end_line": 6986, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo [bar](/url)**\n", + "html": "<p><strong>foo <a href=\"/url\">bar</a></strong></p>\n", + "example": 422, + "start_line": 6995, + "end_line": 6999, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo\nbar**\n", + "html": "<p><strong>foo\nbar</strong></p>\n", + "example": 423, + "start_line": 7002, + "end_line": 7008, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo _bar_ baz__\n", + "html": "<p><strong>foo <em>bar</em> baz</strong></p>\n", + "example": 424, + "start_line": 7014, + "end_line": 7018, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo __bar__ baz__\n", + "html": "<p><strong>foo <strong>bar</strong> baz</strong></p>\n", + "example": 425, + "start_line": 7021, + "end_line": 7025, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "____foo__ bar__\n", + "html": "<p><strong><strong>foo</strong> bar</strong></p>\n", + "example": 426, + "start_line": 7028, + "end_line": 7032, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo **bar****\n", + "html": "<p><strong>foo <strong>bar</strong></strong></p>\n", + "example": 427, + "start_line": 7035, + "end_line": 7039, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo *bar* baz**\n", + "html": "<p><strong>foo <em>bar</em> baz</strong></p>\n", + "example": 428, + "start_line": 7042, + "end_line": 7046, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo*bar*baz**\n", + "html": "<p><strong>foo<em>bar</em>baz</strong></p>\n", + "example": 429, + "start_line": 7049, + "end_line": 7053, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "***foo* bar**\n", + "html": "<p><strong><em>foo</em> bar</strong></p>\n", + "example": 430, + "start_line": 7056, + "end_line": 7060, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo *bar***\n", + "html": "<p><strong>foo <em>bar</em></strong></p>\n", + "example": 431, + "start_line": 7063, + "end_line": 7067, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo *bar **baz**\nbim* bop**\n", + "html": "<p><strong>foo <em>bar <strong>baz</strong>\nbim</em> bop</strong></p>\n", + "example": 432, + "start_line": 7072, + "end_line": 7078, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo [*bar*](/url)**\n", + "html": "<p><strong>foo <a href=\"/url\"><em>bar</em></a></strong></p>\n", + "example": 433, + "start_line": 7081, + "end_line": 7085, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__ is not an empty emphasis\n", + "html": "<p>__ is not an empty emphasis</p>\n", + "example": 434, + "start_line": 7090, + "end_line": 7094, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "____ is not an empty strong emphasis\n", + "html": "<p>____ is not an empty strong emphasis</p>\n", + "example": 435, + "start_line": 7097, + "end_line": 7101, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo ***\n", + "html": "<p>foo ***</p>\n", + "example": 436, + "start_line": 7107, + "end_line": 7111, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo *\\**\n", + "html": "<p>foo <em>*</em></p>\n", + "example": 437, + "start_line": 7114, + "end_line": 7118, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo *_*\n", + "html": "<p>foo <em>_</em></p>\n", + "example": 438, + "start_line": 7121, + "end_line": 7125, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo *****\n", + "html": "<p>foo *****</p>\n", + "example": 439, + "start_line": 7128, + "end_line": 7132, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo **\\***\n", + "html": "<p>foo <strong>*</strong></p>\n", + "example": 440, + "start_line": 7135, + "end_line": 7139, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo **_**\n", + "html": "<p>foo <strong>_</strong></p>\n", + "example": 441, + "start_line": 7142, + "end_line": 7146, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo*\n", + "html": "<p>*<em>foo</em></p>\n", + "example": 442, + "start_line": 7153, + "end_line": 7157, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo**\n", + "html": "<p><em>foo</em>*</p>\n", + "example": 443, + "start_line": 7160, + "end_line": 7164, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "***foo**\n", + "html": "<p>*<strong>foo</strong></p>\n", + "example": 444, + "start_line": 7167, + "end_line": 7171, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "****foo*\n", + "html": "<p>***<em>foo</em></p>\n", + "example": 445, + "start_line": 7174, + "end_line": 7178, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo***\n", + "html": "<p><strong>foo</strong>*</p>\n", + "example": 446, + "start_line": 7181, + "end_line": 7185, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo****\n", + "html": "<p><em>foo</em>***</p>\n", + "example": 447, + "start_line": 7188, + "end_line": 7192, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo ___\n", + "html": "<p>foo ___</p>\n", + "example": 448, + "start_line": 7198, + "end_line": 7202, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo _\\__\n", + "html": "<p>foo <em>_</em></p>\n", + "example": 449, + "start_line": 7205, + "end_line": 7209, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo _*_\n", + "html": "<p>foo <em>*</em></p>\n", + "example": 450, + "start_line": 7212, + "end_line": 7216, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo _____\n", + "html": "<p>foo _____</p>\n", + "example": 451, + "start_line": 7219, + "end_line": 7223, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo __\\___\n", + "html": "<p>foo <strong>_</strong></p>\n", + "example": 452, + "start_line": 7226, + "end_line": 7230, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo __*__\n", + "html": "<p>foo <strong>*</strong></p>\n", + "example": 453, + "start_line": 7233, + "end_line": 7237, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo_\n", + "html": "<p>_<em>foo</em></p>\n", + "example": 454, + "start_line": 7240, + "end_line": 7244, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo__\n", + "html": "<p><em>foo</em>_</p>\n", + "example": 455, + "start_line": 7251, + "end_line": 7255, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "___foo__\n", + "html": "<p>_<strong>foo</strong></p>\n", + "example": 456, + "start_line": 7258, + "end_line": 7262, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "____foo_\n", + "html": "<p>___<em>foo</em></p>\n", + "example": 457, + "start_line": 7265, + "end_line": 7269, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo___\n", + "html": "<p><strong>foo</strong>_</p>\n", + "example": 458, + "start_line": 7272, + "end_line": 7276, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo____\n", + "html": "<p><em>foo</em>___</p>\n", + "example": 459, + "start_line": 7279, + "end_line": 7283, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo**\n", + "html": "<p><strong>foo</strong></p>\n", + "example": 460, + "start_line": 7289, + "end_line": 7293, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*_foo_*\n", + "html": "<p><em><em>foo</em></em></p>\n", + "example": 461, + "start_line": 7296, + "end_line": 7300, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo__\n", + "html": "<p><strong>foo</strong></p>\n", + "example": 462, + "start_line": 7303, + "end_line": 7307, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_*foo*_\n", + "html": "<p><em><em>foo</em></em></p>\n", + "example": 463, + "start_line": 7310, + "end_line": 7314, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "****foo****\n", + "html": "<p><strong><strong>foo</strong></strong></p>\n", + "example": 464, + "start_line": 7320, + "end_line": 7324, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "____foo____\n", + "html": "<p><strong><strong>foo</strong></strong></p>\n", + "example": 465, + "start_line": 7327, + "end_line": 7331, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "******foo******\n", + "html": "<p><strong><strong><strong>foo</strong></strong></strong></p>\n", + "example": 466, + "start_line": 7338, + "end_line": 7342, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "***foo***\n", + "html": "<p><em><strong>foo</strong></em></p>\n", + "example": 467, + "start_line": 7347, + "end_line": 7351, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_____foo_____\n", + "html": "<p><em><strong><strong>foo</strong></strong></em></p>\n", + "example": 468, + "start_line": 7354, + "end_line": 7358, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo _bar* baz_\n", + "html": "<p><em>foo _bar</em> baz_</p>\n", + "example": 469, + "start_line": 7363, + "end_line": 7367, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo __bar *baz bim__ bam*\n", + "html": "<p><em>foo <strong>bar *baz bim</strong> bam</em></p>\n", + "example": 470, + "start_line": 7370, + "end_line": 7374, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo **bar baz**\n", + "html": "<p>**foo <strong>bar baz</strong></p>\n", + "example": 471, + "start_line": 7379, + "end_line": 7383, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo *bar baz*\n", + "html": "<p>*foo <em>bar baz</em></p>\n", + "example": 472, + "start_line": 7386, + "end_line": 7390, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*[bar*](/url)\n", + "html": "<p>*<a href=\"/url\">bar*</a></p>\n", + "example": 473, + "start_line": 7395, + "end_line": 7399, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo [bar_](/url)\n", + "html": "<p>_foo <a href=\"/url\">bar_</a></p>\n", + "example": 474, + "start_line": 7402, + "end_line": 7406, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*<img src=\"foo\" title=\"*\"/>\n", + "html": "<p>*<img src=\"foo\" title=\"*\"/></p>\n", + "example": 475, + "start_line": 7409, + "end_line": 7413, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**<a href=\"**\">\n", + "html": "<p>**<a href=\"**\"></p>\n", + "example": 476, + "start_line": 7416, + "end_line": 7420, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__<a href=\"__\">\n", + "html": "<p>__<a href=\"__\"></p>\n", + "example": 477, + "start_line": 7423, + "end_line": 7427, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*a `*`*\n", + "html": "<p><em>a <code>*</code></em></p>\n", + "example": 478, + "start_line": 7430, + "end_line": 7434, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_a `_`_\n", + "html": "<p><em>a <code>_</code></em></p>\n", + "example": 479, + "start_line": 7437, + "end_line": 7441, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**a<https://foo.bar/?q=**>\n", + "html": "<p>**a<a href=\"https://foo.bar/?q=**\">https://foo.bar/?q=**</a></p>\n", + "example": 480, + "start_line": 7444, + "end_line": 7448, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__a<https://foo.bar/?q=__>\n", + "html": "<p>__a<a href=\"https://foo.bar/?q=__\">https://foo.bar/?q=__</a></p>\n", + "example": 481, + "start_line": 7451, + "end_line": 7455, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "[link](/uri \"title\")\n", + "html": "<p><a href=\"/uri\" title=\"title\">link</a></p>\n", + "example": 482, + "start_line": 7539, + "end_line": 7543, + "section": "Links" + }, + { + "markdown": "[link](/uri)\n", + "html": "<p><a href=\"/uri\">link</a></p>\n", + "example": 483, + "start_line": 7549, + "end_line": 7553, + "section": "Links" + }, + { + "markdown": "[](./target.md)\n", + "html": "<p><a href=\"./target.md\"></a></p>\n", + "example": 484, + "start_line": 7555, + "end_line": 7559, + "section": "Links" + }, + { + "markdown": "[link]()\n", + "html": "<p><a href=\"\">link</a></p>\n", + "example": 485, + "start_line": 7562, + "end_line": 7566, + "section": "Links" + }, + { + "markdown": "[link](<>)\n", + "html": "<p><a href=\"\">link</a></p>\n", + "example": 486, + "start_line": 7569, + "end_line": 7573, + "section": "Links" + }, + { + "markdown": "[]()\n", + "html": "<p><a href=\"\"></a></p>\n", + "example": 487, + "start_line": 7576, + "end_line": 7580, + "section": "Links" + }, + { + "markdown": "[link](/my uri)\n", + "html": "<p>[link](/my uri)</p>\n", + "example": 488, + "start_line": 7585, + "end_line": 7589, + "section": "Links" + }, + { + "markdown": "[link](</my uri>)\n", + "html": "<p><a href=\"/my%20uri\">link</a></p>\n", + "example": 489, + "start_line": 7591, + "end_line": 7595, + "section": "Links" + }, + { + "markdown": "[link](foo\nbar)\n", + "html": "<p>[link](foo\nbar)</p>\n", + "example": 490, + "start_line": 7600, + "end_line": 7606, + "section": "Links" + }, + { + "markdown": "[link](<foo\nbar>)\n", + "html": "<p>[link](<foo\nbar>)</p>\n", + "example": 491, + "start_line": 7608, + "end_line": 7614, + "section": "Links" + }, + { + "markdown": "[a](<b)c>)\n", + "html": "<p><a href=\"b)c\">a</a></p>\n", + "example": 492, + "start_line": 7619, + "end_line": 7623, + "section": "Links" + }, + { + "markdown": "[link](<foo\\>)\n", + "html": "<p>[link](<foo>)</p>\n", + "example": 493, + "start_line": 7627, + "end_line": 7631, + "section": "Links" + }, + { + "markdown": "[a](<b)c\n[a](<b)c>\n[a](<b>c)\n", + "html": "<p>[a](<b)c\n[a](<b)c>\n[a](<b>c)</p>\n", + "example": 494, + "start_line": 7636, + "end_line": 7644, + "section": "Links" + }, + { + "markdown": "[link](\\(foo\\))\n", + "html": "<p><a href=\"(foo)\">link</a></p>\n", + "example": 495, + "start_line": 7648, + "end_line": 7652, + "section": "Links" + }, + { + "markdown": "[link](foo(and(bar)))\n", + "html": "<p><a href=\"foo(and(bar))\">link</a></p>\n", + "example": 496, + "start_line": 7657, + "end_line": 7661, + "section": "Links" + }, + { + "markdown": "[link](foo(and(bar))\n", + "html": "<p>[link](foo(and(bar))</p>\n", + "example": 497, + "start_line": 7666, + "end_line": 7670, + "section": "Links" + }, + { + "markdown": "[link](foo\\(and\\(bar\\))\n", + "html": "<p><a href=\"foo(and(bar)\">link</a></p>\n", + "example": 498, + "start_line": 7673, + "end_line": 7677, + "section": "Links" + }, + { + "markdown": "[link](<foo(and(bar)>)\n", + "html": "<p><a href=\"foo(and(bar)\">link</a></p>\n", + "example": 499, + "start_line": 7680, + "end_line": 7684, + "section": "Links" + }, + { + "markdown": "[link](foo\\)\\:)\n", + "html": "<p><a href=\"foo):\">link</a></p>\n", + "example": 500, + "start_line": 7690, + "end_line": 7694, + "section": "Links" + }, + { + "markdown": "[link](#fragment)\n\n[link](https://example.com#fragment)\n\n[link](https://example.com?foo=3#frag)\n", + "html": "<p><a href=\"#fragment\">link</a></p>\n<p><a href=\"https://example.com#fragment\">link</a></p>\n<p><a href=\"https://example.com?foo=3#frag\">link</a></p>\n", + "example": 501, + "start_line": 7699, + "end_line": 7709, + "section": "Links" + }, + { + "markdown": "[link](foo\\bar)\n", + "html": "<p><a href=\"foo%5Cbar\">link</a></p>\n", + "example": 502, + "start_line": 7715, + "end_line": 7719, + "section": "Links" + }, + { + "markdown": "[link](foo%20bä)\n", + "html": "<p><a href=\"foo%20b%C3%A4\">link</a></p>\n", + "example": 503, + "start_line": 7731, + "end_line": 7735, + "section": "Links" + }, + { + "markdown": "[link](\"title\")\n", + "html": "<p><a href=\"%22title%22\">link</a></p>\n", + "example": 504, + "start_line": 7742, + "end_line": 7746, + "section": "Links" + }, + { + "markdown": "[link](/url \"title\")\n[link](/url 'title')\n[link](/url (title))\n", + "html": "<p><a href=\"/url\" title=\"title\">link</a>\n<a href=\"/url\" title=\"title\">link</a>\n<a href=\"/url\" title=\"title\">link</a></p>\n", + "example": 505, + "start_line": 7751, + "end_line": 7759, + "section": "Links" + }, + { + "markdown": "[link](/url \"title \\\""\")\n", + "html": "<p><a href=\"/url\" title=\"title ""\">link</a></p>\n", + "example": 506, + "start_line": 7765, + "end_line": 7769, + "section": "Links" + }, + { + "markdown": "[link](/url \"title\")\n", + "html": "<p><a href=\"/url%C2%A0%22title%22\">link</a></p>\n", + "example": 507, + "start_line": 7776, + "end_line": 7780, + "section": "Links" + }, + { + "markdown": "[link](/url \"title \"and\" title\")\n", + "html": "<p>[link](/url "title "and" title")</p>\n", + "example": 508, + "start_line": 7785, + "end_line": 7789, + "section": "Links" + }, + { + "markdown": "[link](/url 'title \"and\" title')\n", + "html": "<p><a href=\"/url\" title=\"title "and" title\">link</a></p>\n", + "example": 509, + "start_line": 7794, + "end_line": 7798, + "section": "Links" + }, + { + "markdown": "[link]( /uri\n \"title\" )\n", + "html": "<p><a href=\"/uri\" title=\"title\">link</a></p>\n", + "example": 510, + "start_line": 7819, + "end_line": 7824, + "section": "Links" + }, + { + "markdown": "[link] (/uri)\n", + "html": "<p>[link] (/uri)</p>\n", + "example": 511, + "start_line": 7830, + "end_line": 7834, + "section": "Links" + }, + { + "markdown": "[link [foo [bar]]](/uri)\n", + "html": "<p><a href=\"/uri\">link [foo [bar]]</a></p>\n", + "example": 512, + "start_line": 7840, + "end_line": 7844, + "section": "Links" + }, + { + "markdown": "[link] bar](/uri)\n", + "html": "<p>[link] bar](/uri)</p>\n", + "example": 513, + "start_line": 7847, + "end_line": 7851, + "section": "Links" + }, + { + "markdown": "[link [bar](/uri)\n", + "html": "<p>[link <a href=\"/uri\">bar</a></p>\n", + "example": 514, + "start_line": 7854, + "end_line": 7858, + "section": "Links" + }, + { + "markdown": "[link \\[bar](/uri)\n", + "html": "<p><a href=\"/uri\">link [bar</a></p>\n", + "example": 515, + "start_line": 7861, + "end_line": 7865, + "section": "Links" + }, + { + "markdown": "[link *foo **bar** `#`*](/uri)\n", + "html": "<p><a href=\"/uri\">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>\n", + "example": 516, + "start_line": 7870, + "end_line": 7874, + "section": "Links" + }, + { + "markdown": "[![moon](moon.jpg)](/uri)\n", + "html": "<p><a href=\"/uri\"><img src=\"moon.jpg\" alt=\"moon\" /></a></p>\n", + "example": 517, + "start_line": 7877, + "end_line": 7881, + "section": "Links" + }, + { + "markdown": "[foo [bar](/uri)](/uri)\n", + "html": "<p>[foo <a href=\"/uri\">bar</a>](/uri)</p>\n", + "example": 518, + "start_line": 7886, + "end_line": 7890, + "section": "Links" + }, + { + "markdown": "[foo *[bar [baz](/uri)](/uri)*](/uri)\n", + "html": "<p>[foo <em>[bar <a href=\"/uri\">baz</a>](/uri)</em>](/uri)</p>\n", + "example": 519, + "start_line": 7893, + "end_line": 7897, + "section": "Links" + }, + { + "markdown": "![[[foo](uri1)](uri2)](uri3)\n", + "html": "<p><img src=\"uri3\" alt=\"[foo](uri2)\" /></p>\n", + "example": 520, + "start_line": 7900, + "end_line": 7904, + "section": "Links" + }, + { + "markdown": "*[foo*](/uri)\n", + "html": "<p>*<a href=\"/uri\">foo*</a></p>\n", + "example": 521, + "start_line": 7910, + "end_line": 7914, + "section": "Links" + }, + { + "markdown": "[foo *bar](baz*)\n", + "html": "<p><a href=\"baz*\">foo *bar</a></p>\n", + "example": 522, + "start_line": 7917, + "end_line": 7921, + "section": "Links" + }, + { + "markdown": "*foo [bar* baz]\n", + "html": "<p><em>foo [bar</em> baz]</p>\n", + "example": 523, + "start_line": 7927, + "end_line": 7931, + "section": "Links" + }, + { + "markdown": "[foo <bar attr=\"](baz)\">\n", + "html": "<p>[foo <bar attr=\"](baz)\"></p>\n", + "example": 524, + "start_line": 7937, + "end_line": 7941, + "section": "Links" + }, + { + "markdown": "[foo`](/uri)`\n", + "html": "<p>[foo<code>](/uri)</code></p>\n", + "example": 525, + "start_line": 7944, + "end_line": 7948, + "section": "Links" + }, + { + "markdown": "[foo<https://example.com/?search=](uri)>\n", + "html": "<p>[foo<a href=\"https://example.com/?search=%5D(uri)\">https://example.com/?search=](uri)</a></p>\n", + "example": 526, + "start_line": 7951, + "end_line": 7955, + "section": "Links" + }, + { + "markdown": "[foo][bar]\n\n[bar]: /url \"title\"\n", + "html": "<p><a href=\"/url\" title=\"title\">foo</a></p>\n", + "example": 527, + "start_line": 7989, + "end_line": 7995, + "section": "Links" + }, + { + "markdown": "[link [foo [bar]]][ref]\n\n[ref]: /uri\n", + "html": "<p><a href=\"/uri\">link [foo [bar]]</a></p>\n", + "example": 528, + "start_line": 8004, + "end_line": 8010, + "section": "Links" + }, + { + "markdown": "[link \\[bar][ref]\n\n[ref]: /uri\n", + "html": "<p><a href=\"/uri\">link [bar</a></p>\n", + "example": 529, + "start_line": 8013, + "end_line": 8019, + "section": "Links" + }, + { + "markdown": "[link *foo **bar** `#`*][ref]\n\n[ref]: /uri\n", + "html": "<p><a href=\"/uri\">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>\n", + "example": 530, + "start_line": 8024, + "end_line": 8030, + "section": "Links" + }, + { + "markdown": "[![moon](moon.jpg)][ref]\n\n[ref]: /uri\n", + "html": "<p><a href=\"/uri\"><img src=\"moon.jpg\" alt=\"moon\" /></a></p>\n", + "example": 531, + "start_line": 8033, + "end_line": 8039, + "section": "Links" + }, + { + "markdown": "[foo [bar](/uri)][ref]\n\n[ref]: /uri\n", + "html": "<p>[foo <a href=\"/uri\">bar</a>]<a href=\"/uri\">ref</a></p>\n", + "example": 532, + "start_line": 8044, + "end_line": 8050, + "section": "Links" + }, + { + "markdown": "[foo *bar [baz][ref]*][ref]\n\n[ref]: /uri\n", + "html": "<p>[foo <em>bar <a href=\"/uri\">baz</a></em>]<a href=\"/uri\">ref</a></p>\n", + "example": 533, + "start_line": 8053, + "end_line": 8059, + "section": "Links" + }, + { + "markdown": "*[foo*][ref]\n\n[ref]: /uri\n", + "html": "<p>*<a href=\"/uri\">foo*</a></p>\n", + "example": 534, + "start_line": 8068, + "end_line": 8074, + "section": "Links" + }, + { + "markdown": "[foo *bar][ref]*\n\n[ref]: /uri\n", + "html": "<p><a href=\"/uri\">foo *bar</a>*</p>\n", + "example": 535, + "start_line": 8077, + "end_line": 8083, + "section": "Links" + }, + { + "markdown": "[foo <bar attr=\"][ref]\">\n\n[ref]: /uri\n", + "html": "<p>[foo <bar attr=\"][ref]\"></p>\n", + "example": 536, + "start_line": 8089, + "end_line": 8095, + "section": "Links" + }, + { + "markdown": "[foo`][ref]`\n\n[ref]: /uri\n", + "html": "<p>[foo<code>][ref]</code></p>\n", + "example": 537, + "start_line": 8098, + "end_line": 8104, + "section": "Links" + }, + { + "markdown": "[foo<https://example.com/?search=][ref]>\n\n[ref]: /uri\n", + "html": "<p>[foo<a href=\"https://example.com/?search=%5D%5Bref%5D\">https://example.com/?search=][ref]</a></p>\n", + "example": 538, + "start_line": 8107, + "end_line": 8113, + "section": "Links" + }, + { + "markdown": "[foo][BaR]\n\n[bar]: /url \"title\"\n", + "html": "<p><a href=\"/url\" title=\"title\">foo</a></p>\n", + "example": 539, + "start_line": 8118, + "end_line": 8124, + "section": "Links" + }, + { + "markdown": "[ẞ]\n\n[SS]: /url\n", + "html": "<p><a href=\"/url\">ẞ</a></p>\n", + "example": 540, + "start_line": 8129, + "end_line": 8135, + "section": "Links" + }, + { + "markdown": "[Foo\n bar]: /url\n\n[Baz][Foo bar]\n", + "html": "<p><a href=\"/url\">Baz</a></p>\n", + "example": 541, + "start_line": 8141, + "end_line": 8148, + "section": "Links" + }, + { + "markdown": "[foo] [bar]\n\n[bar]: /url \"title\"\n", + "html": "<p>[foo] <a href=\"/url\" title=\"title\">bar</a></p>\n", + "example": 542, + "start_line": 8154, + "end_line": 8160, + "section": "Links" + }, + { + "markdown": "[foo]\n[bar]\n\n[bar]: /url \"title\"\n", + "html": "<p>[foo]\n<a href=\"/url\" title=\"title\">bar</a></p>\n", + "example": 543, + "start_line": 8163, + "end_line": 8171, + "section": "Links" + }, + { + "markdown": "[foo]: /url1\n\n[foo]: /url2\n\n[bar][foo]\n", + "html": "<p><a href=\"/url1\">bar</a></p>\n", + "example": 544, + "start_line": 8204, + "end_line": 8212, + "section": "Links" + }, + { + "markdown": "[bar][foo\\!]\n\n[foo!]: /url\n", + "html": "<p>[bar][foo!]</p>\n", + "example": 545, + "start_line": 8219, + "end_line": 8225, + "section": "Links" + }, + { + "markdown": "[foo][ref[]\n\n[ref[]: /uri\n", + "html": "<p>[foo][ref[]</p>\n<p>[ref[]: /uri</p>\n", + "example": 546, + "start_line": 8231, + "end_line": 8238, + "section": "Links" + }, + { + "markdown": "[foo][ref[bar]]\n\n[ref[bar]]: /uri\n", + "html": "<p>[foo][ref[bar]]</p>\n<p>[ref[bar]]: /uri</p>\n", + "example": 547, + "start_line": 8241, + "end_line": 8248, + "section": "Links" + }, + { + "markdown": "[[[foo]]]\n\n[[[foo]]]: /url\n", + "html": "<p>[[[foo]]]</p>\n<p>[[[foo]]]: /url</p>\n", + "example": 548, + "start_line": 8251, + "end_line": 8258, + "section": "Links" + }, + { + "markdown": "[foo][ref\\[]\n\n[ref\\[]: /uri\n", + "html": "<p><a href=\"/uri\">foo</a></p>\n", + "example": 549, + "start_line": 8261, + "end_line": 8267, + "section": "Links" + }, + { + "markdown": "[bar\\\\]: /uri\n\n[bar\\\\]\n", + "html": "<p><a href=\"/uri\">bar\\</a></p>\n", + "example": 550, + "start_line": 8272, + "end_line": 8278, + "section": "Links" + }, + { + "markdown": "[]\n\n[]: /uri\n", + "html": "<p>[]</p>\n<p>[]: /uri</p>\n", + "example": 551, + "start_line": 8284, + "end_line": 8291, + "section": "Links" + }, + { + "markdown": "[\n ]\n\n[\n ]: /uri\n", + "html": "<p>[\n]</p>\n<p>[\n]: /uri</p>\n", + "example": 552, + "start_line": 8294, + "end_line": 8305, + "section": "Links" + }, + { + "markdown": "[foo][]\n\n[foo]: /url \"title\"\n", + "html": "<p><a href=\"/url\" title=\"title\">foo</a></p>\n", + "example": 553, + "start_line": 8317, + "end_line": 8323, + "section": "Links" + }, + { + "markdown": "[*foo* bar][]\n\n[*foo* bar]: /url \"title\"\n", + "html": "<p><a href=\"/url\" title=\"title\"><em>foo</em> bar</a></p>\n", + "example": 554, + "start_line": 8326, + "end_line": 8332, + "section": "Links" + }, + { + "markdown": "[Foo][]\n\n[foo]: /url \"title\"\n", + "html": "<p><a href=\"/url\" title=\"title\">Foo</a></p>\n", + "example": 555, + "start_line": 8337, + "end_line": 8343, + "section": "Links" + }, + { + "markdown": "[foo] \n[]\n\n[foo]: /url \"title\"\n", + "html": "<p><a href=\"/url\" title=\"title\">foo</a>\n[]</p>\n", + "example": 556, + "start_line": 8350, + "end_line": 8358, + "section": "Links" + }, + { + "markdown": "[foo]\n\n[foo]: /url \"title\"\n", + "html": "<p><a href=\"/url\" title=\"title\">foo</a></p>\n", + "example": 557, + "start_line": 8370, + "end_line": 8376, + "section": "Links" + }, + { + "markdown": "[*foo* bar]\n\n[*foo* bar]: /url \"title\"\n", + "html": "<p><a href=\"/url\" title=\"title\"><em>foo</em> bar</a></p>\n", + "example": 558, + "start_line": 8379, + "end_line": 8385, + "section": "Links" + }, + { + "markdown": "[[*foo* bar]]\n\n[*foo* bar]: /url \"title\"\n", + "html": "<p>[<a href=\"/url\" title=\"title\"><em>foo</em> bar</a>]</p>\n", + "example": 559, + "start_line": 8388, + "end_line": 8394, + "section": "Links" + }, + { + "markdown": "[[bar [foo]\n\n[foo]: /url\n", + "html": "<p>[[bar <a href=\"/url\">foo</a></p>\n", + "example": 560, + "start_line": 8397, + "end_line": 8403, + "section": "Links" + }, + { + "markdown": "[Foo]\n\n[foo]: /url \"title\"\n", + "html": "<p><a href=\"/url\" title=\"title\">Foo</a></p>\n", + "example": 561, + "start_line": 8408, + "end_line": 8414, + "section": "Links" + }, + { + "markdown": "[foo] bar\n\n[foo]: /url\n", + "html": "<p><a href=\"/url\">foo</a> bar</p>\n", + "example": 562, + "start_line": 8419, + "end_line": 8425, + "section": "Links" + }, + { + "markdown": "\\[foo]\n\n[foo]: /url \"title\"\n", + "html": "<p>[foo]</p>\n", + "example": 563, + "start_line": 8431, + "end_line": 8437, + "section": "Links" + }, + { + "markdown": "[foo*]: /url\n\n*[foo*]\n", + "html": "<p>*<a href=\"/url\">foo*</a></p>\n", + "example": 564, + "start_line": 8443, + "end_line": 8449, + "section": "Links" + }, + { + "markdown": "[foo][bar]\n\n[foo]: /url1\n[bar]: /url2\n", + "html": "<p><a href=\"/url2\">foo</a></p>\n", + "example": 565, + "start_line": 8455, + "end_line": 8462, + "section": "Links" + }, + { + "markdown": "[foo][]\n\n[foo]: /url1\n", + "html": "<p><a href=\"/url1\">foo</a></p>\n", + "example": 566, + "start_line": 8464, + "end_line": 8470, + "section": "Links" + }, + { + "markdown": "[foo]()\n\n[foo]: /url1\n", + "html": "<p><a href=\"\">foo</a></p>\n", + "example": 567, + "start_line": 8474, + "end_line": 8480, + "section": "Links" + }, + { + "markdown": "[foo](not a link)\n\n[foo]: /url1\n", + "html": "<p><a href=\"/url1\">foo</a>(not a link)</p>\n", + "example": 568, + "start_line": 8482, + "end_line": 8488, + "section": "Links" + }, + { + "markdown": "[foo][bar][baz]\n\n[baz]: /url\n", + "html": "<p>[foo]<a href=\"/url\">bar</a></p>\n", + "example": 569, + "start_line": 8493, + "end_line": 8499, + "section": "Links" + }, + { + "markdown": "[foo][bar][baz]\n\n[baz]: /url1\n[bar]: /url2\n", + "html": "<p><a href=\"/url2\">foo</a><a href=\"/url1\">baz</a></p>\n", + "example": 570, + "start_line": 8505, + "end_line": 8512, + "section": "Links" + }, + { + "markdown": "[foo][bar][baz]\n\n[baz]: /url1\n[foo]: /url2\n", + "html": "<p>[foo]<a href=\"/url1\">bar</a></p>\n", + "example": 571, + "start_line": 8518, + "end_line": 8525, + "section": "Links" + }, + { + "markdown": "![foo](/url \"title\")\n", + "html": "<p><img src=\"/url\" alt=\"foo\" title=\"title\" /></p>\n", + "example": 572, + "start_line": 8541, + "end_line": 8545, + "section": "Images" + }, + { + "markdown": "![foo *bar*]\n\n[foo *bar*]: train.jpg \"train & tracks\"\n", + "html": "<p><img src=\"train.jpg\" alt=\"foo bar\" title=\"train & tracks\" /></p>\n", + "example": 573, + "start_line": 8548, + "end_line": 8554, + "section": "Images" + }, + { + "markdown": "![foo ![bar](/url)](/url2)\n", + "html": "<p><img src=\"/url2\" alt=\"foo bar\" /></p>\n", + "example": 574, + "start_line": 8557, + "end_line": 8561, + "section": "Images" + }, + { + "markdown": "![foo [bar](/url)](/url2)\n", + "html": "<p><img src=\"/url2\" alt=\"foo bar\" /></p>\n", + "example": 575, + "start_line": 8564, + "end_line": 8568, + "section": "Images" + }, + { + "markdown": "![foo *bar*][]\n\n[foo *bar*]: train.jpg \"train & tracks\"\n", + "html": "<p><img src=\"train.jpg\" alt=\"foo bar\" title=\"train & tracks\" /></p>\n", + "example": 576, + "start_line": 8578, + "end_line": 8584, + "section": "Images" + }, + { + "markdown": "![foo *bar*][foobar]\n\n[FOOBAR]: train.jpg \"train & tracks\"\n", + "html": "<p><img src=\"train.jpg\" alt=\"foo bar\" title=\"train & tracks\" /></p>\n", + "example": 577, + "start_line": 8587, + "end_line": 8593, + "section": "Images" + }, + { + "markdown": "![foo](train.jpg)\n", + "html": "<p><img src=\"train.jpg\" alt=\"foo\" /></p>\n", + "example": 578, + "start_line": 8596, + "end_line": 8600, + "section": "Images" + }, + { + "markdown": "My ![foo bar](/path/to/train.jpg \"title\" )\n", + "html": "<p>My <img src=\"/path/to/train.jpg\" alt=\"foo bar\" title=\"title\" /></p>\n", + "example": 579, + "start_line": 8603, + "end_line": 8607, + "section": "Images" + }, + { + "markdown": "![foo](<url>)\n", + "html": "<p><img src=\"url\" alt=\"foo\" /></p>\n", + "example": 580, + "start_line": 8610, + "end_line": 8614, + "section": "Images" + }, + { + "markdown": "![](/url)\n", + "html": "<p><img src=\"/url\" alt=\"\" /></p>\n", + "example": 581, + "start_line": 8617, + "end_line": 8621, + "section": "Images" + }, + { + "markdown": "![foo][bar]\n\n[bar]: /url\n", + "html": "<p><img src=\"/url\" alt=\"foo\" /></p>\n", + "example": 582, + "start_line": 8626, + "end_line": 8632, + "section": "Images" + }, + { + "markdown": "![foo][bar]\n\n[BAR]: /url\n", + "html": "<p><img src=\"/url\" alt=\"foo\" /></p>\n", + "example": 583, + "start_line": 8635, + "end_line": 8641, + "section": "Images" + }, + { + "markdown": "![foo][]\n\n[foo]: /url \"title\"\n", + "html": "<p><img src=\"/url\" alt=\"foo\" title=\"title\" /></p>\n", + "example": 584, + "start_line": 8646, + "end_line": 8652, + "section": "Images" + }, + { + "markdown": "![*foo* bar][]\n\n[*foo* bar]: /url \"title\"\n", + "html": "<p><img src=\"/url\" alt=\"foo bar\" title=\"title\" /></p>\n", + "example": 585, + "start_line": 8655, + "end_line": 8661, + "section": "Images" + }, + { + "markdown": "![Foo][]\n\n[foo]: /url \"title\"\n", + "html": "<p><img src=\"/url\" alt=\"Foo\" title=\"title\" /></p>\n", + "example": 586, + "start_line": 8666, + "end_line": 8672, + "section": "Images" + }, + { + "markdown": "![foo] \n[]\n\n[foo]: /url \"title\"\n", + "html": "<p><img src=\"/url\" alt=\"foo\" title=\"title\" />\n[]</p>\n", + "example": 587, + "start_line": 8678, + "end_line": 8686, + "section": "Images" + }, + { + "markdown": "![foo]\n\n[foo]: /url \"title\"\n", + "html": "<p><img src=\"/url\" alt=\"foo\" title=\"title\" /></p>\n", + "example": 588, + "start_line": 8691, + "end_line": 8697, + "section": "Images" + }, + { + "markdown": "![*foo* bar]\n\n[*foo* bar]: /url \"title\"\n", + "html": "<p><img src=\"/url\" alt=\"foo bar\" title=\"title\" /></p>\n", + "example": 589, + "start_line": 8700, + "end_line": 8706, + "section": "Images" + }, + { + "markdown": "![[foo]]\n\n[[foo]]: /url \"title\"\n", + "html": "<p>![[foo]]</p>\n<p>[[foo]]: /url "title"</p>\n", + "example": 590, + "start_line": 8711, + "end_line": 8718, + "section": "Images" + }, + { + "markdown": "![Foo]\n\n[foo]: /url \"title\"\n", + "html": "<p><img src=\"/url\" alt=\"Foo\" title=\"title\" /></p>\n", + "example": 591, + "start_line": 8723, + "end_line": 8729, + "section": "Images" + }, + { + "markdown": "!\\[foo]\n\n[foo]: /url \"title\"\n", + "html": "<p>![foo]</p>\n", + "example": 592, + "start_line": 8735, + "end_line": 8741, + "section": "Images" + }, + { + "markdown": "\\![foo]\n\n[foo]: /url \"title\"\n", + "html": "<p>!<a href=\"/url\" title=\"title\">foo</a></p>\n", + "example": 593, + "start_line": 8747, + "end_line": 8753, + "section": "Images" + }, + { + "markdown": "<http://foo.bar.baz>\n", + "html": "<p><a href=\"http://foo.bar.baz\">http://foo.bar.baz</a></p>\n", + "example": 594, + "start_line": 8780, + "end_line": 8784, + "section": "Autolinks" + }, + { + "markdown": "<https://foo.bar.baz/test?q=hello&id=22&boolean>\n", + "html": "<p><a href=\"https://foo.bar.baz/test?q=hello&id=22&boolean\">https://foo.bar.baz/test?q=hello&id=22&boolean</a></p>\n", + "example": 595, + "start_line": 8787, + "end_line": 8791, + "section": "Autolinks" + }, + { + "markdown": "<irc://foo.bar:2233/baz>\n", + "html": "<p><a href=\"irc://foo.bar:2233/baz\">irc://foo.bar:2233/baz</a></p>\n", + "example": 596, + "start_line": 8794, + "end_line": 8798, + "section": "Autolinks" + }, + { + "markdown": "<MAILTO:FOO@BAR.BAZ>\n", + "html": "<p><a href=\"MAILTO:FOO@BAR.BAZ\">MAILTO:FOO@BAR.BAZ</a></p>\n", + "example": 597, + "start_line": 8803, + "end_line": 8807, + "section": "Autolinks" + }, + { + "markdown": "<a+b+c:d>\n", + "html": "<p><a href=\"a+b+c:d\">a+b+c:d</a></p>\n", + "example": 598, + "start_line": 8815, + "end_line": 8819, + "section": "Autolinks" + }, + { + "markdown": "<made-up-scheme://foo,bar>\n", + "html": "<p><a href=\"made-up-scheme://foo,bar\">made-up-scheme://foo,bar</a></p>\n", + "example": 599, + "start_line": 8822, + "end_line": 8826, + "section": "Autolinks" + }, + { + "markdown": "<https://../>\n", + "html": "<p><a href=\"https://../\">https://../</a></p>\n", + "example": 600, + "start_line": 8829, + "end_line": 8833, + "section": "Autolinks" + }, + { + "markdown": "<localhost:5001/foo>\n", + "html": "<p><a href=\"localhost:5001/foo\">localhost:5001/foo</a></p>\n", + "example": 601, + "start_line": 8836, + "end_line": 8840, + "section": "Autolinks" + }, + { + "markdown": "<https://foo.bar/baz bim>\n", + "html": "<p><https://foo.bar/baz bim></p>\n", + "example": 602, + "start_line": 8845, + "end_line": 8849, + "section": "Autolinks" + }, + { + "markdown": "<https://example.com/\\[\\>\n", + "html": "<p><a href=\"https://example.com/%5C%5B%5C\">https://example.com/\\[\\</a></p>\n", + "example": 603, + "start_line": 8854, + "end_line": 8858, + "section": "Autolinks" + }, + { + "markdown": "<foo@bar.example.com>\n", + "html": "<p><a href=\"mailto:foo@bar.example.com\">foo@bar.example.com</a></p>\n", + "example": 604, + "start_line": 8876, + "end_line": 8880, + "section": "Autolinks" + }, + { + "markdown": "<foo+special@Bar.baz-bar0.com>\n", + "html": "<p><a href=\"mailto:foo+special@Bar.baz-bar0.com\">foo+special@Bar.baz-bar0.com</a></p>\n", + "example": 605, + "start_line": 8883, + "end_line": 8887, + "section": "Autolinks" + }, + { + "markdown": "<foo\\+@bar.example.com>\n", + "html": "<p><foo+@bar.example.com></p>\n", + "example": 606, + "start_line": 8892, + "end_line": 8896, + "section": "Autolinks" + }, + { + "markdown": "<>\n", + "html": "<p><></p>\n", + "example": 607, + "start_line": 8901, + "end_line": 8905, + "section": "Autolinks" + }, + { + "markdown": "< https://foo.bar >\n", + "html": "<p>< https://foo.bar ></p>\n", + "example": 608, + "start_line": 8908, + "end_line": 8912, + "section": "Autolinks" + }, + { + "markdown": "<m:abc>\n", + "html": "<p><m:abc></p>\n", + "example": 609, + "start_line": 8915, + "end_line": 8919, + "section": "Autolinks" + }, + { + "markdown": "<foo.bar.baz>\n", + "html": "<p><foo.bar.baz></p>\n", + "example": 610, + "start_line": 8922, + "end_line": 8926, + "section": "Autolinks" + }, + { + "markdown": "https://example.com\n", + "html": "<p>https://example.com</p>\n", + "example": 611, + "start_line": 8929, + "end_line": 8933, + "section": "Autolinks" + }, + { + "markdown": "foo@bar.example.com\n", + "html": "<p>foo@bar.example.com</p>\n", + "example": 612, + "start_line": 8936, + "end_line": 8940, + "section": "Autolinks" + }, + { + "markdown": "<a><bab><c2c>\n", + "html": "<p><a><bab><c2c></p>\n", + "example": 613, + "start_line": 9016, + "end_line": 9020, + "section": "Raw HTML" + }, + { + "markdown": "<a/><b2/>\n", + "html": "<p><a/><b2/></p>\n", + "example": 614, + "start_line": 9025, + "end_line": 9029, + "section": "Raw HTML" + }, + { + "markdown": "<a /><b2\ndata=\"foo\" >\n", + "html": "<p><a /><b2\ndata=\"foo\" ></p>\n", + "example": 615, + "start_line": 9034, + "end_line": 9040, + "section": "Raw HTML" + }, + { + "markdown": "<a foo=\"bar\" bam = 'baz <em>\"</em>'\n_boolean zoop:33=zoop:33 />\n", + "html": "<p><a foo=\"bar\" bam = 'baz <em>\"</em>'\n_boolean zoop:33=zoop:33 /></p>\n", + "example": 616, + "start_line": 9045, + "end_line": 9051, + "section": "Raw HTML" + }, + { + "markdown": "Foo <responsive-image src=\"foo.jpg\" />\n", + "html": "<p>Foo <responsive-image src=\"foo.jpg\" /></p>\n", + "example": 617, + "start_line": 9056, + "end_line": 9060, + "section": "Raw HTML" + }, + { + "markdown": "<33> <__>\n", + "html": "<p><33> <__></p>\n", + "example": 618, + "start_line": 9065, + "end_line": 9069, + "section": "Raw HTML" + }, + { + "markdown": "<a h*#ref=\"hi\">\n", + "html": "<p><a h*#ref="hi"></p>\n", + "example": 619, + "start_line": 9074, + "end_line": 9078, + "section": "Raw HTML" + }, + { + "markdown": "<a href=\"hi'> <a href=hi'>\n", + "html": "<p><a href="hi'> <a href=hi'></p>\n", + "example": 620, + "start_line": 9083, + "end_line": 9087, + "section": "Raw HTML" + }, + { + "markdown": "< a><\nfoo><bar/ >\n<foo bar=baz\nbim!bop />\n", + "html": "<p>< a><\nfoo><bar/ >\n<foo bar=baz\nbim!bop /></p>\n", + "example": 621, + "start_line": 9092, + "end_line": 9102, + "section": "Raw HTML" + }, + { + "markdown": "<a href='bar'title=title>\n", + "html": "<p><a href='bar'title=title></p>\n", + "example": 622, + "start_line": 9107, + "end_line": 9111, + "section": "Raw HTML" + }, + { + "markdown": "</a></foo >\n", + "html": "<p></a></foo ></p>\n", + "example": 623, + "start_line": 9116, + "end_line": 9120, + "section": "Raw HTML" + }, + { + "markdown": "</a href=\"foo\">\n", + "html": "<p></a href="foo"></p>\n", + "example": 624, + "start_line": 9125, + "end_line": 9129, + "section": "Raw HTML" + }, + { + "markdown": "foo <!-- this is a --\ncomment - with hyphens -->\n", + "html": "<p>foo <!-- this is a --\ncomment - with hyphens --></p>\n", + "example": 625, + "start_line": 9134, + "end_line": 9140, + "section": "Raw HTML" + }, + { + "markdown": "foo <!--> foo -->\n\nfoo <!---> foo -->\n", + "html": "<p>foo <!--> foo --></p>\n<p>foo <!---> foo --></p>\n", + "example": 626, + "start_line": 9142, + "end_line": 9149, + "section": "Raw HTML" + }, + { + "markdown": "foo <?php echo $a; ?>\n", + "html": "<p>foo <?php echo $a; ?></p>\n", + "example": 627, + "start_line": 9154, + "end_line": 9158, + "section": "Raw HTML" + }, + { + "markdown": "foo <!ELEMENT br EMPTY>\n", + "html": "<p>foo <!ELEMENT br EMPTY></p>\n", + "example": 628, + "start_line": 9163, + "end_line": 9167, + "section": "Raw HTML" + }, + { + "markdown": "foo <![CDATA[>&<]]>\n", + "html": "<p>foo <![CDATA[>&<]]></p>\n", + "example": 629, + "start_line": 9172, + "end_line": 9176, + "section": "Raw HTML" + }, + { + "markdown": "foo <a href=\"ö\">\n", + "html": "<p>foo <a href=\"ö\"></p>\n", + "example": 630, + "start_line": 9182, + "end_line": 9186, + "section": "Raw HTML" + }, + { + "markdown": "foo <a href=\"\\*\">\n", + "html": "<p>foo <a href=\"\\*\"></p>\n", + "example": 631, + "start_line": 9191, + "end_line": 9195, + "section": "Raw HTML" + }, + { + "markdown": "<a href=\"\\\"\">\n", + "html": "<p><a href="""></p>\n", + "example": 632, + "start_line": 9198, + "end_line": 9202, + "section": "Raw HTML" + }, + { + "markdown": "foo \nbaz\n", + "html": "<p>foo<br />\nbaz</p>\n", + "example": 633, + "start_line": 9212, + "end_line": 9218, + "section": "Hard line breaks" + }, + { + "markdown": "foo\\\nbaz\n", + "html": "<p>foo<br />\nbaz</p>\n", + "example": 634, + "start_line": 9224, + "end_line": 9230, + "section": "Hard line breaks" + }, + { + "markdown": "foo \nbaz\n", + "html": "<p>foo<br />\nbaz</p>\n", + "example": 635, + "start_line": 9235, + "end_line": 9241, + "section": "Hard line breaks" + }, + { + "markdown": "foo \n bar\n", + "html": "<p>foo<br />\nbar</p>\n", + "example": 636, + "start_line": 9246, + "end_line": 9252, + "section": "Hard line breaks" + }, + { + "markdown": "foo\\\n bar\n", + "html": "<p>foo<br />\nbar</p>\n", + "example": 637, + "start_line": 9255, + "end_line": 9261, + "section": "Hard line breaks" + }, + { + "markdown": "*foo \nbar*\n", + "html": "<p><em>foo<br />\nbar</em></p>\n", + "example": 638, + "start_line": 9267, + "end_line": 9273, + "section": "Hard line breaks" + }, + { + "markdown": "*foo\\\nbar*\n", + "html": "<p><em>foo<br />\nbar</em></p>\n", + "example": 639, + "start_line": 9276, + "end_line": 9282, + "section": "Hard line breaks" + }, + { + "markdown": "`code \nspan`\n", + "html": "<p><code>code span</code></p>\n", + "example": 640, + "start_line": 9287, + "end_line": 9292, + "section": "Hard line breaks" + }, + { + "markdown": "`code\\\nspan`\n", + "html": "<p><code>code\\ span</code></p>\n", + "example": 641, + "start_line": 9295, + "end_line": 9300, + "section": "Hard line breaks" + }, + { + "markdown": "<a href=\"foo \nbar\">\n", + "html": "<p><a href=\"foo \nbar\"></p>\n", + "example": 642, + "start_line": 9305, + "end_line": 9311, + "section": "Hard line breaks" + }, + { + "markdown": "<a href=\"foo\\\nbar\">\n", + "html": "<p><a href=\"foo\\\nbar\"></p>\n", + "example": 643, + "start_line": 9314, + "end_line": 9320, + "section": "Hard line breaks" + }, + { + "markdown": "foo\\\n", + "html": "<p>foo\\</p>\n", + "example": 644, + "start_line": 9327, + "end_line": 9331, + "section": "Hard line breaks" + }, + { + "markdown": "foo \n", + "html": "<p>foo</p>\n", + "example": 645, + "start_line": 9334, + "end_line": 9338, + "section": "Hard line breaks" + }, + { + "markdown": "### foo\\\n", + "html": "<h3>foo\\</h3>\n", + "example": 646, + "start_line": 9341, + "end_line": 9345, + "section": "Hard line breaks" + }, + { + "markdown": "### foo \n", + "html": "<h3>foo</h3>\n", + "example": 647, + "start_line": 9348, + "end_line": 9352, + "section": "Hard line breaks" + }, + { + "markdown": "foo\nbaz\n", + "html": "<p>foo\nbaz</p>\n", + "example": 648, + "start_line": 9363, + "end_line": 9369, + "section": "Soft line breaks" + }, + { + "markdown": "foo \n baz\n", + "html": "<p>foo\nbaz</p>\n", + "example": 649, + "start_line": 9375, + "end_line": 9381, + "section": "Soft line breaks" + }, + { + "markdown": "hello $.;'there\n", + "html": "<p>hello $.;'there</p>\n", + "example": 650, + "start_line": 9395, + "end_line": 9399, + "section": "Textual content" + }, + { + "markdown": "Foo χρῆν\n", + "html": "<p>Foo χρῆν</p>\n", + "example": 651, + "start_line": 9402, + "end_line": 9406, + "section": "Textual content" + }, + { + "markdown": "Multiple spaces\n", + "html": "<p>Multiple spaces</p>\n", + "example": 652, + "start_line": 9411, + "end_line": 9415, + "section": "Textual content" + } +] \ No newline at end of file diff --git a/pkgs/markdown/tool/dartdoc_compare.dart b/pkgs/markdown/tool/dartdoc_compare.dart new file mode 100644 index 000000000..e6100eeb6 --- /dev/null +++ b/pkgs/markdown/tool/dartdoc_compare.dart @@ -0,0 +1,189 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:convert' show jsonDecode, jsonEncode; +import 'dart:io' show Directory, File, Platform, Process, exitCode; + +import 'package:args/args.dart' show ArgParser; +import 'package:path/path.dart' show absolute; +import 'package:yaml/yaml.dart' show loadYaml; + +const _dartdocDir = 'dartdoc-dir'; +const _markdownBefore = 'before'; +const _markdownAfter = 'after'; +const _sdk = 'sdk'; +const _help = 'help'; + +void main(List<String> arguments) { + final parser = ArgParser() + ..addSeparator('Usage: dartdoc-compare.dart [OPTIONS] <dart-package>') + ..addOption(_dartdocDir, help: 'Directory of the dartdoc package') + ..addOption(_markdownBefore, help: "Markdown package 'before' ref") + ..addOption( + _markdownAfter, + defaultsTo: 'HEAD', + help: "Markdown package 'after' ref (or 'local')", + ) + ..addFlag( + _sdk, + negatable: false, + help: 'Is the package the SDK?', + ) + ..addFlag(_help, abbr: 'h', hide: true); + + final options = parser.parse(arguments); + if (options[_help] as bool) { + print(parser.usage); + exitCode = 0; + return; + } + if (options[_dartdocDir] == null || options[_markdownBefore] == null) { + print( + 'Invalid arguments: Options --$_dartdocDir and --$_markdownBefore ' + 'must be specified', + ); + print(parser.usage); + exitCode = 1; + return; + } + final comparer = DartdocCompare( + options[_dartdocDir] as String, + options[_markdownBefore] as String, + options[_markdownAfter] as String, + absolute(options[_dartdocDir] as String, 'bin/dartdoc.dart'), + absolute(options[_dartdocDir] as String, 'pubspec.yaml'), + options[_sdk] as bool, + ); + + String? path; + if (comparer.sdk) { + if (options.rest.isNotEmpty) { + path = options.rest.single; + } + } else { + path = options.rest.single; + } + + if (comparer.compare(path)) { + exitCode = 0; + } else { + exitCode = 1; + } +} + +class DartdocCompare { + final String dartdocDir; + final String markdownBefore; + final String markdownAfter; + final String dartdocBin; + final String dartdocPubspecPath; + final bool sdk; + final String markdownPath = File(Platform.script.path).parent.parent.path; + + DartdocCompare( + this.dartdocDir, + this.markdownBefore, + this.markdownAfter, + this.dartdocBin, + this.dartdocPubspecPath, + this.sdk, + ); + + bool compare(String? package) { + // Generate docs with Markdown "Before". + final outBefore = _runDartdoc(markdownBefore, package); + + // Generate docs with Markdown "After". + final outAfter = _runDartdoc(markdownAfter, package); + + // Compare outputs + final diffOptions = ['-r', '-B', outBefore, outAfter]; + final result = Process.runSync('diff', diffOptions, runInShell: true); + final nlines = '\n'.allMatches(result.stdout as String).length; + print('Diff lines: $nlines'); + print('diff ${diffOptions.join(" ")}'); + return result.exitCode == 0; + } + + String _runDartdoc(String markdownRef, String? path) { + print('=========================================================='); + print('Running dartdoc for $markdownRef...'); + print('=========================================================='); + _doInPath(dartdocDir, () { + final returnCode = _updateDartdocPubspec(markdownRef); + if (returnCode != 0) { + throw Exception("Could not update dartdoc's pubspec!"); + } + }); + return _doInPath(path, () { + if (!sdk) { + _system('pub', ['upgrade']); + } + final out = Directory.systemTemp + .createTempSync('dartdoc-compare-${markdownRef}__'); + const cmd = 'dart'; + final args = [dartdocBin, '--output=${out.path}']; + + if (sdk) { + args.add('--sdk-docs'); + } + + print('Command: $cmd ${args.join(' ')}'); + final startTime = DateTime.now(); + _system(cmd, args); + final endTime = DateTime.now(); + final duration = endTime.difference(startTime).inSeconds; + print('dartdoc generation for $markdownRef took $duration seconds.'); + print(''); + + return out.path; + }); + } + + int _updateDartdocPubspec(String markdownRef) { + var dartdocPubspec = + loadYaml(File(dartdocPubspecPath).readAsStringSync()) as Map; + // make modifiable copy + dartdocPubspec = jsonDecode(jsonEncode(dartdocPubspec)) as Map; + + final dependencies = dartdocPubspec['dependencies'] as Map; + + if (markdownRef == 'local') { + dependencies['markdown'] = { + 'path': markdownPath, + }; + } else { + dependencies['markdown'] = { + 'git': { + 'url': 'git://github.com/dart-lang/markdown.git', + 'ref': markdownRef + } + }; + } + + File(dartdocPubspecPath).writeAsStringSync(jsonEncode(dartdocPubspec)); + return _system('pub', ['upgrade']); + } +} + +int _system(String cmd, List<String> args) { + final result = Process.runSync(cmd, args); + print(result.stdout); + print(result.stderr); + return result.exitCode; +} + +T _doInPath<T>(String? path, T Function() f) { + if (path == null) { + return f(); + } + + final former = Directory.current.path; + Directory.current = path; + try { + return f(); + } finally { + Directory.current = former; + } +} diff --git a/pkgs/markdown/tool/entities.json b/pkgs/markdown/tool/entities.json new file mode 100644 index 000000000..557170b41 --- /dev/null +++ b/pkgs/markdown/tool/entities.json @@ -0,0 +1,2233 @@ +{ + "Æ": { "codepoints": [198], "characters": "\u00C6" }, + "Æ": { "codepoints": [198], "characters": "\u00C6" }, + "&": { "codepoints": [38], "characters": "\u0026" }, + "&": { "codepoints": [38], "characters": "\u0026" }, + "Á": { "codepoints": [193], "characters": "\u00C1" }, + "Á": { "codepoints": [193], "characters": "\u00C1" }, + "Ă": { "codepoints": [258], "characters": "\u0102" }, + "Â": { "codepoints": [194], "characters": "\u00C2" }, + "Â": { "codepoints": [194], "characters": "\u00C2" }, + "А": { "codepoints": [1040], "characters": "\u0410" }, + "𝔄": { "codepoints": [120068], "characters": "\uD835\uDD04" }, + "À": { "codepoints": [192], "characters": "\u00C0" }, + "À": { "codepoints": [192], "characters": "\u00C0" }, + "Α": { "codepoints": [913], "characters": "\u0391" }, + "Ā": { "codepoints": [256], "characters": "\u0100" }, + "⩓": { "codepoints": [10835], "characters": "\u2A53" }, + "Ą": { "codepoints": [260], "characters": "\u0104" }, + "𝔸": { "codepoints": [120120], "characters": "\uD835\uDD38" }, + "⁡": { "codepoints": [8289], "characters": "\u2061" }, + "Å": { "codepoints": [197], "characters": "\u00C5" }, + "Å": { "codepoints": [197], "characters": "\u00C5" }, + "𝒜": { "codepoints": [119964], "characters": "\uD835\uDC9C" }, + "≔": { "codepoints": [8788], "characters": "\u2254" }, + "Ã": { "codepoints": [195], "characters": "\u00C3" }, + "Ã": { "codepoints": [195], "characters": "\u00C3" }, + "Ä": { "codepoints": [196], "characters": "\u00C4" }, + "Ä": { "codepoints": [196], "characters": "\u00C4" }, + "∖": { "codepoints": [8726], "characters": "\u2216" }, + "⫧": { "codepoints": [10983], "characters": "\u2AE7" }, + "⌆": { "codepoints": [8966], "characters": "\u2306" }, + "Б": { "codepoints": [1041], "characters": "\u0411" }, + "∵": { "codepoints": [8757], "characters": "\u2235" }, + "ℬ": { "codepoints": [8492], "characters": "\u212C" }, + "Β": { "codepoints": [914], "characters": "\u0392" }, + "𝔅": { "codepoints": [120069], "characters": "\uD835\uDD05" }, + "𝔹": { "codepoints": [120121], "characters": "\uD835\uDD39" }, + "˘": { "codepoints": [728], "characters": "\u02D8" }, + "ℬ": { "codepoints": [8492], "characters": "\u212C" }, + "≎": { "codepoints": [8782], "characters": "\u224E" }, + "Ч": { "codepoints": [1063], "characters": "\u0427" }, + "©": { "codepoints": [169], "characters": "\u00A9" }, + "©": { "codepoints": [169], "characters": "\u00A9" }, + "Ć": { "codepoints": [262], "characters": "\u0106" }, + "⋒": { "codepoints": [8914], "characters": "\u22D2" }, + "ⅅ": { "codepoints": [8517], "characters": "\u2145" }, + "ℭ": { "codepoints": [8493], "characters": "\u212D" }, + "Č": { "codepoints": [268], "characters": "\u010C" }, + "Ç": { "codepoints": [199], "characters": "\u00C7" }, + "Ç": { "codepoints": [199], "characters": "\u00C7" }, + "Ĉ": { "codepoints": [264], "characters": "\u0108" }, + "∰": { "codepoints": [8752], "characters": "\u2230" }, + "Ċ": { "codepoints": [266], "characters": "\u010A" }, + "¸": { "codepoints": [184], "characters": "\u00B8" }, + "·": { "codepoints": [183], "characters": "\u00B7" }, + "ℭ": { "codepoints": [8493], "characters": "\u212D" }, + "Χ": { "codepoints": [935], "characters": "\u03A7" }, + "⊙": { "codepoints": [8857], "characters": "\u2299" }, + "⊖": { "codepoints": [8854], "characters": "\u2296" }, + "⊕": { "codepoints": [8853], "characters": "\u2295" }, + "⊗": { "codepoints": [8855], "characters": "\u2297" }, + "∲": { "codepoints": [8754], "characters": "\u2232" }, + "”": { "codepoints": [8221], "characters": "\u201D" }, + "’": { "codepoints": [8217], "characters": "\u2019" }, + "∷": { "codepoints": [8759], "characters": "\u2237" }, + "⩴": { "codepoints": [10868], "characters": "\u2A74" }, + "≡": { "codepoints": [8801], "characters": "\u2261" }, + "∯": { "codepoints": [8751], "characters": "\u222F" }, + "∮": { "codepoints": [8750], "characters": "\u222E" }, + "ℂ": { "codepoints": [8450], "characters": "\u2102" }, + "∐": { "codepoints": [8720], "characters": "\u2210" }, + "∳": { "codepoints": [8755], "characters": "\u2233" }, + "⨯": { "codepoints": [10799], "characters": "\u2A2F" }, + "𝒞": { "codepoints": [119966], "characters": "\uD835\uDC9E" }, + "⋓": { "codepoints": [8915], "characters": "\u22D3" }, + "≍": { "codepoints": [8781], "characters": "\u224D" }, + "ⅅ": { "codepoints": [8517], "characters": "\u2145" }, + "⤑": { "codepoints": [10513], "characters": "\u2911" }, + "Ђ": { "codepoints": [1026], "characters": "\u0402" }, + "Ѕ": { "codepoints": [1029], "characters": "\u0405" }, + "Џ": { "codepoints": [1039], "characters": "\u040F" }, + "‡": { "codepoints": [8225], "characters": "\u2021" }, + "↡": { "codepoints": [8609], "characters": "\u21A1" }, + "⫤": { "codepoints": [10980], "characters": "\u2AE4" }, + "Ď": { "codepoints": [270], "characters": "\u010E" }, + "Д": { "codepoints": [1044], "characters": "\u0414" }, + "∇": { "codepoints": [8711], "characters": "\u2207" }, + "Δ": { "codepoints": [916], "characters": "\u0394" }, + "𝔇": { "codepoints": [120071], "characters": "\uD835\uDD07" }, + "´": { "codepoints": [180], "characters": "\u00B4" }, + "˙": { "codepoints": [729], "characters": "\u02D9" }, + "˝": { "codepoints": [733], "characters": "\u02DD" }, + "`": { "codepoints": [96], "characters": "\u0060" }, + "˜": { "codepoints": [732], "characters": "\u02DC" }, + "⋄": { "codepoints": [8900], "characters": "\u22C4" }, + "ⅆ": { "codepoints": [8518], "characters": "\u2146" }, + "𝔻": { "codepoints": [120123], "characters": "\uD835\uDD3B" }, + "¨": { "codepoints": [168], "characters": "\u00A8" }, + "⃜": { "codepoints": [8412], "characters": "\u20DC" }, + "≐": { "codepoints": [8784], "characters": "\u2250" }, + "∯": { "codepoints": [8751], "characters": "\u222F" }, + "¨": { "codepoints": [168], "characters": "\u00A8" }, + "⇓": { "codepoints": [8659], "characters": "\u21D3" }, + "⇐": { "codepoints": [8656], "characters": "\u21D0" }, + "⇔": { "codepoints": [8660], "characters": "\u21D4" }, + "⫤": { "codepoints": [10980], "characters": "\u2AE4" }, + "⟸": { "codepoints": [10232], "characters": "\u27F8" }, + "⟺": { "codepoints": [10234], "characters": "\u27FA" }, + "⟹": { "codepoints": [10233], "characters": "\u27F9" }, + "⇒": { "codepoints": [8658], "characters": "\u21D2" }, + "⊨": { "codepoints": [8872], "characters": "\u22A8" }, + "⇑": { "codepoints": [8657], "characters": "\u21D1" }, + "⇕": { "codepoints": [8661], "characters": "\u21D5" }, + "∥": { "codepoints": [8741], "characters": "\u2225" }, + "↓": { "codepoints": [8595], "characters": "\u2193" }, + "⤓": { "codepoints": [10515], "characters": "\u2913" }, + "⇵": { "codepoints": [8693], "characters": "\u21F5" }, + "̑": { "codepoints": [785], "characters": "\u0311" }, + "⥐": { "codepoints": [10576], "characters": "\u2950" }, + "⥞": { "codepoints": [10590], "characters": "\u295E" }, + "↽": { "codepoints": [8637], "characters": "\u21BD" }, + "⥖": { "codepoints": [10582], "characters": "\u2956" }, + "⥟": { "codepoints": [10591], "characters": "\u295F" }, + "⇁": { "codepoints": [8641], "characters": "\u21C1" }, + "⥗": { "codepoints": [10583], "characters": "\u2957" }, + "⊤": { "codepoints": [8868], "characters": "\u22A4" }, + "↧": { "codepoints": [8615], "characters": "\u21A7" }, + "⇓": { "codepoints": [8659], "characters": "\u21D3" }, + "𝒟": { "codepoints": [119967], "characters": "\uD835\uDC9F" }, + "Đ": { "codepoints": [272], "characters": "\u0110" }, + "Ŋ": { "codepoints": [330], "characters": "\u014A" }, + "Ð": { "codepoints": [208], "characters": "\u00D0" }, + "Ð": { "codepoints": [208], "characters": "\u00D0" }, + "É": { "codepoints": [201], "characters": "\u00C9" }, + "É": { "codepoints": [201], "characters": "\u00C9" }, + "Ě": { "codepoints": [282], "characters": "\u011A" }, + "Ê": { "codepoints": [202], "characters": "\u00CA" }, + "Ê": { "codepoints": [202], "characters": "\u00CA" }, + "Э": { "codepoints": [1069], "characters": "\u042D" }, + "Ė": { "codepoints": [278], "characters": "\u0116" }, + "𝔈": { "codepoints": [120072], "characters": "\uD835\uDD08" }, + "È": { "codepoints": [200], "characters": "\u00C8" }, + "È": { "codepoints": [200], "characters": "\u00C8" }, + "∈": { "codepoints": [8712], "characters": "\u2208" }, + "Ē": { "codepoints": [274], "characters": "\u0112" }, + "◻": { "codepoints": [9723], "characters": "\u25FB" }, + "▫": { "codepoints": [9643], "characters": "\u25AB" }, + "Ę": { "codepoints": [280], "characters": "\u0118" }, + "𝔼": { "codepoints": [120124], "characters": "\uD835\uDD3C" }, + "Ε": { "codepoints": [917], "characters": "\u0395" }, + "⩵": { "codepoints": [10869], "characters": "\u2A75" }, + "≂": { "codepoints": [8770], "characters": "\u2242" }, + "⇌": { "codepoints": [8652], "characters": "\u21CC" }, + "ℰ": { "codepoints": [8496], "characters": "\u2130" }, + "⩳": { "codepoints": [10867], "characters": "\u2A73" }, + "Η": { "codepoints": [919], "characters": "\u0397" }, + "Ë": { "codepoints": [203], "characters": "\u00CB" }, + "Ë": { "codepoints": [203], "characters": "\u00CB" }, + "∃": { "codepoints": [8707], "characters": "\u2203" }, + "ⅇ": { "codepoints": [8519], "characters": "\u2147" }, + "Ф": { "codepoints": [1060], "characters": "\u0424" }, + "𝔉": { "codepoints": [120073], "characters": "\uD835\uDD09" }, + "◼": { "codepoints": [9724], "characters": "\u25FC" }, + "▪": { "codepoints": [9642], "characters": "\u25AA" }, + "𝔽": { "codepoints": [120125], "characters": "\uD835\uDD3D" }, + "∀": { "codepoints": [8704], "characters": "\u2200" }, + "ℱ": { "codepoints": [8497], "characters": "\u2131" }, + "ℱ": { "codepoints": [8497], "characters": "\u2131" }, + "Ѓ": { "codepoints": [1027], "characters": "\u0403" }, + ">": { "codepoints": [62], "characters": "\u003E" }, + ">": { "codepoints": [62], "characters": "\u003E" }, + "Γ": { "codepoints": [915], "characters": "\u0393" }, + "Ϝ": { "codepoints": [988], "characters": "\u03DC" }, + "Ğ": { "codepoints": [286], "characters": "\u011E" }, + "Ģ": { "codepoints": [290], "characters": "\u0122" }, + "Ĝ": { "codepoints": [284], "characters": "\u011C" }, + "Г": { "codepoints": [1043], "characters": "\u0413" }, + "Ġ": { "codepoints": [288], "characters": "\u0120" }, + "𝔊": { "codepoints": [120074], "characters": "\uD835\uDD0A" }, + "⋙": { "codepoints": [8921], "characters": "\u22D9" }, + "𝔾": { "codepoints": [120126], "characters": "\uD835\uDD3E" }, + "≥": { "codepoints": [8805], "characters": "\u2265" }, + "⋛": { "codepoints": [8923], "characters": "\u22DB" }, + "≧": { "codepoints": [8807], "characters": "\u2267" }, + "⪢": { "codepoints": [10914], "characters": "\u2AA2" }, + "≷": { "codepoints": [8823], "characters": "\u2277" }, + "⩾": { "codepoints": [10878], "characters": "\u2A7E" }, + "≳": { "codepoints": [8819], "characters": "\u2273" }, + "𝒢": { "codepoints": [119970], "characters": "\uD835\uDCA2" }, + "≫": { "codepoints": [8811], "characters": "\u226B" }, + "Ъ": { "codepoints": [1066], "characters": "\u042A" }, + "ˇ": { "codepoints": [711], "characters": "\u02C7" }, + "^": { "codepoints": [94], "characters": "\u005E" }, + "Ĥ": { "codepoints": [292], "characters": "\u0124" }, + "ℌ": { "codepoints": [8460], "characters": "\u210C" }, + "ℋ": { "codepoints": [8459], "characters": "\u210B" }, + "ℍ": { "codepoints": [8461], "characters": "\u210D" }, + "─": { "codepoints": [9472], "characters": "\u2500" }, + "ℋ": { "codepoints": [8459], "characters": "\u210B" }, + "Ħ": { "codepoints": [294], "characters": "\u0126" }, + "≎": { "codepoints": [8782], "characters": "\u224E" }, + "≏": { "codepoints": [8783], "characters": "\u224F" }, + "Е": { "codepoints": [1045], "characters": "\u0415" }, + "IJ": { "codepoints": [306], "characters": "\u0132" }, + "Ё": { "codepoints": [1025], "characters": "\u0401" }, + "Í": { "codepoints": [205], "characters": "\u00CD" }, + "Í": { "codepoints": [205], "characters": "\u00CD" }, + "Î": { "codepoints": [206], "characters": "\u00CE" }, + "Î": { "codepoints": [206], "characters": "\u00CE" }, + "И": { "codepoints": [1048], "characters": "\u0418" }, + "İ": { "codepoints": [304], "characters": "\u0130" }, + "ℑ": { "codepoints": [8465], "characters": "\u2111" }, + "Ì": { "codepoints": [204], "characters": "\u00CC" }, + "Ì": { "codepoints": [204], "characters": "\u00CC" }, + "ℑ": { "codepoints": [8465], "characters": "\u2111" }, + "Ī": { "codepoints": [298], "characters": "\u012A" }, + "ⅈ": { "codepoints": [8520], "characters": "\u2148" }, + "⇒": { "codepoints": [8658], "characters": "\u21D2" }, + "∬": { "codepoints": [8748], "characters": "\u222C" }, + "∫": { "codepoints": [8747], "characters": "\u222B" }, + "⋂": { "codepoints": [8898], "characters": "\u22C2" }, + "⁣": { "codepoints": [8291], "characters": "\u2063" }, + "⁢": { "codepoints": [8290], "characters": "\u2062" }, + "Į": { "codepoints": [302], "characters": "\u012E" }, + "𝕀": { "codepoints": [120128], "characters": "\uD835\uDD40" }, + "Ι": { "codepoints": [921], "characters": "\u0399" }, + "ℐ": { "codepoints": [8464], "characters": "\u2110" }, + "Ĩ": { "codepoints": [296], "characters": "\u0128" }, + "І": { "codepoints": [1030], "characters": "\u0406" }, + "Ï": { "codepoints": [207], "characters": "\u00CF" }, + "Ï": { "codepoints": [207], "characters": "\u00CF" }, + "Ĵ": { "codepoints": [308], "characters": "\u0134" }, + "Й": { "codepoints": [1049], "characters": "\u0419" }, + "𝔍": { "codepoints": [120077], "characters": "\uD835\uDD0D" }, + "𝕁": { "codepoints": [120129], "characters": "\uD835\uDD41" }, + "𝒥": { "codepoints": [119973], "characters": "\uD835\uDCA5" }, + "Ј": { "codepoints": [1032], "characters": "\u0408" }, + "Є": { "codepoints": [1028], "characters": "\u0404" }, + "Х": { "codepoints": [1061], "characters": "\u0425" }, + "Ќ": { "codepoints": [1036], "characters": "\u040C" }, + "Κ": { "codepoints": [922], "characters": "\u039A" }, + "Ķ": { "codepoints": [310], "characters": "\u0136" }, + "К": { "codepoints": [1050], "characters": "\u041A" }, + "𝔎": { "codepoints": [120078], "characters": "\uD835\uDD0E" }, + "𝕂": { "codepoints": [120130], "characters": "\uD835\uDD42" }, + "𝒦": { "codepoints": [119974], "characters": "\uD835\uDCA6" }, + "Љ": { "codepoints": [1033], "characters": "\u0409" }, + "<": { "codepoints": [60], "characters": "\u003C" }, + "<": { "codepoints": [60], "characters": "\u003C" }, + "Ĺ": { "codepoints": [313], "characters": "\u0139" }, + "Λ": { "codepoints": [923], "characters": "\u039B" }, + "⟪": { "codepoints": [10218], "characters": "\u27EA" }, + "ℒ": { "codepoints": [8466], "characters": "\u2112" }, + "↞": { "codepoints": [8606], "characters": "\u219E" }, + "Ľ": { "codepoints": [317], "characters": "\u013D" }, + "Ļ": { "codepoints": [315], "characters": "\u013B" }, + "Л": { "codepoints": [1051], "characters": "\u041B" }, + "⟨": { "codepoints": [10216], "characters": "\u27E8" }, + "←": { "codepoints": [8592], "characters": "\u2190" }, + "⇤": { "codepoints": [8676], "characters": "\u21E4" }, + "⇆": { "codepoints": [8646], "characters": "\u21C6" }, + "⌈": { "codepoints": [8968], "characters": "\u2308" }, + "⟦": { "codepoints": [10214], "characters": "\u27E6" }, + "⥡": { "codepoints": [10593], "characters": "\u2961" }, + "⇃": { "codepoints": [8643], "characters": "\u21C3" }, + "⥙": { "codepoints": [10585], "characters": "\u2959" }, + "⌊": { "codepoints": [8970], "characters": "\u230A" }, + "↔": { "codepoints": [8596], "characters": "\u2194" }, + "⥎": { "codepoints": [10574], "characters": "\u294E" }, + "⊣": { "codepoints": [8867], "characters": "\u22A3" }, + "↤": { "codepoints": [8612], "characters": "\u21A4" }, + "⥚": { "codepoints": [10586], "characters": "\u295A" }, + "⊲": { "codepoints": [8882], "characters": "\u22B2" }, + "⧏": { "codepoints": [10703], "characters": "\u29CF" }, + "⊴": { "codepoints": [8884], "characters": "\u22B4" }, + "⥑": { "codepoints": [10577], "characters": "\u2951" }, + "⥠": { "codepoints": [10592], "characters": "\u2960" }, + "↿": { "codepoints": [8639], "characters": "\u21BF" }, + "⥘": { "codepoints": [10584], "characters": "\u2958" }, + "↼": { "codepoints": [8636], "characters": "\u21BC" }, + "⥒": { "codepoints": [10578], "characters": "\u2952" }, + "⇐": { "codepoints": [8656], "characters": "\u21D0" }, + "⇔": { "codepoints": [8660], "characters": "\u21D4" }, + "⋚": { "codepoints": [8922], "characters": "\u22DA" }, + "≦": { "codepoints": [8806], "characters": "\u2266" }, + "≶": { "codepoints": [8822], "characters": "\u2276" }, + "⪡": { "codepoints": [10913], "characters": "\u2AA1" }, + "⩽": { "codepoints": [10877], "characters": "\u2A7D" }, + "≲": { "codepoints": [8818], "characters": "\u2272" }, + "𝔏": { "codepoints": [120079], "characters": "\uD835\uDD0F" }, + "⋘": { "codepoints": [8920], "characters": "\u22D8" }, + "⇚": { "codepoints": [8666], "characters": "\u21DA" }, + "Ŀ": { "codepoints": [319], "characters": "\u013F" }, + "⟵": { "codepoints": [10229], "characters": "\u27F5" }, + "⟷": { "codepoints": [10231], "characters": "\u27F7" }, + "⟶": { "codepoints": [10230], "characters": "\u27F6" }, + "⟸": { "codepoints": [10232], "characters": "\u27F8" }, + "⟺": { "codepoints": [10234], "characters": "\u27FA" }, + "⟹": { "codepoints": [10233], "characters": "\u27F9" }, + "𝕃": { "codepoints": [120131], "characters": "\uD835\uDD43" }, + "↙": { "codepoints": [8601], "characters": "\u2199" }, + "↘": { "codepoints": [8600], "characters": "\u2198" }, + "ℒ": { "codepoints": [8466], "characters": "\u2112" }, + "↰": { "codepoints": [8624], "characters": "\u21B0" }, + "Ł": { "codepoints": [321], "characters": "\u0141" }, + "≪": { "codepoints": [8810], "characters": "\u226A" }, + "⤅": { "codepoints": [10501], "characters": "\u2905" }, + "М": { "codepoints": [1052], "characters": "\u041C" }, + " ": { "codepoints": [8287], "characters": "\u205F" }, + "ℳ": { "codepoints": [8499], "characters": "\u2133" }, + "𝔐": { "codepoints": [120080], "characters": "\uD835\uDD10" }, + "∓": { "codepoints": [8723], "characters": "\u2213" }, + "𝕄": { "codepoints": [120132], "characters": "\uD835\uDD44" }, + "ℳ": { "codepoints": [8499], "characters": "\u2133" }, + "Μ": { "codepoints": [924], "characters": "\u039C" }, + "Њ": { "codepoints": [1034], "characters": "\u040A" }, + "Ń": { "codepoints": [323], "characters": "\u0143" }, + "Ň": { "codepoints": [327], "characters": "\u0147" }, + "Ņ": { "codepoints": [325], "characters": "\u0145" }, + "Н": { "codepoints": [1053], "characters": "\u041D" }, + "​": { "codepoints": [8203], "characters": "\u200B" }, + "​": { "codepoints": [8203], "characters": "\u200B" }, + "​": { "codepoints": [8203], "characters": "\u200B" }, + "​": { "codepoints": [8203], "characters": "\u200B" }, + "≫": { "codepoints": [8811], "characters": "\u226B" }, + "≪": { "codepoints": [8810], "characters": "\u226A" }, + " ": { "codepoints": [10], "characters": "\u000A" }, + "𝔑": { "codepoints": [120081], "characters": "\uD835\uDD11" }, + "⁠": { "codepoints": [8288], "characters": "\u2060" }, + " ": { "codepoints": [160], "characters": "\u00A0" }, + "ℕ": { "codepoints": [8469], "characters": "\u2115" }, + "⫬": { "codepoints": [10988], "characters": "\u2AEC" }, + "≢": { "codepoints": [8802], "characters": "\u2262" }, + "≭": { "codepoints": [8813], "characters": "\u226D" }, + "∦": { "codepoints": [8742], "characters": "\u2226" }, + "∉": { "codepoints": [8713], "characters": "\u2209" }, + "≠": { "codepoints": [8800], "characters": "\u2260" }, + "≂̸": { "codepoints": [8770, 824], "characters": "\u2242\u0338" }, + "∄": { "codepoints": [8708], "characters": "\u2204" }, + "≯": { "codepoints": [8815], "characters": "\u226F" }, + "≱": { "codepoints": [8817], "characters": "\u2271" }, + "≧̸": { "codepoints": [8807, 824], "characters": "\u2267\u0338" }, + "≫̸": { "codepoints": [8811, 824], "characters": "\u226B\u0338" }, + "≹": { "codepoints": [8825], "characters": "\u2279" }, + "⩾̸": { "codepoints": [10878, 824], "characters": "\u2A7E\u0338" }, + "≵": { "codepoints": [8821], "characters": "\u2275" }, + "≎̸": { "codepoints": [8782, 824], "characters": "\u224E\u0338" }, + "≏̸": { "codepoints": [8783, 824], "characters": "\u224F\u0338" }, + "⋪": { "codepoints": [8938], "characters": "\u22EA" }, + "⧏̸": { "codepoints": [10703, 824], "characters": "\u29CF\u0338" }, + "⋬": { "codepoints": [8940], "characters": "\u22EC" }, + "≮": { "codepoints": [8814], "characters": "\u226E" }, + "≰": { "codepoints": [8816], "characters": "\u2270" }, + "≸": { "codepoints": [8824], "characters": "\u2278" }, + "≪̸": { "codepoints": [8810, 824], "characters": "\u226A\u0338" }, + "⩽̸": { "codepoints": [10877, 824], "characters": "\u2A7D\u0338" }, + "≴": { "codepoints": [8820], "characters": "\u2274" }, + "⪢̸": { "codepoints": [10914, 824], "characters": "\u2AA2\u0338" }, + "⪡̸": { "codepoints": [10913, 824], "characters": "\u2AA1\u0338" }, + "⊀": { "codepoints": [8832], "characters": "\u2280" }, + "⪯̸": { "codepoints": [10927, 824], "characters": "\u2AAF\u0338" }, + "⋠": { "codepoints": [8928], "characters": "\u22E0" }, + "∌": { "codepoints": [8716], "characters": "\u220C" }, + "⋫": { "codepoints": [8939], "characters": "\u22EB" }, + "⧐̸": { "codepoints": [10704, 824], "characters": "\u29D0\u0338" }, + "⋭": { "codepoints": [8941], "characters": "\u22ED" }, + "⊏̸": { "codepoints": [8847, 824], "characters": "\u228F\u0338" }, + "⋢": { "codepoints": [8930], "characters": "\u22E2" }, + "⊐̸": { "codepoints": [8848, 824], "characters": "\u2290\u0338" }, + "⋣": { "codepoints": [8931], "characters": "\u22E3" }, + "⊂⃒": { "codepoints": [8834, 8402], "characters": "\u2282\u20D2" }, + "⊈": { "codepoints": [8840], "characters": "\u2288" }, + "⊁": { "codepoints": [8833], "characters": "\u2281" }, + "⪰̸": { "codepoints": [10928, 824], "characters": "\u2AB0\u0338" }, + "⋡": { "codepoints": [8929], "characters": "\u22E1" }, + "≿̸": { "codepoints": [8831, 824], "characters": "\u227F\u0338" }, + "⊃⃒": { "codepoints": [8835, 8402], "characters": "\u2283\u20D2" }, + "⊉": { "codepoints": [8841], "characters": "\u2289" }, + "≁": { "codepoints": [8769], "characters": "\u2241" }, + "≄": { "codepoints": [8772], "characters": "\u2244" }, + "≇": { "codepoints": [8775], "characters": "\u2247" }, + "≉": { "codepoints": [8777], "characters": "\u2249" }, + "∤": { "codepoints": [8740], "characters": "\u2224" }, + "𝒩": { "codepoints": [119977], "characters": "\uD835\uDCA9" }, + "Ñ": { "codepoints": [209], "characters": "\u00D1" }, + "Ñ": { "codepoints": [209], "characters": "\u00D1" }, + "Ν": { "codepoints": [925], "characters": "\u039D" }, + "Œ": { "codepoints": [338], "characters": "\u0152" }, + "Ó": { "codepoints": [211], "characters": "\u00D3" }, + "Ó": { "codepoints": [211], "characters": "\u00D3" }, + "Ô": { "codepoints": [212], "characters": "\u00D4" }, + "Ô": { "codepoints": [212], "characters": "\u00D4" }, + "О": { "codepoints": [1054], "characters": "\u041E" }, + "Ő": { "codepoints": [336], "characters": "\u0150" }, + "𝔒": { "codepoints": [120082], "characters": "\uD835\uDD12" }, + "Ò": { "codepoints": [210], "characters": "\u00D2" }, + "Ò": { "codepoints": [210], "characters": "\u00D2" }, + "Ō": { "codepoints": [332], "characters": "\u014C" }, + "Ω": { "codepoints": [937], "characters": "\u03A9" }, + "Ο": { "codepoints": [927], "characters": "\u039F" }, + "𝕆": { "codepoints": [120134], "characters": "\uD835\uDD46" }, + "“": { "codepoints": [8220], "characters": "\u201C" }, + "‘": { "codepoints": [8216], "characters": "\u2018" }, + "⩔": { "codepoints": [10836], "characters": "\u2A54" }, + "𝒪": { "codepoints": [119978], "characters": "\uD835\uDCAA" }, + "Ø": { "codepoints": [216], "characters": "\u00D8" }, + "Ø": { "codepoints": [216], "characters": "\u00D8" }, + "Õ": { "codepoints": [213], "characters": "\u00D5" }, + "Õ": { "codepoints": [213], "characters": "\u00D5" }, + "⨷": { "codepoints": [10807], "characters": "\u2A37" }, + "Ö": { "codepoints": [214], "characters": "\u00D6" }, + "Ö": { "codepoints": [214], "characters": "\u00D6" }, + "‾": { "codepoints": [8254], "characters": "\u203E" }, + "⏞": { "codepoints": [9182], "characters": "\u23DE" }, + "⎴": { "codepoints": [9140], "characters": "\u23B4" }, + "⏜": { "codepoints": [9180], "characters": "\u23DC" }, + "∂": { "codepoints": [8706], "characters": "\u2202" }, + "П": { "codepoints": [1055], "characters": "\u041F" }, + "𝔓": { "codepoints": [120083], "characters": "\uD835\uDD13" }, + "Φ": { "codepoints": [934], "characters": "\u03A6" }, + "Π": { "codepoints": [928], "characters": "\u03A0" }, + "±": { "codepoints": [177], "characters": "\u00B1" }, + "ℌ": { "codepoints": [8460], "characters": "\u210C" }, + "ℙ": { "codepoints": [8473], "characters": "\u2119" }, + "⪻": { "codepoints": [10939], "characters": "\u2ABB" }, + "≺": { "codepoints": [8826], "characters": "\u227A" }, + "⪯": { "codepoints": [10927], "characters": "\u2AAF" }, + "≼": { "codepoints": [8828], "characters": "\u227C" }, + "≾": { "codepoints": [8830], "characters": "\u227E" }, + "″": { "codepoints": [8243], "characters": "\u2033" }, + "∏": { "codepoints": [8719], "characters": "\u220F" }, + "∷": { "codepoints": [8759], "characters": "\u2237" }, + "∝": { "codepoints": [8733], "characters": "\u221D" }, + "𝒫": { "codepoints": [119979], "characters": "\uD835\uDCAB" }, + "Ψ": { "codepoints": [936], "characters": "\u03A8" }, + """: { "codepoints": [34], "characters": "\u0022" }, + """: { "codepoints": [34], "characters": "\u0022" }, + "𝔔": { "codepoints": [120084], "characters": "\uD835\uDD14" }, + "ℚ": { "codepoints": [8474], "characters": "\u211A" }, + "𝒬": { "codepoints": [119980], "characters": "\uD835\uDCAC" }, + "⤐": { "codepoints": [10512], "characters": "\u2910" }, + "®": { "codepoints": [174], "characters": "\u00AE" }, + "®": { "codepoints": [174], "characters": "\u00AE" }, + "Ŕ": { "codepoints": [340], "characters": "\u0154" }, + "⟫": { "codepoints": [10219], "characters": "\u27EB" }, + "↠": { "codepoints": [8608], "characters": "\u21A0" }, + "⤖": { "codepoints": [10518], "characters": "\u2916" }, + "Ř": { "codepoints": [344], "characters": "\u0158" }, + "Ŗ": { "codepoints": [342], "characters": "\u0156" }, + "Р": { "codepoints": [1056], "characters": "\u0420" }, + "ℜ": { "codepoints": [8476], "characters": "\u211C" }, + "∋": { "codepoints": [8715], "characters": "\u220B" }, + "⇋": { "codepoints": [8651], "characters": "\u21CB" }, + "⥯": { "codepoints": [10607], "characters": "\u296F" }, + "ℜ": { "codepoints": [8476], "characters": "\u211C" }, + "Ρ": { "codepoints": [929], "characters": "\u03A1" }, + "⟩": { "codepoints": [10217], "characters": "\u27E9" }, + "→": { "codepoints": [8594], "characters": "\u2192" }, + "⇥": { "codepoints": [8677], "characters": "\u21E5" }, + "⇄": { "codepoints": [8644], "characters": "\u21C4" }, + "⌉": { "codepoints": [8969], "characters": "\u2309" }, + "⟧": { "codepoints": [10215], "characters": "\u27E7" }, + "⥝": { "codepoints": [10589], "characters": "\u295D" }, + "⇂": { "codepoints": [8642], "characters": "\u21C2" }, + "⥕": { "codepoints": [10581], "characters": "\u2955" }, + "⌋": { "codepoints": [8971], "characters": "\u230B" }, + "⊢": { "codepoints": [8866], "characters": "\u22A2" }, + "↦": { "codepoints": [8614], "characters": "\u21A6" }, + "⥛": { "codepoints": [10587], "characters": "\u295B" }, + "⊳": { "codepoints": [8883], "characters": "\u22B3" }, + "⧐": { "codepoints": [10704], "characters": "\u29D0" }, + "⊵": { "codepoints": [8885], "characters": "\u22B5" }, + "⥏": { "codepoints": [10575], "characters": "\u294F" }, + "⥜": { "codepoints": [10588], "characters": "\u295C" }, + "↾": { "codepoints": [8638], "characters": "\u21BE" }, + "⥔": { "codepoints": [10580], "characters": "\u2954" }, + "⇀": { "codepoints": [8640], "characters": "\u21C0" }, + "⥓": { "codepoints": [10579], "characters": "\u2953" }, + "⇒": { "codepoints": [8658], "characters": "\u21D2" }, + "ℝ": { "codepoints": [8477], "characters": "\u211D" }, + "⥰": { "codepoints": [10608], "characters": "\u2970" }, + "⇛": { "codepoints": [8667], "characters": "\u21DB" }, + "ℛ": { "codepoints": [8475], "characters": "\u211B" }, + "↱": { "codepoints": [8625], "characters": "\u21B1" }, + "⧴": { "codepoints": [10740], "characters": "\u29F4" }, + "Щ": { "codepoints": [1065], "characters": "\u0429" }, + "Ш": { "codepoints": [1064], "characters": "\u0428" }, + "Ь": { "codepoints": [1068], "characters": "\u042C" }, + "Ś": { "codepoints": [346], "characters": "\u015A" }, + "⪼": { "codepoints": [10940], "characters": "\u2ABC" }, + "Š": { "codepoints": [352], "characters": "\u0160" }, + "Ş": { "codepoints": [350], "characters": "\u015E" }, + "Ŝ": { "codepoints": [348], "characters": "\u015C" }, + "С": { "codepoints": [1057], "characters": "\u0421" }, + "𝔖": { "codepoints": [120086], "characters": "\uD835\uDD16" }, + "↓": { "codepoints": [8595], "characters": "\u2193" }, + "←": { "codepoints": [8592], "characters": "\u2190" }, + "→": { "codepoints": [8594], "characters": "\u2192" }, + "↑": { "codepoints": [8593], "characters": "\u2191" }, + "Σ": { "codepoints": [931], "characters": "\u03A3" }, + "∘": { "codepoints": [8728], "characters": "\u2218" }, + "𝕊": { "codepoints": [120138], "characters": "\uD835\uDD4A" }, + "√": { "codepoints": [8730], "characters": "\u221A" }, + "□": { "codepoints": [9633], "characters": "\u25A1" }, + "⊓": { "codepoints": [8851], "characters": "\u2293" }, + "⊏": { "codepoints": [8847], "characters": "\u228F" }, + "⊑": { "codepoints": [8849], "characters": "\u2291" }, + "⊐": { "codepoints": [8848], "characters": "\u2290" }, + "⊒": { "codepoints": [8850], "characters": "\u2292" }, + "⊔": { "codepoints": [8852], "characters": "\u2294" }, + "𝒮": { "codepoints": [119982], "characters": "\uD835\uDCAE" }, + "⋆": { "codepoints": [8902], "characters": "\u22C6" }, + "⋐": { "codepoints": [8912], "characters": "\u22D0" }, + "⋐": { "codepoints": [8912], "characters": "\u22D0" }, + "⊆": { "codepoints": [8838], "characters": "\u2286" }, + "≻": { "codepoints": [8827], "characters": "\u227B" }, + "⪰": { "codepoints": [10928], "characters": "\u2AB0" }, + "≽": { "codepoints": [8829], "characters": "\u227D" }, + "≿": { "codepoints": [8831], "characters": "\u227F" }, + "∋": { "codepoints": [8715], "characters": "\u220B" }, + "∑": { "codepoints": [8721], "characters": "\u2211" }, + "⋑": { "codepoints": [8913], "characters": "\u22D1" }, + "⊃": { "codepoints": [8835], "characters": "\u2283" }, + "⊇": { "codepoints": [8839], "characters": "\u2287" }, + "⋑": { "codepoints": [8913], "characters": "\u22D1" }, + "Þ": { "codepoints": [222], "characters": "\u00DE" }, + "Þ": { "codepoints": [222], "characters": "\u00DE" }, + "™": { "codepoints": [8482], "characters": "\u2122" }, + "Ћ": { "codepoints": [1035], "characters": "\u040B" }, + "Ц": { "codepoints": [1062], "characters": "\u0426" }, + " ": { "codepoints": [9], "characters": "\u0009" }, + "Τ": { "codepoints": [932], "characters": "\u03A4" }, + "Ť": { "codepoints": [356], "characters": "\u0164" }, + "Ţ": { "codepoints": [354], "characters": "\u0162" }, + "Т": { "codepoints": [1058], "characters": "\u0422" }, + "𝔗": { "codepoints": [120087], "characters": "\uD835\uDD17" }, + "∴": { "codepoints": [8756], "characters": "\u2234" }, + "Θ": { "codepoints": [920], "characters": "\u0398" }, + "  ": { "codepoints": [8287, 8202], "characters": "\u205F\u200A" }, + " ": { "codepoints": [8201], "characters": "\u2009" }, + "∼": { "codepoints": [8764], "characters": "\u223C" }, + "≃": { "codepoints": [8771], "characters": "\u2243" }, + "≅": { "codepoints": [8773], "characters": "\u2245" }, + "≈": { "codepoints": [8776], "characters": "\u2248" }, + "𝕋": { "codepoints": [120139], "characters": "\uD835\uDD4B" }, + "⃛": { "codepoints": [8411], "characters": "\u20DB" }, + "𝒯": { "codepoints": [119983], "characters": "\uD835\uDCAF" }, + "Ŧ": { "codepoints": [358], "characters": "\u0166" }, + "Ú": { "codepoints": [218], "characters": "\u00DA" }, + "Ú": { "codepoints": [218], "characters": "\u00DA" }, + "↟": { "codepoints": [8607], "characters": "\u219F" }, + "⥉": { "codepoints": [10569], "characters": "\u2949" }, + "Ў": { "codepoints": [1038], "characters": "\u040E" }, + "Ŭ": { "codepoints": [364], "characters": "\u016C" }, + "Û": { "codepoints": [219], "characters": "\u00DB" }, + "Û": { "codepoints": [219], "characters": "\u00DB" }, + "У": { "codepoints": [1059], "characters": "\u0423" }, + "Ű": { "codepoints": [368], "characters": "\u0170" }, + "𝔘": { "codepoints": [120088], "characters": "\uD835\uDD18" }, + "Ù": { "codepoints": [217], "characters": "\u00D9" }, + "Ù": { "codepoints": [217], "characters": "\u00D9" }, + "Ū": { "codepoints": [362], "characters": "\u016A" }, + "_": { "codepoints": [95], "characters": "\u005F" }, + "⏟": { "codepoints": [9183], "characters": "\u23DF" }, + "⎵": { "codepoints": [9141], "characters": "\u23B5" }, + "⏝": { "codepoints": [9181], "characters": "\u23DD" }, + "⋃": { "codepoints": [8899], "characters": "\u22C3" }, + "⊎": { "codepoints": [8846], "characters": "\u228E" }, + "Ų": { "codepoints": [370], "characters": "\u0172" }, + "𝕌": { "codepoints": [120140], "characters": "\uD835\uDD4C" }, + "↑": { "codepoints": [8593], "characters": "\u2191" }, + "⤒": { "codepoints": [10514], "characters": "\u2912" }, + "⇅": { "codepoints": [8645], "characters": "\u21C5" }, + "↕": { "codepoints": [8597], "characters": "\u2195" }, + "⥮": { "codepoints": [10606], "characters": "\u296E" }, + "⊥": { "codepoints": [8869], "characters": "\u22A5" }, + "↥": { "codepoints": [8613], "characters": "\u21A5" }, + "⇑": { "codepoints": [8657], "characters": "\u21D1" }, + "⇕": { "codepoints": [8661], "characters": "\u21D5" }, + "↖": { "codepoints": [8598], "characters": "\u2196" }, + "↗": { "codepoints": [8599], "characters": "\u2197" }, + "ϒ": { "codepoints": [978], "characters": "\u03D2" }, + "Υ": { "codepoints": [933], "characters": "\u03A5" }, + "Ů": { "codepoints": [366], "characters": "\u016E" }, + "𝒰": { "codepoints": [119984], "characters": "\uD835\uDCB0" }, + "Ũ": { "codepoints": [360], "characters": "\u0168" }, + "Ü": { "codepoints": [220], "characters": "\u00DC" }, + "Ü": { "codepoints": [220], "characters": "\u00DC" }, + "⊫": { "codepoints": [8875], "characters": "\u22AB" }, + "⫫": { "codepoints": [10987], "characters": "\u2AEB" }, + "В": { "codepoints": [1042], "characters": "\u0412" }, + "⊩": { "codepoints": [8873], "characters": "\u22A9" }, + "⫦": { "codepoints": [10982], "characters": "\u2AE6" }, + "⋁": { "codepoints": [8897], "characters": "\u22C1" }, + "‖": { "codepoints": [8214], "characters": "\u2016" }, + "‖": { "codepoints": [8214], "characters": "\u2016" }, + "∣": { "codepoints": [8739], "characters": "\u2223" }, + "|": { "codepoints": [124], "characters": "\u007C" }, + "❘": { "codepoints": [10072], "characters": "\u2758" }, + "≀": { "codepoints": [8768], "characters": "\u2240" }, + " ": { "codepoints": [8202], "characters": "\u200A" }, + "𝔙": { "codepoints": [120089], "characters": "\uD835\uDD19" }, + "𝕍": { "codepoints": [120141], "characters": "\uD835\uDD4D" }, + "𝒱": { "codepoints": [119985], "characters": "\uD835\uDCB1" }, + "⊪": { "codepoints": [8874], "characters": "\u22AA" }, + "Ŵ": { "codepoints": [372], "characters": "\u0174" }, + "⋀": { "codepoints": [8896], "characters": "\u22C0" }, + "𝔚": { "codepoints": [120090], "characters": "\uD835\uDD1A" }, + "𝕎": { "codepoints": [120142], "characters": "\uD835\uDD4E" }, + "𝒲": { "codepoints": [119986], "characters": "\uD835\uDCB2" }, + "𝔛": { "codepoints": [120091], "characters": "\uD835\uDD1B" }, + "Ξ": { "codepoints": [926], "characters": "\u039E" }, + "𝕏": { "codepoints": [120143], "characters": "\uD835\uDD4F" }, + "𝒳": { "codepoints": [119987], "characters": "\uD835\uDCB3" }, + "Я": { "codepoints": [1071], "characters": "\u042F" }, + "Ї": { "codepoints": [1031], "characters": "\u0407" }, + "Ю": { "codepoints": [1070], "characters": "\u042E" }, + "Ý": { "codepoints": [221], "characters": "\u00DD" }, + "Ý": { "codepoints": [221], "characters": "\u00DD" }, + "Ŷ": { "codepoints": [374], "characters": "\u0176" }, + "Ы": { "codepoints": [1067], "characters": "\u042B" }, + "𝔜": { "codepoints": [120092], "characters": "\uD835\uDD1C" }, + "𝕐": { "codepoints": [120144], "characters": "\uD835\uDD50" }, + "𝒴": { "codepoints": [119988], "characters": "\uD835\uDCB4" }, + "Ÿ": { "codepoints": [376], "characters": "\u0178" }, + "Ж": { "codepoints": [1046], "characters": "\u0416" }, + "Ź": { "codepoints": [377], "characters": "\u0179" }, + "Ž": { "codepoints": [381], "characters": "\u017D" }, + "З": { "codepoints": [1047], "characters": "\u0417" }, + "Ż": { "codepoints": [379], "characters": "\u017B" }, + "​": { "codepoints": [8203], "characters": "\u200B" }, + "Ζ": { "codepoints": [918], "characters": "\u0396" }, + "ℨ": { "codepoints": [8488], "characters": "\u2128" }, + "ℤ": { "codepoints": [8484], "characters": "\u2124" }, + "𝒵": { "codepoints": [119989], "characters": "\uD835\uDCB5" }, + "á": { "codepoints": [225], "characters": "\u00E1" }, + "á": { "codepoints": [225], "characters": "\u00E1" }, + "ă": { "codepoints": [259], "characters": "\u0103" }, + "∾": { "codepoints": [8766], "characters": "\u223E" }, + "∾̳": { "codepoints": [8766, 819], "characters": "\u223E\u0333" }, + "∿": { "codepoints": [8767], "characters": "\u223F" }, + "â": { "codepoints": [226], "characters": "\u00E2" }, + "â": { "codepoints": [226], "characters": "\u00E2" }, + "´": { "codepoints": [180], "characters": "\u00B4" }, + "´": { "codepoints": [180], "characters": "\u00B4" }, + "а": { "codepoints": [1072], "characters": "\u0430" }, + "æ": { "codepoints": [230], "characters": "\u00E6" }, + "æ": { "codepoints": [230], "characters": "\u00E6" }, + "⁡": { "codepoints": [8289], "characters": "\u2061" }, + "𝔞": { "codepoints": [120094], "characters": "\uD835\uDD1E" }, + "à": { "codepoints": [224], "characters": "\u00E0" }, + "à": { "codepoints": [224], "characters": "\u00E0" }, + "ℵ": { "codepoints": [8501], "characters": "\u2135" }, + "ℵ": { "codepoints": [8501], "characters": "\u2135" }, + "α": { "codepoints": [945], "characters": "\u03B1" }, + "ā": { "codepoints": [257], "characters": "\u0101" }, + "⨿": { "codepoints": [10815], "characters": "\u2A3F" }, + "&": { "codepoints": [38], "characters": "\u0026" }, + "&": { "codepoints": [38], "characters": "\u0026" }, + "∧": { "codepoints": [8743], "characters": "\u2227" }, + "⩕": { "codepoints": [10837], "characters": "\u2A55" }, + "⩜": { "codepoints": [10844], "characters": "\u2A5C" }, + "⩘": { "codepoints": [10840], "characters": "\u2A58" }, + "⩚": { "codepoints": [10842], "characters": "\u2A5A" }, + "∠": { "codepoints": [8736], "characters": "\u2220" }, + "⦤": { "codepoints": [10660], "characters": "\u29A4" }, + "∠": { "codepoints": [8736], "characters": "\u2220" }, + "∡": { "codepoints": [8737], "characters": "\u2221" }, + "⦨": { "codepoints": [10664], "characters": "\u29A8" }, + "⦩": { "codepoints": [10665], "characters": "\u29A9" }, + "⦪": { "codepoints": [10666], "characters": "\u29AA" }, + "⦫": { "codepoints": [10667], "characters": "\u29AB" }, + "⦬": { "codepoints": [10668], "characters": "\u29AC" }, + "⦭": { "codepoints": [10669], "characters": "\u29AD" }, + "⦮": { "codepoints": [10670], "characters": "\u29AE" }, + "⦯": { "codepoints": [10671], "characters": "\u29AF" }, + "∟": { "codepoints": [8735], "characters": "\u221F" }, + "⊾": { "codepoints": [8894], "characters": "\u22BE" }, + "⦝": { "codepoints": [10653], "characters": "\u299D" }, + "∢": { "codepoints": [8738], "characters": "\u2222" }, + "Å": { "codepoints": [197], "characters": "\u00C5" }, + "⍼": { "codepoints": [9084], "characters": "\u237C" }, + "ą": { "codepoints": [261], "characters": "\u0105" }, + "𝕒": { "codepoints": [120146], "characters": "\uD835\uDD52" }, + "≈": { "codepoints": [8776], "characters": "\u2248" }, + "⩰": { "codepoints": [10864], "characters": "\u2A70" }, + "⩯": { "codepoints": [10863], "characters": "\u2A6F" }, + "≊": { "codepoints": [8778], "characters": "\u224A" }, + "≋": { "codepoints": [8779], "characters": "\u224B" }, + "'": { "codepoints": [39], "characters": "\u0027" }, + "≈": { "codepoints": [8776], "characters": "\u2248" }, + "≊": { "codepoints": [8778], "characters": "\u224A" }, + "å": { "codepoints": [229], "characters": "\u00E5" }, + "å": { "codepoints": [229], "characters": "\u00E5" }, + "𝒶": { "codepoints": [119990], "characters": "\uD835\uDCB6" }, + "*": { "codepoints": [42], "characters": "\u002A" }, + "≈": { "codepoints": [8776], "characters": "\u2248" }, + "≍": { "codepoints": [8781], "characters": "\u224D" }, + "ã": { "codepoints": [227], "characters": "\u00E3" }, + "ã": { "codepoints": [227], "characters": "\u00E3" }, + "ä": { "codepoints": [228], "characters": "\u00E4" }, + "ä": { "codepoints": [228], "characters": "\u00E4" }, + "∳": { "codepoints": [8755], "characters": "\u2233" }, + "⨑": { "codepoints": [10769], "characters": "\u2A11" }, + "⫭": { "codepoints": [10989], "characters": "\u2AED" }, + "≌": { "codepoints": [8780], "characters": "\u224C" }, + "϶": { "codepoints": [1014], "characters": "\u03F6" }, + "‵": { "codepoints": [8245], "characters": "\u2035" }, + "∽": { "codepoints": [8765], "characters": "\u223D" }, + "⋍": { "codepoints": [8909], "characters": "\u22CD" }, + "⊽": { "codepoints": [8893], "characters": "\u22BD" }, + "⌅": { "codepoints": [8965], "characters": "\u2305" }, + "⌅": { "codepoints": [8965], "characters": "\u2305" }, + "⎵": { "codepoints": [9141], "characters": "\u23B5" }, + "⎶": { "codepoints": [9142], "characters": "\u23B6" }, + "≌": { "codepoints": [8780], "characters": "\u224C" }, + "б": { "codepoints": [1073], "characters": "\u0431" }, + "„": { "codepoints": [8222], "characters": "\u201E" }, + "∵": { "codepoints": [8757], "characters": "\u2235" }, + "∵": { "codepoints": [8757], "characters": "\u2235" }, + "⦰": { "codepoints": [10672], "characters": "\u29B0" }, + "϶": { "codepoints": [1014], "characters": "\u03F6" }, + "ℬ": { "codepoints": [8492], "characters": "\u212C" }, + "β": { "codepoints": [946], "characters": "\u03B2" }, + "ℶ": { "codepoints": [8502], "characters": "\u2136" }, + "≬": { "codepoints": [8812], "characters": "\u226C" }, + "𝔟": { "codepoints": [120095], "characters": "\uD835\uDD1F" }, + "⋂": { "codepoints": [8898], "characters": "\u22C2" }, + "◯": { "codepoints": [9711], "characters": "\u25EF" }, + "⋃": { "codepoints": [8899], "characters": "\u22C3" }, + "⨀": { "codepoints": [10752], "characters": "\u2A00" }, + "⨁": { "codepoints": [10753], "characters": "\u2A01" }, + "⨂": { "codepoints": [10754], "characters": "\u2A02" }, + "⨆": { "codepoints": [10758], "characters": "\u2A06" }, + "★": { "codepoints": [9733], "characters": "\u2605" }, + "▽": { "codepoints": [9661], "characters": "\u25BD" }, + "△": { "codepoints": [9651], "characters": "\u25B3" }, + "⨄": { "codepoints": [10756], "characters": "\u2A04" }, + "⋁": { "codepoints": [8897], "characters": "\u22C1" }, + "⋀": { "codepoints": [8896], "characters": "\u22C0" }, + "⤍": { "codepoints": [10509], "characters": "\u290D" }, + "⧫": { "codepoints": [10731], "characters": "\u29EB" }, + "▪": { "codepoints": [9642], "characters": "\u25AA" }, + "▴": { "codepoints": [9652], "characters": "\u25B4" }, + "▾": { "codepoints": [9662], "characters": "\u25BE" }, + "◂": { "codepoints": [9666], "characters": "\u25C2" }, + "▸": { "codepoints": [9656], "characters": "\u25B8" }, + "␣": { "codepoints": [9251], "characters": "\u2423" }, + "▒": { "codepoints": [9618], "characters": "\u2592" }, + "░": { "codepoints": [9617], "characters": "\u2591" }, + "▓": { "codepoints": [9619], "characters": "\u2593" }, + "█": { "codepoints": [9608], "characters": "\u2588" }, + "=⃥": { "codepoints": [61, 8421], "characters": "\u003D\u20E5" }, + "≡⃥": { "codepoints": [8801, 8421], "characters": "\u2261\u20E5" }, + "⌐": { "codepoints": [8976], "characters": "\u2310" }, + "𝕓": { "codepoints": [120147], "characters": "\uD835\uDD53" }, + "⊥": { "codepoints": [8869], "characters": "\u22A5" }, + "⊥": { "codepoints": [8869], "characters": "\u22A5" }, + "⋈": { "codepoints": [8904], "characters": "\u22C8" }, + "╗": { "codepoints": [9559], "characters": "\u2557" }, + "╔": { "codepoints": [9556], "characters": "\u2554" }, + "╖": { "codepoints": [9558], "characters": "\u2556" }, + "╓": { "codepoints": [9555], "characters": "\u2553" }, + "═": { "codepoints": [9552], "characters": "\u2550" }, + "╦": { "codepoints": [9574], "characters": "\u2566" }, + "╩": { "codepoints": [9577], "characters": "\u2569" }, + "╤": { "codepoints": [9572], "characters": "\u2564" }, + "╧": { "codepoints": [9575], "characters": "\u2567" }, + "╝": { "codepoints": [9565], "characters": "\u255D" }, + "╚": { "codepoints": [9562], "characters": "\u255A" }, + "╜": { "codepoints": [9564], "characters": "\u255C" }, + "╙": { "codepoints": [9561], "characters": "\u2559" }, + "║": { "codepoints": [9553], "characters": "\u2551" }, + "╬": { "codepoints": [9580], "characters": "\u256C" }, + "╣": { "codepoints": [9571], "characters": "\u2563" }, + "╠": { "codepoints": [9568], "characters": "\u2560" }, + "╫": { "codepoints": [9579], "characters": "\u256B" }, + "╢": { "codepoints": [9570], "characters": "\u2562" }, + "╟": { "codepoints": [9567], "characters": "\u255F" }, + "⧉": { "codepoints": [10697], "characters": "\u29C9" }, + "╕": { "codepoints": [9557], "characters": "\u2555" }, + "╒": { "codepoints": [9554], "characters": "\u2552" }, + "┐": { "codepoints": [9488], "characters": "\u2510" }, + "┌": { "codepoints": [9484], "characters": "\u250C" }, + "─": { "codepoints": [9472], "characters": "\u2500" }, + "╥": { "codepoints": [9573], "characters": "\u2565" }, + "╨": { "codepoints": [9576], "characters": "\u2568" }, + "┬": { "codepoints": [9516], "characters": "\u252C" }, + "┴": { "codepoints": [9524], "characters": "\u2534" }, + "⊟": { "codepoints": [8863], "characters": "\u229F" }, + "⊞": { "codepoints": [8862], "characters": "\u229E" }, + "⊠": { "codepoints": [8864], "characters": "\u22A0" }, + "╛": { "codepoints": [9563], "characters": "\u255B" }, + "╘": { "codepoints": [9560], "characters": "\u2558" }, + "┘": { "codepoints": [9496], "characters": "\u2518" }, + "└": { "codepoints": [9492], "characters": "\u2514" }, + "│": { "codepoints": [9474], "characters": "\u2502" }, + "╪": { "codepoints": [9578], "characters": "\u256A" }, + "╡": { "codepoints": [9569], "characters": "\u2561" }, + "╞": { "codepoints": [9566], "characters": "\u255E" }, + "┼": { "codepoints": [9532], "characters": "\u253C" }, + "┤": { "codepoints": [9508], "characters": "\u2524" }, + "├": { "codepoints": [9500], "characters": "\u251C" }, + "‵": { "codepoints": [8245], "characters": "\u2035" }, + "˘": { "codepoints": [728], "characters": "\u02D8" }, + "¦": { "codepoints": [166], "characters": "\u00A6" }, + "¦": { "codepoints": [166], "characters": "\u00A6" }, + "𝒷": { "codepoints": [119991], "characters": "\uD835\uDCB7" }, + "⁏": { "codepoints": [8271], "characters": "\u204F" }, + "∽": { "codepoints": [8765], "characters": "\u223D" }, + "⋍": { "codepoints": [8909], "characters": "\u22CD" }, + "\": { "codepoints": [92], "characters": "\u005C" }, + "⧅": { "codepoints": [10693], "characters": "\u29C5" }, + "⟈": { "codepoints": [10184], "characters": "\u27C8" }, + "•": { "codepoints": [8226], "characters": "\u2022" }, + "•": { "codepoints": [8226], "characters": "\u2022" }, + "≎": { "codepoints": [8782], "characters": "\u224E" }, + "⪮": { "codepoints": [10926], "characters": "\u2AAE" }, + "≏": { "codepoints": [8783], "characters": "\u224F" }, + "≏": { "codepoints": [8783], "characters": "\u224F" }, + "ć": { "codepoints": [263], "characters": "\u0107" }, + "∩": { "codepoints": [8745], "characters": "\u2229" }, + "⩄": { "codepoints": [10820], "characters": "\u2A44" }, + "⩉": { "codepoints": [10825], "characters": "\u2A49" }, + "⩋": { "codepoints": [10827], "characters": "\u2A4B" }, + "⩇": { "codepoints": [10823], "characters": "\u2A47" }, + "⩀": { "codepoints": [10816], "characters": "\u2A40" }, + "∩︀": { "codepoints": [8745, 65024], "characters": "\u2229\uFE00" }, + "⁁": { "codepoints": [8257], "characters": "\u2041" }, + "ˇ": { "codepoints": [711], "characters": "\u02C7" }, + "⩍": { "codepoints": [10829], "characters": "\u2A4D" }, + "č": { "codepoints": [269], "characters": "\u010D" }, + "ç": { "codepoints": [231], "characters": "\u00E7" }, + "ç": { "codepoints": [231], "characters": "\u00E7" }, + "ĉ": { "codepoints": [265], "characters": "\u0109" }, + "⩌": { "codepoints": [10828], "characters": "\u2A4C" }, + "⩐": { "codepoints": [10832], "characters": "\u2A50" }, + "ċ": { "codepoints": [267], "characters": "\u010B" }, + "¸": { "codepoints": [184], "characters": "\u00B8" }, + "¸": { "codepoints": [184], "characters": "\u00B8" }, + "⦲": { "codepoints": [10674], "characters": "\u29B2" }, + "¢": { "codepoints": [162], "characters": "\u00A2" }, + "¢": { "codepoints": [162], "characters": "\u00A2" }, + "·": { "codepoints": [183], "characters": "\u00B7" }, + "𝔠": { "codepoints": [120096], "characters": "\uD835\uDD20" }, + "ч": { "codepoints": [1095], "characters": "\u0447" }, + "✓": { "codepoints": [10003], "characters": "\u2713" }, + "✓": { "codepoints": [10003], "characters": "\u2713" }, + "χ": { "codepoints": [967], "characters": "\u03C7" }, + "○": { "codepoints": [9675], "characters": "\u25CB" }, + "⧃": { "codepoints": [10691], "characters": "\u29C3" }, + "ˆ": { "codepoints": [710], "characters": "\u02C6" }, + "≗": { "codepoints": [8791], "characters": "\u2257" }, + "↺": { "codepoints": [8634], "characters": "\u21BA" }, + "↻": { "codepoints": [8635], "characters": "\u21BB" }, + "®": { "codepoints": [174], "characters": "\u00AE" }, + "Ⓢ": { "codepoints": [9416], "characters": "\u24C8" }, + "⊛": { "codepoints": [8859], "characters": "\u229B" }, + "⊚": { "codepoints": [8858], "characters": "\u229A" }, + "⊝": { "codepoints": [8861], "characters": "\u229D" }, + "≗": { "codepoints": [8791], "characters": "\u2257" }, + "⨐": { "codepoints": [10768], "characters": "\u2A10" }, + "⫯": { "codepoints": [10991], "characters": "\u2AEF" }, + "⧂": { "codepoints": [10690], "characters": "\u29C2" }, + "♣": { "codepoints": [9827], "characters": "\u2663" }, + "♣": { "codepoints": [9827], "characters": "\u2663" }, + ":": { "codepoints": [58], "characters": "\u003A" }, + "≔": { "codepoints": [8788], "characters": "\u2254" }, + "≔": { "codepoints": [8788], "characters": "\u2254" }, + ",": { "codepoints": [44], "characters": "\u002C" }, + "@": { "codepoints": [64], "characters": "\u0040" }, + "∁": { "codepoints": [8705], "characters": "\u2201" }, + "∘": { "codepoints": [8728], "characters": "\u2218" }, + "∁": { "codepoints": [8705], "characters": "\u2201" }, + "ℂ": { "codepoints": [8450], "characters": "\u2102" }, + "≅": { "codepoints": [8773], "characters": "\u2245" }, + "⩭": { "codepoints": [10861], "characters": "\u2A6D" }, + "∮": { "codepoints": [8750], "characters": "\u222E" }, + "𝕔": { "codepoints": [120148], "characters": "\uD835\uDD54" }, + "∐": { "codepoints": [8720], "characters": "\u2210" }, + "©": { "codepoints": [169], "characters": "\u00A9" }, + "©": { "codepoints": [169], "characters": "\u00A9" }, + "℗": { "codepoints": [8471], "characters": "\u2117" }, + "↵": { "codepoints": [8629], "characters": "\u21B5" }, + "✗": { "codepoints": [10007], "characters": "\u2717" }, + "𝒸": { "codepoints": [119992], "characters": "\uD835\uDCB8" }, + "⫏": { "codepoints": [10959], "characters": "\u2ACF" }, + "⫑": { "codepoints": [10961], "characters": "\u2AD1" }, + "⫐": { "codepoints": [10960], "characters": "\u2AD0" }, + "⫒": { "codepoints": [10962], "characters": "\u2AD2" }, + "⋯": { "codepoints": [8943], "characters": "\u22EF" }, + "⤸": { "codepoints": [10552], "characters": "\u2938" }, + "⤵": { "codepoints": [10549], "characters": "\u2935" }, + "⋞": { "codepoints": [8926], "characters": "\u22DE" }, + "⋟": { "codepoints": [8927], "characters": "\u22DF" }, + "↶": { "codepoints": [8630], "characters": "\u21B6" }, + "⤽": { "codepoints": [10557], "characters": "\u293D" }, + "∪": { "codepoints": [8746], "characters": "\u222A" }, + "⩈": { "codepoints": [10824], "characters": "\u2A48" }, + "⩆": { "codepoints": [10822], "characters": "\u2A46" }, + "⩊": { "codepoints": [10826], "characters": "\u2A4A" }, + "⊍": { "codepoints": [8845], "characters": "\u228D" }, + "⩅": { "codepoints": [10821], "characters": "\u2A45" }, + "∪︀": { "codepoints": [8746, 65024], "characters": "\u222A\uFE00" }, + "↷": { "codepoints": [8631], "characters": "\u21B7" }, + "⤼": { "codepoints": [10556], "characters": "\u293C" }, + "⋞": { "codepoints": [8926], "characters": "\u22DE" }, + "⋟": { "codepoints": [8927], "characters": "\u22DF" }, + "⋎": { "codepoints": [8910], "characters": "\u22CE" }, + "⋏": { "codepoints": [8911], "characters": "\u22CF" }, + "¤": { "codepoints": [164], "characters": "\u00A4" }, + "¤": { "codepoints": [164], "characters": "\u00A4" }, + "↶": { "codepoints": [8630], "characters": "\u21B6" }, + "↷": { "codepoints": [8631], "characters": "\u21B7" }, + "⋎": { "codepoints": [8910], "characters": "\u22CE" }, + "⋏": { "codepoints": [8911], "characters": "\u22CF" }, + "∲": { "codepoints": [8754], "characters": "\u2232" }, + "∱": { "codepoints": [8753], "characters": "\u2231" }, + "⌭": { "codepoints": [9005], "characters": "\u232D" }, + "⇓": { "codepoints": [8659], "characters": "\u21D3" }, + "⥥": { "codepoints": [10597], "characters": "\u2965" }, + "†": { "codepoints": [8224], "characters": "\u2020" }, + "ℸ": { "codepoints": [8504], "characters": "\u2138" }, + "↓": { "codepoints": [8595], "characters": "\u2193" }, + "‐": { "codepoints": [8208], "characters": "\u2010" }, + "⊣": { "codepoints": [8867], "characters": "\u22A3" }, + "⤏": { "codepoints": [10511], "characters": "\u290F" }, + "˝": { "codepoints": [733], "characters": "\u02DD" }, + "ď": { "codepoints": [271], "characters": "\u010F" }, + "д": { "codepoints": [1076], "characters": "\u0434" }, + "ⅆ": { "codepoints": [8518], "characters": "\u2146" }, + "‡": { "codepoints": [8225], "characters": "\u2021" }, + "⇊": { "codepoints": [8650], "characters": "\u21CA" }, + "⩷": { "codepoints": [10871], "characters": "\u2A77" }, + "°": { "codepoints": [176], "characters": "\u00B0" }, + "°": { "codepoints": [176], "characters": "\u00B0" }, + "δ": { "codepoints": [948], "characters": "\u03B4" }, + "⦱": { "codepoints": [10673], "characters": "\u29B1" }, + "⥿": { "codepoints": [10623], "characters": "\u297F" }, + "𝔡": { "codepoints": [120097], "characters": "\uD835\uDD21" }, + "⇃": { "codepoints": [8643], "characters": "\u21C3" }, + "⇂": { "codepoints": [8642], "characters": "\u21C2" }, + "⋄": { "codepoints": [8900], "characters": "\u22C4" }, + "⋄": { "codepoints": [8900], "characters": "\u22C4" }, + "♦": { "codepoints": [9830], "characters": "\u2666" }, + "♦": { "codepoints": [9830], "characters": "\u2666" }, + "¨": { "codepoints": [168], "characters": "\u00A8" }, + "ϝ": { "codepoints": [989], "characters": "\u03DD" }, + "⋲": { "codepoints": [8946], "characters": "\u22F2" }, + "÷": { "codepoints": [247], "characters": "\u00F7" }, + "÷": { "codepoints": [247], "characters": "\u00F7" }, + "÷": { "codepoints": [247], "characters": "\u00F7" }, + "⋇": { "codepoints": [8903], "characters": "\u22C7" }, + "⋇": { "codepoints": [8903], "characters": "\u22C7" }, + "ђ": { "codepoints": [1106], "characters": "\u0452" }, + "⌞": { "codepoints": [8990], "characters": "\u231E" }, + "⌍": { "codepoints": [8973], "characters": "\u230D" }, + "$": { "codepoints": [36], "characters": "\u0024" }, + "𝕕": { "codepoints": [120149], "characters": "\uD835\uDD55" }, + "˙": { "codepoints": [729], "characters": "\u02D9" }, + "≐": { "codepoints": [8784], "characters": "\u2250" }, + "≑": { "codepoints": [8785], "characters": "\u2251" }, + "∸": { "codepoints": [8760], "characters": "\u2238" }, + "∔": { "codepoints": [8724], "characters": "\u2214" }, + "⊡": { "codepoints": [8865], "characters": "\u22A1" }, + "⌆": { "codepoints": [8966], "characters": "\u2306" }, + "↓": { "codepoints": [8595], "characters": "\u2193" }, + "⇊": { "codepoints": [8650], "characters": "\u21CA" }, + "⇃": { "codepoints": [8643], "characters": "\u21C3" }, + "⇂": { "codepoints": [8642], "characters": "\u21C2" }, + "⤐": { "codepoints": [10512], "characters": "\u2910" }, + "⌟": { "codepoints": [8991], "characters": "\u231F" }, + "⌌": { "codepoints": [8972], "characters": "\u230C" }, + "𝒹": { "codepoints": [119993], "characters": "\uD835\uDCB9" }, + "ѕ": { "codepoints": [1109], "characters": "\u0455" }, + "⧶": { "codepoints": [10742], "characters": "\u29F6" }, + "đ": { "codepoints": [273], "characters": "\u0111" }, + "⋱": { "codepoints": [8945], "characters": "\u22F1" }, + "▿": { "codepoints": [9663], "characters": "\u25BF" }, + "▾": { "codepoints": [9662], "characters": "\u25BE" }, + "⇵": { "codepoints": [8693], "characters": "\u21F5" }, + "⥯": { "codepoints": [10607], "characters": "\u296F" }, + "⦦": { "codepoints": [10662], "characters": "\u29A6" }, + "џ": { "codepoints": [1119], "characters": "\u045F" }, + "⟿": { "codepoints": [10239], "characters": "\u27FF" }, + "⩷": { "codepoints": [10871], "characters": "\u2A77" }, + "≑": { "codepoints": [8785], "characters": "\u2251" }, + "é": { "codepoints": [233], "characters": "\u00E9" }, + "é": { "codepoints": [233], "characters": "\u00E9" }, + "⩮": { "codepoints": [10862], "characters": "\u2A6E" }, + "ě": { "codepoints": [283], "characters": "\u011B" }, + "≖": { "codepoints": [8790], "characters": "\u2256" }, + "ê": { "codepoints": [234], "characters": "\u00EA" }, + "ê": { "codepoints": [234], "characters": "\u00EA" }, + "≕": { "codepoints": [8789], "characters": "\u2255" }, + "э": { "codepoints": [1101], "characters": "\u044D" }, + "ė": { "codepoints": [279], "characters": "\u0117" }, + "ⅇ": { "codepoints": [8519], "characters": "\u2147" }, + "≒": { "codepoints": [8786], "characters": "\u2252" }, + "𝔢": { "codepoints": [120098], "characters": "\uD835\uDD22" }, + "⪚": { "codepoints": [10906], "characters": "\u2A9A" }, + "è": { "codepoints": [232], "characters": "\u00E8" }, + "è": { "codepoints": [232], "characters": "\u00E8" }, + "⪖": { "codepoints": [10902], "characters": "\u2A96" }, + "⪘": { "codepoints": [10904], "characters": "\u2A98" }, + "⪙": { "codepoints": [10905], "characters": "\u2A99" }, + "⏧": { "codepoints": [9191], "characters": "\u23E7" }, + "ℓ": { "codepoints": [8467], "characters": "\u2113" }, + "⪕": { "codepoints": [10901], "characters": "\u2A95" }, + "⪗": { "codepoints": [10903], "characters": "\u2A97" }, + "ē": { "codepoints": [275], "characters": "\u0113" }, + "∅": { "codepoints": [8709], "characters": "\u2205" }, + "∅": { "codepoints": [8709], "characters": "\u2205" }, + "∅": { "codepoints": [8709], "characters": "\u2205" }, + " ": { "codepoints": [8196], "characters": "\u2004" }, + " ": { "codepoints": [8197], "characters": "\u2005" }, + " ": { "codepoints": [8195], "characters": "\u2003" }, + "ŋ": { "codepoints": [331], "characters": "\u014B" }, + " ": { "codepoints": [8194], "characters": "\u2002" }, + "ę": { "codepoints": [281], "characters": "\u0119" }, + "𝕖": { "codepoints": [120150], "characters": "\uD835\uDD56" }, + "⋕": { "codepoints": [8917], "characters": "\u22D5" }, + "⧣": { "codepoints": [10723], "characters": "\u29E3" }, + "⩱": { "codepoints": [10865], "characters": "\u2A71" }, + "ε": { "codepoints": [949], "characters": "\u03B5" }, + "ε": { "codepoints": [949], "characters": "\u03B5" }, + "ϵ": { "codepoints": [1013], "characters": "\u03F5" }, + "≖": { "codepoints": [8790], "characters": "\u2256" }, + "≕": { "codepoints": [8789], "characters": "\u2255" }, + "≂": { "codepoints": [8770], "characters": "\u2242" }, + "⪖": { "codepoints": [10902], "characters": "\u2A96" }, + "⪕": { "codepoints": [10901], "characters": "\u2A95" }, + "=": { "codepoints": [61], "characters": "\u003D" }, + "≟": { "codepoints": [8799], "characters": "\u225F" }, + "≡": { "codepoints": [8801], "characters": "\u2261" }, + "⩸": { "codepoints": [10872], "characters": "\u2A78" }, + "⧥": { "codepoints": [10725], "characters": "\u29E5" }, + "≓": { "codepoints": [8787], "characters": "\u2253" }, + "⥱": { "codepoints": [10609], "characters": "\u2971" }, + "ℯ": { "codepoints": [8495], "characters": "\u212F" }, + "≐": { "codepoints": [8784], "characters": "\u2250" }, + "≂": { "codepoints": [8770], "characters": "\u2242" }, + "η": { "codepoints": [951], "characters": "\u03B7" }, + "ð": { "codepoints": [240], "characters": "\u00F0" }, + "ð": { "codepoints": [240], "characters": "\u00F0" }, + "ë": { "codepoints": [235], "characters": "\u00EB" }, + "ë": { "codepoints": [235], "characters": "\u00EB" }, + "€": { "codepoints": [8364], "characters": "\u20AC" }, + "!": { "codepoints": [33], "characters": "\u0021" }, + "∃": { "codepoints": [8707], "characters": "\u2203" }, + "ℰ": { "codepoints": [8496], "characters": "\u2130" }, + "ⅇ": { "codepoints": [8519], "characters": "\u2147" }, + "≒": { "codepoints": [8786], "characters": "\u2252" }, + "ф": { "codepoints": [1092], "characters": "\u0444" }, + "♀": { "codepoints": [9792], "characters": "\u2640" }, + "ffi": { "codepoints": [64259], "characters": "\uFB03" }, + "ff": { "codepoints": [64256], "characters": "\uFB00" }, + "ffl": { "codepoints": [64260], "characters": "\uFB04" }, + "𝔣": { "codepoints": [120099], "characters": "\uD835\uDD23" }, + "fi": { "codepoints": [64257], "characters": "\uFB01" }, + "fj": { "codepoints": [102, 106], "characters": "\u0066\u006A" }, + "♭": { "codepoints": [9837], "characters": "\u266D" }, + "fl": { "codepoints": [64258], "characters": "\uFB02" }, + "▱": { "codepoints": [9649], "characters": "\u25B1" }, + "ƒ": { "codepoints": [402], "characters": "\u0192" }, + "𝕗": { "codepoints": [120151], "characters": "\uD835\uDD57" }, + "∀": { "codepoints": [8704], "characters": "\u2200" }, + "⋔": { "codepoints": [8916], "characters": "\u22D4" }, + "⫙": { "codepoints": [10969], "characters": "\u2AD9" }, + "⨍": { "codepoints": [10765], "characters": "\u2A0D" }, + "½": { "codepoints": [189], "characters": "\u00BD" }, + "½": { "codepoints": [189], "characters": "\u00BD" }, + "⅓": { "codepoints": [8531], "characters": "\u2153" }, + "¼": { "codepoints": [188], "characters": "\u00BC" }, + "¼": { "codepoints": [188], "characters": "\u00BC" }, + "⅕": { "codepoints": [8533], "characters": "\u2155" }, + "⅙": { "codepoints": [8537], "characters": "\u2159" }, + "⅛": { "codepoints": [8539], "characters": "\u215B" }, + "⅔": { "codepoints": [8532], "characters": "\u2154" }, + "⅖": { "codepoints": [8534], "characters": "\u2156" }, + "¾": { "codepoints": [190], "characters": "\u00BE" }, + "¾": { "codepoints": [190], "characters": "\u00BE" }, + "⅗": { "codepoints": [8535], "characters": "\u2157" }, + "⅜": { "codepoints": [8540], "characters": "\u215C" }, + "⅘": { "codepoints": [8536], "characters": "\u2158" }, + "⅚": { "codepoints": [8538], "characters": "\u215A" }, + "⅝": { "codepoints": [8541], "characters": "\u215D" }, + "⅞": { "codepoints": [8542], "characters": "\u215E" }, + "⁄": { "codepoints": [8260], "characters": "\u2044" }, + "⌢": { "codepoints": [8994], "characters": "\u2322" }, + "𝒻": { "codepoints": [119995], "characters": "\uD835\uDCBB" }, + "≧": { "codepoints": [8807], "characters": "\u2267" }, + "⪌": { "codepoints": [10892], "characters": "\u2A8C" }, + "ǵ": { "codepoints": [501], "characters": "\u01F5" }, + "γ": { "codepoints": [947], "characters": "\u03B3" }, + "ϝ": { "codepoints": [989], "characters": "\u03DD" }, + "⪆": { "codepoints": [10886], "characters": "\u2A86" }, + "ğ": { "codepoints": [287], "characters": "\u011F" }, + "ĝ": { "codepoints": [285], "characters": "\u011D" }, + "г": { "codepoints": [1075], "characters": "\u0433" }, + "ġ": { "codepoints": [289], "characters": "\u0121" }, + "≥": { "codepoints": [8805], "characters": "\u2265" }, + "⋛": { "codepoints": [8923], "characters": "\u22DB" }, + "≥": { "codepoints": [8805], "characters": "\u2265" }, + "≧": { "codepoints": [8807], "characters": "\u2267" }, + "⩾": { "codepoints": [10878], "characters": "\u2A7E" }, + "⩾": { "codepoints": [10878], "characters": "\u2A7E" }, + "⪩": { "codepoints": [10921], "characters": "\u2AA9" }, + "⪀": { "codepoints": [10880], "characters": "\u2A80" }, + "⪂": { "codepoints": [10882], "characters": "\u2A82" }, + "⪄": { "codepoints": [10884], "characters": "\u2A84" }, + "⋛︀": { "codepoints": [8923, 65024], "characters": "\u22DB\uFE00" }, + "⪔": { "codepoints": [10900], "characters": "\u2A94" }, + "𝔤": { "codepoints": [120100], "characters": "\uD835\uDD24" }, + "≫": { "codepoints": [8811], "characters": "\u226B" }, + "⋙": { "codepoints": [8921], "characters": "\u22D9" }, + "ℷ": { "codepoints": [8503], "characters": "\u2137" }, + "ѓ": { "codepoints": [1107], "characters": "\u0453" }, + "≷": { "codepoints": [8823], "characters": "\u2277" }, + "⪒": { "codepoints": [10898], "characters": "\u2A92" }, + "⪥": { "codepoints": [10917], "characters": "\u2AA5" }, + "⪤": { "codepoints": [10916], "characters": "\u2AA4" }, + "≩": { "codepoints": [8809], "characters": "\u2269" }, + "⪊": { "codepoints": [10890], "characters": "\u2A8A" }, + "⪊": { "codepoints": [10890], "characters": "\u2A8A" }, + "⪈": { "codepoints": [10888], "characters": "\u2A88" }, + "⪈": { "codepoints": [10888], "characters": "\u2A88" }, + "≩": { "codepoints": [8809], "characters": "\u2269" }, + "⋧": { "codepoints": [8935], "characters": "\u22E7" }, + "𝕘": { "codepoints": [120152], "characters": "\uD835\uDD58" }, + "`": { "codepoints": [96], "characters": "\u0060" }, + "ℊ": { "codepoints": [8458], "characters": "\u210A" }, + "≳": { "codepoints": [8819], "characters": "\u2273" }, + "⪎": { "codepoints": [10894], "characters": "\u2A8E" }, + "⪐": { "codepoints": [10896], "characters": "\u2A90" }, + ">": { "codepoints": [62], "characters": "\u003E" }, + ">": { "codepoints": [62], "characters": "\u003E" }, + "⪧": { "codepoints": [10919], "characters": "\u2AA7" }, + "⩺": { "codepoints": [10874], "characters": "\u2A7A" }, + "⋗": { "codepoints": [8919], "characters": "\u22D7" }, + "⦕": { "codepoints": [10645], "characters": "\u2995" }, + "⩼": { "codepoints": [10876], "characters": "\u2A7C" }, + "⪆": { "codepoints": [10886], "characters": "\u2A86" }, + "⥸": { "codepoints": [10616], "characters": "\u2978" }, + "⋗": { "codepoints": [8919], "characters": "\u22D7" }, + "⋛": { "codepoints": [8923], "characters": "\u22DB" }, + "⪌": { "codepoints": [10892], "characters": "\u2A8C" }, + "≷": { "codepoints": [8823], "characters": "\u2277" }, + "≳": { "codepoints": [8819], "characters": "\u2273" }, + "≩︀": { "codepoints": [8809, 65024], "characters": "\u2269\uFE00" }, + "≩︀": { "codepoints": [8809, 65024], "characters": "\u2269\uFE00" }, + "⇔": { "codepoints": [8660], "characters": "\u21D4" }, + " ": { "codepoints": [8202], "characters": "\u200A" }, + "½": { "codepoints": [189], "characters": "\u00BD" }, + "ℋ": { "codepoints": [8459], "characters": "\u210B" }, + "ъ": { "codepoints": [1098], "characters": "\u044A" }, + "↔": { "codepoints": [8596], "characters": "\u2194" }, + "⥈": { "codepoints": [10568], "characters": "\u2948" }, + "↭": { "codepoints": [8621], "characters": "\u21AD" }, + "ℏ": { "codepoints": [8463], "characters": "\u210F" }, + "ĥ": { "codepoints": [293], "characters": "\u0125" }, + "♥": { "codepoints": [9829], "characters": "\u2665" }, + "♥": { "codepoints": [9829], "characters": "\u2665" }, + "…": { "codepoints": [8230], "characters": "\u2026" }, + "⊹": { "codepoints": [8889], "characters": "\u22B9" }, + "𝔥": { "codepoints": [120101], "characters": "\uD835\uDD25" }, + "⤥": { "codepoints": [10533], "characters": "\u2925" }, + "⤦": { "codepoints": [10534], "characters": "\u2926" }, + "⇿": { "codepoints": [8703], "characters": "\u21FF" }, + "∻": { "codepoints": [8763], "characters": "\u223B" }, + "↩": { "codepoints": [8617], "characters": "\u21A9" }, + "↪": { "codepoints": [8618], "characters": "\u21AA" }, + "𝕙": { "codepoints": [120153], "characters": "\uD835\uDD59" }, + "―": { "codepoints": [8213], "characters": "\u2015" }, + "𝒽": { "codepoints": [119997], "characters": "\uD835\uDCBD" }, + "ℏ": { "codepoints": [8463], "characters": "\u210F" }, + "ħ": { "codepoints": [295], "characters": "\u0127" }, + "⁃": { "codepoints": [8259], "characters": "\u2043" }, + "‐": { "codepoints": [8208], "characters": "\u2010" }, + "í": { "codepoints": [237], "characters": "\u00ED" }, + "í": { "codepoints": [237], "characters": "\u00ED" }, + "⁣": { "codepoints": [8291], "characters": "\u2063" }, + "î": { "codepoints": [238], "characters": "\u00EE" }, + "î": { "codepoints": [238], "characters": "\u00EE" }, + "и": { "codepoints": [1080], "characters": "\u0438" }, + "е": { "codepoints": [1077], "characters": "\u0435" }, + "¡": { "codepoints": [161], "characters": "\u00A1" }, + "¡": { "codepoints": [161], "characters": "\u00A1" }, + "⇔": { "codepoints": [8660], "characters": "\u21D4" }, + "𝔦": { "codepoints": [120102], "characters": "\uD835\uDD26" }, + "ì": { "codepoints": [236], "characters": "\u00EC" }, + "ì": { "codepoints": [236], "characters": "\u00EC" }, + "ⅈ": { "codepoints": [8520], "characters": "\u2148" }, + "⨌": { "codepoints": [10764], "characters": "\u2A0C" }, + "∭": { "codepoints": [8749], "characters": "\u222D" }, + "⧜": { "codepoints": [10716], "characters": "\u29DC" }, + "℩": { "codepoints": [8489], "characters": "\u2129" }, + "ij": { "codepoints": [307], "characters": "\u0133" }, + "ī": { "codepoints": [299], "characters": "\u012B" }, + "ℑ": { "codepoints": [8465], "characters": "\u2111" }, + "ℐ": { "codepoints": [8464], "characters": "\u2110" }, + "ℑ": { "codepoints": [8465], "characters": "\u2111" }, + "ı": { "codepoints": [305], "characters": "\u0131" }, + "⊷": { "codepoints": [8887], "characters": "\u22B7" }, + "Ƶ": { "codepoints": [437], "characters": "\u01B5" }, + "∈": { "codepoints": [8712], "characters": "\u2208" }, + "℅": { "codepoints": [8453], "characters": "\u2105" }, + "∞": { "codepoints": [8734], "characters": "\u221E" }, + "⧝": { "codepoints": [10717], "characters": "\u29DD" }, + "ı": { "codepoints": [305], "characters": "\u0131" }, + "∫": { "codepoints": [8747], "characters": "\u222B" }, + "⊺": { "codepoints": [8890], "characters": "\u22BA" }, + "ℤ": { "codepoints": [8484], "characters": "\u2124" }, + "⊺": { "codepoints": [8890], "characters": "\u22BA" }, + "⨗": { "codepoints": [10775], "characters": "\u2A17" }, + "⨼": { "codepoints": [10812], "characters": "\u2A3C" }, + "ё": { "codepoints": [1105], "characters": "\u0451" }, + "į": { "codepoints": [303], "characters": "\u012F" }, + "𝕚": { "codepoints": [120154], "characters": "\uD835\uDD5A" }, + "ι": { "codepoints": [953], "characters": "\u03B9" }, + "⨼": { "codepoints": [10812], "characters": "\u2A3C" }, + "¿": { "codepoints": [191], "characters": "\u00BF" }, + "¿": { "codepoints": [191], "characters": "\u00BF" }, + "𝒾": { "codepoints": [119998], "characters": "\uD835\uDCBE" }, + "∈": { "codepoints": [8712], "characters": "\u2208" }, + "⋹": { "codepoints": [8953], "characters": "\u22F9" }, + "⋵": { "codepoints": [8949], "characters": "\u22F5" }, + "⋴": { "codepoints": [8948], "characters": "\u22F4" }, + "⋳": { "codepoints": [8947], "characters": "\u22F3" }, + "∈": { "codepoints": [8712], "characters": "\u2208" }, + "⁢": { "codepoints": [8290], "characters": "\u2062" }, + "ĩ": { "codepoints": [297], "characters": "\u0129" }, + "і": { "codepoints": [1110], "characters": "\u0456" }, + "ï": { "codepoints": [239], "characters": "\u00EF" }, + "ï": { "codepoints": [239], "characters": "\u00EF" }, + "ĵ": { "codepoints": [309], "characters": "\u0135" }, + "й": { "codepoints": [1081], "characters": "\u0439" }, + "𝔧": { "codepoints": [120103], "characters": "\uD835\uDD27" }, + "ȷ": { "codepoints": [567], "characters": "\u0237" }, + "𝕛": { "codepoints": [120155], "characters": "\uD835\uDD5B" }, + "𝒿": { "codepoints": [119999], "characters": "\uD835\uDCBF" }, + "ј": { "codepoints": [1112], "characters": "\u0458" }, + "є": { "codepoints": [1108], "characters": "\u0454" }, + "κ": { "codepoints": [954], "characters": "\u03BA" }, + "ϰ": { "codepoints": [1008], "characters": "\u03F0" }, + "ķ": { "codepoints": [311], "characters": "\u0137" }, + "к": { "codepoints": [1082], "characters": "\u043A" }, + "𝔨": { "codepoints": [120104], "characters": "\uD835\uDD28" }, + "ĸ": { "codepoints": [312], "characters": "\u0138" }, + "х": { "codepoints": [1093], "characters": "\u0445" }, + "ќ": { "codepoints": [1116], "characters": "\u045C" }, + "𝕜": { "codepoints": [120156], "characters": "\uD835\uDD5C" }, + "𝓀": { "codepoints": [120000], "characters": "\uD835\uDCC0" }, + "⇚": { "codepoints": [8666], "characters": "\u21DA" }, + "⇐": { "codepoints": [8656], "characters": "\u21D0" }, + "⤛": { "codepoints": [10523], "characters": "\u291B" }, + "⤎": { "codepoints": [10510], "characters": "\u290E" }, + "≦": { "codepoints": [8806], "characters": "\u2266" }, + "⪋": { "codepoints": [10891], "characters": "\u2A8B" }, + "⥢": { "codepoints": [10594], "characters": "\u2962" }, + "ĺ": { "codepoints": [314], "characters": "\u013A" }, + "⦴": { "codepoints": [10676], "characters": "\u29B4" }, + "ℒ": { "codepoints": [8466], "characters": "\u2112" }, + "λ": { "codepoints": [955], "characters": "\u03BB" }, + "⟨": { "codepoints": [10216], "characters": "\u27E8" }, + "⦑": { "codepoints": [10641], "characters": "\u2991" }, + "⟨": { "codepoints": [10216], "characters": "\u27E8" }, + "⪅": { "codepoints": [10885], "characters": "\u2A85" }, + "«": { "codepoints": [171], "characters": "\u00AB" }, + "«": { "codepoints": [171], "characters": "\u00AB" }, + "←": { "codepoints": [8592], "characters": "\u2190" }, + "⇤": { "codepoints": [8676], "characters": "\u21E4" }, + "⤟": { "codepoints": [10527], "characters": "\u291F" }, + "⤝": { "codepoints": [10525], "characters": "\u291D" }, + "↩": { "codepoints": [8617], "characters": "\u21A9" }, + "↫": { "codepoints": [8619], "characters": "\u21AB" }, + "⤹": { "codepoints": [10553], "characters": "\u2939" }, + "⥳": { "codepoints": [10611], "characters": "\u2973" }, + "↢": { "codepoints": [8610], "characters": "\u21A2" }, + "⪫": { "codepoints": [10923], "characters": "\u2AAB" }, + "⤙": { "codepoints": [10521], "characters": "\u2919" }, + "⪭": { "codepoints": [10925], "characters": "\u2AAD" }, + "⪭︀": { "codepoints": [10925, 65024], "characters": "\u2AAD\uFE00" }, + "⤌": { "codepoints": [10508], "characters": "\u290C" }, + "❲": { "codepoints": [10098], "characters": "\u2772" }, + "{": { "codepoints": [123], "characters": "\u007B" }, + "[": { "codepoints": [91], "characters": "\u005B" }, + "⦋": { "codepoints": [10635], "characters": "\u298B" }, + "⦏": { "codepoints": [10639], "characters": "\u298F" }, + "⦍": { "codepoints": [10637], "characters": "\u298D" }, + "ľ": { "codepoints": [318], "characters": "\u013E" }, + "ļ": { "codepoints": [316], "characters": "\u013C" }, + "⌈": { "codepoints": [8968], "characters": "\u2308" }, + "{": { "codepoints": [123], "characters": "\u007B" }, + "л": { "codepoints": [1083], "characters": "\u043B" }, + "⤶": { "codepoints": [10550], "characters": "\u2936" }, + "“": { "codepoints": [8220], "characters": "\u201C" }, + "„": { "codepoints": [8222], "characters": "\u201E" }, + "⥧": { "codepoints": [10599], "characters": "\u2967" }, + "⥋": { "codepoints": [10571], "characters": "\u294B" }, + "↲": { "codepoints": [8626], "characters": "\u21B2" }, + "≤": { "codepoints": [8804], "characters": "\u2264" }, + "←": { "codepoints": [8592], "characters": "\u2190" }, + "↢": { "codepoints": [8610], "characters": "\u21A2" }, + "↽": { "codepoints": [8637], "characters": "\u21BD" }, + "↼": { "codepoints": [8636], "characters": "\u21BC" }, + "⇇": { "codepoints": [8647], "characters": "\u21C7" }, + "↔": { "codepoints": [8596], "characters": "\u2194" }, + "⇆": { "codepoints": [8646], "characters": "\u21C6" }, + "⇋": { "codepoints": [8651], "characters": "\u21CB" }, + "↭": { "codepoints": [8621], "characters": "\u21AD" }, + "⋋": { "codepoints": [8907], "characters": "\u22CB" }, + "⋚": { "codepoints": [8922], "characters": "\u22DA" }, + "≤": { "codepoints": [8804], "characters": "\u2264" }, + "≦": { "codepoints": [8806], "characters": "\u2266" }, + "⩽": { "codepoints": [10877], "characters": "\u2A7D" }, + "⩽": { "codepoints": [10877], "characters": "\u2A7D" }, + "⪨": { "codepoints": [10920], "characters": "\u2AA8" }, + "⩿": { "codepoints": [10879], "characters": "\u2A7F" }, + "⪁": { "codepoints": [10881], "characters": "\u2A81" }, + "⪃": { "codepoints": [10883], "characters": "\u2A83" }, + "⋚︀": { "codepoints": [8922, 65024], "characters": "\u22DA\uFE00" }, + "⪓": { "codepoints": [10899], "characters": "\u2A93" }, + "⪅": { "codepoints": [10885], "characters": "\u2A85" }, + "⋖": { "codepoints": [8918], "characters": "\u22D6" }, + "⋚": { "codepoints": [8922], "characters": "\u22DA" }, + "⪋": { "codepoints": [10891], "characters": "\u2A8B" }, + "≶": { "codepoints": [8822], "characters": "\u2276" }, + "≲": { "codepoints": [8818], "characters": "\u2272" }, + "⥼": { "codepoints": [10620], "characters": "\u297C" }, + "⌊": { "codepoints": [8970], "characters": "\u230A" }, + "𝔩": { "codepoints": [120105], "characters": "\uD835\uDD29" }, + "≶": { "codepoints": [8822], "characters": "\u2276" }, + "⪑": { "codepoints": [10897], "characters": "\u2A91" }, + "↽": { "codepoints": [8637], "characters": "\u21BD" }, + "↼": { "codepoints": [8636], "characters": "\u21BC" }, + "⥪": { "codepoints": [10602], "characters": "\u296A" }, + "▄": { "codepoints": [9604], "characters": "\u2584" }, + "љ": { "codepoints": [1113], "characters": "\u0459" }, + "≪": { "codepoints": [8810], "characters": "\u226A" }, + "⇇": { "codepoints": [8647], "characters": "\u21C7" }, + "⌞": { "codepoints": [8990], "characters": "\u231E" }, + "⥫": { "codepoints": [10603], "characters": "\u296B" }, + "◺": { "codepoints": [9722], "characters": "\u25FA" }, + "ŀ": { "codepoints": [320], "characters": "\u0140" }, + "⎰": { "codepoints": [9136], "characters": "\u23B0" }, + "⎰": { "codepoints": [9136], "characters": "\u23B0" }, + "≨": { "codepoints": [8808], "characters": "\u2268" }, + "⪉": { "codepoints": [10889], "characters": "\u2A89" }, + "⪉": { "codepoints": [10889], "characters": "\u2A89" }, + "⪇": { "codepoints": [10887], "characters": "\u2A87" }, + "⪇": { "codepoints": [10887], "characters": "\u2A87" }, + "≨": { "codepoints": [8808], "characters": "\u2268" }, + "⋦": { "codepoints": [8934], "characters": "\u22E6" }, + "⟬": { "codepoints": [10220], "characters": "\u27EC" }, + "⇽": { "codepoints": [8701], "characters": "\u21FD" }, + "⟦": { "codepoints": [10214], "characters": "\u27E6" }, + "⟵": { "codepoints": [10229], "characters": "\u27F5" }, + "⟷": { "codepoints": [10231], "characters": "\u27F7" }, + "⟼": { "codepoints": [10236], "characters": "\u27FC" }, + "⟶": { "codepoints": [10230], "characters": "\u27F6" }, + "↫": { "codepoints": [8619], "characters": "\u21AB" }, + "↬": { "codepoints": [8620], "characters": "\u21AC" }, + "⦅": { "codepoints": [10629], "characters": "\u2985" }, + "𝕝": { "codepoints": [120157], "characters": "\uD835\uDD5D" }, + "⨭": { "codepoints": [10797], "characters": "\u2A2D" }, + "⨴": { "codepoints": [10804], "characters": "\u2A34" }, + "∗": { "codepoints": [8727], "characters": "\u2217" }, + "_": { "codepoints": [95], "characters": "\u005F" }, + "◊": { "codepoints": [9674], "characters": "\u25CA" }, + "◊": { "codepoints": [9674], "characters": "\u25CA" }, + "⧫": { "codepoints": [10731], "characters": "\u29EB" }, + "(": { "codepoints": [40], "characters": "\u0028" }, + "⦓": { "codepoints": [10643], "characters": "\u2993" }, + "⇆": { "codepoints": [8646], "characters": "\u21C6" }, + "⌟": { "codepoints": [8991], "characters": "\u231F" }, + "⇋": { "codepoints": [8651], "characters": "\u21CB" }, + "⥭": { "codepoints": [10605], "characters": "\u296D" }, + "‎": { "codepoints": [8206], "characters": "\u200E" }, + "⊿": { "codepoints": [8895], "characters": "\u22BF" }, + "‹": { "codepoints": [8249], "characters": "\u2039" }, + "𝓁": { "codepoints": [120001], "characters": "\uD835\uDCC1" }, + "↰": { "codepoints": [8624], "characters": "\u21B0" }, + "≲": { "codepoints": [8818], "characters": "\u2272" }, + "⪍": { "codepoints": [10893], "characters": "\u2A8D" }, + "⪏": { "codepoints": [10895], "characters": "\u2A8F" }, + "[": { "codepoints": [91], "characters": "\u005B" }, + "‘": { "codepoints": [8216], "characters": "\u2018" }, + "‚": { "codepoints": [8218], "characters": "\u201A" }, + "ł": { "codepoints": [322], "characters": "\u0142" }, + "<": { "codepoints": [60], "characters": "\u003C" }, + "<": { "codepoints": [60], "characters": "\u003C" }, + "⪦": { "codepoints": [10918], "characters": "\u2AA6" }, + "⩹": { "codepoints": [10873], "characters": "\u2A79" }, + "⋖": { "codepoints": [8918], "characters": "\u22D6" }, + "⋋": { "codepoints": [8907], "characters": "\u22CB" }, + "⋉": { "codepoints": [8905], "characters": "\u22C9" }, + "⥶": { "codepoints": [10614], "characters": "\u2976" }, + "⩻": { "codepoints": [10875], "characters": "\u2A7B" }, + "⦖": { "codepoints": [10646], "characters": "\u2996" }, + "◃": { "codepoints": [9667], "characters": "\u25C3" }, + "⊴": { "codepoints": [8884], "characters": "\u22B4" }, + "◂": { "codepoints": [9666], "characters": "\u25C2" }, + "⥊": { "codepoints": [10570], "characters": "\u294A" }, + "⥦": { "codepoints": [10598], "characters": "\u2966" }, + "≨︀": { "codepoints": [8808, 65024], "characters": "\u2268\uFE00" }, + "≨︀": { "codepoints": [8808, 65024], "characters": "\u2268\uFE00" }, + "∺": { "codepoints": [8762], "characters": "\u223A" }, + "¯": { "codepoints": [175], "characters": "\u00AF" }, + "¯": { "codepoints": [175], "characters": "\u00AF" }, + "♂": { "codepoints": [9794], "characters": "\u2642" }, + "✠": { "codepoints": [10016], "characters": "\u2720" }, + "✠": { "codepoints": [10016], "characters": "\u2720" }, + "↦": { "codepoints": [8614], "characters": "\u21A6" }, + "↦": { "codepoints": [8614], "characters": "\u21A6" }, + "↧": { "codepoints": [8615], "characters": "\u21A7" }, + "↤": { "codepoints": [8612], "characters": "\u21A4" }, + "↥": { "codepoints": [8613], "characters": "\u21A5" }, + "▮": { "codepoints": [9646], "characters": "\u25AE" }, + "⨩": { "codepoints": [10793], "characters": "\u2A29" }, + "м": { "codepoints": [1084], "characters": "\u043C" }, + "—": { "codepoints": [8212], "characters": "\u2014" }, + "∡": { "codepoints": [8737], "characters": "\u2221" }, + "𝔪": { "codepoints": [120106], "characters": "\uD835\uDD2A" }, + "℧": { "codepoints": [8487], "characters": "\u2127" }, + "µ": { "codepoints": [181], "characters": "\u00B5" }, + "µ": { "codepoints": [181], "characters": "\u00B5" }, + "∣": { "codepoints": [8739], "characters": "\u2223" }, + "*": { "codepoints": [42], "characters": "\u002A" }, + "⫰": { "codepoints": [10992], "characters": "\u2AF0" }, + "·": { "codepoints": [183], "characters": "\u00B7" }, + "·": { "codepoints": [183], "characters": "\u00B7" }, + "−": { "codepoints": [8722], "characters": "\u2212" }, + "⊟": { "codepoints": [8863], "characters": "\u229F" }, + "∸": { "codepoints": [8760], "characters": "\u2238" }, + "⨪": { "codepoints": [10794], "characters": "\u2A2A" }, + "⫛": { "codepoints": [10971], "characters": "\u2ADB" }, + "…": { "codepoints": [8230], "characters": "\u2026" }, + "∓": { "codepoints": [8723], "characters": "\u2213" }, + "⊧": { "codepoints": [8871], "characters": "\u22A7" }, + "𝕞": { "codepoints": [120158], "characters": "\uD835\uDD5E" }, + "∓": { "codepoints": [8723], "characters": "\u2213" }, + "𝓂": { "codepoints": [120002], "characters": "\uD835\uDCC2" }, + "∾": { "codepoints": [8766], "characters": "\u223E" }, + "μ": { "codepoints": [956], "characters": "\u03BC" }, + "⊸": { "codepoints": [8888], "characters": "\u22B8" }, + "⊸": { "codepoints": [8888], "characters": "\u22B8" }, + "⋙̸": { "codepoints": [8921, 824], "characters": "\u22D9\u0338" }, + "≫⃒": { "codepoints": [8811, 8402], "characters": "\u226B\u20D2" }, + "≫̸": { "codepoints": [8811, 824], "characters": "\u226B\u0338" }, + "⇍": { "codepoints": [8653], "characters": "\u21CD" }, + "⇎": { "codepoints": [8654], "characters": "\u21CE" }, + "⋘̸": { "codepoints": [8920, 824], "characters": "\u22D8\u0338" }, + "≪⃒": { "codepoints": [8810, 8402], "characters": "\u226A\u20D2" }, + "≪̸": { "codepoints": [8810, 824], "characters": "\u226A\u0338" }, + "⇏": { "codepoints": [8655], "characters": "\u21CF" }, + "⊯": { "codepoints": [8879], "characters": "\u22AF" }, + "⊮": { "codepoints": [8878], "characters": "\u22AE" }, + "∇": { "codepoints": [8711], "characters": "\u2207" }, + "ń": { "codepoints": [324], "characters": "\u0144" }, + "∠⃒": { "codepoints": [8736, 8402], "characters": "\u2220\u20D2" }, + "≉": { "codepoints": [8777], "characters": "\u2249" }, + "⩰̸": { "codepoints": [10864, 824], "characters": "\u2A70\u0338" }, + "≋̸": { "codepoints": [8779, 824], "characters": "\u224B\u0338" }, + "ʼn": { "codepoints": [329], "characters": "\u0149" }, + "≉": { "codepoints": [8777], "characters": "\u2249" }, + "♮": { "codepoints": [9838], "characters": "\u266E" }, + "♮": { "codepoints": [9838], "characters": "\u266E" }, + "ℕ": { "codepoints": [8469], "characters": "\u2115" }, + " ": { "codepoints": [160], "characters": "\u00A0" }, + " ": { "codepoints": [160], "characters": "\u00A0" }, + "≎̸": { "codepoints": [8782, 824], "characters": "\u224E\u0338" }, + "≏̸": { "codepoints": [8783, 824], "characters": "\u224F\u0338" }, + "⩃": { "codepoints": [10819], "characters": "\u2A43" }, + "ň": { "codepoints": [328], "characters": "\u0148" }, + "ņ": { "codepoints": [326], "characters": "\u0146" }, + "≇": { "codepoints": [8775], "characters": "\u2247" }, + "⩭̸": { "codepoints": [10861, 824], "characters": "\u2A6D\u0338" }, + "⩂": { "codepoints": [10818], "characters": "\u2A42" }, + "н": { "codepoints": [1085], "characters": "\u043D" }, + "–": { "codepoints": [8211], "characters": "\u2013" }, + "≠": { "codepoints": [8800], "characters": "\u2260" }, + "⇗": { "codepoints": [8663], "characters": "\u21D7" }, + "⤤": { "codepoints": [10532], "characters": "\u2924" }, + "↗": { "codepoints": [8599], "characters": "\u2197" }, + "↗": { "codepoints": [8599], "characters": "\u2197" }, + "≐̸": { "codepoints": [8784, 824], "characters": "\u2250\u0338" }, + "≢": { "codepoints": [8802], "characters": "\u2262" }, + "⤨": { "codepoints": [10536], "characters": "\u2928" }, + "≂̸": { "codepoints": [8770, 824], "characters": "\u2242\u0338" }, + "∄": { "codepoints": [8708], "characters": "\u2204" }, + "∄": { "codepoints": [8708], "characters": "\u2204" }, + "𝔫": { "codepoints": [120107], "characters": "\uD835\uDD2B" }, + "≧̸": { "codepoints": [8807, 824], "characters": "\u2267\u0338" }, + "≱": { "codepoints": [8817], "characters": "\u2271" }, + "≱": { "codepoints": [8817], "characters": "\u2271" }, + "≧̸": { "codepoints": [8807, 824], "characters": "\u2267\u0338" }, + "⩾̸": { "codepoints": [10878, 824], "characters": "\u2A7E\u0338" }, + "⩾̸": { "codepoints": [10878, 824], "characters": "\u2A7E\u0338" }, + "≵": { "codepoints": [8821], "characters": "\u2275" }, + "≯": { "codepoints": [8815], "characters": "\u226F" }, + "≯": { "codepoints": [8815], "characters": "\u226F" }, + "⇎": { "codepoints": [8654], "characters": "\u21CE" }, + "↮": { "codepoints": [8622], "characters": "\u21AE" }, + "⫲": { "codepoints": [10994], "characters": "\u2AF2" }, + "∋": { "codepoints": [8715], "characters": "\u220B" }, + "⋼": { "codepoints": [8956], "characters": "\u22FC" }, + "⋺": { "codepoints": [8954], "characters": "\u22FA" }, + "∋": { "codepoints": [8715], "characters": "\u220B" }, + "њ": { "codepoints": [1114], "characters": "\u045A" }, + "⇍": { "codepoints": [8653], "characters": "\u21CD" }, + "≦̸": { "codepoints": [8806, 824], "characters": "\u2266\u0338" }, + "↚": { "codepoints": [8602], "characters": "\u219A" }, + "‥": { "codepoints": [8229], "characters": "\u2025" }, + "≰": { "codepoints": [8816], "characters": "\u2270" }, + "↚": { "codepoints": [8602], "characters": "\u219A" }, + "↮": { "codepoints": [8622], "characters": "\u21AE" }, + "≰": { "codepoints": [8816], "characters": "\u2270" }, + "≦̸": { "codepoints": [8806, 824], "characters": "\u2266\u0338" }, + "⩽̸": { "codepoints": [10877, 824], "characters": "\u2A7D\u0338" }, + "⩽̸": { "codepoints": [10877, 824], "characters": "\u2A7D\u0338" }, + "≮": { "codepoints": [8814], "characters": "\u226E" }, + "≴": { "codepoints": [8820], "characters": "\u2274" }, + "≮": { "codepoints": [8814], "characters": "\u226E" }, + "⋪": { "codepoints": [8938], "characters": "\u22EA" }, + "⋬": { "codepoints": [8940], "characters": "\u22EC" }, + "∤": { "codepoints": [8740], "characters": "\u2224" }, + "𝕟": { "codepoints": [120159], "characters": "\uD835\uDD5F" }, + "¬": { "codepoints": [172], "characters": "\u00AC" }, + "¬": { "codepoints": [172], "characters": "\u00AC" }, + "∉": { "codepoints": [8713], "characters": "\u2209" }, + "⋹̸": { "codepoints": [8953, 824], "characters": "\u22F9\u0338" }, + "⋵̸": { "codepoints": [8949, 824], "characters": "\u22F5\u0338" }, + "∉": { "codepoints": [8713], "characters": "\u2209" }, + "⋷": { "codepoints": [8951], "characters": "\u22F7" }, + "⋶": { "codepoints": [8950], "characters": "\u22F6" }, + "∌": { "codepoints": [8716], "characters": "\u220C" }, + "∌": { "codepoints": [8716], "characters": "\u220C" }, + "⋾": { "codepoints": [8958], "characters": "\u22FE" }, + "⋽": { "codepoints": [8957], "characters": "\u22FD" }, + "∦": { "codepoints": [8742], "characters": "\u2226" }, + "∦": { "codepoints": [8742], "characters": "\u2226" }, + "⫽⃥": { "codepoints": [11005, 8421], "characters": "\u2AFD\u20E5" }, + "∂̸": { "codepoints": [8706, 824], "characters": "\u2202\u0338" }, + "⨔": { "codepoints": [10772], "characters": "\u2A14" }, + "⊀": { "codepoints": [8832], "characters": "\u2280" }, + "⋠": { "codepoints": [8928], "characters": "\u22E0" }, + "⪯̸": { "codepoints": [10927, 824], "characters": "\u2AAF\u0338" }, + "⊀": { "codepoints": [8832], "characters": "\u2280" }, + "⪯̸": { "codepoints": [10927, 824], "characters": "\u2AAF\u0338" }, + "⇏": { "codepoints": [8655], "characters": "\u21CF" }, + "↛": { "codepoints": [8603], "characters": "\u219B" }, + "⤳̸": { "codepoints": [10547, 824], "characters": "\u2933\u0338" }, + "↝̸": { "codepoints": [8605, 824], "characters": "\u219D\u0338" }, + "↛": { "codepoints": [8603], "characters": "\u219B" }, + "⋫": { "codepoints": [8939], "characters": "\u22EB" }, + "⋭": { "codepoints": [8941], "characters": "\u22ED" }, + "⊁": { "codepoints": [8833], "characters": "\u2281" }, + "⋡": { "codepoints": [8929], "characters": "\u22E1" }, + "⪰̸": { "codepoints": [10928, 824], "characters": "\u2AB0\u0338" }, + "𝓃": { "codepoints": [120003], "characters": "\uD835\uDCC3" }, + "∤": { "codepoints": [8740], "characters": "\u2224" }, + "∦": { "codepoints": [8742], "characters": "\u2226" }, + "≁": { "codepoints": [8769], "characters": "\u2241" }, + "≄": { "codepoints": [8772], "characters": "\u2244" }, + "≄": { "codepoints": [8772], "characters": "\u2244" }, + "∤": { "codepoints": [8740], "characters": "\u2224" }, + "∦": { "codepoints": [8742], "characters": "\u2226" }, + "⋢": { "codepoints": [8930], "characters": "\u22E2" }, + "⋣": { "codepoints": [8931], "characters": "\u22E3" }, + "⊄": { "codepoints": [8836], "characters": "\u2284" }, + "⫅̸": { "codepoints": [10949, 824], "characters": "\u2AC5\u0338" }, + "⊈": { "codepoints": [8840], "characters": "\u2288" }, + "⊂⃒": { "codepoints": [8834, 8402], "characters": "\u2282\u20D2" }, + "⊈": { "codepoints": [8840], "characters": "\u2288" }, + "⫅̸": { "codepoints": [10949, 824], "characters": "\u2AC5\u0338" }, + "⊁": { "codepoints": [8833], "characters": "\u2281" }, + "⪰̸": { "codepoints": [10928, 824], "characters": "\u2AB0\u0338" }, + "⊅": { "codepoints": [8837], "characters": "\u2285" }, + "⫆̸": { "codepoints": [10950, 824], "characters": "\u2AC6\u0338" }, + "⊉": { "codepoints": [8841], "characters": "\u2289" }, + "⊃⃒": { "codepoints": [8835, 8402], "characters": "\u2283\u20D2" }, + "⊉": { "codepoints": [8841], "characters": "\u2289" }, + "⫆̸": { "codepoints": [10950, 824], "characters": "\u2AC6\u0338" }, + "≹": { "codepoints": [8825], "characters": "\u2279" }, + "ñ": { "codepoints": [241], "characters": "\u00F1" }, + "ñ": { "codepoints": [241], "characters": "\u00F1" }, + "≸": { "codepoints": [8824], "characters": "\u2278" }, + "⋪": { "codepoints": [8938], "characters": "\u22EA" }, + "⋬": { "codepoints": [8940], "characters": "\u22EC" }, + "⋫": { "codepoints": [8939], "characters": "\u22EB" }, + "⋭": { "codepoints": [8941], "characters": "\u22ED" }, + "ν": { "codepoints": [957], "characters": "\u03BD" }, + "#": { "codepoints": [35], "characters": "\u0023" }, + "№": { "codepoints": [8470], "characters": "\u2116" }, + " ": { "codepoints": [8199], "characters": "\u2007" }, + "⊭": { "codepoints": [8877], "characters": "\u22AD" }, + "⤄": { "codepoints": [10500], "characters": "\u2904" }, + "≍⃒": { "codepoints": [8781, 8402], "characters": "\u224D\u20D2" }, + "⊬": { "codepoints": [8876], "characters": "\u22AC" }, + "≥⃒": { "codepoints": [8805, 8402], "characters": "\u2265\u20D2" }, + ">⃒": { "codepoints": [62, 8402], "characters": "\u003E\u20D2" }, + "⧞": { "codepoints": [10718], "characters": "\u29DE" }, + "⤂": { "codepoints": [10498], "characters": "\u2902" }, + "≤⃒": { "codepoints": [8804, 8402], "characters": "\u2264\u20D2" }, + "<⃒": { "codepoints": [60, 8402], "characters": "\u003C\u20D2" }, + "⊴⃒": { "codepoints": [8884, 8402], "characters": "\u22B4\u20D2" }, + "⤃": { "codepoints": [10499], "characters": "\u2903" }, + "⊵⃒": { "codepoints": [8885, 8402], "characters": "\u22B5\u20D2" }, + "∼⃒": { "codepoints": [8764, 8402], "characters": "\u223C\u20D2" }, + "⇖": { "codepoints": [8662], "characters": "\u21D6" }, + "⤣": { "codepoints": [10531], "characters": "\u2923" }, + "↖": { "codepoints": [8598], "characters": "\u2196" }, + "↖": { "codepoints": [8598], "characters": "\u2196" }, + "⤧": { "codepoints": [10535], "characters": "\u2927" }, + "Ⓢ": { "codepoints": [9416], "characters": "\u24C8" }, + "ó": { "codepoints": [243], "characters": "\u00F3" }, + "ó": { "codepoints": [243], "characters": "\u00F3" }, + "⊛": { "codepoints": [8859], "characters": "\u229B" }, + "⊚": { "codepoints": [8858], "characters": "\u229A" }, + "ô": { "codepoints": [244], "characters": "\u00F4" }, + "ô": { "codepoints": [244], "characters": "\u00F4" }, + "о": { "codepoints": [1086], "characters": "\u043E" }, + "⊝": { "codepoints": [8861], "characters": "\u229D" }, + "ő": { "codepoints": [337], "characters": "\u0151" }, + "⨸": { "codepoints": [10808], "characters": "\u2A38" }, + "⊙": { "codepoints": [8857], "characters": "\u2299" }, + "⦼": { "codepoints": [10684], "characters": "\u29BC" }, + "œ": { "codepoints": [339], "characters": "\u0153" }, + "⦿": { "codepoints": [10687], "characters": "\u29BF" }, + "𝔬": { "codepoints": [120108], "characters": "\uD835\uDD2C" }, + "˛": { "codepoints": [731], "characters": "\u02DB" }, + "ò": { "codepoints": [242], "characters": "\u00F2" }, + "ò": { "codepoints": [242], "characters": "\u00F2" }, + "⧁": { "codepoints": [10689], "characters": "\u29C1" }, + "⦵": { "codepoints": [10677], "characters": "\u29B5" }, + "Ω": { "codepoints": [937], "characters": "\u03A9" }, + "∮": { "codepoints": [8750], "characters": "\u222E" }, + "↺": { "codepoints": [8634], "characters": "\u21BA" }, + "⦾": { "codepoints": [10686], "characters": "\u29BE" }, + "⦻": { "codepoints": [10683], "characters": "\u29BB" }, + "‾": { "codepoints": [8254], "characters": "\u203E" }, + "⧀": { "codepoints": [10688], "characters": "\u29C0" }, + "ō": { "codepoints": [333], "characters": "\u014D" }, + "ω": { "codepoints": [969], "characters": "\u03C9" }, + "ο": { "codepoints": [959], "characters": "\u03BF" }, + "⦶": { "codepoints": [10678], "characters": "\u29B6" }, + "⊖": { "codepoints": [8854], "characters": "\u2296" }, + "𝕠": { "codepoints": [120160], "characters": "\uD835\uDD60" }, + "⦷": { "codepoints": [10679], "characters": "\u29B7" }, + "⦹": { "codepoints": [10681], "characters": "\u29B9" }, + "⊕": { "codepoints": [8853], "characters": "\u2295" }, + "∨": { "codepoints": [8744], "characters": "\u2228" }, + "↻": { "codepoints": [8635], "characters": "\u21BB" }, + "⩝": { "codepoints": [10845], "characters": "\u2A5D" }, + "ℴ": { "codepoints": [8500], "characters": "\u2134" }, + "ℴ": { "codepoints": [8500], "characters": "\u2134" }, + "ª": { "codepoints": [170], "characters": "\u00AA" }, + "ª": { "codepoints": [170], "characters": "\u00AA" }, + "º": { "codepoints": [186], "characters": "\u00BA" }, + "º": { "codepoints": [186], "characters": "\u00BA" }, + "⊶": { "codepoints": [8886], "characters": "\u22B6" }, + "⩖": { "codepoints": [10838], "characters": "\u2A56" }, + "⩗": { "codepoints": [10839], "characters": "\u2A57" }, + "⩛": { "codepoints": [10843], "characters": "\u2A5B" }, + "ℴ": { "codepoints": [8500], "characters": "\u2134" }, + "ø": { "codepoints": [248], "characters": "\u00F8" }, + "ø": { "codepoints": [248], "characters": "\u00F8" }, + "⊘": { "codepoints": [8856], "characters": "\u2298" }, + "õ": { "codepoints": [245], "characters": "\u00F5" }, + "õ": { "codepoints": [245], "characters": "\u00F5" }, + "⊗": { "codepoints": [8855], "characters": "\u2297" }, + "⨶": { "codepoints": [10806], "characters": "\u2A36" }, + "ö": { "codepoints": [246], "characters": "\u00F6" }, + "ö": { "codepoints": [246], "characters": "\u00F6" }, + "⌽": { "codepoints": [9021], "characters": "\u233D" }, + "∥": { "codepoints": [8741], "characters": "\u2225" }, + "¶": { "codepoints": [182], "characters": "\u00B6" }, + "¶": { "codepoints": [182], "characters": "\u00B6" }, + "∥": { "codepoints": [8741], "characters": "\u2225" }, + "⫳": { "codepoints": [10995], "characters": "\u2AF3" }, + "⫽": { "codepoints": [11005], "characters": "\u2AFD" }, + "∂": { "codepoints": [8706], "characters": "\u2202" }, + "п": { "codepoints": [1087], "characters": "\u043F" }, + "%": { "codepoints": [37], "characters": "\u0025" }, + ".": { "codepoints": [46], "characters": "\u002E" }, + "‰": { "codepoints": [8240], "characters": "\u2030" }, + "⊥": { "codepoints": [8869], "characters": "\u22A5" }, + "‱": { "codepoints": [8241], "characters": "\u2031" }, + "𝔭": { "codepoints": [120109], "characters": "\uD835\uDD2D" }, + "φ": { "codepoints": [966], "characters": "\u03C6" }, + "ϕ": { "codepoints": [981], "characters": "\u03D5" }, + "ℳ": { "codepoints": [8499], "characters": "\u2133" }, + "☎": { "codepoints": [9742], "characters": "\u260E" }, + "π": { "codepoints": [960], "characters": "\u03C0" }, + "⋔": { "codepoints": [8916], "characters": "\u22D4" }, + "ϖ": { "codepoints": [982], "characters": "\u03D6" }, + "ℏ": { "codepoints": [8463], "characters": "\u210F" }, + "ℎ": { "codepoints": [8462], "characters": "\u210E" }, + "ℏ": { "codepoints": [8463], "characters": "\u210F" }, + "+": { "codepoints": [43], "characters": "\u002B" }, + "⨣": { "codepoints": [10787], "characters": "\u2A23" }, + "⊞": { "codepoints": [8862], "characters": "\u229E" }, + "⨢": { "codepoints": [10786], "characters": "\u2A22" }, + "∔": { "codepoints": [8724], "characters": "\u2214" }, + "⨥": { "codepoints": [10789], "characters": "\u2A25" }, + "⩲": { "codepoints": [10866], "characters": "\u2A72" }, + "±": { "codepoints": [177], "characters": "\u00B1" }, + "±": { "codepoints": [177], "characters": "\u00B1" }, + "⨦": { "codepoints": [10790], "characters": "\u2A26" }, + "⨧": { "codepoints": [10791], "characters": "\u2A27" }, + "±": { "codepoints": [177], "characters": "\u00B1" }, + "⨕": { "codepoints": [10773], "characters": "\u2A15" }, + "𝕡": { "codepoints": [120161], "characters": "\uD835\uDD61" }, + "£": { "codepoints": [163], "characters": "\u00A3" }, + "£": { "codepoints": [163], "characters": "\u00A3" }, + "≺": { "codepoints": [8826], "characters": "\u227A" }, + "⪳": { "codepoints": [10931], "characters": "\u2AB3" }, + "⪷": { "codepoints": [10935], "characters": "\u2AB7" }, + "≼": { "codepoints": [8828], "characters": "\u227C" }, + "⪯": { "codepoints": [10927], "characters": "\u2AAF" }, + "≺": { "codepoints": [8826], "characters": "\u227A" }, + "⪷": { "codepoints": [10935], "characters": "\u2AB7" }, + "≼": { "codepoints": [8828], "characters": "\u227C" }, + "⪯": { "codepoints": [10927], "characters": "\u2AAF" }, + "⪹": { "codepoints": [10937], "characters": "\u2AB9" }, + "⪵": { "codepoints": [10933], "characters": "\u2AB5" }, + "⋨": { "codepoints": [8936], "characters": "\u22E8" }, + "≾": { "codepoints": [8830], "characters": "\u227E" }, + "′": { "codepoints": [8242], "characters": "\u2032" }, + "ℙ": { "codepoints": [8473], "characters": "\u2119" }, + "⪵": { "codepoints": [10933], "characters": "\u2AB5" }, + "⪹": { "codepoints": [10937], "characters": "\u2AB9" }, + "⋨": { "codepoints": [8936], "characters": "\u22E8" }, + "∏": { "codepoints": [8719], "characters": "\u220F" }, + "⌮": { "codepoints": [9006], "characters": "\u232E" }, + "⌒": { "codepoints": [8978], "characters": "\u2312" }, + "⌓": { "codepoints": [8979], "characters": "\u2313" }, + "∝": { "codepoints": [8733], "characters": "\u221D" }, + "∝": { "codepoints": [8733], "characters": "\u221D" }, + "≾": { "codepoints": [8830], "characters": "\u227E" }, + "⊰": { "codepoints": [8880], "characters": "\u22B0" }, + "𝓅": { "codepoints": [120005], "characters": "\uD835\uDCC5" }, + "ψ": { "codepoints": [968], "characters": "\u03C8" }, + " ": { "codepoints": [8200], "characters": "\u2008" }, + "𝔮": { "codepoints": [120110], "characters": "\uD835\uDD2E" }, + "⨌": { "codepoints": [10764], "characters": "\u2A0C" }, + "𝕢": { "codepoints": [120162], "characters": "\uD835\uDD62" }, + "⁗": { "codepoints": [8279], "characters": "\u2057" }, + "𝓆": { "codepoints": [120006], "characters": "\uD835\uDCC6" }, + "ℍ": { "codepoints": [8461], "characters": "\u210D" }, + "⨖": { "codepoints": [10774], "characters": "\u2A16" }, + "?": { "codepoints": [63], "characters": "\u003F" }, + "≟": { "codepoints": [8799], "characters": "\u225F" }, + """: { "codepoints": [34], "characters": "\u0022" }, + """: { "codepoints": [34], "characters": "\u0022" }, + "⇛": { "codepoints": [8667], "characters": "\u21DB" }, + "⇒": { "codepoints": [8658], "characters": "\u21D2" }, + "⤜": { "codepoints": [10524], "characters": "\u291C" }, + "⤏": { "codepoints": [10511], "characters": "\u290F" }, + "⥤": { "codepoints": [10596], "characters": "\u2964" }, + "∽̱": { "codepoints": [8765, 817], "characters": "\u223D\u0331" }, + "ŕ": { "codepoints": [341], "characters": "\u0155" }, + "√": { "codepoints": [8730], "characters": "\u221A" }, + "⦳": { "codepoints": [10675], "characters": "\u29B3" }, + "⟩": { "codepoints": [10217], "characters": "\u27E9" }, + "⦒": { "codepoints": [10642], "characters": "\u2992" }, + "⦥": { "codepoints": [10661], "characters": "\u29A5" }, + "⟩": { "codepoints": [10217], "characters": "\u27E9" }, + "»": { "codepoints": [187], "characters": "\u00BB" }, + "»": { "codepoints": [187], "characters": "\u00BB" }, + "→": { "codepoints": [8594], "characters": "\u2192" }, + "⥵": { "codepoints": [10613], "characters": "\u2975" }, + "⇥": { "codepoints": [8677], "characters": "\u21E5" }, + "⤠": { "codepoints": [10528], "characters": "\u2920" }, + "⤳": { "codepoints": [10547], "characters": "\u2933" }, + "⤞": { "codepoints": [10526], "characters": "\u291E" }, + "↪": { "codepoints": [8618], "characters": "\u21AA" }, + "↬": { "codepoints": [8620], "characters": "\u21AC" }, + "⥅": { "codepoints": [10565], "characters": "\u2945" }, + "⥴": { "codepoints": [10612], "characters": "\u2974" }, + "↣": { "codepoints": [8611], "characters": "\u21A3" }, + "↝": { "codepoints": [8605], "characters": "\u219D" }, + "⤚": { "codepoints": [10522], "characters": "\u291A" }, + "∶": { "codepoints": [8758], "characters": "\u2236" }, + "ℚ": { "codepoints": [8474], "characters": "\u211A" }, + "⤍": { "codepoints": [10509], "characters": "\u290D" }, + "❳": { "codepoints": [10099], "characters": "\u2773" }, + "}": { "codepoints": [125], "characters": "\u007D" }, + "]": { "codepoints": [93], "characters": "\u005D" }, + "⦌": { "codepoints": [10636], "characters": "\u298C" }, + "⦎": { "codepoints": [10638], "characters": "\u298E" }, + "⦐": { "codepoints": [10640], "characters": "\u2990" }, + "ř": { "codepoints": [345], "characters": "\u0159" }, + "ŗ": { "codepoints": [343], "characters": "\u0157" }, + "⌉": { "codepoints": [8969], "characters": "\u2309" }, + "}": { "codepoints": [125], "characters": "\u007D" }, + "р": { "codepoints": [1088], "characters": "\u0440" }, + "⤷": { "codepoints": [10551], "characters": "\u2937" }, + "⥩": { "codepoints": [10601], "characters": "\u2969" }, + "”": { "codepoints": [8221], "characters": "\u201D" }, + "”": { "codepoints": [8221], "characters": "\u201D" }, + "↳": { "codepoints": [8627], "characters": "\u21B3" }, + "ℜ": { "codepoints": [8476], "characters": "\u211C" }, + "ℛ": { "codepoints": [8475], "characters": "\u211B" }, + "ℜ": { "codepoints": [8476], "characters": "\u211C" }, + "ℝ": { "codepoints": [8477], "characters": "\u211D" }, + "▭": { "codepoints": [9645], "characters": "\u25AD" }, + "®": { "codepoints": [174], "characters": "\u00AE" }, + "®": { "codepoints": [174], "characters": "\u00AE" }, + "⥽": { "codepoints": [10621], "characters": "\u297D" }, + "⌋": { "codepoints": [8971], "characters": "\u230B" }, + "𝔯": { "codepoints": [120111], "characters": "\uD835\uDD2F" }, + "⇁": { "codepoints": [8641], "characters": "\u21C1" }, + "⇀": { "codepoints": [8640], "characters": "\u21C0" }, + "⥬": { "codepoints": [10604], "characters": "\u296C" }, + "ρ": { "codepoints": [961], "characters": "\u03C1" }, + "ϱ": { "codepoints": [1009], "characters": "\u03F1" }, + "→": { "codepoints": [8594], "characters": "\u2192" }, + "↣": { "codepoints": [8611], "characters": "\u21A3" }, + "⇁": { "codepoints": [8641], "characters": "\u21C1" }, + "⇀": { "codepoints": [8640], "characters": "\u21C0" }, + "⇄": { "codepoints": [8644], "characters": "\u21C4" }, + "⇌": { "codepoints": [8652], "characters": "\u21CC" }, + "⇉": { "codepoints": [8649], "characters": "\u21C9" }, + "↝": { "codepoints": [8605], "characters": "\u219D" }, + "⋌": { "codepoints": [8908], "characters": "\u22CC" }, + "˚": { "codepoints": [730], "characters": "\u02DA" }, + "≓": { "codepoints": [8787], "characters": "\u2253" }, + "⇄": { "codepoints": [8644], "characters": "\u21C4" }, + "⇌": { "codepoints": [8652], "characters": "\u21CC" }, + "‏": { "codepoints": [8207], "characters": "\u200F" }, + "⎱": { "codepoints": [9137], "characters": "\u23B1" }, + "⎱": { "codepoints": [9137], "characters": "\u23B1" }, + "⫮": { "codepoints": [10990], "characters": "\u2AEE" }, + "⟭": { "codepoints": [10221], "characters": "\u27ED" }, + "⇾": { "codepoints": [8702], "characters": "\u21FE" }, + "⟧": { "codepoints": [10215], "characters": "\u27E7" }, + "⦆": { "codepoints": [10630], "characters": "\u2986" }, + "𝕣": { "codepoints": [120163], "characters": "\uD835\uDD63" }, + "⨮": { "codepoints": [10798], "characters": "\u2A2E" }, + "⨵": { "codepoints": [10805], "characters": "\u2A35" }, + ")": { "codepoints": [41], "characters": "\u0029" }, + "⦔": { "codepoints": [10644], "characters": "\u2994" }, + "⨒": { "codepoints": [10770], "characters": "\u2A12" }, + "⇉": { "codepoints": [8649], "characters": "\u21C9" }, + "›": { "codepoints": [8250], "characters": "\u203A" }, + "𝓇": { "codepoints": [120007], "characters": "\uD835\uDCC7" }, + "↱": { "codepoints": [8625], "characters": "\u21B1" }, + "]": { "codepoints": [93], "characters": "\u005D" }, + "’": { "codepoints": [8217], "characters": "\u2019" }, + "’": { "codepoints": [8217], "characters": "\u2019" }, + "⋌": { "codepoints": [8908], "characters": "\u22CC" }, + "⋊": { "codepoints": [8906], "characters": "\u22CA" }, + "▹": { "codepoints": [9657], "characters": "\u25B9" }, + "⊵": { "codepoints": [8885], "characters": "\u22B5" }, + "▸": { "codepoints": [9656], "characters": "\u25B8" }, + "⧎": { "codepoints": [10702], "characters": "\u29CE" }, + "⥨": { "codepoints": [10600], "characters": "\u2968" }, + "℞": { "codepoints": [8478], "characters": "\u211E" }, + "ś": { "codepoints": [347], "characters": "\u015B" }, + "‚": { "codepoints": [8218], "characters": "\u201A" }, + "≻": { "codepoints": [8827], "characters": "\u227B" }, + "⪴": { "codepoints": [10932], "characters": "\u2AB4" }, + "⪸": { "codepoints": [10936], "characters": "\u2AB8" }, + "š": { "codepoints": [353], "characters": "\u0161" }, + "≽": { "codepoints": [8829], "characters": "\u227D" }, + "⪰": { "codepoints": [10928], "characters": "\u2AB0" }, + "ş": { "codepoints": [351], "characters": "\u015F" }, + "ŝ": { "codepoints": [349], "characters": "\u015D" }, + "⪶": { "codepoints": [10934], "characters": "\u2AB6" }, + "⪺": { "codepoints": [10938], "characters": "\u2ABA" }, + "⋩": { "codepoints": [8937], "characters": "\u22E9" }, + "⨓": { "codepoints": [10771], "characters": "\u2A13" }, + "≿": { "codepoints": [8831], "characters": "\u227F" }, + "с": { "codepoints": [1089], "characters": "\u0441" }, + "⋅": { "codepoints": [8901], "characters": "\u22C5" }, + "⊡": { "codepoints": [8865], "characters": "\u22A1" }, + "⩦": { "codepoints": [10854], "characters": "\u2A66" }, + "⇘": { "codepoints": [8664], "characters": "\u21D8" }, + "⤥": { "codepoints": [10533], "characters": "\u2925" }, + "↘": { "codepoints": [8600], "characters": "\u2198" }, + "↘": { "codepoints": [8600], "characters": "\u2198" }, + "§": { "codepoints": [167], "characters": "\u00A7" }, + "§": { "codepoints": [167], "characters": "\u00A7" }, + ";": { "codepoints": [59], "characters": "\u003B" }, + "⤩": { "codepoints": [10537], "characters": "\u2929" }, + "∖": { "codepoints": [8726], "characters": "\u2216" }, + "∖": { "codepoints": [8726], "characters": "\u2216" }, + "✶": { "codepoints": [10038], "characters": "\u2736" }, + "𝔰": { "codepoints": [120112], "characters": "\uD835\uDD30" }, + "⌢": { "codepoints": [8994], "characters": "\u2322" }, + "♯": { "codepoints": [9839], "characters": "\u266F" }, + "щ": { "codepoints": [1097], "characters": "\u0449" }, + "ш": { "codepoints": [1096], "characters": "\u0448" }, + "∣": { "codepoints": [8739], "characters": "\u2223" }, + "∥": { "codepoints": [8741], "characters": "\u2225" }, + "­": { "codepoints": [173], "characters": "\u00AD" }, + "­": { "codepoints": [173], "characters": "\u00AD" }, + "σ": { "codepoints": [963], "characters": "\u03C3" }, + "ς": { "codepoints": [962], "characters": "\u03C2" }, + "ς": { "codepoints": [962], "characters": "\u03C2" }, + "∼": { "codepoints": [8764], "characters": "\u223C" }, + "⩪": { "codepoints": [10858], "characters": "\u2A6A" }, + "≃": { "codepoints": [8771], "characters": "\u2243" }, + "≃": { "codepoints": [8771], "characters": "\u2243" }, + "⪞": { "codepoints": [10910], "characters": "\u2A9E" }, + "⪠": { "codepoints": [10912], "characters": "\u2AA0" }, + "⪝": { "codepoints": [10909], "characters": "\u2A9D" }, + "⪟": { "codepoints": [10911], "characters": "\u2A9F" }, + "≆": { "codepoints": [8774], "characters": "\u2246" }, + "⨤": { "codepoints": [10788], "characters": "\u2A24" }, + "⥲": { "codepoints": [10610], "characters": "\u2972" }, + "←": { "codepoints": [8592], "characters": "\u2190" }, + "∖": { "codepoints": [8726], "characters": "\u2216" }, + "⨳": { "codepoints": [10803], "characters": "\u2A33" }, + "⧤": { "codepoints": [10724], "characters": "\u29E4" }, + "∣": { "codepoints": [8739], "characters": "\u2223" }, + "⌣": { "codepoints": [8995], "characters": "\u2323" }, + "⪪": { "codepoints": [10922], "characters": "\u2AAA" }, + "⪬": { "codepoints": [10924], "characters": "\u2AAC" }, + "⪬︀": { "codepoints": [10924, 65024], "characters": "\u2AAC\uFE00" }, + "ь": { "codepoints": [1100], "characters": "\u044C" }, + "/": { "codepoints": [47], "characters": "\u002F" }, + "⧄": { "codepoints": [10692], "characters": "\u29C4" }, + "⌿": { "codepoints": [9023], "characters": "\u233F" }, + "𝕤": { "codepoints": [120164], "characters": "\uD835\uDD64" }, + "♠": { "codepoints": [9824], "characters": "\u2660" }, + "♠": { "codepoints": [9824], "characters": "\u2660" }, + "∥": { "codepoints": [8741], "characters": "\u2225" }, + "⊓": { "codepoints": [8851], "characters": "\u2293" }, + "⊓︀": { "codepoints": [8851, 65024], "characters": "\u2293\uFE00" }, + "⊔": { "codepoints": [8852], "characters": "\u2294" }, + "⊔︀": { "codepoints": [8852, 65024], "characters": "\u2294\uFE00" }, + "⊏": { "codepoints": [8847], "characters": "\u228F" }, + "⊑": { "codepoints": [8849], "characters": "\u2291" }, + "⊏": { "codepoints": [8847], "characters": "\u228F" }, + "⊑": { "codepoints": [8849], "characters": "\u2291" }, + "⊐": { "codepoints": [8848], "characters": "\u2290" }, + "⊒": { "codepoints": [8850], "characters": "\u2292" }, + "⊐": { "codepoints": [8848], "characters": "\u2290" }, + "⊒": { "codepoints": [8850], "characters": "\u2292" }, + "□": { "codepoints": [9633], "characters": "\u25A1" }, + "□": { "codepoints": [9633], "characters": "\u25A1" }, + "▪": { "codepoints": [9642], "characters": "\u25AA" }, + "▪": { "codepoints": [9642], "characters": "\u25AA" }, + "→": { "codepoints": [8594], "characters": "\u2192" }, + "𝓈": { "codepoints": [120008], "characters": "\uD835\uDCC8" }, + "∖": { "codepoints": [8726], "characters": "\u2216" }, + "⌣": { "codepoints": [8995], "characters": "\u2323" }, + "⋆": { "codepoints": [8902], "characters": "\u22C6" }, + "☆": { "codepoints": [9734], "characters": "\u2606" }, + "★": { "codepoints": [9733], "characters": "\u2605" }, + "ϵ": { "codepoints": [1013], "characters": "\u03F5" }, + "ϕ": { "codepoints": [981], "characters": "\u03D5" }, + "¯": { "codepoints": [175], "characters": "\u00AF" }, + "⊂": { "codepoints": [8834], "characters": "\u2282" }, + "⫅": { "codepoints": [10949], "characters": "\u2AC5" }, + "⪽": { "codepoints": [10941], "characters": "\u2ABD" }, + "⊆": { "codepoints": [8838], "characters": "\u2286" }, + "⫃": { "codepoints": [10947], "characters": "\u2AC3" }, + "⫁": { "codepoints": [10945], "characters": "\u2AC1" }, + "⫋": { "codepoints": [10955], "characters": "\u2ACB" }, + "⊊": { "codepoints": [8842], "characters": "\u228A" }, + "⪿": { "codepoints": [10943], "characters": "\u2ABF" }, + "⥹": { "codepoints": [10617], "characters": "\u2979" }, + "⊂": { "codepoints": [8834], "characters": "\u2282" }, + "⊆": { "codepoints": [8838], "characters": "\u2286" }, + "⫅": { "codepoints": [10949], "characters": "\u2AC5" }, + "⊊": { "codepoints": [8842], "characters": "\u228A" }, + "⫋": { "codepoints": [10955], "characters": "\u2ACB" }, + "⫇": { "codepoints": [10951], "characters": "\u2AC7" }, + "⫕": { "codepoints": [10965], "characters": "\u2AD5" }, + "⫓": { "codepoints": [10963], "characters": "\u2AD3" }, + "≻": { "codepoints": [8827], "characters": "\u227B" }, + "⪸": { "codepoints": [10936], "characters": "\u2AB8" }, + "≽": { "codepoints": [8829], "characters": "\u227D" }, + "⪰": { "codepoints": [10928], "characters": "\u2AB0" }, + "⪺": { "codepoints": [10938], "characters": "\u2ABA" }, + "⪶": { "codepoints": [10934], "characters": "\u2AB6" }, + "⋩": { "codepoints": [8937], "characters": "\u22E9" }, + "≿": { "codepoints": [8831], "characters": "\u227F" }, + "∑": { "codepoints": [8721], "characters": "\u2211" }, + "♪": { "codepoints": [9834], "characters": "\u266A" }, + "¹": { "codepoints": [185], "characters": "\u00B9" }, + "¹": { "codepoints": [185], "characters": "\u00B9" }, + "²": { "codepoints": [178], "characters": "\u00B2" }, + "²": { "codepoints": [178], "characters": "\u00B2" }, + "³": { "codepoints": [179], "characters": "\u00B3" }, + "³": { "codepoints": [179], "characters": "\u00B3" }, + "⊃": { "codepoints": [8835], "characters": "\u2283" }, + "⫆": { "codepoints": [10950], "characters": "\u2AC6" }, + "⪾": { "codepoints": [10942], "characters": "\u2ABE" }, + "⫘": { "codepoints": [10968], "characters": "\u2AD8" }, + "⊇": { "codepoints": [8839], "characters": "\u2287" }, + "⫄": { "codepoints": [10948], "characters": "\u2AC4" }, + "⟉": { "codepoints": [10185], "characters": "\u27C9" }, + "⫗": { "codepoints": [10967], "characters": "\u2AD7" }, + "⥻": { "codepoints": [10619], "characters": "\u297B" }, + "⫂": { "codepoints": [10946], "characters": "\u2AC2" }, + "⫌": { "codepoints": [10956], "characters": "\u2ACC" }, + "⊋": { "codepoints": [8843], "characters": "\u228B" }, + "⫀": { "codepoints": [10944], "characters": "\u2AC0" }, + "⊃": { "codepoints": [8835], "characters": "\u2283" }, + "⊇": { "codepoints": [8839], "characters": "\u2287" }, + "⫆": { "codepoints": [10950], "characters": "\u2AC6" }, + "⊋": { "codepoints": [8843], "characters": "\u228B" }, + "⫌": { "codepoints": [10956], "characters": "\u2ACC" }, + "⫈": { "codepoints": [10952], "characters": "\u2AC8" }, + "⫔": { "codepoints": [10964], "characters": "\u2AD4" }, + "⫖": { "codepoints": [10966], "characters": "\u2AD6" }, + "⇙": { "codepoints": [8665], "characters": "\u21D9" }, + "⤦": { "codepoints": [10534], "characters": "\u2926" }, + "↙": { "codepoints": [8601], "characters": "\u2199" }, + "↙": { "codepoints": [8601], "characters": "\u2199" }, + "⤪": { "codepoints": [10538], "characters": "\u292A" }, + "ß": { "codepoints": [223], "characters": "\u00DF" }, + "ß": { "codepoints": [223], "characters": "\u00DF" }, + "⌖": { "codepoints": [8982], "characters": "\u2316" }, + "τ": { "codepoints": [964], "characters": "\u03C4" }, + "⎴": { "codepoints": [9140], "characters": "\u23B4" }, + "ť": { "codepoints": [357], "characters": "\u0165" }, + "ţ": { "codepoints": [355], "characters": "\u0163" }, + "т": { "codepoints": [1090], "characters": "\u0442" }, + "⃛": { "codepoints": [8411], "characters": "\u20DB" }, + "⌕": { "codepoints": [8981], "characters": "\u2315" }, + "𝔱": { "codepoints": [120113], "characters": "\uD835\uDD31" }, + "∴": { "codepoints": [8756], "characters": "\u2234" }, + "∴": { "codepoints": [8756], "characters": "\u2234" }, + "θ": { "codepoints": [952], "characters": "\u03B8" }, + "ϑ": { "codepoints": [977], "characters": "\u03D1" }, + "ϑ": { "codepoints": [977], "characters": "\u03D1" }, + "≈": { "codepoints": [8776], "characters": "\u2248" }, + "∼": { "codepoints": [8764], "characters": "\u223C" }, + " ": { "codepoints": [8201], "characters": "\u2009" }, + "≈": { "codepoints": [8776], "characters": "\u2248" }, + "∼": { "codepoints": [8764], "characters": "\u223C" }, + "þ": { "codepoints": [254], "characters": "\u00FE" }, + "þ": { "codepoints": [254], "characters": "\u00FE" }, + "˜": { "codepoints": [732], "characters": "\u02DC" }, + "×": { "codepoints": [215], "characters": "\u00D7" }, + "×": { "codepoints": [215], "characters": "\u00D7" }, + "⊠": { "codepoints": [8864], "characters": "\u22A0" }, + "⨱": { "codepoints": [10801], "characters": "\u2A31" }, + "⨰": { "codepoints": [10800], "characters": "\u2A30" }, + "∭": { "codepoints": [8749], "characters": "\u222D" }, + "⤨": { "codepoints": [10536], "characters": "\u2928" }, + "⊤": { "codepoints": [8868], "characters": "\u22A4" }, + "⌶": { "codepoints": [9014], "characters": "\u2336" }, + "⫱": { "codepoints": [10993], "characters": "\u2AF1" }, + "𝕥": { "codepoints": [120165], "characters": "\uD835\uDD65" }, + "⫚": { "codepoints": [10970], "characters": "\u2ADA" }, + "⤩": { "codepoints": [10537], "characters": "\u2929" }, + "‴": { "codepoints": [8244], "characters": "\u2034" }, + "™": { "codepoints": [8482], "characters": "\u2122" }, + "▵": { "codepoints": [9653], "characters": "\u25B5" }, + "▿": { "codepoints": [9663], "characters": "\u25BF" }, + "◃": { "codepoints": [9667], "characters": "\u25C3" }, + "⊴": { "codepoints": [8884], "characters": "\u22B4" }, + "≜": { "codepoints": [8796], "characters": "\u225C" }, + "▹": { "codepoints": [9657], "characters": "\u25B9" }, + "⊵": { "codepoints": [8885], "characters": "\u22B5" }, + "◬": { "codepoints": [9708], "characters": "\u25EC" }, + "≜": { "codepoints": [8796], "characters": "\u225C" }, + "⨺": { "codepoints": [10810], "characters": "\u2A3A" }, + "⨹": { "codepoints": [10809], "characters": "\u2A39" }, + "⧍": { "codepoints": [10701], "characters": "\u29CD" }, + "⨻": { "codepoints": [10811], "characters": "\u2A3B" }, + "⏢": { "codepoints": [9186], "characters": "\u23E2" }, + "𝓉": { "codepoints": [120009], "characters": "\uD835\uDCC9" }, + "ц": { "codepoints": [1094], "characters": "\u0446" }, + "ћ": { "codepoints": [1115], "characters": "\u045B" }, + "ŧ": { "codepoints": [359], "characters": "\u0167" }, + "≬": { "codepoints": [8812], "characters": "\u226C" }, + "↞": { "codepoints": [8606], "characters": "\u219E" }, + "↠": { "codepoints": [8608], "characters": "\u21A0" }, + "⇑": { "codepoints": [8657], "characters": "\u21D1" }, + "⥣": { "codepoints": [10595], "characters": "\u2963" }, + "ú": { "codepoints": [250], "characters": "\u00FA" }, + "ú": { "codepoints": [250], "characters": "\u00FA" }, + "↑": { "codepoints": [8593], "characters": "\u2191" }, + "ў": { "codepoints": [1118], "characters": "\u045E" }, + "ŭ": { "codepoints": [365], "characters": "\u016D" }, + "û": { "codepoints": [251], "characters": "\u00FB" }, + "û": { "codepoints": [251], "characters": "\u00FB" }, + "у": { "codepoints": [1091], "characters": "\u0443" }, + "⇅": { "codepoints": [8645], "characters": "\u21C5" }, + "ű": { "codepoints": [369], "characters": "\u0171" }, + "⥮": { "codepoints": [10606], "characters": "\u296E" }, + "⥾": { "codepoints": [10622], "characters": "\u297E" }, + "𝔲": { "codepoints": [120114], "characters": "\uD835\uDD32" }, + "ù": { "codepoints": [249], "characters": "\u00F9" }, + "ù": { "codepoints": [249], "characters": "\u00F9" }, + "↿": { "codepoints": [8639], "characters": "\u21BF" }, + "↾": { "codepoints": [8638], "characters": "\u21BE" }, + "▀": { "codepoints": [9600], "characters": "\u2580" }, + "⌜": { "codepoints": [8988], "characters": "\u231C" }, + "⌜": { "codepoints": [8988], "characters": "\u231C" }, + "⌏": { "codepoints": [8975], "characters": "\u230F" }, + "◸": { "codepoints": [9720], "characters": "\u25F8" }, + "ū": { "codepoints": [363], "characters": "\u016B" }, + "¨": { "codepoints": [168], "characters": "\u00A8" }, + "¨": { "codepoints": [168], "characters": "\u00A8" }, + "ų": { "codepoints": [371], "characters": "\u0173" }, + "𝕦": { "codepoints": [120166], "characters": "\uD835\uDD66" }, + "↑": { "codepoints": [8593], "characters": "\u2191" }, + "↕": { "codepoints": [8597], "characters": "\u2195" }, + "↿": { "codepoints": [8639], "characters": "\u21BF" }, + "↾": { "codepoints": [8638], "characters": "\u21BE" }, + "⊎": { "codepoints": [8846], "characters": "\u228E" }, + "υ": { "codepoints": [965], "characters": "\u03C5" }, + "ϒ": { "codepoints": [978], "characters": "\u03D2" }, + "υ": { "codepoints": [965], "characters": "\u03C5" }, + "⇈": { "codepoints": [8648], "characters": "\u21C8" }, + "⌝": { "codepoints": [8989], "characters": "\u231D" }, + "⌝": { "codepoints": [8989], "characters": "\u231D" }, + "⌎": { "codepoints": [8974], "characters": "\u230E" }, + "ů": { "codepoints": [367], "characters": "\u016F" }, + "◹": { "codepoints": [9721], "characters": "\u25F9" }, + "𝓊": { "codepoints": [120010], "characters": "\uD835\uDCCA" }, + "⋰": { "codepoints": [8944], "characters": "\u22F0" }, + "ũ": { "codepoints": [361], "characters": "\u0169" }, + "▵": { "codepoints": [9653], "characters": "\u25B5" }, + "▴": { "codepoints": [9652], "characters": "\u25B4" }, + "⇈": { "codepoints": [8648], "characters": "\u21C8" }, + "ü": { "codepoints": [252], "characters": "\u00FC" }, + "ü": { "codepoints": [252], "characters": "\u00FC" }, + "⦧": { "codepoints": [10663], "characters": "\u29A7" }, + "⇕": { "codepoints": [8661], "characters": "\u21D5" }, + "⫨": { "codepoints": [10984], "characters": "\u2AE8" }, + "⫩": { "codepoints": [10985], "characters": "\u2AE9" }, + "⊨": { "codepoints": [8872], "characters": "\u22A8" }, + "⦜": { "codepoints": [10652], "characters": "\u299C" }, + "ϵ": { "codepoints": [1013], "characters": "\u03F5" }, + "ϰ": { "codepoints": [1008], "characters": "\u03F0" }, + "∅": { "codepoints": [8709], "characters": "\u2205" }, + "ϕ": { "codepoints": [981], "characters": "\u03D5" }, + "ϖ": { "codepoints": [982], "characters": "\u03D6" }, + "∝": { "codepoints": [8733], "characters": "\u221D" }, + "↕": { "codepoints": [8597], "characters": "\u2195" }, + "ϱ": { "codepoints": [1009], "characters": "\u03F1" }, + "ς": { "codepoints": [962], "characters": "\u03C2" }, + "⊊︀": { "codepoints": [8842, 65024], "characters": "\u228A\uFE00" }, + "⫋︀": { "codepoints": [10955, 65024], "characters": "\u2ACB\uFE00" }, + "⊋︀": { "codepoints": [8843, 65024], "characters": "\u228B\uFE00" }, + "⫌︀": { "codepoints": [10956, 65024], "characters": "\u2ACC\uFE00" }, + "ϑ": { "codepoints": [977], "characters": "\u03D1" }, + "⊲": { "codepoints": [8882], "characters": "\u22B2" }, + "⊳": { "codepoints": [8883], "characters": "\u22B3" }, + "в": { "codepoints": [1074], "characters": "\u0432" }, + "⊢": { "codepoints": [8866], "characters": "\u22A2" }, + "∨": { "codepoints": [8744], "characters": "\u2228" }, + "⊻": { "codepoints": [8891], "characters": "\u22BB" }, + "≚": { "codepoints": [8794], "characters": "\u225A" }, + "⋮": { "codepoints": [8942], "characters": "\u22EE" }, + "|": { "codepoints": [124], "characters": "\u007C" }, + "|": { "codepoints": [124], "characters": "\u007C" }, + "𝔳": { "codepoints": [120115], "characters": "\uD835\uDD33" }, + "⊲": { "codepoints": [8882], "characters": "\u22B2" }, + "⊂⃒": { "codepoints": [8834, 8402], "characters": "\u2282\u20D2" }, + "⊃⃒": { "codepoints": [8835, 8402], "characters": "\u2283\u20D2" }, + "𝕧": { "codepoints": [120167], "characters": "\uD835\uDD67" }, + "∝": { "codepoints": [8733], "characters": "\u221D" }, + "⊳": { "codepoints": [8883], "characters": "\u22B3" }, + "𝓋": { "codepoints": [120011], "characters": "\uD835\uDCCB" }, + "⫋︀": { "codepoints": [10955, 65024], "characters": "\u2ACB\uFE00" }, + "⊊︀": { "codepoints": [8842, 65024], "characters": "\u228A\uFE00" }, + "⫌︀": { "codepoints": [10956, 65024], "characters": "\u2ACC\uFE00" }, + "⊋︀": { "codepoints": [8843, 65024], "characters": "\u228B\uFE00" }, + "⦚": { "codepoints": [10650], "characters": "\u299A" }, + "ŵ": { "codepoints": [373], "characters": "\u0175" }, + "⩟": { "codepoints": [10847], "characters": "\u2A5F" }, + "∧": { "codepoints": [8743], "characters": "\u2227" }, + "≙": { "codepoints": [8793], "characters": "\u2259" }, + "℘": { "codepoints": [8472], "characters": "\u2118" }, + "𝔴": { "codepoints": [120116], "characters": "\uD835\uDD34" }, + "𝕨": { "codepoints": [120168], "characters": "\uD835\uDD68" }, + "℘": { "codepoints": [8472], "characters": "\u2118" }, + "≀": { "codepoints": [8768], "characters": "\u2240" }, + "≀": { "codepoints": [8768], "characters": "\u2240" }, + "𝓌": { "codepoints": [120012], "characters": "\uD835\uDCCC" }, + "⋂": { "codepoints": [8898], "characters": "\u22C2" }, + "◯": { "codepoints": [9711], "characters": "\u25EF" }, + "⋃": { "codepoints": [8899], "characters": "\u22C3" }, + "▽": { "codepoints": [9661], "characters": "\u25BD" }, + "𝔵": { "codepoints": [120117], "characters": "\uD835\uDD35" }, + "⟺": { "codepoints": [10234], "characters": "\u27FA" }, + "⟷": { "codepoints": [10231], "characters": "\u27F7" }, + "ξ": { "codepoints": [958], "characters": "\u03BE" }, + "⟸": { "codepoints": [10232], "characters": "\u27F8" }, + "⟵": { "codepoints": [10229], "characters": "\u27F5" }, + "⟼": { "codepoints": [10236], "characters": "\u27FC" }, + "⋻": { "codepoints": [8955], "characters": "\u22FB" }, + "⨀": { "codepoints": [10752], "characters": "\u2A00" }, + "𝕩": { "codepoints": [120169], "characters": "\uD835\uDD69" }, + "⨁": { "codepoints": [10753], "characters": "\u2A01" }, + "⨂": { "codepoints": [10754], "characters": "\u2A02" }, + "⟹": { "codepoints": [10233], "characters": "\u27F9" }, + "⟶": { "codepoints": [10230], "characters": "\u27F6" }, + "𝓍": { "codepoints": [120013], "characters": "\uD835\uDCCD" }, + "⨆": { "codepoints": [10758], "characters": "\u2A06" }, + "⨄": { "codepoints": [10756], "characters": "\u2A04" }, + "△": { "codepoints": [9651], "characters": "\u25B3" }, + "⋁": { "codepoints": [8897], "characters": "\u22C1" }, + "⋀": { "codepoints": [8896], "characters": "\u22C0" }, + "ý": { "codepoints": [253], "characters": "\u00FD" }, + "ý": { "codepoints": [253], "characters": "\u00FD" }, + "я": { "codepoints": [1103], "characters": "\u044F" }, + "ŷ": { "codepoints": [375], "characters": "\u0177" }, + "ы": { "codepoints": [1099], "characters": "\u044B" }, + "¥": { "codepoints": [165], "characters": "\u00A5" }, + "¥": { "codepoints": [165], "characters": "\u00A5" }, + "𝔶": { "codepoints": [120118], "characters": "\uD835\uDD36" }, + "ї": { "codepoints": [1111], "characters": "\u0457" }, + "𝕪": { "codepoints": [120170], "characters": "\uD835\uDD6A" }, + "𝓎": { "codepoints": [120014], "characters": "\uD835\uDCCE" }, + "ю": { "codepoints": [1102], "characters": "\u044E" }, + "ÿ": { "codepoints": [255], "characters": "\u00FF" }, + "ÿ": { "codepoints": [255], "characters": "\u00FF" }, + "ź": { "codepoints": [378], "characters": "\u017A" }, + "ž": { "codepoints": [382], "characters": "\u017E" }, + "з": { "codepoints": [1079], "characters": "\u0437" }, + "ż": { "codepoints": [380], "characters": "\u017C" }, + "ℨ": { "codepoints": [8488], "characters": "\u2128" }, + "ζ": { "codepoints": [950], "characters": "\u03B6" }, + "𝔷": { "codepoints": [120119], "characters": "\uD835\uDD37" }, + "ж": { "codepoints": [1078], "characters": "\u0436" }, + "⇝": { "codepoints": [8669], "characters": "\u21DD" }, + "𝕫": { "codepoints": [120171], "characters": "\uD835\uDD6B" }, + "𝓏": { "codepoints": [120015], "characters": "\uD835\uDCCF" }, + "‍": { "codepoints": [8205], "characters": "\u200D" }, + "‌": { "codepoints": [8204], "characters": "\u200C" } +} diff --git a/pkgs/markdown/tool/expected_output.dart b/pkgs/markdown/tool/expected_output.dart new file mode 100644 index 000000000..aa7bab363 --- /dev/null +++ b/pkgs/markdown/tool/expected_output.dart @@ -0,0 +1,159 @@ +// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:io'; + +import 'package:path/path.dart' as p; + +/// Parse and yield data cases (each a [DataCase]) from [path]. +Iterable<DataCase> dataCasesInFile({ + required String path, + String? baseDir, +}) sync* { + final file = p.basename(path).replaceFirst(RegExp(r'\..+$'), ''); + baseDir ??= p.relative(p.dirname(path), from: p.dirname(p.dirname(path))); + + // Explicitly create a File, in case the entry is a Link. + final lines = File(path).readAsLinesSync(); + + final frontMatter = StringBuffer(); + + var i = 0; + + while (!lines[i].startsWith('>>>')) { + frontMatter.write('${lines[i++]}\n'); + } + + while (i < lines.length) { + var description = lines[i++].replaceFirst(RegExp(r'>>>\s*'), '').trim(); + final skip = description.startsWith('skip:'); + if (description == '') { + description = 'line ${i + 1}'; + } else { + description = 'line ${i + 1}: $description'; + } + + final input = StringBuffer(); + while (!lines[i].startsWith('<<<')) { + input.writeln(lines[i++]); + } + + final expectedOutput = StringBuffer(); + while (++i < lines.length && !lines[i].startsWith('>>>')) { + expectedOutput.writeln(lines[i]); + } + + final dataCase = DataCase( + directory: baseDir, + file: file, + front_matter: frontMatter.toString(), + description: description, + skip: skip, + input: input.toString(), + expectedOutput: expectedOutput.toString(), + ); + yield dataCase; + } +} + +/// Parse and return data cases (each a [DataCase]) from [directory]. +/// +/// By default, only read data cases from files with a `.unit` extension. Data +/// cases are read from files located immediately in [directory], or +/// recursively, according to [recursive]. +Iterable<DataCase> _dataCases({ + required String directory, + String extension = 'unit', + bool recursive = true, +}) { + final entries = + Directory(directory).listSync(recursive: recursive, followLinks: false); + final results = <DataCase>[]; + for (final entry in entries) { + if (!entry.path.endsWith(extension)) { + continue; + } + + final relativeDir = + p.relative(p.dirname(entry.path), from: p.dirname(directory)); + + results.addAll(dataCasesInFile(path: entry.path, baseDir: relativeDir)); + } + + // The API makes no guarantees on order. This is just here for stability in + // tests. + results.sort((a, b) { + final compare = a.directory.compareTo(b.directory); + if (compare != 0) return compare; + + return a.file.compareTo(b.file); + }); + return results; +} + +/// Parse and yield data cases (each a [DataCase]) from [testDirectory]. +/// +/// By default, only read data cases from files with a `.unit` extension. Data +/// cases are read from files located immediately in [testDirectory], or +/// recursively, according to [recursive]. +/// +/// The typical use case of this method is to declare a library at the top of a +/// Dart test file, then reference the symbol with a pound sign. Example: +/// +/// ```dart +/// library my_package.test.this_test; +/// +/// import 'package:expected_output/expected_output.dart'; +/// import 'package:test/test.dart'; +/// +/// void main() { +/// for (final dataCase +/// in dataCasesUnder(library: #my_package.test.this_test)) { +/// // ... +/// } +/// } +/// ``` +Iterable<DataCase> dataCasesUnder({ + required String testDirectory, + String extension = 'unit', + bool recursive = true, +}) sync* { + final directory = p.join(p.current, 'test', testDirectory); + for (final dataCase in _dataCases( + directory: directory, + extension: extension, + recursive: recursive, + )) { + yield dataCase; + } +} + +/// All of the data pertaining to a particular test case, namely the [input] and +/// [expectedOutput]. +class DataCase { + final String directory; + final String file; + + // ignore: non_constant_identifier_names + final String front_matter; + final String description; + final bool skip; + final String input; + final String expectedOutput; + + DataCase({ + this.directory = '', + this.file = '', + // ignore: non_constant_identifier_names + this.front_matter = '', + this.description = '', + this.skip = false, + required this.input, + required this.expectedOutput, + }); + + /// A good standard description for `test()`, derived from the data directory, + /// the particular data file, and the test case description. + String get testDescription => [directory, file, description].join(' '); +} diff --git a/pkgs/markdown/tool/gfm_stats.json b/pkgs/markdown/tool/gfm_stats.json new file mode 100644 index 000000000..93c0cab29 --- /dev/null +++ b/pkgs/markdown/tool/gfm_stats.json @@ -0,0 +1,732 @@ +{ + "ATX headings": { + "32": "strict", + "33": "strict", + "34": "strict", + "35": "strict", + "36": "strict", + "37": "strict", + "38": "strict", + "39": "strict", + "40": "strict", + "41": "strict", + "42": "strict", + "43": "strict", + "44": "strict", + "45": "strict", + "46": "strict", + "47": "strict", + "48": "strict", + "49": "strict" + }, + "Autolinks": { + "602": "strict", + "603": "strict", + "604": "strict", + "605": "strict", + "606": "strict", + "607": "strict", + "608": "strict", + "609": "strict", + "610": "strict", + "611": "strict", + "612": "strict", + "613": "strict", + "614": "strict", + "615": "strict", + "616": "strict", + "617": "strict", + "618": "strict", + "619": "strict", + "620": "strict" + }, + "Autolinks (extension)": { + "621": "strict", + "622": "strict", + "623": "strict", + "624": "strict", + "625": "strict", + "626": "strict", + "627": "strict", + "628": "strict", + "629": "strict", + "630": "strict", + "631": "strict" + }, + "Backslash escapes": { + "308": "strict", + "309": "strict", + "310": "strict", + "311": "strict", + "312": "strict", + "313": "strict", + "314": "strict", + "315": "strict", + "316": "strict", + "317": "strict", + "318": "strict", + "319": "strict", + "320": "strict" + }, + "Blank lines": { + "197": "strict" + }, + "Block quotes": { + "206": "strict", + "207": "strict", + "208": "strict", + "209": "strict", + "210": "strict", + "211": "strict", + "212": "strict", + "213": "strict", + "214": "strict", + "215": "strict", + "216": "strict", + "217": "strict", + "218": "strict", + "219": "strict", + "220": "strict", + "221": "strict", + "222": "strict", + "223": "strict", + "224": "strict", + "225": "strict", + "226": "strict", + "227": "strict", + "228": "strict", + "229": "strict", + "230": "strict" + }, + "Code spans": { + "338": "strict", + "339": "strict", + "340": "strict", + "341": "strict", + "342": "strict", + "343": "strict", + "344": "strict", + "345": "strict", + "346": "strict", + "347": "strict", + "348": "strict", + "349": "strict", + "350": "strict", + "351": "strict", + "352": "strict", + "353": "strict", + "354": "strict", + "355": "strict", + "356": "strict", + "357": "strict", + "358": "strict", + "359": "strict" + }, + "Disallowed Raw HTML (extension)": { + "652": "loose" + }, + "Emphasis and strong emphasis": { + "360": "strict", + "361": "strict", + "362": "strict", + "363": "strict", + "364": "strict", + "365": "strict", + "366": "strict", + "367": "strict", + "368": "strict", + "369": "strict", + "370": "strict", + "371": "strict", + "372": "strict", + "373": "strict", + "374": "strict", + "375": "strict", + "376": "strict", + "377": "strict", + "378": "strict", + "379": "strict", + "380": "strict", + "381": "strict", + "382": "strict", + "383": "strict", + "384": "strict", + "385": "strict", + "386": "strict", + "387": "strict", + "388": "strict", + "389": "strict", + "390": "strict", + "391": "strict", + "392": "strict", + "393": "strict", + "394": "strict", + "395": "strict", + "396": "strict", + "397": "strict", + "398": "strict", + "399": "strict", + "400": "strict", + "401": "strict", + "402": "strict", + "403": "strict", + "404": "strict", + "405": "strict", + "406": "strict", + "407": "strict", + "408": "strict", + "409": "strict", + "410": "strict", + "411": "strict", + "412": "strict", + "413": "strict", + "414": "strict", + "415": "strict", + "416": "strict", + "417": "strict", + "418": "strict", + "419": "strict", + "420": "strict", + "421": "strict", + "422": "strict", + "423": "strict", + "424": "strict", + "425": "strict", + "426": "strict", + "427": "strict", + "428": "strict", + "429": "strict", + "430": "strict", + "431": "strict", + "432": "strict", + "433": "strict", + "434": "strict", + "435": "strict", + "436": "strict", + "437": "strict", + "438": "strict", + "439": "strict", + "440": "strict", + "441": "strict", + "442": "strict", + "443": "strict", + "444": "strict", + "445": "strict", + "446": "strict", + "447": "strict", + "448": "strict", + "449": "strict", + "450": "strict", + "451": "strict", + "452": "strict", + "453": "strict", + "454": "strict", + "455": "strict", + "456": "strict", + "457": "strict", + "458": "strict", + "459": "strict", + "460": "strict", + "461": "strict", + "462": "strict", + "463": "strict", + "464": "strict", + "465": "strict", + "466": "strict", + "467": "strict", + "468": "strict", + "469": "strict", + "470": "strict", + "471": "strict", + "472": "strict", + "473": "strict", + "474": "strict", + "475": "strict", + "476": "strict", + "477": "strict", + "478": "strict", + "479": "strict", + "480": "strict", + "481": "strict", + "482": "strict", + "483": "strict", + "484": "strict", + "485": "strict", + "486": "strict", + "487": "strict", + "488": "strict", + "489": "strict", + "490": "strict" + }, + "Entity and numeric character references": { + "321": "loose", + "322": "strict", + "323": "strict", + "324": "strict", + "325": "strict", + "326": "strict", + "327": "strict", + "328": "strict", + "329": "strict", + "330": "strict", + "331": "strict", + "332": "strict", + "333": "strict", + "334": "strict", + "335": "strict", + "336": "loose", + "337": "strict" + }, + "Fenced code blocks": { + "89": "strict", + "90": "strict", + "91": "strict", + "92": "strict", + "93": "strict", + "94": "strict", + "95": "strict", + "96": "strict", + "97": "strict", + "98": "strict", + "99": "strict", + "100": "strict", + "101": "strict", + "102": "strict", + "103": "strict", + "104": "strict", + "105": "strict", + "106": "strict", + "107": "strict", + "108": "strict", + "109": "strict", + "110": "strict", + "111": "strict", + "112": "strict", + "113": "strict", + "114": "strict", + "115": "strict", + "116": "strict", + "117": "strict" + }, + "Hard line breaks": { + "653": "strict", + "654": "strict", + "655": "strict", + "656": "strict", + "657": "strict", + "658": "strict", + "659": "strict", + "660": "strict", + "661": "strict", + "662": "strict", + "663": "strict", + "664": "strict", + "665": "strict", + "666": "strict", + "667": "strict" + }, + "HTML blocks": { + "118": "strict", + "119": "strict", + "120": "strict", + "121": "strict", + "122": "strict", + "123": "strict", + "124": "strict", + "125": "strict", + "126": "strict", + "127": "strict", + "128": "strict", + "129": "strict", + "130": "strict", + "131": "strict", + "132": "strict", + "133": "strict", + "134": "strict", + "135": "strict", + "136": "strict", + "137": "strict", + "138": "strict", + "139": "strict", + "140": "strict", + "141": "strict", + "142": "strict", + "143": "strict", + "144": "strict", + "145": "strict", + "146": "strict", + "147": "strict", + "148": "strict", + "149": "strict", + "150": "strict", + "151": "strict", + "152": "strict", + "153": "strict", + "154": "strict", + "155": "strict", + "156": "strict", + "157": "strict", + "158": "strict", + "159": "strict", + "160": "strict" + }, + "Images": { + "580": "strict", + "581": "strict", + "582": "strict", + "583": "strict", + "584": "strict", + "585": "strict", + "586": "strict", + "587": "strict", + "588": "strict", + "589": "strict", + "590": "strict", + "591": "strict", + "592": "strict", + "593": "strict", + "594": "strict", + "595": "strict", + "596": "strict", + "597": "strict", + "598": "strict", + "599": "strict", + "600": "strict", + "601": "strict" + }, + "Indented code blocks": { + "77": "strict", + "78": "strict", + "79": "strict", + "80": "strict", + "81": "strict", + "82": "strict", + "83": "strict", + "84": "strict", + "85": "strict", + "86": "strict", + "87": "strict", + "88": "strict" + }, + "Inlines": { + "307": "strict" + }, + "Link reference definitions": { + "161": "strict", + "162": "strict", + "163": "strict", + "164": "strict", + "165": "strict", + "166": "strict", + "167": "strict", + "168": "strict", + "169": "strict", + "170": "strict", + "171": "strict", + "172": "strict", + "173": "strict", + "174": "strict", + "175": "strict", + "176": "loose", + "177": "strict", + "178": "strict", + "179": "strict", + "180": "strict", + "181": "strict", + "182": "strict", + "183": "strict", + "184": "strict", + "185": "strict", + "186": "strict", + "187": "strict", + "188": "loose" + }, + "Links": { + "493": "strict", + "494": "strict", + "495": "strict", + "496": "strict", + "497": "strict", + "498": "strict", + "499": "strict", + "500": "strict", + "501": "strict", + "502": "strict", + "503": "strict", + "504": "strict", + "505": "strict", + "506": "strict", + "507": "strict", + "508": "strict", + "509": "strict", + "510": "strict", + "511": "strict", + "512": "strict", + "513": "strict", + "514": "strict", + "515": "strict", + "516": "strict", + "517": "strict", + "518": "strict", + "519": "strict", + "520": "strict", + "521": "strict", + "522": "strict", + "523": "strict", + "524": "strict", + "525": "strict", + "526": "strict", + "527": "strict", + "528": "strict", + "529": "strict", + "530": "strict", + "531": "strict", + "532": "strict", + "533": "strict", + "534": "strict", + "535": "strict", + "536": "strict", + "537": "strict", + "538": "strict", + "539": "strict", + "540": "strict", + "541": "strict", + "542": "strict", + "543": "strict", + "544": "strict", + "545": "strict", + "546": "strict", + "547": "strict", + "548": "strict", + "549": "strict", + "550": "strict", + "551": "strict", + "552": "strict", + "553": "strict", + "554": "strict", + "555": "strict", + "556": "strict", + "557": "strict", + "558": "strict", + "559": "strict", + "560": "strict", + "561": "strict", + "562": "strict", + "563": "strict", + "564": "strict", + "565": "strict", + "566": "strict", + "567": "strict", + "568": "strict", + "569": "strict", + "570": "strict", + "571": "strict", + "572": "strict", + "573": "strict", + "574": "strict", + "575": "strict", + "576": "strict", + "577": "strict", + "578": "strict", + "579": "strict" + }, + "List items": { + "231": "strict", + "232": "strict", + "233": "strict", + "234": "strict", + "235": "strict", + "236": "strict", + "237": "strict", + "238": "strict", + "239": "strict", + "240": "strict", + "241": "strict", + "242": "strict", + "243": "strict", + "244": "strict", + "245": "strict", + "246": "strict", + "247": "strict", + "248": "strict", + "249": "strict", + "250": "strict", + "251": "strict", + "252": "strict", + "253": "strict", + "254": "strict", + "255": "strict", + "256": "strict", + "257": "strict", + "258": "strict", + "259": "strict", + "260": "strict", + "261": "strict", + "262": "strict", + "263": "strict", + "264": "strict", + "265": "strict", + "266": "strict", + "267": "strict", + "268": "strict", + "269": "strict", + "270": "strict", + "271": "strict", + "272": "strict", + "273": "strict", + "274": "strict", + "275": "strict", + "276": "strict", + "277": "strict", + "278": "strict" + }, + "Lists": { + "281": "strict", + "282": "strict", + "283": "strict", + "284": "strict", + "285": "strict", + "286": "strict", + "287": "strict", + "288": "strict", + "289": "strict", + "290": "strict", + "291": "strict", + "292": "strict", + "293": "strict", + "294": "strict", + "295": "strict", + "296": "strict", + "297": "strict", + "298": "strict", + "299": "strict", + "300": "strict", + "301": "strict", + "302": "strict", + "303": "strict", + "304": "strict", + "305": "strict", + "306": "strict" + }, + "Paragraphs": { + "189": "strict", + "190": "strict", + "191": "strict", + "192": "strict", + "193": "strict", + "194": "strict", + "195": "strict", + "196": "strict" + }, + "Precedence": { + "12": "strict" + }, + "Raw HTML": { + "632": "strict", + "633": "strict", + "634": "strict", + "635": "strict", + "636": "strict", + "637": "strict", + "638": "strict", + "639": "strict", + "640": "strict", + "641": "strict", + "642": "strict", + "643": "strict", + "644": "loose", + "645": "loose", + "646": "strict", + "647": "strict", + "648": "strict", + "649": "strict", + "650": "strict", + "651": "strict" + }, + "Setext headings": { + "50": "strict", + "51": "strict", + "52": "loose", + "53": "strict", + "54": "loose", + "55": "strict", + "56": "strict", + "57": "strict", + "58": "strict", + "59": "strict", + "60": "strict", + "61": "strict", + "62": "strict", + "63": "strict", + "64": "strict", + "65": "strict", + "66": "strict", + "67": "strict", + "68": "strict", + "69": "strict", + "70": "strict", + "71": "strict", + "72": "strict", + "73": "strict", + "74": "strict", + "75": "strict", + "76": "strict" + }, + "Soft line breaks": { + "668": "strict", + "669": "strict" + }, + "Strikethrough (extension)": { + "491": "strict", + "492": "strict" + }, + "Tables (extension)": { + "198": "strict", + "199": "strict", + "200": "strict", + "201": "strict", + "202": "strict", + "203": "strict", + "204": "strict", + "205": "strict" + }, + "Tabs": { + "1": "strict", + "2": "strict", + "3": "strict", + "4": "strict", + "5": "strict", + "6": "loose", + "7": "strict", + "8": "strict", + "9": "strict", + "10": "strict", + "11": "strict" + }, + "Textual content": { + "670": "strict", + "671": "strict", + "672": "strict" + }, + "Thematic breaks": { + "13": "strict", + "14": "strict", + "15": "strict", + "16": "strict", + "17": "strict", + "18": "strict", + "19": "strict", + "20": "strict", + "21": "strict", + "22": "strict", + "23": "strict", + "24": "strict", + "25": "strict", + "26": "strict", + "27": "strict", + "28": "strict", + "29": "strict", + "30": "strict", + "31": "strict" + } +} diff --git a/pkgs/markdown/tool/gfm_stats.txt b/pkgs/markdown/tool/gfm_stats.txt new file mode 100644 index 000000000..06e240bdb --- /dev/null +++ b/pkgs/markdown/tool/gfm_stats.txt @@ -0,0 +1,32 @@ + 18 of 18 – 100.0% ATX headings + 19 of 19 – 100.0% Autolinks + 11 of 11 – 100.0% Autolinks (extension) + 13 of 13 – 100.0% Backslash escapes + 1 of 1 – 100.0% Blank lines + 25 of 25 – 100.0% Block quotes + 22 of 22 – 100.0% Code spans + 1 of 1 – 100.0% Disallowed Raw HTML (extension) + 131 of 131 – 100.0% Emphasis and strong emphasis + 17 of 17 – 100.0% Entity and numeric character references + 29 of 29 – 100.0% Fenced code blocks + 15 of 15 – 100.0% Hard line breaks + 43 of 43 – 100.0% HTML blocks + 22 of 22 – 100.0% Images + 12 of 12 – 100.0% Indented code blocks + 1 of 1 – 100.0% Inlines + 28 of 28 – 100.0% Link reference definitions + 87 of 87 – 100.0% Links + 48 of 48 – 100.0% List items + 26 of 26 – 100.0% Lists + 8 of 8 – 100.0% Paragraphs + 1 of 1 – 100.0% Precedence + 20 of 20 – 100.0% Raw HTML + 27 of 27 – 100.0% Setext headings + 2 of 2 – 100.0% Soft line breaks + 2 of 2 – 100.0% Strikethrough (extension) + 8 of 8 – 100.0% Tables (extension) + 11 of 11 – 100.0% Tabs + 3 of 3 – 100.0% Textual content + 19 of 19 – 100.0% Thematic breaks + 670 of 670 – 100.0% TOTAL + 660 of 670 – 98.5% TOTAL Strict diff --git a/pkgs/markdown/tool/gfm_tests.json b/pkgs/markdown/tool/gfm_tests.json new file mode 100644 index 000000000..e5e849c1c --- /dev/null +++ b/pkgs/markdown/tool/gfm_tests.json @@ -0,0 +1,6076 @@ +[ + { + "markdown": "\tfoo\tbaz\t\tbim\n", + "html": "<pre><code>foo\tbaz\t\tbim\n</code></pre>\n", + "example": 1, + "start_line": 368, + "end_line": 373, + "section": "Tabs", + "extensions": [] + }, + { + "markdown": " \tfoo\tbaz\t\tbim\n", + "html": "<pre><code>foo\tbaz\t\tbim\n</code></pre>\n", + "example": 2, + "start_line": 375, + "end_line": 380, + "section": "Tabs", + "extensions": [] + }, + { + "markdown": " a\ta\n \u1f50\ta\n", + "html": "<pre><code>a\ta\n\u1f50\ta\n</code></pre>\n", + "example": 3, + "start_line": 382, + "end_line": 389, + "section": "Tabs", + "extensions": [] + }, + { + "markdown": " - foo\n\n\tbar\n", + "html": "<ul>\n<li>\n<p>foo</p>\n<p>bar</p>\n</li>\n</ul>\n", + "example": 4, + "start_line": 395, + "end_line": 406, + "section": "Tabs", + "extensions": [] + }, + { + "markdown": "- foo\n\n\t\tbar\n", + "html": "<ul>\n<li>\n<p>foo</p>\n<pre><code> bar\n</code></pre>\n</li>\n</ul>\n", + "example": 5, + "start_line": 408, + "end_line": 420, + "section": "Tabs", + "extensions": [] + }, + { + "markdown": ">\t\tfoo\n", + "html": "<blockquote>\n<pre><code> foo\n</code></pre>\n</blockquote>\n", + "example": 6, + "start_line": 431, + "end_line": 438, + "section": "Tabs", + "extensions": [] + }, + { + "markdown": "-\t\tfoo\n", + "html": "<ul>\n<li>\n<pre><code> foo\n</code></pre>\n</li>\n</ul>\n", + "example": 7, + "start_line": 440, + "end_line": 449, + "section": "Tabs", + "extensions": [] + }, + { + "markdown": " foo\n\tbar\n", + "html": "<pre><code>foo\nbar\n</code></pre>\n", + "example": 8, + "start_line": 452, + "end_line": 459, + "section": "Tabs", + "extensions": [] + }, + { + "markdown": " - foo\n - bar\n\t - baz\n", + "html": "<ul>\n<li>foo\n<ul>\n<li>bar\n<ul>\n<li>baz</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n", + "example": 9, + "start_line": 461, + "end_line": 477, + "section": "Tabs", + "extensions": [] + }, + { + "markdown": "#\tFoo\n", + "html": "<h1>Foo</h1>\n", + "example": 10, + "start_line": 479, + "end_line": 483, + "section": "Tabs", + "extensions": [] + }, + { + "markdown": "*\t*\t*\t\n", + "html": "<hr />\n", + "example": 11, + "start_line": 485, + "end_line": 489, + "section": "Tabs", + "extensions": [] + }, + { + "markdown": "- `one\n- two`\n", + "html": "<ul>\n<li>`one</li>\n<li>two`</li>\n</ul>\n", + "example": 12, + "start_line": 512, + "end_line": 520, + "section": "Precedence", + "extensions": [] + }, + { + "markdown": "***\n---\n___\n", + "html": "<hr />\n<hr />\n<hr />\n", + "example": 13, + "start_line": 551, + "end_line": 559, + "section": "Thematic breaks", + "extensions": [] + }, + { + "markdown": "+++\n", + "html": "<p>+++</p>\n", + "example": 14, + "start_line": 564, + "end_line": 568, + "section": "Thematic breaks", + "extensions": [] + }, + { + "markdown": "===\n", + "html": "<p>===</p>\n", + "example": 15, + "start_line": 571, + "end_line": 575, + "section": "Thematic breaks", + "extensions": [] + }, + { + "markdown": "--\n**\n__\n", + "html": "<p>--\n**\n__</p>\n", + "example": 16, + "start_line": 580, + "end_line": 588, + "section": "Thematic breaks", + "extensions": [] + }, + { + "markdown": " ***\n ***\n ***\n", + "html": "<hr />\n<hr />\n<hr />\n", + "example": 17, + "start_line": 593, + "end_line": 601, + "section": "Thematic breaks", + "extensions": [] + }, + { + "markdown": " ***\n", + "html": "<pre><code>***\n</code></pre>\n", + "example": 18, + "start_line": 606, + "end_line": 611, + "section": "Thematic breaks", + "extensions": [] + }, + { + "markdown": "Foo\n ***\n", + "html": "<p>Foo\n***</p>\n", + "example": 19, + "start_line": 614, + "end_line": 620, + "section": "Thematic breaks", + "extensions": [] + }, + { + "markdown": "_____________________________________\n", + "html": "<hr />\n", + "example": 20, + "start_line": 625, + "end_line": 629, + "section": "Thematic breaks", + "extensions": [] + }, + { + "markdown": " - - -\n", + "html": "<hr />\n", + "example": 21, + "start_line": 634, + "end_line": 638, + "section": "Thematic breaks", + "extensions": [] + }, + { + "markdown": " ** * ** * ** * **\n", + "html": "<hr />\n", + "example": 22, + "start_line": 641, + "end_line": 645, + "section": "Thematic breaks", + "extensions": [] + }, + { + "markdown": "- - - -\n", + "html": "<hr />\n", + "example": 23, + "start_line": 648, + "end_line": 652, + "section": "Thematic breaks", + "extensions": [] + }, + { + "markdown": "- - - - \n", + "html": "<hr />\n", + "example": 24, + "start_line": 657, + "end_line": 661, + "section": "Thematic breaks", + "extensions": [] + }, + { + "markdown": "_ _ _ _ a\n\na------\n\n---a---\n", + "html": "<p>_ _ _ _ a</p>\n<p>a------</p>\n<p>---a---</p>\n", + "example": 25, + "start_line": 666, + "end_line": 676, + "section": "Thematic breaks", + "extensions": [] + }, + { + "markdown": " *-*\n", + "html": "<p><em>-</em></p>\n", + "example": 26, + "start_line": 682, + "end_line": 686, + "section": "Thematic breaks", + "extensions": [] + }, + { + "markdown": "- foo\n***\n- bar\n", + "html": "<ul>\n<li>foo</li>\n</ul>\n<hr />\n<ul>\n<li>bar</li>\n</ul>\n", + "example": 27, + "start_line": 691, + "end_line": 703, + "section": "Thematic breaks", + "extensions": [] + }, + { + "markdown": "Foo\n***\nbar\n", + "html": "<p>Foo</p>\n<hr />\n<p>bar</p>\n", + "example": 28, + "start_line": 708, + "end_line": 716, + "section": "Thematic breaks", + "extensions": [] + }, + { + "markdown": "Foo\n---\nbar\n", + "html": "<h2>Foo</h2>\n<p>bar</p>\n", + "example": 29, + "start_line": 725, + "end_line": 732, + "section": "Thematic breaks", + "extensions": [] + }, + { + "markdown": "* Foo\n* * *\n* Bar\n", + "html": "<ul>\n<li>Foo</li>\n</ul>\n<hr />\n<ul>\n<li>Bar</li>\n</ul>\n", + "example": 30, + "start_line": 738, + "end_line": 750, + "section": "Thematic breaks", + "extensions": [] + }, + { + "markdown": "- Foo\n- * * *\n", + "html": "<ul>\n<li>Foo</li>\n<li>\n<hr />\n</li>\n</ul>\n", + "example": 31, + "start_line": 755, + "end_line": 765, + "section": "Thematic breaks", + "extensions": [] + }, + { + "markdown": "# foo\n## foo\n### foo\n#### foo\n##### foo\n###### foo\n", + "html": "<h1>foo</h1>\n<h2>foo</h2>\n<h3>foo</h3>\n<h4>foo</h4>\n<h5>foo</h5>\n<h6>foo</h6>\n", + "example": 32, + "start_line": 784, + "end_line": 798, + "section": "ATX headings", + "extensions": [] + }, + { + "markdown": "####### foo\n", + "html": "<p>####### foo</p>\n", + "example": 33, + "start_line": 803, + "end_line": 807, + "section": "ATX headings", + "extensions": [] + }, + { + "markdown": "#5 bolt\n\n#hashtag\n", + "html": "<p>#5 bolt</p>\n<p>#hashtag</p>\n", + "example": 34, + "start_line": 818, + "end_line": 825, + "section": "ATX headings", + "extensions": [] + }, + { + "markdown": "\\## foo\n", + "html": "<p>## foo</p>\n", + "example": 35, + "start_line": 830, + "end_line": 834, + "section": "ATX headings", + "extensions": [] + }, + { + "markdown": "# foo *bar* \\*baz\\*\n", + "html": "<h1>foo <em>bar</em> *baz*</h1>\n", + "example": 36, + "start_line": 839, + "end_line": 843, + "section": "ATX headings", + "extensions": [] + }, + { + "markdown": "# foo \n", + "html": "<h1>foo</h1>\n", + "example": 37, + "start_line": 848, + "end_line": 852, + "section": "ATX headings", + "extensions": [] + }, + { + "markdown": " ### foo\n ## foo\n # foo\n", + "html": "<h3>foo</h3>\n<h2>foo</h2>\n<h1>foo</h1>\n", + "example": 38, + "start_line": 857, + "end_line": 865, + "section": "ATX headings", + "extensions": [] + }, + { + "markdown": " # foo\n", + "html": "<pre><code># foo\n</code></pre>\n", + "example": 39, + "start_line": 870, + "end_line": 875, + "section": "ATX headings", + "extensions": [] + }, + { + "markdown": "foo\n # bar\n", + "html": "<p>foo\n# bar</p>\n", + "example": 40, + "start_line": 878, + "end_line": 884, + "section": "ATX headings", + "extensions": [] + }, + { + "markdown": "## foo ##\n ### bar ###\n", + "html": "<h2>foo</h2>\n<h3>bar</h3>\n", + "example": 41, + "start_line": 889, + "end_line": 895, + "section": "ATX headings", + "extensions": [] + }, + { + "markdown": "# foo ##################################\n##### foo ##\n", + "html": "<h1>foo</h1>\n<h5>foo</h5>\n", + "example": 42, + "start_line": 900, + "end_line": 906, + "section": "ATX headings", + "extensions": [] + }, + { + "markdown": "### foo ### \n", + "html": "<h3>foo</h3>\n", + "example": 43, + "start_line": 911, + "end_line": 915, + "section": "ATX headings", + "extensions": [] + }, + { + "markdown": "### foo ### b\n", + "html": "<h3>foo ### b</h3>\n", + "example": 44, + "start_line": 922, + "end_line": 926, + "section": "ATX headings", + "extensions": [] + }, + { + "markdown": "# foo#\n", + "html": "<h1>foo#</h1>\n", + "example": 45, + "start_line": 931, + "end_line": 935, + "section": "ATX headings", + "extensions": [] + }, + { + "markdown": "### foo \\###\n## foo #\\##\n# foo \\#\n", + "html": "<h3>foo ###</h3>\n<h2>foo ###</h2>\n<h1>foo #</h1>\n", + "example": 46, + "start_line": 941, + "end_line": 949, + "section": "ATX headings", + "extensions": [] + }, + { + "markdown": "****\n## foo\n****\n", + "html": "<hr />\n<h2>foo</h2>\n<hr />\n", + "example": 47, + "start_line": 955, + "end_line": 963, + "section": "ATX headings", + "extensions": [] + }, + { + "markdown": "Foo bar\n# baz\nBar foo\n", + "html": "<p>Foo bar</p>\n<h1>baz</h1>\n<p>Bar foo</p>\n", + "example": 48, + "start_line": 966, + "end_line": 974, + "section": "ATX headings", + "extensions": [] + }, + { + "markdown": "## \n#\n### ###\n", + "html": "<h2></h2>\n<h1></h1>\n<h3></h3>\n", + "example": 49, + "start_line": 979, + "end_line": 987, + "section": "ATX headings", + "extensions": [] + }, + { + "markdown": "Foo *bar*\n=========\n\nFoo *bar*\n---------\n", + "html": "<h1>Foo <em>bar</em></h1>\n<h2>Foo <em>bar</em></h2>\n", + "example": 50, + "start_line": 1019, + "end_line": 1028, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "Foo *bar\nbaz*\n====\n", + "html": "<h1>Foo <em>bar\nbaz</em></h1>\n", + "example": 51, + "start_line": 1033, + "end_line": 1040, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": " Foo *bar\nbaz*\t\n====\n", + "html": "<h1>Foo <em>bar\nbaz</em></h1>\n", + "example": 52, + "start_line": 1047, + "end_line": 1054, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "Foo\n-------------------------\n\nFoo\n=\n", + "html": "<h2>Foo</h2>\n<h1>Foo</h1>\n", + "example": 53, + "start_line": 1059, + "end_line": 1068, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": " Foo\n---\n\n Foo\n-----\n\n Foo\n ===\n", + "html": "<h2>Foo</h2>\n<h2>Foo</h2>\n<h1>Foo</h1>\n", + "example": 54, + "start_line": 1074, + "end_line": 1087, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": " Foo\n ---\n\n Foo\n---\n", + "html": "<pre><code>Foo\n---\n\nFoo\n</code></pre>\n<hr />\n", + "example": 55, + "start_line": 1092, + "end_line": 1105, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "Foo\n ---- \n", + "html": "<h2>Foo</h2>\n", + "example": 56, + "start_line": 1111, + "end_line": 1116, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "Foo\n ---\n", + "html": "<p>Foo\n---</p>\n", + "example": 57, + "start_line": 1121, + "end_line": 1127, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "Foo\n= =\n\nFoo\n--- -\n", + "html": "<p>Foo\n= =</p>\n<p>Foo</p>\n<hr />\n", + "example": 58, + "start_line": 1132, + "end_line": 1143, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "Foo \n-----\n", + "html": "<h2>Foo</h2>\n", + "example": 59, + "start_line": 1148, + "end_line": 1153, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "Foo\\\n----\n", + "html": "<h2>Foo\\</h2>\n", + "example": 60, + "start_line": 1158, + "end_line": 1163, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "`Foo\n----\n`\n\n<a title=\"a lot\n---\nof dashes\"/>\n", + "html": "<h2>`Foo</h2>\n<p>`</p>\n<h2><a title="a lot</h2>\n<p>of dashes"/></p>\n", + "example": 61, + "start_line": 1169, + "end_line": 1182, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "> Foo\n---\n", + "html": "<blockquote>\n<p>Foo</p>\n</blockquote>\n<hr />\n", + "example": 62, + "start_line": 1188, + "end_line": 1196, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "> foo\nbar\n===\n", + "html": "<blockquote>\n<p>foo\nbar\n===</p>\n</blockquote>\n", + "example": 63, + "start_line": 1199, + "end_line": 1209, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "- Foo\n---\n", + "html": "<ul>\n<li>Foo</li>\n</ul>\n<hr />\n", + "example": 64, + "start_line": 1212, + "end_line": 1220, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "Foo\nBar\n---\n", + "html": "<h2>Foo\nBar</h2>\n", + "example": 65, + "start_line": 1227, + "end_line": 1234, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "---\nFoo\n---\nBar\n---\nBaz\n", + "html": "<hr />\n<h2>Foo</h2>\n<h2>Bar</h2>\n<p>Baz</p>\n", + "example": 66, + "start_line": 1240, + "end_line": 1252, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "\n====\n", + "html": "<p>====</p>\n", + "example": 67, + "start_line": 1257, + "end_line": 1262, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "---\n---\n", + "html": "<hr />\n<hr />\n", + "example": 68, + "start_line": 1269, + "end_line": 1275, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "- foo\n-----\n", + "html": "<ul>\n<li>foo</li>\n</ul>\n<hr />\n", + "example": 69, + "start_line": 1278, + "end_line": 1286, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": " foo\n---\n", + "html": "<pre><code>foo\n</code></pre>\n<hr />\n", + "example": 70, + "start_line": 1289, + "end_line": 1296, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "> foo\n-----\n", + "html": "<blockquote>\n<p>foo</p>\n</blockquote>\n<hr />\n", + "example": 71, + "start_line": 1299, + "end_line": 1307, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "\\> foo\n------\n", + "html": "<h2>> foo</h2>\n", + "example": 72, + "start_line": 1313, + "end_line": 1318, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "Foo\n\nbar\n---\nbaz\n", + "html": "<p>Foo</p>\n<h2>bar</h2>\n<p>baz</p>\n", + "example": 73, + "start_line": 1344, + "end_line": 1354, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "Foo\nbar\n\n---\n\nbaz\n", + "html": "<p>Foo\nbar</p>\n<hr />\n<p>baz</p>\n", + "example": 74, + "start_line": 1360, + "end_line": 1372, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "Foo\nbar\n* * *\nbaz\n", + "html": "<p>Foo\nbar</p>\n<hr />\n<p>baz</p>\n", + "example": 75, + "start_line": 1378, + "end_line": 1388, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": "Foo\nbar\n\\---\nbaz\n", + "html": "<p>Foo\nbar\n---\nbaz</p>\n", + "example": 76, + "start_line": 1393, + "end_line": 1403, + "section": "Setext headings", + "extensions": [] + }, + { + "markdown": " a simple\n indented code block\n", + "html": "<pre><code>a simple\n indented code block\n</code></pre>\n", + "example": 77, + "start_line": 1421, + "end_line": 1428, + "section": "Indented code blocks", + "extensions": [] + }, + { + "markdown": " - foo\n\n bar\n", + "html": "<ul>\n<li>\n<p>foo</p>\n<p>bar</p>\n</li>\n</ul>\n", + "example": 78, + "start_line": 1435, + "end_line": 1446, + "section": "Indented code blocks", + "extensions": [] + }, + { + "markdown": "1. foo\n\n - bar\n", + "html": "<ol>\n<li>\n<p>foo</p>\n<ul>\n<li>bar</li>\n</ul>\n</li>\n</ol>\n", + "example": 79, + "start_line": 1449, + "end_line": 1462, + "section": "Indented code blocks", + "extensions": [] + }, + { + "markdown": " <a/>\n *hi*\n\n - one\n", + "html": "<pre><code><a/>\n*hi*\n\n- one\n</code></pre>\n", + "example": 80, + "start_line": 1469, + "end_line": 1480, + "section": "Indented code blocks", + "extensions": [] + }, + { + "markdown": " chunk1\n\n chunk2\n \n \n \n chunk3\n", + "html": "<pre><code>chunk1\n\nchunk2\n\n\n\nchunk3\n</code></pre>\n", + "example": 81, + "start_line": 1485, + "end_line": 1502, + "section": "Indented code blocks", + "extensions": [] + }, + { + "markdown": " chunk1\n \n chunk2\n", + "html": "<pre><code>chunk1\n \n chunk2\n</code></pre>\n", + "example": 82, + "start_line": 1508, + "end_line": 1517, + "section": "Indented code blocks", + "extensions": [] + }, + { + "markdown": "Foo\n bar\n\n", + "html": "<p>Foo\nbar</p>\n", + "example": 83, + "start_line": 1523, + "end_line": 1530, + "section": "Indented code blocks", + "extensions": [] + }, + { + "markdown": " foo\nbar\n", + "html": "<pre><code>foo\n</code></pre>\n<p>bar</p>\n", + "example": 84, + "start_line": 1537, + "end_line": 1544, + "section": "Indented code blocks", + "extensions": [] + }, + { + "markdown": "# Heading\n foo\nHeading\n------\n foo\n----\n", + "html": "<h1>Heading</h1>\n<pre><code>foo\n</code></pre>\n<h2>Heading</h2>\n<pre><code>foo\n</code></pre>\n<hr />\n", + "example": 85, + "start_line": 1550, + "end_line": 1565, + "section": "Indented code blocks", + "extensions": [] + }, + { + "markdown": " foo\n bar\n", + "html": "<pre><code> foo\nbar\n</code></pre>\n", + "example": 86, + "start_line": 1570, + "end_line": 1577, + "section": "Indented code blocks", + "extensions": [] + }, + { + "markdown": "\n \n foo\n \n\n", + "html": "<pre><code>foo\n</code></pre>\n", + "example": 87, + "start_line": 1583, + "end_line": 1592, + "section": "Indented code blocks", + "extensions": [] + }, + { + "markdown": " foo \n", + "html": "<pre><code>foo \n</code></pre>\n", + "example": 88, + "start_line": 1597, + "end_line": 1602, + "section": "Indented code blocks", + "extensions": [] + }, + { + "markdown": "```\n<\n >\n```\n", + "html": "<pre><code><\n >\n</code></pre>\n", + "example": 89, + "start_line": 1652, + "end_line": 1661, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "~~~\n<\n >\n~~~\n", + "html": "<pre><code><\n >\n</code></pre>\n", + "example": 90, + "start_line": 1666, + "end_line": 1675, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "``\nfoo\n``\n", + "html": "<p><code>foo</code></p>\n", + "example": 91, + "start_line": 1679, + "end_line": 1685, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "```\naaa\n~~~\n```\n", + "html": "<pre><code>aaa\n~~~\n</code></pre>\n", + "example": 92, + "start_line": 1690, + "end_line": 1699, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "~~~\naaa\n```\n~~~\n", + "html": "<pre><code>aaa\n```\n</code></pre>\n", + "example": 93, + "start_line": 1702, + "end_line": 1711, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "````\naaa\n```\n``````\n", + "html": "<pre><code>aaa\n```\n</code></pre>\n", + "example": 94, + "start_line": 1716, + "end_line": 1725, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "~~~~\naaa\n~~~\n~~~~\n", + "html": "<pre><code>aaa\n~~~\n</code></pre>\n", + "example": 95, + "start_line": 1728, + "end_line": 1737, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "```\n", + "html": "<pre><code></code></pre>\n", + "example": 96, + "start_line": 1743, + "end_line": 1747, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "`````\n\n```\naaa\n", + "html": "<pre><code>\n```\naaa\n</code></pre>\n", + "example": 97, + "start_line": 1750, + "end_line": 1760, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "> ```\n> aaa\n\nbbb\n", + "html": "<blockquote>\n<pre><code>aaa\n</code></pre>\n</blockquote>\n<p>bbb</p>\n", + "example": 98, + "start_line": 1763, + "end_line": 1774, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "```\n\n \n```\n", + "html": "<pre><code>\n \n</code></pre>\n", + "example": 99, + "start_line": 1779, + "end_line": 1788, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "```\n```\n", + "html": "<pre><code></code></pre>\n", + "example": 100, + "start_line": 1793, + "end_line": 1798, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": " ```\n aaa\naaa\n```\n", + "html": "<pre><code>aaa\naaa\n</code></pre>\n", + "example": 101, + "start_line": 1805, + "end_line": 1814, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": " ```\naaa\n aaa\naaa\n ```\n", + "html": "<pre><code>aaa\naaa\naaa\n</code></pre>\n", + "example": 102, + "start_line": 1817, + "end_line": 1828, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": " ```\n aaa\n aaa\n aaa\n ```\n", + "html": "<pre><code>aaa\n aaa\naaa\n</code></pre>\n", + "example": 103, + "start_line": 1831, + "end_line": 1842, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": " ```\n aaa\n ```\n", + "html": "<pre><code>```\naaa\n```\n</code></pre>\n", + "example": 104, + "start_line": 1847, + "end_line": 1856, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "```\naaa\n ```\n", + "html": "<pre><code>aaa\n</code></pre>\n", + "example": 105, + "start_line": 1862, + "end_line": 1869, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": " ```\naaa\n ```\n", + "html": "<pre><code>aaa\n</code></pre>\n", + "example": 106, + "start_line": 1872, + "end_line": 1879, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "```\naaa\n ```\n", + "html": "<pre><code>aaa\n ```\n</code></pre>\n", + "example": 107, + "start_line": 1884, + "end_line": 1892, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "``` ```\naaa\n", + "html": "<p><code> </code>\naaa</p>\n", + "example": 108, + "start_line": 1898, + "end_line": 1904, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "~~~~~~\naaa\n~~~ ~~\n", + "html": "<pre><code>aaa\n~~~ ~~\n</code></pre>\n", + "example": 109, + "start_line": 1907, + "end_line": 1915, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "foo\n```\nbar\n```\nbaz\n", + "html": "<p>foo</p>\n<pre><code>bar\n</code></pre>\n<p>baz</p>\n", + "example": 110, + "start_line": 1921, + "end_line": 1932, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "foo\n---\n~~~\nbar\n~~~\n# baz\n", + "html": "<h2>foo</h2>\n<pre><code>bar\n</code></pre>\n<h1>baz</h1>\n", + "example": 111, + "start_line": 1938, + "end_line": 1950, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "```ruby\ndef foo(x)\n return 3\nend\n```\n", + "html": "<pre><code class=\"language-ruby\">def foo(x)\n return 3\nend\n</code></pre>\n", + "example": 112, + "start_line": 1960, + "end_line": 1971, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "~~~~ ruby startline=3 $%@#$\ndef foo(x)\n return 3\nend\n~~~~~~~\n", + "html": "<pre><code class=\"language-ruby\">def foo(x)\n return 3\nend\n</code></pre>\n", + "example": 113, + "start_line": 1974, + "end_line": 1985, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "````;\n````\n", + "html": "<pre><code class=\"language-;\"></code></pre>\n", + "example": 114, + "start_line": 1988, + "end_line": 1993, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "``` aa ```\nfoo\n", + "html": "<p><code>aa</code>\nfoo</p>\n", + "example": 115, + "start_line": 1998, + "end_line": 2004, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "~~~ aa ``` ~~~\nfoo\n~~~\n", + "html": "<pre><code class=\"language-aa\">foo\n</code></pre>\n", + "example": 116, + "start_line": 2009, + "end_line": 2016, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "```\n``` aaa\n```\n", + "html": "<pre><code>``` aaa\n</code></pre>\n", + "example": 117, + "start_line": 2021, + "end_line": 2028, + "section": "Fenced code blocks", + "extensions": [] + }, + { + "markdown": "<table><tr><td>\n<pre>\n**Hello**,\n\n_world_.\n</pre>\n</td></tr></table>\n", + "html": "<table><tr><td>\n<pre>\n**Hello**,\n<p><em>world</em>.\n</pre></p>\n</td></tr></table>\n", + "example": 118, + "start_line": 2100, + "end_line": 2115, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<table>\n <tr>\n <td>\n hi\n </td>\n </tr>\n</table>\n\nokay.\n", + "html": "<table>\n <tr>\n <td>\n hi\n </td>\n </tr>\n</table>\n<p>okay.</p>\n", + "example": 119, + "start_line": 2129, + "end_line": 2148, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": " <div>\n *hello*\n <foo><a>\n", + "html": " <div>\n *hello*\n <foo><a>\n", + "example": 120, + "start_line": 2151, + "end_line": 2159, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "</div>\n*foo*\n", + "html": "</div>\n*foo*\n", + "example": 121, + "start_line": 2164, + "end_line": 2170, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<DIV CLASS=\"foo\">\n\n*Markdown*\n\n</DIV>\n", + "html": "<DIV CLASS=\"foo\">\n<p><em>Markdown</em></p>\n</DIV>\n", + "example": 122, + "start_line": 2175, + "end_line": 2185, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<div id=\"foo\"\n class=\"bar\">\n</div>\n", + "html": "<div id=\"foo\"\n class=\"bar\">\n</div>\n", + "example": 123, + "start_line": 2191, + "end_line": 2199, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<div id=\"foo\" class=\"bar\n baz\">\n</div>\n", + "html": "<div id=\"foo\" class=\"bar\n baz\">\n</div>\n", + "example": 124, + "start_line": 2202, + "end_line": 2210, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<div>\n*foo*\n\n*bar*\n", + "html": "<div>\n*foo*\n<p><em>bar</em></p>\n", + "example": 125, + "start_line": 2214, + "end_line": 2223, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<div id=\"foo\"\n*hi*\n", + "html": "<div id=\"foo\"\n*hi*\n", + "example": 126, + "start_line": 2230, + "end_line": 2236, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<div class\nfoo\n", + "html": "<div class\nfoo\n", + "example": 127, + "start_line": 2239, + "end_line": 2245, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<div *???-&&&-<---\n*foo*\n", + "html": "<div *???-&&&-<---\n*foo*\n", + "example": 128, + "start_line": 2251, + "end_line": 2257, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<div><a href=\"bar\">*foo*</a></div>\n", + "html": "<div><a href=\"bar\">*foo*</a></div>\n", + "example": 129, + "start_line": 2263, + "end_line": 2267, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<table><tr><td>\nfoo\n</td></tr></table>\n", + "html": "<table><tr><td>\nfoo\n</td></tr></table>\n", + "example": 130, + "start_line": 2270, + "end_line": 2278, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<div></div>\n``` c\nint x = 33;\n```\n", + "html": "<div></div>\n``` c\nint x = 33;\n```\n", + "example": 131, + "start_line": 2287, + "end_line": 2297, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<a href=\"foo\">\n*bar*\n</a>\n", + "html": "<a href=\"foo\">\n*bar*\n</a>\n", + "example": 132, + "start_line": 2304, + "end_line": 2312, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<Warning>\n*bar*\n</Warning>\n", + "html": "<Warning>\n*bar*\n</Warning>\n", + "example": 133, + "start_line": 2317, + "end_line": 2325, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<i class=\"foo\">\n*bar*\n</i>\n", + "html": "<i class=\"foo\">\n*bar*\n</i>\n", + "example": 134, + "start_line": 2328, + "end_line": 2336, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "</ins>\n*bar*\n", + "html": "</ins>\n*bar*\n", + "example": 135, + "start_line": 2339, + "end_line": 2345, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<del>\n*foo*\n</del>\n", + "html": "<del>\n*foo*\n</del>\n", + "example": 136, + "start_line": 2354, + "end_line": 2362, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<del>\n\n*foo*\n\n</del>\n", + "html": "<del>\n<p><em>foo</em></p>\n</del>\n", + "example": 137, + "start_line": 2369, + "end_line": 2379, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<del>*foo*</del>\n", + "html": "<p><del><em>foo</em></del></p>\n", + "example": 138, + "start_line": 2387, + "end_line": 2391, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<pre language=\"haskell\"><code>\nimport Text.HTML.TagSoup\n\nmain :: IO ()\nmain = print $ parseTags tags\n</code></pre>\nokay\n", + "html": "<pre language=\"haskell\"><code>\nimport Text.HTML.TagSoup\n\nmain :: IO ()\nmain = print $ parseTags tags\n</code></pre>\n<p>okay</p>\n", + "example": 139, + "start_line": 2403, + "end_line": 2419, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<script type=\"text/javascript\">\n// JavaScript example\n\ndocument.getElementById(\"demo\").innerHTML = \"Hello JavaScript!\";\n</script>\nokay\n", + "html": "<script type=\"text/javascript\">\n// JavaScript example\n\ndocument.getElementById(\"demo\").innerHTML = \"Hello JavaScript!\";\n</script>\n<p>okay</p>\n", + "example": 140, + "start_line": 2424, + "end_line": 2438, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<style\n type=\"text/css\">\nh1 {color:red;}\n\np {color:blue;}\n</style>\nokay\n", + "html": "<style\n type=\"text/css\">\nh1 {color:red;}\n\np {color:blue;}\n</style>\n<p>okay</p>\n", + "example": 141, + "start_line": 2443, + "end_line": 2459, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<style\n type=\"text/css\">\n\nfoo\n", + "html": "<style\n type=\"text/css\">\n\nfoo\n", + "example": 142, + "start_line": 2466, + "end_line": 2476, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "> <div>\n> foo\n\nbar\n", + "html": "<blockquote>\n<div>\nfoo\n</blockquote>\n<p>bar</p>\n", + "example": 143, + "start_line": 2479, + "end_line": 2490, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "- <div>\n- foo\n", + "html": "<ul>\n<li>\n<div>\n</li>\n<li>foo</li>\n</ul>\n", + "example": 144, + "start_line": 2493, + "end_line": 2503, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<style>p{color:red;}</style>\n*foo*\n", + "html": "<style>p{color:red;}</style>\n<p><em>foo</em></p>\n", + "example": 145, + "start_line": 2508, + "end_line": 2514, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<!-- foo -->*bar*\n*baz*\n", + "html": "<!-- foo -->*bar*\n<p><em>baz</em></p>\n", + "example": 146, + "start_line": 2517, + "end_line": 2523, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<script>\nfoo\n</script>1. *bar*\n", + "html": "<script>\nfoo\n</script>1. *bar*\n", + "example": 147, + "start_line": 2529, + "end_line": 2537, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<!-- Foo\n\nbar\n baz -->\nokay\n", + "html": "<!-- Foo\n\nbar\n baz -->\n<p>okay</p>\n", + "example": 148, + "start_line": 2542, + "end_line": 2554, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<?php\n\n echo '>';\n\n?>\nokay\n", + "html": "<?php\n\n echo '>';\n\n?>\n<p>okay</p>\n", + "example": 149, + "start_line": 2560, + "end_line": 2574, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<!DOCTYPE html>\n", + "html": "<!DOCTYPE html>\n", + "example": 150, + "start_line": 2579, + "end_line": 2583, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<![CDATA[\nfunction matchwo(a,b)\n{\n if (a < b && a < 0) then {\n return 1;\n\n } else {\n\n return 0;\n }\n}\n]]>\nokay\n", + "html": "<![CDATA[\nfunction matchwo(a,b)\n{\n if (a < b && a < 0) then {\n return 1;\n\n } else {\n\n return 0;\n }\n}\n]]>\n<p>okay</p>\n", + "example": 151, + "start_line": 2588, + "end_line": 2616, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": " <!-- foo -->\n\n <!-- foo -->\n", + "html": " <!-- foo -->\n<pre><code><!-- foo -->\n</code></pre>\n", + "example": 152, + "start_line": 2621, + "end_line": 2629, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": " <div>\n\n <div>\n", + "html": " <div>\n<pre><code><div>\n</code></pre>\n", + "example": 153, + "start_line": 2632, + "end_line": 2640, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "Foo\n<div>\nbar\n</div>\n", + "html": "<p>Foo</p>\n<div>\nbar\n</div>\n", + "example": 154, + "start_line": 2646, + "end_line": 2656, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<div>\nbar\n</div>\n*foo*\n", + "html": "<div>\nbar\n</div>\n*foo*\n", + "example": 155, + "start_line": 2663, + "end_line": 2673, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "Foo\n<a href=\"bar\">\nbaz\n", + "html": "<p>Foo\n<a href=\"bar\">\nbaz</p>\n", + "example": 156, + "start_line": 2678, + "end_line": 2686, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<div>\n\n*Emphasized* text.\n\n</div>\n", + "html": "<div>\n<p><em>Emphasized</em> text.</p>\n</div>\n", + "example": 157, + "start_line": 2719, + "end_line": 2729, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<div>\n*Emphasized* text.\n</div>\n", + "html": "<div>\n*Emphasized* text.\n</div>\n", + "example": 158, + "start_line": 2732, + "end_line": 2740, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<table>\n\n<tr>\n\n<td>\nHi\n</td>\n\n</tr>\n\n</table>\n", + "html": "<table>\n<tr>\n<td>\nHi\n</td>\n</tr>\n</table>\n", + "example": 159, + "start_line": 2754, + "end_line": 2774, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "<table>\n\n <tr>\n\n <td>\n Hi\n </td>\n\n </tr>\n\n</table>\n", + "html": "<table>\n <tr>\n<pre><code><td>\n Hi\n</td>\n</code></pre>\n </tr>\n</table>\n", + "example": 160, + "start_line": 2781, + "end_line": 2802, + "section": "HTML blocks", + "extensions": [] + }, + { + "markdown": "[foo]: /url \"title\"\n\n[foo]\n", + "html": "<p><a href=\"/url\" title=\"title\">foo</a></p>\n", + "example": 161, + "start_line": 2829, + "end_line": 2835, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": " [foo]: \n /url \n 'the title' \n\n[foo]\n", + "html": "<p><a href=\"/url\" title=\"the title\">foo</a></p>\n", + "example": 162, + "start_line": 2838, + "end_line": 2846, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[Foo*bar\\]]:my_(url) 'title (with parens)'\n\n[Foo*bar\\]]\n", + "html": "<p><a href=\"my_(url)\" title=\"title (with parens)\">Foo*bar]</a></p>\n", + "example": 163, + "start_line": 2849, + "end_line": 2855, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[Foo bar]:\n<my url>\n'title'\n\n[Foo bar]\n", + "html": "<p><a href=\"my%20url\" title=\"title\">Foo bar</a></p>\n", + "example": 164, + "start_line": 2858, + "end_line": 2866, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[foo]: /url '\ntitle\nline1\nline2\n'\n\n[foo]\n", + "html": "<p><a href=\"/url\" title=\"\ntitle\nline1\nline2\n\">foo</a></p>\n", + "example": 165, + "start_line": 2871, + "end_line": 2885, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[foo]: /url 'title\n\nwith blank line'\n\n[foo]\n", + "html": "<p>[foo]: /url 'title</p>\n<p>with blank line'</p>\n<p>[foo]</p>\n", + "example": 166, + "start_line": 2890, + "end_line": 2900, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[foo]:\n/url\n\n[foo]\n", + "html": "<p><a href=\"/url\">foo</a></p>\n", + "example": 167, + "start_line": 2905, + "end_line": 2912, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[foo]:\n\n[foo]\n", + "html": "<p>[foo]:</p>\n<p>[foo]</p>\n", + "example": 168, + "start_line": 2917, + "end_line": 2924, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[foo]: <>\n\n[foo]\n", + "html": "<p><a href=\"\">foo</a></p>\n", + "example": 169, + "start_line": 2929, + "end_line": 2935, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[foo]: <bar>(baz)\n\n[foo]\n", + "html": "<p>[foo]: <bar>(baz)</p>\n<p>[foo]</p>\n", + "example": 170, + "start_line": 2940, + "end_line": 2947, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[foo]: /url\\bar\\*baz \"foo\\\"bar\\baz\"\n\n[foo]\n", + "html": "<p><a href=\"/url%5Cbar*baz\" title=\"foo"bar\\baz\">foo</a></p>\n", + "example": 171, + "start_line": 2953, + "end_line": 2959, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[foo]\n\n[foo]: url\n", + "html": "<p><a href=\"url\">foo</a></p>\n", + "example": 172, + "start_line": 2964, + "end_line": 2970, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[foo]\n\n[foo]: first\n[foo]: second\n", + "html": "<p><a href=\"first\">foo</a></p>\n", + "example": 173, + "start_line": 2976, + "end_line": 2983, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[FOO]: /url\n\n[Foo]\n", + "html": "<p><a href=\"/url\">Foo</a></p>\n", + "example": 174, + "start_line": 2989, + "end_line": 2995, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[\u0391\u0393\u03a9]: /\u03c6\u03bf\u03c5\n\n[\u03b1\u03b3\u03c9]\n", + "html": "<p><a href=\"/%CF%86%CE%BF%CF%85\">\u03b1\u03b3\u03c9</a></p>\n", + "example": 175, + "start_line": 2998, + "end_line": 3004, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[foo]: /url\n", + "html": "", + "example": 176, + "start_line": 3010, + "end_line": 3013, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[\nfoo\n]: /url\nbar\n", + "html": "<p>bar</p>\n", + "example": 177, + "start_line": 3018, + "end_line": 3025, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[foo]: /url \"title\" ok\n", + "html": "<p>[foo]: /url "title" ok</p>\n", + "example": 178, + "start_line": 3031, + "end_line": 3035, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[foo]: /url\n\"title\" ok\n", + "html": "<p>"title" ok</p>\n", + "example": 179, + "start_line": 3040, + "end_line": 3045, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": " [foo]: /url \"title\"\n\n[foo]\n", + "html": "<pre><code>[foo]: /url "title"\n</code></pre>\n<p>[foo]</p>\n", + "example": 180, + "start_line": 3051, + "end_line": 3059, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "```\n[foo]: /url\n```\n\n[foo]\n", + "html": "<pre><code>[foo]: /url\n</code></pre>\n<p>[foo]</p>\n", + "example": 181, + "start_line": 3065, + "end_line": 3075, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "Foo\n[bar]: /baz\n\n[bar]\n", + "html": "<p>Foo\n[bar]: /baz</p>\n<p>[bar]</p>\n", + "example": 182, + "start_line": 3080, + "end_line": 3089, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "# [Foo]\n[foo]: /url\n> bar\n", + "html": "<h1><a href=\"/url\">Foo</a></h1>\n<blockquote>\n<p>bar</p>\n</blockquote>\n", + "example": 183, + "start_line": 3095, + "end_line": 3104, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[foo]: /url\nbar\n===\n[foo]\n", + "html": "<h1>bar</h1>\n<p><a href=\"/url\">foo</a></p>\n", + "example": 184, + "start_line": 3106, + "end_line": 3114, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[foo]: /url\n===\n[foo]\n", + "html": "<p>===\n<a href=\"/url\">foo</a></p>\n", + "example": 185, + "start_line": 3116, + "end_line": 3123, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[foo]: /foo-url \"foo\"\n[bar]: /bar-url\n \"bar\"\n[baz]: /baz-url\n\n[foo],\n[bar],\n[baz]\n", + "html": "<p><a href=\"/foo-url\" title=\"foo\">foo</a>,\n<a href=\"/bar-url\" title=\"bar\">bar</a>,\n<a href=\"/baz-url\">baz</a></p>\n", + "example": 186, + "start_line": 3129, + "end_line": 3142, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[foo]\n\n> [foo]: /url\n", + "html": "<p><a href=\"/url\">foo</a></p>\n<blockquote>\n</blockquote>\n", + "example": 187, + "start_line": 3150, + "end_line": 3158, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "[foo]: /url\n", + "html": "", + "example": 188, + "start_line": 3167, + "end_line": 3170, + "section": "Link reference definitions", + "extensions": [] + }, + { + "markdown": "aaa\n\nbbb\n", + "html": "<p>aaa</p>\n<p>bbb</p>\n", + "example": 189, + "start_line": 3184, + "end_line": 3191, + "section": "Paragraphs", + "extensions": [] + }, + { + "markdown": "aaa\nbbb\n\nccc\nddd\n", + "html": "<p>aaa\nbbb</p>\n<p>ccc\nddd</p>\n", + "example": 190, + "start_line": 3196, + "end_line": 3207, + "section": "Paragraphs", + "extensions": [] + }, + { + "markdown": "aaa\n\n\nbbb\n", + "html": "<p>aaa</p>\n<p>bbb</p>\n", + "example": 191, + "start_line": 3212, + "end_line": 3220, + "section": "Paragraphs", + "extensions": [] + }, + { + "markdown": " aaa\n bbb\n", + "html": "<p>aaa\nbbb</p>\n", + "example": 192, + "start_line": 3225, + "end_line": 3231, + "section": "Paragraphs", + "extensions": [] + }, + { + "markdown": "aaa\n bbb\n ccc\n", + "html": "<p>aaa\nbbb\nccc</p>\n", + "example": 193, + "start_line": 3237, + "end_line": 3245, + "section": "Paragraphs", + "extensions": [] + }, + { + "markdown": " aaa\nbbb\n", + "html": "<p>aaa\nbbb</p>\n", + "example": 194, + "start_line": 3251, + "end_line": 3257, + "section": "Paragraphs", + "extensions": [] + }, + { + "markdown": " aaa\nbbb\n", + "html": "<pre><code>aaa\n</code></pre>\n<p>bbb</p>\n", + "example": 195, + "start_line": 3260, + "end_line": 3267, + "section": "Paragraphs", + "extensions": [] + }, + { + "markdown": "aaa \nbbb \n", + "html": "<p>aaa<br />\nbbb</p>\n", + "example": 196, + "start_line": 3274, + "end_line": 3280, + "section": "Paragraphs", + "extensions": [] + }, + { + "markdown": " \n\naaa\n \n\n# aaa\n\n \n", + "html": "<p>aaa</p>\n<h1>aaa</h1>\n", + "example": 197, + "start_line": 3291, + "end_line": 3303, + "section": "Blank lines", + "extensions": [] + }, + { + "markdown": "| foo | bar |\n| --- | --- |\n| baz | bim |\n", + "html": "<table>\n<thead>\n<tr>\n<th>foo</th>\n<th>bar</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>baz</td>\n<td>bim</td>\n</tr>\n</tbody>\n</table>\n", + "example": 198, + "start_line": 3326, + "end_line": 3345, + "section": "Tables (extension)", + "extensions": [ + "table" + ] + }, + { + "markdown": "| abc | defghi |\n:-: | -----------:\nbar | baz\n", + "html": "<table>\n<thead>\n<tr>\n<th align=\"center\">abc</th>\n<th align=\"right\">defghi</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td align=\"center\">bar</td>\n<td align=\"right\">baz</td>\n</tr>\n</tbody>\n</table>\n", + "example": 199, + "start_line": 3350, + "end_line": 3369, + "section": "Tables (extension)", + "extensions": [ + "table" + ] + }, + { + "markdown": "| f\\|oo |\n| ------ |\n| b `\\|` az |\n| b **\\|** im |\n", + "html": "<table>\n<thead>\n<tr>\n<th>f|oo</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>b <code>|</code> az</td>\n</tr>\n<tr>\n<td>b <strong>|</strong> im</td>\n</tr>\n</tbody>\n</table>\n", + "example": 200, + "start_line": 3374, + "end_line": 3395, + "section": "Tables (extension)", + "extensions": [ + "table" + ] + }, + { + "markdown": "| abc | def |\n| --- | --- |\n| bar | baz |\n> bar\n", + "html": "<table>\n<thead>\n<tr>\n<th>abc</th>\n<th>def</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>bar</td>\n<td>baz</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>bar</p>\n</blockquote>\n", + "example": 201, + "start_line": 3400, + "end_line": 3423, + "section": "Tables (extension)", + "extensions": [ + "table" + ] + }, + { + "markdown": "| abc | def |\n| --- | --- |\n| bar | baz |\nbar\n\nbar\n", + "html": "<table>\n<thead>\n<tr>\n<th>abc</th>\n<th>def</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>bar</td>\n<td>baz</td>\n</tr>\n<tr>\n<td>bar</td>\n<td></td>\n</tr>\n</tbody>\n</table>\n<p>bar</p>\n", + "example": 202, + "start_line": 3425, + "end_line": 3452, + "section": "Tables (extension)", + "extensions": [ + "table" + ] + }, + { + "markdown": "| abc | def |\n| --- |\n| bar |\n", + "html": "<p>| abc | def |\n| --- |\n| bar |</p>\n", + "example": 203, + "start_line": 3457, + "end_line": 3465, + "section": "Tables (extension)", + "extensions": [ + "table" + ] + }, + { + "markdown": "| abc | def |\n| --- | --- |\n| bar |\n| bar | baz | boo |\n", + "html": "<table>\n<thead>\n<tr>\n<th>abc</th>\n<th>def</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>bar</td>\n<td></td>\n</tr>\n<tr>\n<td>bar</td>\n<td>baz</td>\n</tr>\n</tbody>\n</table>\n", + "example": 204, + "start_line": 3471, + "end_line": 3495, + "section": "Tables (extension)", + "extensions": [ + "table" + ] + }, + { + "markdown": "| abc | def |\n| --- | --- |\n", + "html": "<table>\n<thead>\n<tr>\n<th>abc</th>\n<th>def</th>\n</tr>\n</thead>\n</table>\n", + "example": 205, + "start_line": 3499, + "end_line": 3511, + "section": "Tables (extension)", + "extensions": [ + "table" + ] + }, + { + "markdown": "> # Foo\n> bar\n> baz\n", + "html": "<blockquote>\n<h1>Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>\n", + "example": 206, + "start_line": 3565, + "end_line": 3575, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": "># Foo\n>bar\n> baz\n", + "html": "<blockquote>\n<h1>Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>\n", + "example": 207, + "start_line": 3580, + "end_line": 3590, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": " > # Foo\n > bar\n > baz\n", + "html": "<blockquote>\n<h1>Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>\n", + "example": 208, + "start_line": 3595, + "end_line": 3605, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": " > # Foo\n > bar\n > baz\n", + "html": "<pre><code>> # Foo\n> bar\n> baz\n</code></pre>\n", + "example": 209, + "start_line": 3610, + "end_line": 3619, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": "> # Foo\n> bar\nbaz\n", + "html": "<blockquote>\n<h1>Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>\n", + "example": 210, + "start_line": 3625, + "end_line": 3635, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": "> bar\nbaz\n> foo\n", + "html": "<blockquote>\n<p>bar\nbaz\nfoo</p>\n</blockquote>\n", + "example": 211, + "start_line": 3641, + "end_line": 3651, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": "> foo\n---\n", + "html": "<blockquote>\n<p>foo</p>\n</blockquote>\n<hr />\n", + "example": 212, + "start_line": 3665, + "end_line": 3673, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": "> - foo\n- bar\n", + "html": "<blockquote>\n<ul>\n<li>foo</li>\n</ul>\n</blockquote>\n<ul>\n<li>bar</li>\n</ul>\n", + "example": 213, + "start_line": 3685, + "end_line": 3697, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": "> foo\n bar\n", + "html": "<blockquote>\n<pre><code>foo\n</code></pre>\n</blockquote>\n<pre><code>bar\n</code></pre>\n", + "example": 214, + "start_line": 3703, + "end_line": 3713, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": "> ```\nfoo\n```\n", + "html": "<blockquote>\n<pre><code></code></pre>\n</blockquote>\n<p>foo</p>\n<pre><code></code></pre>\n", + "example": 215, + "start_line": 3716, + "end_line": 3726, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": "> foo\n - bar\n", + "html": "<blockquote>\n<p>foo\n- bar</p>\n</blockquote>\n", + "example": 216, + "start_line": 3732, + "end_line": 3740, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": ">\n", + "html": "<blockquote>\n</blockquote>\n", + "example": 217, + "start_line": 3756, + "end_line": 3761, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": ">\n> \n> \n", + "html": "<blockquote>\n</blockquote>\n", + "example": 218, + "start_line": 3764, + "end_line": 3771, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": ">\n> foo\n> \n", + "html": "<blockquote>\n<p>foo</p>\n</blockquote>\n", + "example": 219, + "start_line": 3776, + "end_line": 3784, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": "> foo\n\n> bar\n", + "html": "<blockquote>\n<p>foo</p>\n</blockquote>\n<blockquote>\n<p>bar</p>\n</blockquote>\n", + "example": 220, + "start_line": 3789, + "end_line": 3800, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": "> foo\n> bar\n", + "html": "<blockquote>\n<p>foo\nbar</p>\n</blockquote>\n", + "example": 221, + "start_line": 3811, + "end_line": 3819, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": "> foo\n>\n> bar\n", + "html": "<blockquote>\n<p>foo</p>\n<p>bar</p>\n</blockquote>\n", + "example": 222, + "start_line": 3824, + "end_line": 3833, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": "foo\n> bar\n", + "html": "<p>foo</p>\n<blockquote>\n<p>bar</p>\n</blockquote>\n", + "example": 223, + "start_line": 3838, + "end_line": 3846, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": "> aaa\n***\n> bbb\n", + "html": "<blockquote>\n<p>aaa</p>\n</blockquote>\n<hr />\n<blockquote>\n<p>bbb</p>\n</blockquote>\n", + "example": 224, + "start_line": 3852, + "end_line": 3864, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": "> bar\nbaz\n", + "html": "<blockquote>\n<p>bar\nbaz</p>\n</blockquote>\n", + "example": 225, + "start_line": 3870, + "end_line": 3878, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": "> bar\n\nbaz\n", + "html": "<blockquote>\n<p>bar</p>\n</blockquote>\n<p>baz</p>\n", + "example": 226, + "start_line": 3881, + "end_line": 3890, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": "> bar\n>\nbaz\n", + "html": "<blockquote>\n<p>bar</p>\n</blockquote>\n<p>baz</p>\n", + "example": 227, + "start_line": 3893, + "end_line": 3902, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": "> > > foo\nbar\n", + "html": "<blockquote>\n<blockquote>\n<blockquote>\n<p>foo\nbar</p>\n</blockquote>\n</blockquote>\n</blockquote>\n", + "example": 228, + "start_line": 3909, + "end_line": 3921, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": ">>> foo\n> bar\n>>baz\n", + "html": "<blockquote>\n<blockquote>\n<blockquote>\n<p>foo\nbar\nbaz</p>\n</blockquote>\n</blockquote>\n</blockquote>\n", + "example": 229, + "start_line": 3924, + "end_line": 3938, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": "> code\n\n> not code\n", + "html": "<blockquote>\n<pre><code>code\n</code></pre>\n</blockquote>\n<blockquote>\n<p>not code</p>\n</blockquote>\n", + "example": 230, + "start_line": 3946, + "end_line": 3958, + "section": "Block quotes", + "extensions": [] + }, + { + "markdown": "A paragraph\nwith two lines.\n\n indented code\n\n> A block quote.\n", + "html": "<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n", + "example": 231, + "start_line": 4000, + "end_line": 4015, + "section": "List items", + "extensions": [] + }, + { + "markdown": "1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n", + "html": "<ol>\n<li>\n<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n</li>\n</ol>\n", + "example": 232, + "start_line": 4022, + "end_line": 4041, + "section": "List items", + "extensions": [] + }, + { + "markdown": "- one\n\n two\n", + "html": "<ul>\n<li>one</li>\n</ul>\n<p>two</p>\n", + "example": 233, + "start_line": 4055, + "end_line": 4064, + "section": "List items", + "extensions": [] + }, + { + "markdown": "- one\n\n two\n", + "html": "<ul>\n<li>\n<p>one</p>\n<p>two</p>\n</li>\n</ul>\n", + "example": 234, + "start_line": 4067, + "end_line": 4078, + "section": "List items", + "extensions": [] + }, + { + "markdown": " - one\n\n two\n", + "html": "<ul>\n<li>one</li>\n</ul>\n<pre><code> two\n</code></pre>\n", + "example": 235, + "start_line": 4081, + "end_line": 4091, + "section": "List items", + "extensions": [] + }, + { + "markdown": " - one\n\n two\n", + "html": "<ul>\n<li>\n<p>one</p>\n<p>two</p>\n</li>\n</ul>\n", + "example": 236, + "start_line": 4094, + "end_line": 4105, + "section": "List items", + "extensions": [] + }, + { + "markdown": " > > 1. one\n>>\n>> two\n", + "html": "<blockquote>\n<blockquote>\n<ol>\n<li>\n<p>one</p>\n<p>two</p>\n</li>\n</ol>\n</blockquote>\n</blockquote>\n", + "example": 237, + "start_line": 4116, + "end_line": 4131, + "section": "List items", + "extensions": [] + }, + { + "markdown": ">>- one\n>>\n > > two\n", + "html": "<blockquote>\n<blockquote>\n<ul>\n<li>one</li>\n</ul>\n<p>two</p>\n</blockquote>\n</blockquote>\n", + "example": 238, + "start_line": 4143, + "end_line": 4156, + "section": "List items", + "extensions": [] + }, + { + "markdown": "-one\n\n2.two\n", + "html": "<p>-one</p>\n<p>2.two</p>\n", + "example": 239, + "start_line": 4162, + "end_line": 4169, + "section": "List items", + "extensions": [] + }, + { + "markdown": "- foo\n\n\n bar\n", + "html": "<ul>\n<li>\n<p>foo</p>\n<p>bar</p>\n</li>\n</ul>\n", + "example": 240, + "start_line": 4175, + "end_line": 4187, + "section": "List items", + "extensions": [] + }, + { + "markdown": "1. foo\n\n ```\n bar\n ```\n\n baz\n\n > bam\n", + "html": "<ol>\n<li>\n<p>foo</p>\n<pre><code>bar\n</code></pre>\n<p>baz</p>\n<blockquote>\n<p>bam</p>\n</blockquote>\n</li>\n</ol>\n", + "example": 241, + "start_line": 4192, + "end_line": 4214, + "section": "List items", + "extensions": [] + }, + { + "markdown": "- Foo\n\n bar\n\n\n baz\n", + "html": "<ul>\n<li>\n<p>Foo</p>\n<pre><code>bar\n\n\nbaz\n</code></pre>\n</li>\n</ul>\n", + "example": 242, + "start_line": 4220, + "end_line": 4238, + "section": "List items", + "extensions": [] + }, + { + "markdown": "123456789. ok\n", + "html": "<ol start=\"123456789\">\n<li>ok</li>\n</ol>\n", + "example": 243, + "start_line": 4242, + "end_line": 4248, + "section": "List items", + "extensions": [] + }, + { + "markdown": "1234567890. not ok\n", + "html": "<p>1234567890. not ok</p>\n", + "example": 244, + "start_line": 4251, + "end_line": 4255, + "section": "List items", + "extensions": [] + }, + { + "markdown": "0. ok\n", + "html": "<ol start=\"0\">\n<li>ok</li>\n</ol>\n", + "example": 245, + "start_line": 4260, + "end_line": 4266, + "section": "List items", + "extensions": [] + }, + { + "markdown": "003. ok\n", + "html": "<ol start=\"3\">\n<li>ok</li>\n</ol>\n", + "example": 246, + "start_line": 4269, + "end_line": 4275, + "section": "List items", + "extensions": [] + }, + { + "markdown": "-1. not ok\n", + "html": "<p>-1. not ok</p>\n", + "example": 247, + "start_line": 4280, + "end_line": 4284, + "section": "List items", + "extensions": [] + }, + { + "markdown": "- foo\n\n bar\n", + "html": "<ul>\n<li>\n<p>foo</p>\n<pre><code>bar\n</code></pre>\n</li>\n</ul>\n", + "example": 248, + "start_line": 4303, + "end_line": 4315, + "section": "List items", + "extensions": [] + }, + { + "markdown": " 10. foo\n\n bar\n", + "html": "<ol start=\"10\">\n<li>\n<p>foo</p>\n<pre><code>bar\n</code></pre>\n</li>\n</ol>\n", + "example": 249, + "start_line": 4320, + "end_line": 4332, + "section": "List items", + "extensions": [] + }, + { + "markdown": " indented code\n\nparagraph\n\n more code\n", + "html": "<pre><code>indented code\n</code></pre>\n<p>paragraph</p>\n<pre><code>more code\n</code></pre>\n", + "example": 250, + "start_line": 4339, + "end_line": 4351, + "section": "List items", + "extensions": [] + }, + { + "markdown": "1. indented code\n\n paragraph\n\n more code\n", + "html": "<ol>\n<li>\n<pre><code>indented code\n</code></pre>\n<p>paragraph</p>\n<pre><code>more code\n</code></pre>\n</li>\n</ol>\n", + "example": 251, + "start_line": 4354, + "end_line": 4370, + "section": "List items", + "extensions": [] + }, + { + "markdown": "1. indented code\n\n paragraph\n\n more code\n", + "html": "<ol>\n<li>\n<pre><code> indented code\n</code></pre>\n<p>paragraph</p>\n<pre><code>more code\n</code></pre>\n</li>\n</ol>\n", + "example": 252, + "start_line": 4376, + "end_line": 4392, + "section": "List items", + "extensions": [] + }, + { + "markdown": " foo\n\nbar\n", + "html": "<p>foo</p>\n<p>bar</p>\n", + "example": 253, + "start_line": 4403, + "end_line": 4410, + "section": "List items", + "extensions": [] + }, + { + "markdown": "- foo\n\n bar\n", + "html": "<ul>\n<li>foo</li>\n</ul>\n<p>bar</p>\n", + "example": 254, + "start_line": 4413, + "end_line": 4422, + "section": "List items", + "extensions": [] + }, + { + "markdown": "- foo\n\n bar\n", + "html": "<ul>\n<li>\n<p>foo</p>\n<p>bar</p>\n</li>\n</ul>\n", + "example": 255, + "start_line": 4430, + "end_line": 4441, + "section": "List items", + "extensions": [] + }, + { + "markdown": "-\n foo\n-\n ```\n bar\n ```\n-\n baz\n", + "html": "<ul>\n<li>foo</li>\n<li>\n<pre><code>bar\n</code></pre>\n</li>\n<li>\n<pre><code>baz\n</code></pre>\n</li>\n</ul>\n", + "example": 256, + "start_line": 4458, + "end_line": 4479, + "section": "List items", + "extensions": [] + }, + { + "markdown": "- \n foo\n", + "html": "<ul>\n<li>foo</li>\n</ul>\n", + "example": 257, + "start_line": 4484, + "end_line": 4491, + "section": "List items", + "extensions": [] + }, + { + "markdown": "-\n\n foo\n", + "html": "<ul>\n<li></li>\n</ul>\n<p>foo</p>\n", + "example": 258, + "start_line": 4498, + "end_line": 4507, + "section": "List items", + "extensions": [] + }, + { + "markdown": "- foo\n-\n- bar\n", + "html": "<ul>\n<li>foo</li>\n<li></li>\n<li>bar</li>\n</ul>\n", + "example": 259, + "start_line": 4512, + "end_line": 4522, + "section": "List items", + "extensions": [] + }, + { + "markdown": "- foo\n- \n- bar\n", + "html": "<ul>\n<li>foo</li>\n<li></li>\n<li>bar</li>\n</ul>\n", + "example": 260, + "start_line": 4527, + "end_line": 4537, + "section": "List items", + "extensions": [] + }, + { + "markdown": "1. foo\n2.\n3. bar\n", + "html": "<ol>\n<li>foo</li>\n<li></li>\n<li>bar</li>\n</ol>\n", + "example": 261, + "start_line": 4542, + "end_line": 4552, + "section": "List items", + "extensions": [] + }, + { + "markdown": "*\n", + "html": "<ul>\n<li></li>\n</ul>\n", + "example": 262, + "start_line": 4557, + "end_line": 4563, + "section": "List items", + "extensions": [] + }, + { + "markdown": "foo\n*\n\nfoo\n1.\n", + "html": "<p>foo\n*</p>\n<p>foo\n1.</p>\n", + "example": 263, + "start_line": 4567, + "end_line": 4578, + "section": "List items", + "extensions": [] + }, + { + "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n", + "html": "<ol>\n<li>\n<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n</li>\n</ol>\n", + "example": 264, + "start_line": 4589, + "end_line": 4608, + "section": "List items", + "extensions": [] + }, + { + "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n", + "html": "<ol>\n<li>\n<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n</li>\n</ol>\n", + "example": 265, + "start_line": 4613, + "end_line": 4632, + "section": "List items", + "extensions": [] + }, + { + "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n", + "html": "<ol>\n<li>\n<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n</li>\n</ol>\n", + "example": 266, + "start_line": 4637, + "end_line": 4656, + "section": "List items", + "extensions": [] + }, + { + "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n", + "html": "<pre><code>1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n</code></pre>\n", + "example": 267, + "start_line": 4661, + "end_line": 4676, + "section": "List items", + "extensions": [] + }, + { + "markdown": " 1. A paragraph\nwith two lines.\n\n indented code\n\n > A block quote.\n", + "html": "<ol>\n<li>\n<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n</li>\n</ol>\n", + "example": 268, + "start_line": 4691, + "end_line": 4710, + "section": "List items", + "extensions": [] + }, + { + "markdown": " 1. A paragraph\n with two lines.\n", + "html": "<ol>\n<li>A paragraph\nwith two lines.</li>\n</ol>\n", + "example": 269, + "start_line": 4715, + "end_line": 4723, + "section": "List items", + "extensions": [] + }, + { + "markdown": "> 1. > Blockquote\ncontinued here.\n", + "html": "<blockquote>\n<ol>\n<li>\n<blockquote>\n<p>Blockquote\ncontinued here.</p>\n</blockquote>\n</li>\n</ol>\n</blockquote>\n", + "example": 270, + "start_line": 4728, + "end_line": 4742, + "section": "List items", + "extensions": [] + }, + { + "markdown": "> 1. > Blockquote\n> continued here.\n", + "html": "<blockquote>\n<ol>\n<li>\n<blockquote>\n<p>Blockquote\ncontinued here.</p>\n</blockquote>\n</li>\n</ol>\n</blockquote>\n", + "example": 271, + "start_line": 4745, + "end_line": 4759, + "section": "List items", + "extensions": [] + }, + { + "markdown": "- foo\n - bar\n - baz\n - boo\n", + "html": "<ul>\n<li>foo\n<ul>\n<li>bar\n<ul>\n<li>baz\n<ul>\n<li>boo</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n", + "example": 272, + "start_line": 4773, + "end_line": 4794, + "section": "List items", + "extensions": [] + }, + { + "markdown": "- foo\n - bar\n - baz\n - boo\n", + "html": "<ul>\n<li>foo</li>\n<li>bar</li>\n<li>baz</li>\n<li>boo</li>\n</ul>\n", + "example": 273, + "start_line": 4799, + "end_line": 4811, + "section": "List items", + "extensions": [] + }, + { + "markdown": "10) foo\n - bar\n", + "html": "<ol start=\"10\">\n<li>foo\n<ul>\n<li>bar</li>\n</ul>\n</li>\n</ol>\n", + "example": 274, + "start_line": 4816, + "end_line": 4827, + "section": "List items", + "extensions": [] + }, + { + "markdown": "10) foo\n - bar\n", + "html": "<ol start=\"10\">\n<li>foo</li>\n</ol>\n<ul>\n<li>bar</li>\n</ul>\n", + "example": 275, + "start_line": 4832, + "end_line": 4842, + "section": "List items", + "extensions": [] + }, + { + "markdown": "- - foo\n", + "html": "<ul>\n<li>\n<ul>\n<li>foo</li>\n</ul>\n</li>\n</ul>\n", + "example": 276, + "start_line": 4847, + "end_line": 4857, + "section": "List items", + "extensions": [] + }, + { + "markdown": "1. - 2. foo\n", + "html": "<ol>\n<li>\n<ul>\n<li>\n<ol start=\"2\">\n<li>foo</li>\n</ol>\n</li>\n</ul>\n</li>\n</ol>\n", + "example": 277, + "start_line": 4860, + "end_line": 4874, + "section": "List items", + "extensions": [] + }, + { + "markdown": "- # Foo\n- Bar\n ---\n baz\n", + "html": "<ul>\n<li>\n<h1>Foo</h1>\n</li>\n<li>\n<h2>Bar</h2>\nbaz</li>\n</ul>\n", + "example": 278, + "start_line": 4879, + "end_line": 4893, + "section": "List items", + "extensions": [] + }, + { + "markdown": "- foo\n- bar\n+ baz\n", + "html": "<ul>\n<li>foo</li>\n<li>bar</li>\n</ul>\n<ul>\n<li>baz</li>\n</ul>\n", + "example": 281, + "start_line": 5172, + "end_line": 5184, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "1. foo\n2. bar\n3) baz\n", + "html": "<ol>\n<li>foo</li>\n<li>bar</li>\n</ol>\n<ol start=\"3\">\n<li>baz</li>\n</ol>\n", + "example": 282, + "start_line": 5187, + "end_line": 5199, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "Foo\n- bar\n- baz\n", + "html": "<p>Foo</p>\n<ul>\n<li>bar</li>\n<li>baz</li>\n</ul>\n", + "example": 283, + "start_line": 5206, + "end_line": 5216, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "The number of windows in my house is\n14. The number of doors is 6.\n", + "html": "<p>The number of windows in my house is\n14. The number of doors is 6.</p>\n", + "example": 284, + "start_line": 5283, + "end_line": 5289, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "The number of windows in my house is\n1. The number of doors is 6.\n", + "html": "<p>The number of windows in my house is</p>\n<ol>\n<li>The number of doors is 6.</li>\n</ol>\n", + "example": 285, + "start_line": 5293, + "end_line": 5301, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "- foo\n\n- bar\n\n\n- baz\n", + "html": "<ul>\n<li>\n<p>foo</p>\n</li>\n<li>\n<p>bar</p>\n</li>\n<li>\n<p>baz</p>\n</li>\n</ul>\n", + "example": 286, + "start_line": 5307, + "end_line": 5326, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "- foo\n - bar\n - baz\n\n\n bim\n", + "html": "<ul>\n<li>foo\n<ul>\n<li>bar\n<ul>\n<li>\n<p>baz</p>\n<p>bim</p>\n</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n", + "example": 287, + "start_line": 5328, + "end_line": 5350, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "- foo\n- bar\n\n<!-- -->\n\n- baz\n- bim\n", + "html": "<ul>\n<li>foo</li>\n<li>bar</li>\n</ul>\n<!-- -->\n<ul>\n<li>baz</li>\n<li>bim</li>\n</ul>\n", + "example": 288, + "start_line": 5358, + "end_line": 5376, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "- foo\n\n notcode\n\n- foo\n\n<!-- -->\n\n code\n", + "html": "<ul>\n<li>\n<p>foo</p>\n<p>notcode</p>\n</li>\n<li>\n<p>foo</p>\n</li>\n</ul>\n<!-- -->\n<pre><code>code\n</code></pre>\n", + "example": 289, + "start_line": 5379, + "end_line": 5402, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "- a\n - b\n - c\n - d\n - e\n - f\n- g\n", + "html": "<ul>\n<li>a</li>\n<li>b</li>\n<li>c</li>\n<li>d</li>\n<li>e</li>\n<li>f</li>\n<li>g</li>\n</ul>\n", + "example": 290, + "start_line": 5410, + "end_line": 5428, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "1. a\n\n 2. b\n\n 3. c\n", + "html": "<ol>\n<li>\n<p>a</p>\n</li>\n<li>\n<p>b</p>\n</li>\n<li>\n<p>c</p>\n</li>\n</ol>\n", + "example": 291, + "start_line": 5431, + "end_line": 5449, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "- a\n - b\n - c\n - d\n - e\n", + "html": "<ul>\n<li>a</li>\n<li>b</li>\n<li>c</li>\n<li>d\n- e</li>\n</ul>\n", + "example": 292, + "start_line": 5455, + "end_line": 5469, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "1. a\n\n 2. b\n\n 3. c\n", + "html": "<ol>\n<li>\n<p>a</p>\n</li>\n<li>\n<p>b</p>\n</li>\n</ol>\n<pre><code>3. c\n</code></pre>\n", + "example": 293, + "start_line": 5475, + "end_line": 5492, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "- a\n- b\n\n- c\n", + "html": "<ul>\n<li>\n<p>a</p>\n</li>\n<li>\n<p>b</p>\n</li>\n<li>\n<p>c</p>\n</li>\n</ul>\n", + "example": 294, + "start_line": 5498, + "end_line": 5515, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "* a\n*\n\n* c\n", + "html": "<ul>\n<li>\n<p>a</p>\n</li>\n<li></li>\n<li>\n<p>c</p>\n</li>\n</ul>\n", + "example": 295, + "start_line": 5520, + "end_line": 5535, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "- a\n- b\n\n c\n- d\n", + "html": "<ul>\n<li>\n<p>a</p>\n</li>\n<li>\n<p>b</p>\n<p>c</p>\n</li>\n<li>\n<p>d</p>\n</li>\n</ul>\n", + "example": 296, + "start_line": 5542, + "end_line": 5561, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "- a\n- b\n\n [ref]: /url\n- d\n", + "html": "<ul>\n<li>\n<p>a</p>\n</li>\n<li>\n<p>b</p>\n</li>\n<li>\n<p>d</p>\n</li>\n</ul>\n", + "example": 297, + "start_line": 5564, + "end_line": 5582, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "- a\n- ```\n b\n\n\n ```\n- c\n", + "html": "<ul>\n<li>a</li>\n<li>\n<pre><code>b\n\n\n</code></pre>\n</li>\n<li>c</li>\n</ul>\n", + "example": 298, + "start_line": 5587, + "end_line": 5606, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "- a\n - b\n\n c\n- d\n", + "html": "<ul>\n<li>a\n<ul>\n<li>\n<p>b</p>\n<p>c</p>\n</li>\n</ul>\n</li>\n<li>d</li>\n</ul>\n", + "example": 299, + "start_line": 5613, + "end_line": 5631, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "* a\n > b\n >\n* c\n", + "html": "<ul>\n<li>a\n<blockquote>\n<p>b</p>\n</blockquote>\n</li>\n<li>c</li>\n</ul>\n", + "example": 300, + "start_line": 5637, + "end_line": 5651, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "- a\n > b\n ```\n c\n ```\n- d\n", + "html": "<ul>\n<li>a\n<blockquote>\n<p>b</p>\n</blockquote>\n<pre><code>c\n</code></pre>\n</li>\n<li>d</li>\n</ul>\n", + "example": 301, + "start_line": 5657, + "end_line": 5675, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "- a\n", + "html": "<ul>\n<li>a</li>\n</ul>\n", + "example": 302, + "start_line": 5680, + "end_line": 5686, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "- a\n - b\n", + "html": "<ul>\n<li>a\n<ul>\n<li>b</li>\n</ul>\n</li>\n</ul>\n", + "example": 303, + "start_line": 5689, + "end_line": 5700, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "1. ```\n foo\n ```\n\n bar\n", + "html": "<ol>\n<li>\n<pre><code>foo\n</code></pre>\n<p>bar</p>\n</li>\n</ol>\n", + "example": 304, + "start_line": 5706, + "end_line": 5720, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "* foo\n * bar\n\n baz\n", + "html": "<ul>\n<li>\n<p>foo</p>\n<ul>\n<li>bar</li>\n</ul>\n<p>baz</p>\n</li>\n</ul>\n", + "example": 305, + "start_line": 5725, + "end_line": 5740, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "- a\n - b\n - c\n\n- d\n - e\n - f\n", + "html": "<ul>\n<li>\n<p>a</p>\n<ul>\n<li>b</li>\n<li>c</li>\n</ul>\n</li>\n<li>\n<p>d</p>\n<ul>\n<li>e</li>\n<li>f</li>\n</ul>\n</li>\n</ul>\n", + "example": 306, + "start_line": 5743, + "end_line": 5768, + "section": "Lists", + "extensions": [] + }, + { + "markdown": "`hi`lo`\n", + "html": "<p><code>hi</code>lo`</p>\n", + "example": 307, + "start_line": 5777, + "end_line": 5781, + "section": "Inlines", + "extensions": [] + }, + { + "markdown": "\\!\\\"\\#\\$\\%\\&\\'\\(\\)\\*\\+\\,\\-\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\\\\\]\\^\\_\\`\\{\\|\\}\\~\n", + "html": "<p>!"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~</p>\n", + "example": 308, + "start_line": 5791, + "end_line": 5795, + "section": "Backslash escapes", + "extensions": [] + }, + { + "markdown": "\\\t\\A\\a\\ \\3\\\u03c6\\\u00ab\n", + "html": "<p>\\\t\\A\\a\\ \\3\\\u03c6\\\u00ab</p>\n", + "example": 309, + "start_line": 5801, + "end_line": 5805, + "section": "Backslash escapes", + "extensions": [] + }, + { + "markdown": "\\*not emphasized*\n\\<br/> not a tag\n\\[not a link](/foo)\n\\`not code`\n1\\. not a list\n\\* not a list\n\\# not a heading\n\\[foo]: /url \"not a reference\"\n\\ö not a character entity\n", + "html": "<p>*not emphasized*\n<br/> not a tag\n[not a link](/foo)\n`not code`\n1. not a list\n* not a list\n# not a heading\n[foo]: /url "not a reference"\n&ouml; not a character entity</p>\n", + "example": 310, + "start_line": 5811, + "end_line": 5831, + "section": "Backslash escapes", + "extensions": [] + }, + { + "markdown": "\\\\*emphasis*\n", + "html": "<p>\\<em>emphasis</em></p>\n", + "example": 311, + "start_line": 5836, + "end_line": 5840, + "section": "Backslash escapes", + "extensions": [] + }, + { + "markdown": "foo\\\nbar\n", + "html": "<p>foo<br />\nbar</p>\n", + "example": 312, + "start_line": 5845, + "end_line": 5851, + "section": "Backslash escapes", + "extensions": [] + }, + { + "markdown": "`` \\[\\` ``\n", + "html": "<p><code>\\[\\`</code></p>\n", + "example": 313, + "start_line": 5857, + "end_line": 5861, + "section": "Backslash escapes", + "extensions": [] + }, + { + "markdown": " \\[\\]\n", + "html": "<pre><code>\\[\\]\n</code></pre>\n", + "example": 314, + "start_line": 5864, + "end_line": 5869, + "section": "Backslash escapes", + "extensions": [] + }, + { + "markdown": "~~~\n\\[\\]\n~~~\n", + "html": "<pre><code>\\[\\]\n</code></pre>\n", + "example": 315, + "start_line": 5872, + "end_line": 5879, + "section": "Backslash escapes", + "extensions": [] + }, + { + "markdown": "<http://example.com?find=\\*>\n", + "html": "<p><a href=\"http://example.com?find=%5C*\">http://example.com?find=\\*</a></p>\n", + "example": 316, + "start_line": 5882, + "end_line": 5886, + "section": "Backslash escapes", + "extensions": [] + }, + { + "markdown": "<a href=\"/bar\\/)\">\n", + "html": "<a href=\"/bar\\/)\">\n", + "example": 317, + "start_line": 5889, + "end_line": 5893, + "section": "Backslash escapes", + "extensions": [] + }, + { + "markdown": "[foo](/bar\\* \"ti\\*tle\")\n", + "html": "<p><a href=\"/bar*\" title=\"ti*tle\">foo</a></p>\n", + "example": 318, + "start_line": 5899, + "end_line": 5903, + "section": "Backslash escapes", + "extensions": [] + }, + { + "markdown": "[foo]\n\n[foo]: /bar\\* \"ti\\*tle\"\n", + "html": "<p><a href=\"/bar*\" title=\"ti*tle\">foo</a></p>\n", + "example": 319, + "start_line": 5906, + "end_line": 5912, + "section": "Backslash escapes", + "extensions": [] + }, + { + "markdown": "``` foo\\+bar\nfoo\n```\n", + "html": "<pre><code class=\"language-foo+bar\">foo\n</code></pre>\n", + "example": 320, + "start_line": 5915, + "end_line": 5922, + "section": "Backslash escapes", + "extensions": [] + }, + { + "markdown": "  & © Æ Ď\n¾ ℋ ⅆ\n∲ ≧̸\n", + "html": "<p>\u00a0 & \u00a9 \u00c6 \u010e\n\u00be \u210b \u2146\n\u2232 \u2267\u0338</p>\n", + "example": 321, + "start_line": 5952, + "end_line": 5960, + "section": "Entity and numeric character references", + "extensions": [] + }, + { + "markdown": "# Ӓ Ϡ �\n", + "html": "<p># \u04d2 \u03e0 \ufffd</p>\n", + "example": 322, + "start_line": 5971, + "end_line": 5975, + "section": "Entity and numeric character references", + "extensions": [] + }, + { + "markdown": "" ആ ಫ\n", + "html": "<p>" \u0d06 \u0cab</p>\n", + "example": 323, + "start_line": 5984, + "end_line": 5988, + "section": "Entity and numeric character references", + "extensions": [] + }, + { + "markdown": "  &x; &#; &#x;\n�\n&#abcdef0;\n&ThisIsNotDefined; &hi?;\n", + "html": "<p>&nbsp &x; &#; &#x;\n&#987654321;\n&#abcdef0;\n&ThisIsNotDefined; &hi?;</p>\n", + "example": 324, + "start_line": 5993, + "end_line": 6003, + "section": "Entity and numeric character references", + "extensions": [] + }, + { + "markdown": "©\n", + "html": "<p>&copy</p>\n", + "example": 325, + "start_line": 6010, + "end_line": 6014, + "section": "Entity and numeric character references", + "extensions": [] + }, + { + "markdown": "&MadeUpEntity;\n", + "html": "<p>&MadeUpEntity;</p>\n", + "example": 326, + "start_line": 6020, + "end_line": 6024, + "section": "Entity and numeric character references", + "extensions": [] + }, + { + "markdown": "<a href=\"öö.html\">\n", + "html": "<a href=\"öö.html\">\n", + "example": 327, + "start_line": 6031, + "end_line": 6035, + "section": "Entity and numeric character references", + "extensions": [] + }, + { + "markdown": "[foo](/föö \"föö\")\n", + "html": "<p><a href=\"/f%C3%B6%C3%B6\" title=\"f\u00f6\u00f6\">foo</a></p>\n", + "example": 328, + "start_line": 6038, + "end_line": 6042, + "section": "Entity and numeric character references", + "extensions": [] + }, + { + "markdown": "[foo]\n\n[foo]: /föö \"föö\"\n", + "html": "<p><a href=\"/f%C3%B6%C3%B6\" title=\"f\u00f6\u00f6\">foo</a></p>\n", + "example": 329, + "start_line": 6045, + "end_line": 6051, + "section": "Entity and numeric character references", + "extensions": [] + }, + { + "markdown": "``` föö\nfoo\n```\n", + "html": "<pre><code class=\"language-f\u00f6\u00f6\">foo\n</code></pre>\n", + "example": 330, + "start_line": 6054, + "end_line": 6061, + "section": "Entity and numeric character references", + "extensions": [] + }, + { + "markdown": "`föö`\n", + "html": "<p><code>f&ouml;&ouml;</code></p>\n", + "example": 331, + "start_line": 6067, + "end_line": 6071, + "section": "Entity and numeric character references", + "extensions": [] + }, + { + "markdown": " föfö\n", + "html": "<pre><code>f&ouml;f&ouml;\n</code></pre>\n", + "example": 332, + "start_line": 6074, + "end_line": 6079, + "section": "Entity and numeric character references", + "extensions": [] + }, + { + "markdown": "*foo*\n*foo*\n", + "html": "<p>*foo*\n<em>foo</em></p>\n", + "example": 333, + "start_line": 6086, + "end_line": 6092, + "section": "Entity and numeric character references", + "extensions": [] + }, + { + "markdown": "* foo\n\n* foo\n", + "html": "<p>* foo</p>\n<ul>\n<li>foo</li>\n</ul>\n", + "example": 334, + "start_line": 6094, + "end_line": 6103, + "section": "Entity and numeric character references", + "extensions": [] + }, + { + "markdown": "foo bar\n", + "html": "<p>foo\n\nbar</p>\n", + "example": 335, + "start_line": 6105, + "end_line": 6111, + "section": "Entity and numeric character references", + "extensions": [] + }, + { + "markdown": " foo\n", + "html": "<p>\tfoo</p>\n", + "example": 336, + "start_line": 6113, + "end_line": 6117, + "section": "Entity and numeric character references", + "extensions": [] + }, + { + "markdown": "[a](url "tit")\n", + "html": "<p>[a](url "tit")</p>\n", + "example": 337, + "start_line": 6120, + "end_line": 6124, + "section": "Entity and numeric character references", + "extensions": [] + }, + { + "markdown": "`foo`\n", + "html": "<p><code>foo</code></p>\n", + "example": 338, + "start_line": 6148, + "end_line": 6152, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "`` foo ` bar ``\n", + "html": "<p><code>foo ` bar</code></p>\n", + "example": 339, + "start_line": 6159, + "end_line": 6163, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "` `` `\n", + "html": "<p><code>``</code></p>\n", + "example": 340, + "start_line": 6169, + "end_line": 6173, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "` `` `\n", + "html": "<p><code> `` </code></p>\n", + "example": 341, + "start_line": 6177, + "end_line": 6181, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "` a`\n", + "html": "<p><code> a</code></p>\n", + "example": 342, + "start_line": 6186, + "end_line": 6190, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "`\u00a0b\u00a0`\n", + "html": "<p><code>\u00a0b\u00a0</code></p>\n", + "example": 343, + "start_line": 6195, + "end_line": 6199, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "`\u00a0`\n` `\n", + "html": "<p><code>\u00a0</code>\n<code> </code></p>\n", + "example": 344, + "start_line": 6203, + "end_line": 6209, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "``\nfoo\nbar \nbaz\n``\n", + "html": "<p><code>foo bar baz</code></p>\n", + "example": 345, + "start_line": 6214, + "end_line": 6222, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "``\nfoo \n``\n", + "html": "<p><code>foo </code></p>\n", + "example": 346, + "start_line": 6224, + "end_line": 6230, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "`foo bar \nbaz`\n", + "html": "<p><code>foo bar baz</code></p>\n", + "example": 347, + "start_line": 6235, + "end_line": 6240, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "`foo\\`bar`\n", + "html": "<p><code>foo\\</code>bar`</p>\n", + "example": 348, + "start_line": 6252, + "end_line": 6256, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "``foo`bar``\n", + "html": "<p><code>foo`bar</code></p>\n", + "example": 349, + "start_line": 6263, + "end_line": 6267, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "` foo `` bar `\n", + "html": "<p><code>foo `` bar</code></p>\n", + "example": 350, + "start_line": 6269, + "end_line": 6273, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "*foo`*`\n", + "html": "<p>*foo<code>*</code></p>\n", + "example": 351, + "start_line": 6281, + "end_line": 6285, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "[not a `link](/foo`)\n", + "html": "<p>[not a <code>link](/foo</code>)</p>\n", + "example": 352, + "start_line": 6290, + "end_line": 6294, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "`<a href=\"`\">`\n", + "html": "<p><code><a href="</code>">`</p>\n", + "example": 353, + "start_line": 6300, + "end_line": 6304, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "<a href=\"`\">`\n", + "html": "<p><a href=\"`\">`</p>\n", + "example": 354, + "start_line": 6309, + "end_line": 6313, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "`<http://foo.bar.`baz>`\n", + "html": "<p><code><http://foo.bar.</code>baz>`</p>\n", + "example": 355, + "start_line": 6318, + "end_line": 6322, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "<http://foo.bar.`baz>`\n", + "html": "<p><a href=\"http://foo.bar.%60baz\">http://foo.bar.`baz</a>`</p>\n", + "example": 356, + "start_line": 6327, + "end_line": 6331, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "```foo``\n", + "html": "<p>```foo``</p>\n", + "example": 357, + "start_line": 6337, + "end_line": 6341, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "`foo\n", + "html": "<p>`foo</p>\n", + "example": 358, + "start_line": 6344, + "end_line": 6348, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "`foo``bar``\n", + "html": "<p>`foo<code>bar</code></p>\n", + "example": 359, + "start_line": 6353, + "end_line": 6357, + "section": "Code spans", + "extensions": [] + }, + { + "markdown": "*foo bar*\n", + "html": "<p><em>foo bar</em></p>\n", + "example": 360, + "start_line": 6570, + "end_line": 6574, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "a * foo bar*\n", + "html": "<p>a * foo bar*</p>\n", + "example": 361, + "start_line": 6580, + "end_line": 6584, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "a*\"foo\"*\n", + "html": "<p>a*"foo"*</p>\n", + "example": 362, + "start_line": 6591, + "end_line": 6595, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*\u00a0a\u00a0*\n", + "html": "<p>*\u00a0a\u00a0*</p>\n", + "example": 363, + "start_line": 6600, + "end_line": 6604, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "foo*bar*\n", + "html": "<p>foo<em>bar</em></p>\n", + "example": 364, + "start_line": 6609, + "end_line": 6613, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "5*6*78\n", + "html": "<p>5<em>6</em>78</p>\n", + "example": 365, + "start_line": 6616, + "end_line": 6620, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "_foo bar_\n", + "html": "<p><em>foo bar</em></p>\n", + "example": 366, + "start_line": 6625, + "end_line": 6629, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "_ foo bar_\n", + "html": "<p>_ foo bar_</p>\n", + "example": 367, + "start_line": 6635, + "end_line": 6639, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "a_\"foo\"_\n", + "html": "<p>a_"foo"_</p>\n", + "example": 368, + "start_line": 6645, + "end_line": 6649, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "foo_bar_\n", + "html": "<p>foo_bar_</p>\n", + "example": 369, + "start_line": 6654, + "end_line": 6658, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "5_6_78\n", + "html": "<p>5_6_78</p>\n", + "example": 370, + "start_line": 6661, + "end_line": 6665, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "\u043f\u0440\u0438\u0441\u0442\u0430\u043d\u044f\u043c_\u0441\u0442\u0440\u0435\u043c\u044f\u0442\u0441\u044f_\n", + "html": "<p>\u043f\u0440\u0438\u0441\u0442\u0430\u043d\u044f\u043c_\u0441\u0442\u0440\u0435\u043c\u044f\u0442\u0441\u044f_</p>\n", + "example": 371, + "start_line": 6668, + "end_line": 6672, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "aa_\"bb\"_cc\n", + "html": "<p>aa_"bb"_cc</p>\n", + "example": 372, + "start_line": 6678, + "end_line": 6682, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "foo-_(bar)_\n", + "html": "<p>foo-<em>(bar)</em></p>\n", + "example": 373, + "start_line": 6689, + "end_line": 6693, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "_foo*\n", + "html": "<p>_foo*</p>\n", + "example": 374, + "start_line": 6701, + "end_line": 6705, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*foo bar *\n", + "html": "<p>*foo bar *</p>\n", + "example": 375, + "start_line": 6711, + "end_line": 6715, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*foo bar\n*\n", + "html": "<p>*foo bar\n*</p>\n", + "example": 376, + "start_line": 6720, + "end_line": 6726, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*(*foo)\n", + "html": "<p>*(*foo)</p>\n", + "example": 377, + "start_line": 6733, + "end_line": 6737, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*(*foo*)*\n", + "html": "<p><em>(<em>foo</em>)</em></p>\n", + "example": 378, + "start_line": 6743, + "end_line": 6747, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*foo*bar\n", + "html": "<p><em>foo</em>bar</p>\n", + "example": 379, + "start_line": 6752, + "end_line": 6756, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "_foo bar _\n", + "html": "<p>_foo bar _</p>\n", + "example": 380, + "start_line": 6765, + "end_line": 6769, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "_(_foo)\n", + "html": "<p>_(_foo)</p>\n", + "example": 381, + "start_line": 6775, + "end_line": 6779, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "_(_foo_)_\n", + "html": "<p><em>(<em>foo</em>)</em></p>\n", + "example": 382, + "start_line": 6784, + "end_line": 6788, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "_foo_bar\n", + "html": "<p>_foo_bar</p>\n", + "example": 383, + "start_line": 6793, + "end_line": 6797, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "_\u043f\u0440\u0438\u0441\u0442\u0430\u043d\u044f\u043c_\u0441\u0442\u0440\u0435\u043c\u044f\u0442\u0441\u044f\n", + "html": "<p>_\u043f\u0440\u0438\u0441\u0442\u0430\u043d\u044f\u043c_\u0441\u0442\u0440\u0435\u043c\u044f\u0442\u0441\u044f</p>\n", + "example": 384, + "start_line": 6800, + "end_line": 6804, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "_foo_bar_baz_\n", + "html": "<p><em>foo_bar_baz</em></p>\n", + "example": 385, + "start_line": 6807, + "end_line": 6811, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "_(bar)_.\n", + "html": "<p><em>(bar)</em>.</p>\n", + "example": 386, + "start_line": 6818, + "end_line": 6822, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**foo bar**\n", + "html": "<p><strong>foo bar</strong></p>\n", + "example": 387, + "start_line": 6827, + "end_line": 6831, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "** foo bar**\n", + "html": "<p>** foo bar**</p>\n", + "example": 388, + "start_line": 6837, + "end_line": 6841, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "a**\"foo\"**\n", + "html": "<p>a**"foo"**</p>\n", + "example": 389, + "start_line": 6848, + "end_line": 6852, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "foo**bar**\n", + "html": "<p>foo<strong>bar</strong></p>\n", + "example": 390, + "start_line": 6857, + "end_line": 6861, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "__foo bar__\n", + "html": "<p><strong>foo bar</strong></p>\n", + "example": 391, + "start_line": 6866, + "end_line": 6870, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "__ foo bar__\n", + "html": "<p>__ foo bar__</p>\n", + "example": 392, + "start_line": 6876, + "end_line": 6880, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "__\nfoo bar__\n", + "html": "<p>__\nfoo bar__</p>\n", + "example": 393, + "start_line": 6884, + "end_line": 6890, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "a__\"foo\"__\n", + "html": "<p>a__"foo"__</p>\n", + "example": 394, + "start_line": 6896, + "end_line": 6900, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "foo__bar__\n", + "html": "<p>foo__bar__</p>\n", + "example": 395, + "start_line": 6905, + "end_line": 6909, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "5__6__78\n", + "html": "<p>5__6__78</p>\n", + "example": 396, + "start_line": 6912, + "end_line": 6916, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "\u043f\u0440\u0438\u0441\u0442\u0430\u043d\u044f\u043c__\u0441\u0442\u0440\u0435\u043c\u044f\u0442\u0441\u044f__\n", + "html": "<p>\u043f\u0440\u0438\u0441\u0442\u0430\u043d\u044f\u043c__\u0441\u0442\u0440\u0435\u043c\u044f\u0442\u0441\u044f__</p>\n", + "example": 397, + "start_line": 6919, + "end_line": 6923, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "__foo, __bar__, baz__\n", + "html": "<p><strong>foo, <strong>bar</strong>, baz</strong></p>\n", + "example": 398, + "start_line": 6926, + "end_line": 6930, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "foo-__(bar)__\n", + "html": "<p>foo-<strong>(bar)</strong></p>\n", + "example": 399, + "start_line": 6937, + "end_line": 6941, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**foo bar **\n", + "html": "<p>**foo bar **</p>\n", + "example": 400, + "start_line": 6950, + "end_line": 6954, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**(**foo)\n", + "html": "<p>**(**foo)</p>\n", + "example": 401, + "start_line": 6963, + "end_line": 6967, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*(**foo**)*\n", + "html": "<p><em>(<strong>foo</strong>)</em></p>\n", + "example": 402, + "start_line": 6973, + "end_line": 6977, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**Gomphocarpus (*Gomphocarpus physocarpus*, syn.\n*Asclepias physocarpa*)**\n", + "html": "<p><strong>Gomphocarpus (<em>Gomphocarpus physocarpus</em>, syn.\n<em>Asclepias physocarpa</em>)</strong></p>\n", + "example": 403, + "start_line": 6980, + "end_line": 6986, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**foo \"*bar*\" foo**\n", + "html": "<p><strong>foo "<em>bar</em>" foo</strong></p>\n", + "example": 404, + "start_line": 6989, + "end_line": 6993, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**foo**bar\n", + "html": "<p><strong>foo</strong>bar</p>\n", + "example": 405, + "start_line": 6998, + "end_line": 7002, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "__foo bar __\n", + "html": "<p>__foo bar __</p>\n", + "example": 406, + "start_line": 7010, + "end_line": 7014, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "__(__foo)\n", + "html": "<p>__(__foo)</p>\n", + "example": 407, + "start_line": 7020, + "end_line": 7024, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "_(__foo__)_\n", + "html": "<p><em>(<strong>foo</strong>)</em></p>\n", + "example": 408, + "start_line": 7030, + "end_line": 7034, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "__foo__bar\n", + "html": "<p>__foo__bar</p>\n", + "example": 409, + "start_line": 7039, + "end_line": 7043, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "__\u043f\u0440\u0438\u0441\u0442\u0430\u043d\u044f\u043c__\u0441\u0442\u0440\u0435\u043c\u044f\u0442\u0441\u044f\n", + "html": "<p>__\u043f\u0440\u0438\u0441\u0442\u0430\u043d\u044f\u043c__\u0441\u0442\u0440\u0435\u043c\u044f\u0442\u0441\u044f</p>\n", + "example": 410, + "start_line": 7046, + "end_line": 7050, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "__foo__bar__baz__\n", + "html": "<p><strong>foo__bar__baz</strong></p>\n", + "example": 411, + "start_line": 7053, + "end_line": 7057, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "__(bar)__.\n", + "html": "<p><strong>(bar)</strong>.</p>\n", + "example": 412, + "start_line": 7064, + "end_line": 7068, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*foo [bar](/url)*\n", + "html": "<p><em>foo <a href=\"/url\">bar</a></em></p>\n", + "example": 413, + "start_line": 7076, + "end_line": 7080, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*foo\nbar*\n", + "html": "<p><em>foo\nbar</em></p>\n", + "example": 414, + "start_line": 7083, + "end_line": 7089, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "_foo __bar__ baz_\n", + "html": "<p><em>foo <strong>bar</strong> baz</em></p>\n", + "example": 415, + "start_line": 7095, + "end_line": 7099, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "_foo _bar_ baz_\n", + "html": "<p><em>foo <em>bar</em> baz</em></p>\n", + "example": 416, + "start_line": 7102, + "end_line": 7106, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "__foo_ bar_\n", + "html": "<p><em><em>foo</em> bar</em></p>\n", + "example": 417, + "start_line": 7109, + "end_line": 7113, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*foo *bar**\n", + "html": "<p><em>foo <em>bar</em></em></p>\n", + "example": 418, + "start_line": 7116, + "end_line": 7120, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*foo **bar** baz*\n", + "html": "<p><em>foo <strong>bar</strong> baz</em></p>\n", + "example": 419, + "start_line": 7123, + "end_line": 7127, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*foo**bar**baz*\n", + "html": "<p><em>foo<strong>bar</strong>baz</em></p>\n", + "example": 420, + "start_line": 7129, + "end_line": 7133, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*foo**bar*\n", + "html": "<p><em>foo**bar</em></p>\n", + "example": 421, + "start_line": 7153, + "end_line": 7157, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "***foo** bar*\n", + "html": "<p><em><strong>foo</strong> bar</em></p>\n", + "example": 422, + "start_line": 7166, + "end_line": 7170, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*foo **bar***\n", + "html": "<p><em>foo <strong>bar</strong></em></p>\n", + "example": 423, + "start_line": 7173, + "end_line": 7177, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*foo**bar***\n", + "html": "<p><em>foo<strong>bar</strong></em></p>\n", + "example": 424, + "start_line": 7180, + "end_line": 7184, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "foo***bar***baz\n", + "html": "<p>foo<em><strong>bar</strong></em>baz</p>\n", + "example": 425, + "start_line": 7191, + "end_line": 7195, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "foo******bar*********baz\n", + "html": "<p>foo<strong><strong><strong>bar</strong></strong></strong>***baz</p>\n", + "example": 426, + "start_line": 7197, + "end_line": 7201, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*foo **bar *baz* bim** bop*\n", + "html": "<p><em>foo <strong>bar <em>baz</em> bim</strong> bop</em></p>\n", + "example": 427, + "start_line": 7206, + "end_line": 7210, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*foo [*bar*](/url)*\n", + "html": "<p><em>foo <a href=\"/url\"><em>bar</em></a></em></p>\n", + "example": 428, + "start_line": 7213, + "end_line": 7217, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "** is not an empty emphasis\n", + "html": "<p>** is not an empty emphasis</p>\n", + "example": 429, + "start_line": 7222, + "end_line": 7226, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**** is not an empty strong emphasis\n", + "html": "<p>**** is not an empty strong emphasis</p>\n", + "example": 430, + "start_line": 7229, + "end_line": 7233, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**foo [bar](/url)**\n", + "html": "<p><strong>foo <a href=\"/url\">bar</a></strong></p>\n", + "example": 431, + "start_line": 7242, + "end_line": 7246, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**foo\nbar**\n", + "html": "<p><strong>foo\nbar</strong></p>\n", + "example": 432, + "start_line": 7249, + "end_line": 7255, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "__foo _bar_ baz__\n", + "html": "<p><strong>foo <em>bar</em> baz</strong></p>\n", + "example": 433, + "start_line": 7261, + "end_line": 7265, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "__foo __bar__ baz__\n", + "html": "<p><strong>foo <strong>bar</strong> baz</strong></p>\n", + "example": 434, + "start_line": 7268, + "end_line": 7272, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "____foo__ bar__\n", + "html": "<p><strong><strong>foo</strong> bar</strong></p>\n", + "example": 435, + "start_line": 7275, + "end_line": 7279, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**foo **bar****\n", + "html": "<p><strong>foo <strong>bar</strong></strong></p>\n", + "example": 436, + "start_line": 7282, + "end_line": 7286, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**foo *bar* baz**\n", + "html": "<p><strong>foo <em>bar</em> baz</strong></p>\n", + "example": 437, + "start_line": 7289, + "end_line": 7293, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**foo*bar*baz**\n", + "html": "<p><strong>foo<em>bar</em>baz</strong></p>\n", + "example": 438, + "start_line": 7296, + "end_line": 7300, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "***foo* bar**\n", + "html": "<p><strong><em>foo</em> bar</strong></p>\n", + "example": 439, + "start_line": 7303, + "end_line": 7307, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**foo *bar***\n", + "html": "<p><strong>foo <em>bar</em></strong></p>\n", + "example": 440, + "start_line": 7310, + "end_line": 7314, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**foo *bar **baz**\nbim* bop**\n", + "html": "<p><strong>foo <em>bar <strong>baz</strong>\nbim</em> bop</strong></p>\n", + "example": 441, + "start_line": 7319, + "end_line": 7325, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**foo [*bar*](/url)**\n", + "html": "<p><strong>foo <a href=\"/url\"><em>bar</em></a></strong></p>\n", + "example": 442, + "start_line": 7328, + "end_line": 7332, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "__ is not an empty emphasis\n", + "html": "<p>__ is not an empty emphasis</p>\n", + "example": 443, + "start_line": 7337, + "end_line": 7341, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "____ is not an empty strong emphasis\n", + "html": "<p>____ is not an empty strong emphasis</p>\n", + "example": 444, + "start_line": 7344, + "end_line": 7348, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "foo ***\n", + "html": "<p>foo ***</p>\n", + "example": 445, + "start_line": 7354, + "end_line": 7358, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "foo *\\**\n", + "html": "<p>foo <em>*</em></p>\n", + "example": 446, + "start_line": 7361, + "end_line": 7365, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "foo *_*\n", + "html": "<p>foo <em>_</em></p>\n", + "example": 447, + "start_line": 7368, + "end_line": 7372, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "foo *****\n", + "html": "<p>foo *****</p>\n", + "example": 448, + "start_line": 7375, + "end_line": 7379, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "foo **\\***\n", + "html": "<p>foo <strong>*</strong></p>\n", + "example": 449, + "start_line": 7382, + "end_line": 7386, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "foo **_**\n", + "html": "<p>foo <strong>_</strong></p>\n", + "example": 450, + "start_line": 7389, + "end_line": 7393, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**foo*\n", + "html": "<p>*<em>foo</em></p>\n", + "example": 451, + "start_line": 7400, + "end_line": 7404, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*foo**\n", + "html": "<p><em>foo</em>*</p>\n", + "example": 452, + "start_line": 7407, + "end_line": 7411, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "***foo**\n", + "html": "<p>*<strong>foo</strong></p>\n", + "example": 453, + "start_line": 7414, + "end_line": 7418, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "****foo*\n", + "html": "<p>***<em>foo</em></p>\n", + "example": 454, + "start_line": 7421, + "end_line": 7425, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**foo***\n", + "html": "<p><strong>foo</strong>*</p>\n", + "example": 455, + "start_line": 7428, + "end_line": 7432, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*foo****\n", + "html": "<p><em>foo</em>***</p>\n", + "example": 456, + "start_line": 7435, + "end_line": 7439, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "foo ___\n", + "html": "<p>foo ___</p>\n", + "example": 457, + "start_line": 7445, + "end_line": 7449, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "foo _\\__\n", + "html": "<p>foo <em>_</em></p>\n", + "example": 458, + "start_line": 7452, + "end_line": 7456, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "foo _*_\n", + "html": "<p>foo <em>*</em></p>\n", + "example": 459, + "start_line": 7459, + "end_line": 7463, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "foo _____\n", + "html": "<p>foo _____</p>\n", + "example": 460, + "start_line": 7466, + "end_line": 7470, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "foo __\\___\n", + "html": "<p>foo <strong>_</strong></p>\n", + "example": 461, + "start_line": 7473, + "end_line": 7477, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "foo __*__\n", + "html": "<p>foo <strong>*</strong></p>\n", + "example": 462, + "start_line": 7480, + "end_line": 7484, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "__foo_\n", + "html": "<p>_<em>foo</em></p>\n", + "example": 463, + "start_line": 7487, + "end_line": 7491, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "_foo__\n", + "html": "<p><em>foo</em>_</p>\n", + "example": 464, + "start_line": 7498, + "end_line": 7502, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "___foo__\n", + "html": "<p>_<strong>foo</strong></p>\n", + "example": 465, + "start_line": 7505, + "end_line": 7509, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "____foo_\n", + "html": "<p>___<em>foo</em></p>\n", + "example": 466, + "start_line": 7512, + "end_line": 7516, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "__foo___\n", + "html": "<p><strong>foo</strong>_</p>\n", + "example": 467, + "start_line": 7519, + "end_line": 7523, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "_foo____\n", + "html": "<p><em>foo</em>___</p>\n", + "example": 468, + "start_line": 7526, + "end_line": 7530, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**foo**\n", + "html": "<p><strong>foo</strong></p>\n", + "example": 469, + "start_line": 7536, + "end_line": 7540, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*_foo_*\n", + "html": "<p><em><em>foo</em></em></p>\n", + "example": 470, + "start_line": 7543, + "end_line": 7547, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "__foo__\n", + "html": "<p><strong>foo</strong></p>\n", + "example": 471, + "start_line": 7550, + "end_line": 7554, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "_*foo*_\n", + "html": "<p><em><em>foo</em></em></p>\n", + "example": 472, + "start_line": 7557, + "end_line": 7561, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "****foo****\n", + "html": "<p><strong><strong>foo</strong></strong></p>\n", + "example": 473, + "start_line": 7567, + "end_line": 7571, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "____foo____\n", + "html": "<p><strong><strong>foo</strong></strong></p>\n", + "example": 474, + "start_line": 7574, + "end_line": 7578, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "******foo******\n", + "html": "<p><strong><strong><strong>foo</strong></strong></strong></p>\n", + "example": 475, + "start_line": 7585, + "end_line": 7589, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "***foo***\n", + "html": "<p><em><strong>foo</strong></em></p>\n", + "example": 476, + "start_line": 7594, + "end_line": 7598, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "_____foo_____\n", + "html": "<p><em><strong><strong>foo</strong></strong></em></p>\n", + "example": 477, + "start_line": 7601, + "end_line": 7605, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*foo _bar* baz_\n", + "html": "<p><em>foo _bar</em> baz_</p>\n", + "example": 478, + "start_line": 7610, + "end_line": 7614, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*foo __bar *baz bim__ bam*\n", + "html": "<p><em>foo <strong>bar *baz bim</strong> bam</em></p>\n", + "example": 479, + "start_line": 7617, + "end_line": 7621, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**foo **bar baz**\n", + "html": "<p>**foo <strong>bar baz</strong></p>\n", + "example": 480, + "start_line": 7626, + "end_line": 7630, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*foo *bar baz*\n", + "html": "<p>*foo <em>bar baz</em></p>\n", + "example": 481, + "start_line": 7633, + "end_line": 7637, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*[bar*](/url)\n", + "html": "<p>*<a href=\"/url\">bar*</a></p>\n", + "example": 482, + "start_line": 7642, + "end_line": 7646, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "_foo [bar_](/url)\n", + "html": "<p>_foo <a href=\"/url\">bar_</a></p>\n", + "example": 483, + "start_line": 7649, + "end_line": 7653, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*<img src=\"foo\" title=\"*\"/>\n", + "html": "<p>*<img src=\"foo\" title=\"*\"/></p>\n", + "example": 484, + "start_line": 7656, + "end_line": 7660, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**<a href=\"**\">\n", + "html": "<p>**<a href=\"**\"></p>\n", + "example": 485, + "start_line": 7663, + "end_line": 7667, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "__<a href=\"__\">\n", + "html": "<p>__<a href=\"__\"></p>\n", + "example": 486, + "start_line": 7670, + "end_line": 7674, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "*a `*`*\n", + "html": "<p><em>a <code>*</code></em></p>\n", + "example": 487, + "start_line": 7677, + "end_line": 7681, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "_a `_`_\n", + "html": "<p><em>a <code>_</code></em></p>\n", + "example": 488, + "start_line": 7684, + "end_line": 7688, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "**a<http://foo.bar/?q=**>\n", + "html": "<p>**a<a href=\"http://foo.bar/?q=**\">http://foo.bar/?q=**</a></p>\n", + "example": 489, + "start_line": 7691, + "end_line": 7695, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "__a<http://foo.bar/?q=__>\n", + "html": "<p>__a<a href=\"http://foo.bar/?q=__\">http://foo.bar/?q=__</a></p>\n", + "example": 490, + "start_line": 7698, + "end_line": 7702, + "section": "Emphasis and strong emphasis", + "extensions": [] + }, + { + "markdown": "~~Hi~~ Hello, world!\n", + "html": "<p><del>Hi</del> Hello, world!</p>\n", + "example": 491, + "start_line": 7714, + "end_line": 7718, + "section": "Strikethrough (extension)", + "extensions": [ + "strikethrough" + ] + }, + { + "markdown": "This ~~has a\n\nnew paragraph~~.\n", + "html": "<p>This ~~has a</p>\n<p>new paragraph~~.</p>\n", + "example": 492, + "start_line": 7723, + "end_line": 7730, + "section": "Strikethrough (extension)", + "extensions": [ + "strikethrough" + ] + }, + { + "markdown": "[link](/uri \"title\")\n", + "html": "<p><a href=\"/uri\" title=\"title\">link</a></p>\n", + "example": 493, + "start_line": 7809, + "end_line": 7813, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](/uri)\n", + "html": "<p><a href=\"/uri\">link</a></p>\n", + "example": 494, + "start_line": 7818, + "end_line": 7822, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link]()\n", + "html": "<p><a href=\"\">link</a></p>\n", + "example": 495, + "start_line": 7827, + "end_line": 7831, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](<>)\n", + "html": "<p><a href=\"\">link</a></p>\n", + "example": 496, + "start_line": 7834, + "end_line": 7838, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](/my uri)\n", + "html": "<p>[link](/my uri)</p>\n", + "example": 497, + "start_line": 7843, + "end_line": 7847, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](</my uri>)\n", + "html": "<p><a href=\"/my%20uri\">link</a></p>\n", + "example": 498, + "start_line": 7849, + "end_line": 7853, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](foo\nbar)\n", + "html": "<p>[link](foo\nbar)</p>\n", + "example": 499, + "start_line": 7858, + "end_line": 7864, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](<foo\nbar>)\n", + "html": "<p>[link](<foo\nbar>)</p>\n", + "example": 500, + "start_line": 7866, + "end_line": 7872, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[a](<b)c>)\n", + "html": "<p><a href=\"b)c\">a</a></p>\n", + "example": 501, + "start_line": 7877, + "end_line": 7881, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](<foo\\>)\n", + "html": "<p>[link](<foo>)</p>\n", + "example": 502, + "start_line": 7885, + "end_line": 7889, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[a](<b)c\n[a](<b)c>\n[a](<b>c)\n", + "html": "<p>[a](<b)c\n[a](<b)c>\n[a](<b>c)</p>\n", + "example": 503, + "start_line": 7894, + "end_line": 7902, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](\\(foo\\))\n", + "html": "<p><a href=\"(foo)\">link</a></p>\n", + "example": 504, + "start_line": 7906, + "end_line": 7910, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](foo(and(bar)))\n", + "html": "<p><a href=\"foo(and(bar))\">link</a></p>\n", + "example": 505, + "start_line": 7915, + "end_line": 7919, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](foo\\(and\\(bar\\))\n", + "html": "<p><a href=\"foo(and(bar)\">link</a></p>\n", + "example": 506, + "start_line": 7924, + "end_line": 7928, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](<foo(and(bar)>)\n", + "html": "<p><a href=\"foo(and(bar)\">link</a></p>\n", + "example": 507, + "start_line": 7931, + "end_line": 7935, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](foo\\)\\:)\n", + "html": "<p><a href=\"foo):\">link</a></p>\n", + "example": 508, + "start_line": 7941, + "end_line": 7945, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](#fragment)\n\n[link](http://example.com#fragment)\n\n[link](http://example.com?foo=3#frag)\n", + "html": "<p><a href=\"#fragment\">link</a></p>\n<p><a href=\"http://example.com#fragment\">link</a></p>\n<p><a href=\"http://example.com?foo=3#frag\">link</a></p>\n", + "example": 509, + "start_line": 7950, + "end_line": 7960, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](foo\\bar)\n", + "html": "<p><a href=\"foo%5Cbar\">link</a></p>\n", + "example": 510, + "start_line": 7966, + "end_line": 7970, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](foo%20bä)\n", + "html": "<p><a href=\"foo%20b%C3%A4\">link</a></p>\n", + "example": 511, + "start_line": 7982, + "end_line": 7986, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](\"title\")\n", + "html": "<p><a href=\"%22title%22\">link</a></p>\n", + "example": 512, + "start_line": 7993, + "end_line": 7997, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](/url \"title\")\n[link](/url 'title')\n[link](/url (title))\n", + "html": "<p><a href=\"/url\" title=\"title\">link</a>\n<a href=\"/url\" title=\"title\">link</a>\n<a href=\"/url\" title=\"title\">link</a></p>\n", + "example": 513, + "start_line": 8002, + "end_line": 8010, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](/url \"title \\\""\")\n", + "html": "<p><a href=\"/url\" title=\"title ""\">link</a></p>\n", + "example": 514, + "start_line": 8016, + "end_line": 8020, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](/url\u00a0\"title\")\n", + "html": "<p><a href=\"/url%C2%A0%22title%22\">link</a></p>\n", + "example": 515, + "start_line": 8026, + "end_line": 8030, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](/url \"title \"and\" title\")\n", + "html": "<p>[link](/url "title "and" title")</p>\n", + "example": 516, + "start_line": 8035, + "end_line": 8039, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link](/url 'title \"and\" title')\n", + "html": "<p><a href=\"/url\" title=\"title "and" title\">link</a></p>\n", + "example": 517, + "start_line": 8044, + "end_line": 8048, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link]( /uri\n \"title\" )\n", + "html": "<p><a href=\"/uri\" title=\"title\">link</a></p>\n", + "example": 518, + "start_line": 8068, + "end_line": 8073, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link] (/uri)\n", + "html": "<p>[link] (/uri)</p>\n", + "example": 519, + "start_line": 8079, + "end_line": 8083, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link [foo [bar]]](/uri)\n", + "html": "<p><a href=\"/uri\">link [foo [bar]]</a></p>\n", + "example": 520, + "start_line": 8089, + "end_line": 8093, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link] bar](/uri)\n", + "html": "<p>[link] bar](/uri)</p>\n", + "example": 521, + "start_line": 8096, + "end_line": 8100, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link [bar](/uri)\n", + "html": "<p>[link <a href=\"/uri\">bar</a></p>\n", + "example": 522, + "start_line": 8103, + "end_line": 8107, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link \\[bar](/uri)\n", + "html": "<p><a href=\"/uri\">link [bar</a></p>\n", + "example": 523, + "start_line": 8110, + "end_line": 8114, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link *foo **bar** `#`*](/uri)\n", + "html": "<p><a href=\"/uri\">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>\n", + "example": 524, + "start_line": 8119, + "end_line": 8123, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[![moon](moon.jpg)](/uri)\n", + "html": "<p><a href=\"/uri\"><img src=\"moon.jpg\" alt=\"moon\" /></a></p>\n", + "example": 525, + "start_line": 8126, + "end_line": 8130, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo [bar](/uri)](/uri)\n", + "html": "<p>[foo <a href=\"/uri\">bar</a>](/uri)</p>\n", + "example": 526, + "start_line": 8135, + "end_line": 8139, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo *[bar [baz](/uri)](/uri)*](/uri)\n", + "html": "<p>[foo <em>[bar <a href=\"/uri\">baz</a>](/uri)</em>](/uri)</p>\n", + "example": 527, + "start_line": 8142, + "end_line": 8146, + "section": "Links", + "extensions": [] + }, + { + "markdown": "![[[foo](uri1)](uri2)](uri3)\n", + "html": "<p><img src=\"uri3\" alt=\"[foo](uri2)\" /></p>\n", + "example": 528, + "start_line": 8149, + "end_line": 8153, + "section": "Links", + "extensions": [] + }, + { + "markdown": "*[foo*](/uri)\n", + "html": "<p>*<a href=\"/uri\">foo*</a></p>\n", + "example": 529, + "start_line": 8159, + "end_line": 8163, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo *bar](baz*)\n", + "html": "<p><a href=\"baz*\">foo *bar</a></p>\n", + "example": 530, + "start_line": 8166, + "end_line": 8170, + "section": "Links", + "extensions": [] + }, + { + "markdown": "*foo [bar* baz]\n", + "html": "<p><em>foo [bar</em> baz]</p>\n", + "example": 531, + "start_line": 8176, + "end_line": 8180, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo <bar attr=\"](baz)\">\n", + "html": "<p>[foo <bar attr=\"](baz)\"></p>\n", + "example": 532, + "start_line": 8186, + "end_line": 8190, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo`](/uri)`\n", + "html": "<p>[foo<code>](/uri)</code></p>\n", + "example": 533, + "start_line": 8193, + "end_line": 8197, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo<http://example.com/?search=](uri)>\n", + "html": "<p>[foo<a href=\"http://example.com/?search=%5D(uri)\">http://example.com/?search=](uri)</a></p>\n", + "example": 534, + "start_line": 8200, + "end_line": 8204, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo][bar]\n\n[bar]: /url \"title\"\n", + "html": "<p><a href=\"/url\" title=\"title\">foo</a></p>\n", + "example": 535, + "start_line": 8238, + "end_line": 8244, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link [foo [bar]]][ref]\n\n[ref]: /uri\n", + "html": "<p><a href=\"/uri\">link [foo [bar]]</a></p>\n", + "example": 536, + "start_line": 8253, + "end_line": 8259, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link \\[bar][ref]\n\n[ref]: /uri\n", + "html": "<p><a href=\"/uri\">link [bar</a></p>\n", + "example": 537, + "start_line": 8262, + "end_line": 8268, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[link *foo **bar** `#`*][ref]\n\n[ref]: /uri\n", + "html": "<p><a href=\"/uri\">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>\n", + "example": 538, + "start_line": 8273, + "end_line": 8279, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[![moon](moon.jpg)][ref]\n\n[ref]: /uri\n", + "html": "<p><a href=\"/uri\"><img src=\"moon.jpg\" alt=\"moon\" /></a></p>\n", + "example": 539, + "start_line": 8282, + "end_line": 8288, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo [bar](/uri)][ref]\n\n[ref]: /uri\n", + "html": "<p>[foo <a href=\"/uri\">bar</a>]<a href=\"/uri\">ref</a></p>\n", + "example": 540, + "start_line": 8293, + "end_line": 8299, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo *bar [baz][ref]*][ref]\n\n[ref]: /uri\n", + "html": "<p>[foo <em>bar <a href=\"/uri\">baz</a></em>]<a href=\"/uri\">ref</a></p>\n", + "example": 541, + "start_line": 8302, + "end_line": 8308, + "section": "Links", + "extensions": [] + }, + { + "markdown": "*[foo*][ref]\n\n[ref]: /uri\n", + "html": "<p>*<a href=\"/uri\">foo*</a></p>\n", + "example": 542, + "start_line": 8317, + "end_line": 8323, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo *bar][ref]\n\n[ref]: /uri\n", + "html": "<p><a href=\"/uri\">foo *bar</a></p>\n", + "example": 543, + "start_line": 8326, + "end_line": 8332, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo <bar attr=\"][ref]\">\n\n[ref]: /uri\n", + "html": "<p>[foo <bar attr=\"][ref]\"></p>\n", + "example": 544, + "start_line": 8338, + "end_line": 8344, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo`][ref]`\n\n[ref]: /uri\n", + "html": "<p>[foo<code>][ref]</code></p>\n", + "example": 545, + "start_line": 8347, + "end_line": 8353, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo<http://example.com/?search=][ref]>\n\n[ref]: /uri\n", + "html": "<p>[foo<a href=\"http://example.com/?search=%5D%5Bref%5D\">http://example.com/?search=][ref]</a></p>\n", + "example": 546, + "start_line": 8356, + "end_line": 8362, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo][BaR]\n\n[bar]: /url \"title\"\n", + "html": "<p><a href=\"/url\" title=\"title\">foo</a></p>\n", + "example": 547, + "start_line": 8367, + "end_line": 8373, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[\u0422\u043e\u043b\u043f\u043e\u0439][\u0422\u043e\u043b\u043f\u043e\u0439] is a Russian word.\n\n[\u0422\u041e\u041b\u041f\u041e\u0419]: /url\n", + "html": "<p><a href=\"/url\">\u0422\u043e\u043b\u043f\u043e\u0439</a> is a Russian word.</p>\n", + "example": 548, + "start_line": 8378, + "end_line": 8384, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[Foo\n bar]: /url\n\n[Baz][Foo bar]\n", + "html": "<p><a href=\"/url\">Baz</a></p>\n", + "example": 549, + "start_line": 8390, + "end_line": 8397, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo] [bar]\n\n[bar]: /url \"title\"\n", + "html": "<p>[foo] <a href=\"/url\" title=\"title\">bar</a></p>\n", + "example": 550, + "start_line": 8403, + "end_line": 8409, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo]\n[bar]\n\n[bar]: /url \"title\"\n", + "html": "<p>[foo]\n<a href=\"/url\" title=\"title\">bar</a></p>\n", + "example": 551, + "start_line": 8412, + "end_line": 8420, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo]: /url1\n\n[foo]: /url2\n\n[bar][foo]\n", + "html": "<p><a href=\"/url1\">bar</a></p>\n", + "example": 552, + "start_line": 8453, + "end_line": 8461, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[bar][foo\\!]\n\n[foo!]: /url\n", + "html": "<p>[bar][foo!]</p>\n", + "example": 553, + "start_line": 8468, + "end_line": 8474, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo][ref[]\n\n[ref[]: /uri\n", + "html": "<p>[foo][ref[]</p>\n<p>[ref[]: /uri</p>\n", + "example": 554, + "start_line": 8480, + "end_line": 8487, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo][ref[bar]]\n\n[ref[bar]]: /uri\n", + "html": "<p>[foo][ref[bar]]</p>\n<p>[ref[bar]]: /uri</p>\n", + "example": 555, + "start_line": 8490, + "end_line": 8497, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[[[foo]]]\n\n[[[foo]]]: /url\n", + "html": "<p>[[[foo]]]</p>\n<p>[[[foo]]]: /url</p>\n", + "example": 556, + "start_line": 8500, + "end_line": 8507, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo][ref\\[]\n\n[ref\\[]: /uri\n", + "html": "<p><a href=\"/uri\">foo</a></p>\n", + "example": 557, + "start_line": 8510, + "end_line": 8516, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[bar\\\\]: /uri\n\n[bar\\\\]\n", + "html": "<p><a href=\"/uri\">bar\\</a></p>\n", + "example": 558, + "start_line": 8521, + "end_line": 8527, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[]\n\n[]: /uri\n", + "html": "<p>[]</p>\n<p>[]: /uri</p>\n", + "example": 559, + "start_line": 8532, + "end_line": 8539, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[\n ]\n\n[\n ]: /uri\n", + "html": "<p>[\n]</p>\n<p>[\n]: /uri</p>\n", + "example": 560, + "start_line": 8542, + "end_line": 8553, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo][]\n\n[foo]: /url \"title\"\n", + "html": "<p><a href=\"/url\" title=\"title\">foo</a></p>\n", + "example": 561, + "start_line": 8565, + "end_line": 8571, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[*foo* bar][]\n\n[*foo* bar]: /url \"title\"\n", + "html": "<p><a href=\"/url\" title=\"title\"><em>foo</em> bar</a></p>\n", + "example": 562, + "start_line": 8574, + "end_line": 8580, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[Foo][]\n\n[foo]: /url \"title\"\n", + "html": "<p><a href=\"/url\" title=\"title\">Foo</a></p>\n", + "example": 563, + "start_line": 8585, + "end_line": 8591, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo] \n[]\n\n[foo]: /url \"title\"\n", + "html": "<p><a href=\"/url\" title=\"title\">foo</a>\n[]</p>\n", + "example": 564, + "start_line": 8598, + "end_line": 8606, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo]\n\n[foo]: /url \"title\"\n", + "html": "<p><a href=\"/url\" title=\"title\">foo</a></p>\n", + "example": 565, + "start_line": 8618, + "end_line": 8624, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[*foo* bar]\n\n[*foo* bar]: /url \"title\"\n", + "html": "<p><a href=\"/url\" title=\"title\"><em>foo</em> bar</a></p>\n", + "example": 566, + "start_line": 8627, + "end_line": 8633, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[[*foo* bar]]\n\n[*foo* bar]: /url \"title\"\n", + "html": "<p>[<a href=\"/url\" title=\"title\"><em>foo</em> bar</a>]</p>\n", + "example": 567, + "start_line": 8636, + "end_line": 8642, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[[bar [foo]\n\n[foo]: /url\n", + "html": "<p>[[bar <a href=\"/url\">foo</a></p>\n", + "example": 568, + "start_line": 8645, + "end_line": 8651, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[Foo]\n\n[foo]: /url \"title\"\n", + "html": "<p><a href=\"/url\" title=\"title\">Foo</a></p>\n", + "example": 569, + "start_line": 8656, + "end_line": 8662, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo] bar\n\n[foo]: /url\n", + "html": "<p><a href=\"/url\">foo</a> bar</p>\n", + "example": 570, + "start_line": 8667, + "end_line": 8673, + "section": "Links", + "extensions": [] + }, + { + "markdown": "\\[foo]\n\n[foo]: /url \"title\"\n", + "html": "<p>[foo]</p>\n", + "example": 571, + "start_line": 8679, + "end_line": 8685, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo*]: /url\n\n*[foo*]\n", + "html": "<p>*<a href=\"/url\">foo*</a></p>\n", + "example": 572, + "start_line": 8691, + "end_line": 8697, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo][bar]\n\n[foo]: /url1\n[bar]: /url2\n", + "html": "<p><a href=\"/url2\">foo</a></p>\n", + "example": 573, + "start_line": 8703, + "end_line": 8710, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo][]\n\n[foo]: /url1\n", + "html": "<p><a href=\"/url1\">foo</a></p>\n", + "example": 574, + "start_line": 8712, + "end_line": 8718, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo]()\n\n[foo]: /url1\n", + "html": "<p><a href=\"\">foo</a></p>\n", + "example": 575, + "start_line": 8722, + "end_line": 8728, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo](not a link)\n\n[foo]: /url1\n", + "html": "<p><a href=\"/url1\">foo</a>(not a link)</p>\n", + "example": 576, + "start_line": 8730, + "end_line": 8736, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo][bar][baz]\n\n[baz]: /url\n", + "html": "<p>[foo]<a href=\"/url\">bar</a></p>\n", + "example": 577, + "start_line": 8741, + "end_line": 8747, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo][bar][baz]\n\n[baz]: /url1\n[bar]: /url2\n", + "html": "<p><a href=\"/url2\">foo</a><a href=\"/url1\">baz</a></p>\n", + "example": 578, + "start_line": 8753, + "end_line": 8760, + "section": "Links", + "extensions": [] + }, + { + "markdown": "[foo][bar][baz]\n\n[baz]: /url1\n[foo]: /url2\n", + "html": "<p>[foo]<a href=\"/url1\">bar</a></p>\n", + "example": 579, + "start_line": 8766, + "end_line": 8773, + "section": "Links", + "extensions": [] + }, + { + "markdown": "![foo](/url \"title\")\n", + "html": "<p><img src=\"/url\" alt=\"foo\" title=\"title\" /></p>\n", + "example": 580, + "start_line": 8789, + "end_line": 8793, + "section": "Images", + "extensions": [] + }, + { + "markdown": "![foo *bar*]\n\n[foo *bar*]: train.jpg \"train & tracks\"\n", + "html": "<p><img src=\"train.jpg\" alt=\"foo bar\" title=\"train & tracks\" /></p>\n", + "example": 581, + "start_line": 8796, + "end_line": 8802, + "section": "Images", + "extensions": [] + }, + { + "markdown": "![foo ![bar](/url)](/url2)\n", + "html": "<p><img src=\"/url2\" alt=\"foo bar\" /></p>\n", + "example": 582, + "start_line": 8805, + "end_line": 8809, + "section": "Images", + "extensions": [] + }, + { + "markdown": "![foo [bar](/url)](/url2)\n", + "html": "<p><img src=\"/url2\" alt=\"foo bar\" /></p>\n", + "example": 583, + "start_line": 8812, + "end_line": 8816, + "section": "Images", + "extensions": [] + }, + { + "markdown": "![foo *bar*][]\n\n[foo *bar*]: train.jpg \"train & tracks\"\n", + "html": "<p><img src=\"train.jpg\" alt=\"foo bar\" title=\"train & tracks\" /></p>\n", + "example": 584, + "start_line": 8826, + "end_line": 8832, + "section": "Images", + "extensions": [] + }, + { + "markdown": "![foo *bar*][foobar]\n\n[FOOBAR]: train.jpg \"train & tracks\"\n", + "html": "<p><img src=\"train.jpg\" alt=\"foo bar\" title=\"train & tracks\" /></p>\n", + "example": 585, + "start_line": 8835, + "end_line": 8841, + "section": "Images", + "extensions": [] + }, + { + "markdown": "![foo](train.jpg)\n", + "html": "<p><img src=\"train.jpg\" alt=\"foo\" /></p>\n", + "example": 586, + "start_line": 8844, + "end_line": 8848, + "section": "Images", + "extensions": [] + }, + { + "markdown": "My ![foo bar](/path/to/train.jpg \"title\" )\n", + "html": "<p>My <img src=\"/path/to/train.jpg\" alt=\"foo bar\" title=\"title\" /></p>\n", + "example": 587, + "start_line": 8851, + "end_line": 8855, + "section": "Images", + "extensions": [] + }, + { + "markdown": "![foo](<url>)\n", + "html": "<p><img src=\"url\" alt=\"foo\" /></p>\n", + "example": 588, + "start_line": 8858, + "end_line": 8862, + "section": "Images", + "extensions": [] + }, + { + "markdown": "![](/url)\n", + "html": "<p><img src=\"/url\" alt=\"\" /></p>\n", + "example": 589, + "start_line": 8865, + "end_line": 8869, + "section": "Images", + "extensions": [] + }, + { + "markdown": "![foo][bar]\n\n[bar]: /url\n", + "html": "<p><img src=\"/url\" alt=\"foo\" /></p>\n", + "example": 590, + "start_line": 8874, + "end_line": 8880, + "section": "Images", + "extensions": [] + }, + { + "markdown": "![foo][bar]\n\n[BAR]: /url\n", + "html": "<p><img src=\"/url\" alt=\"foo\" /></p>\n", + "example": 591, + "start_line": 8883, + "end_line": 8889, + "section": "Images", + "extensions": [] + }, + { + "markdown": "![foo][]\n\n[foo]: /url \"title\"\n", + "html": "<p><img src=\"/url\" alt=\"foo\" title=\"title\" /></p>\n", + "example": 592, + "start_line": 8894, + "end_line": 8900, + "section": "Images", + "extensions": [] + }, + { + "markdown": "![*foo* bar][]\n\n[*foo* bar]: /url \"title\"\n", + "html": "<p><img src=\"/url\" alt=\"foo bar\" title=\"title\" /></p>\n", + "example": 593, + "start_line": 8903, + "end_line": 8909, + "section": "Images", + "extensions": [] + }, + { + "markdown": "![Foo][]\n\n[foo]: /url \"title\"\n", + "html": "<p><img src=\"/url\" alt=\"Foo\" title=\"title\" /></p>\n", + "example": 594, + "start_line": 8914, + "end_line": 8920, + "section": "Images", + "extensions": [] + }, + { + "markdown": "![foo] \n[]\n\n[foo]: /url \"title\"\n", + "html": "<p><img src=\"/url\" alt=\"foo\" title=\"title\" />\n[]</p>\n", + "example": 595, + "start_line": 8926, + "end_line": 8934, + "section": "Images", + "extensions": [] + }, + { + "markdown": "![foo]\n\n[foo]: /url \"title\"\n", + "html": "<p><img src=\"/url\" alt=\"foo\" title=\"title\" /></p>\n", + "example": 596, + "start_line": 8939, + "end_line": 8945, + "section": "Images", + "extensions": [] + }, + { + "markdown": "![*foo* bar]\n\n[*foo* bar]: /url \"title\"\n", + "html": "<p><img src=\"/url\" alt=\"foo bar\" title=\"title\" /></p>\n", + "example": 597, + "start_line": 8948, + "end_line": 8954, + "section": "Images", + "extensions": [] + }, + { + "markdown": "![[foo]]\n\n[[foo]]: /url \"title\"\n", + "html": "<p>![[foo]]</p>\n<p>[[foo]]: /url "title"</p>\n", + "example": 598, + "start_line": 8959, + "end_line": 8966, + "section": "Images", + "extensions": [] + }, + { + "markdown": "![Foo]\n\n[foo]: /url \"title\"\n", + "html": "<p><img src=\"/url\" alt=\"Foo\" title=\"title\" /></p>\n", + "example": 599, + "start_line": 8971, + "end_line": 8977, + "section": "Images", + "extensions": [] + }, + { + "markdown": "!\\[foo]\n\n[foo]: /url \"title\"\n", + "html": "<p>![foo]</p>\n", + "example": 600, + "start_line": 8983, + "end_line": 8989, + "section": "Images", + "extensions": [] + }, + { + "markdown": "\\![foo]\n\n[foo]: /url \"title\"\n", + "html": "<p>!<a href=\"/url\" title=\"title\">foo</a></p>\n", + "example": 601, + "start_line": 8995, + "end_line": 9001, + "section": "Images", + "extensions": [] + }, + { + "markdown": "<http://foo.bar.baz>\n", + "html": "<p><a href=\"http://foo.bar.baz\">http://foo.bar.baz</a></p>\n", + "example": 602, + "start_line": 9028, + "end_line": 9032, + "section": "Autolinks", + "extensions": [] + }, + { + "markdown": "<http://foo.bar.baz/test?q=hello&id=22&boolean>\n", + "html": "<p><a href=\"http://foo.bar.baz/test?q=hello&id=22&boolean\">http://foo.bar.baz/test?q=hello&id=22&boolean</a></p>\n", + "example": 603, + "start_line": 9035, + "end_line": 9039, + "section": "Autolinks", + "extensions": [] + }, + { + "markdown": "<irc://foo.bar:2233/baz>\n", + "html": "<p><a href=\"irc://foo.bar:2233/baz\">irc://foo.bar:2233/baz</a></p>\n", + "example": 604, + "start_line": 9042, + "end_line": 9046, + "section": "Autolinks", + "extensions": [] + }, + { + "markdown": "<MAILTO:FOO@BAR.BAZ>\n", + "html": "<p><a href=\"MAILTO:FOO@BAR.BAZ\">MAILTO:FOO@BAR.BAZ</a></p>\n", + "example": 605, + "start_line": 9051, + "end_line": 9055, + "section": "Autolinks", + "extensions": [] + }, + { + "markdown": "<a+b+c:d>\n", + "html": "<p><a href=\"a+b+c:d\">a+b+c:d</a></p>\n", + "example": 606, + "start_line": 9063, + "end_line": 9067, + "section": "Autolinks", + "extensions": [] + }, + { + "markdown": "<made-up-scheme://foo,bar>\n", + "html": "<p><a href=\"made-up-scheme://foo,bar\">made-up-scheme://foo,bar</a></p>\n", + "example": 607, + "start_line": 9070, + "end_line": 9074, + "section": "Autolinks", + "extensions": [] + }, + { + "markdown": "<http://../>\n", + "html": "<p><a href=\"http://../\">http://../</a></p>\n", + "example": 608, + "start_line": 9077, + "end_line": 9081, + "section": "Autolinks", + "extensions": [] + }, + { + "markdown": "<localhost:5001/foo>\n", + "html": "<p><a href=\"localhost:5001/foo\">localhost:5001/foo</a></p>\n", + "example": 609, + "start_line": 9084, + "end_line": 9088, + "section": "Autolinks", + "extensions": [] + }, + { + "markdown": "<http://foo.bar/baz bim>\n", + "html": "<p><http://foo.bar/baz bim></p>\n", + "example": 610, + "start_line": 9093, + "end_line": 9097, + "section": "Autolinks", + "extensions": [] + }, + { + "markdown": "<http://example.com/\\[\\>\n", + "html": "<p><a href=\"http://example.com/%5C%5B%5C\">http://example.com/\\[\\</a></p>\n", + "example": 611, + "start_line": 9102, + "end_line": 9106, + "section": "Autolinks", + "extensions": [] + }, + { + "markdown": "<foo@bar.example.com>\n", + "html": "<p><a href=\"mailto:foo@bar.example.com\">foo@bar.example.com</a></p>\n", + "example": 612, + "start_line": 9124, + "end_line": 9128, + "section": "Autolinks", + "extensions": [] + }, + { + "markdown": "<foo+special@Bar.baz-bar0.com>\n", + "html": "<p><a href=\"mailto:foo+special@Bar.baz-bar0.com\">foo+special@Bar.baz-bar0.com</a></p>\n", + "example": 613, + "start_line": 9131, + "end_line": 9135, + "section": "Autolinks", + "extensions": [] + }, + { + "markdown": "<foo\\+@bar.example.com>\n", + "html": "<p><foo+@bar.example.com></p>\n", + "example": 614, + "start_line": 9140, + "end_line": 9144, + "section": "Autolinks", + "extensions": [] + }, + { + "markdown": "<>\n", + "html": "<p><></p>\n", + "example": 615, + "start_line": 9149, + "end_line": 9153, + "section": "Autolinks", + "extensions": [] + }, + { + "markdown": "< http://foo.bar >\n", + "html": "<p>< http://foo.bar ></p>\n", + "example": 616, + "start_line": 9156, + "end_line": 9160, + "section": "Autolinks", + "extensions": [] + }, + { + "markdown": "<m:abc>\n", + "html": "<p><m:abc></p>\n", + "example": 617, + "start_line": 9163, + "end_line": 9167, + "section": "Autolinks", + "extensions": [] + }, + { + "markdown": "<foo.bar.baz>\n", + "html": "<p><foo.bar.baz></p>\n", + "example": 618, + "start_line": 9170, + "end_line": 9174, + "section": "Autolinks", + "extensions": [] + }, + { + "markdown": "http://example.com\n", + "html": "<p>http://example.com</p>\n", + "example": 619, + "start_line": 9177, + "end_line": 9181, + "section": "Autolinks", + "extensions": [] + }, + { + "markdown": "foo@bar.example.com\n", + "html": "<p>foo@bar.example.com</p>\n", + "example": 620, + "start_line": 9184, + "end_line": 9188, + "section": "Autolinks", + "extensions": [] + }, + { + "markdown": "www.commonmark.org\n", + "html": "<p><a href=\"http://www.commonmark.org\">www.commonmark.org</a></p>\n", + "example": 621, + "start_line": 9213, + "end_line": 9217, + "section": "Autolinks (extension)", + "extensions": [ + "autolink" + ] + }, + { + "markdown": "Visit www.commonmark.org/help for more information.\n", + "html": "<p>Visit <a href=\"http://www.commonmark.org/help\">www.commonmark.org/help</a> for more information.</p>\n", + "example": 622, + "start_line": 9221, + "end_line": 9225, + "section": "Autolinks (extension)", + "extensions": [ + "autolink" + ] + }, + { + "markdown": "Visit www.commonmark.org.\n\nVisit www.commonmark.org/a.b.\n", + "html": "<p>Visit <a href=\"http://www.commonmark.org\">www.commonmark.org</a>.</p>\n<p>Visit <a href=\"http://www.commonmark.org/a.b\">www.commonmark.org/a.b</a>.</p>\n", + "example": 623, + "start_line": 9233, + "end_line": 9240, + "section": "Autolinks (extension)", + "extensions": [ + "autolink" + ] + }, + { + "markdown": "www.google.com/search?q=Markup+(business)\n\nwww.google.com/search?q=Markup+(business)))\n\n(www.google.com/search?q=Markup+(business))\n\n(www.google.com/search?q=Markup+(business)\n", + "html": "<p><a href=\"http://www.google.com/search?q=Markup+(business)\">www.google.com/search?q=Markup+(business)</a></p>\n<p><a href=\"http://www.google.com/search?q=Markup+(business)\">www.google.com/search?q=Markup+(business)</a>))</p>\n<p>(<a href=\"http://www.google.com/search?q=Markup+(business)\">www.google.com/search?q=Markup+(business)</a>)</p>\n<p>(<a href=\"http://www.google.com/search?q=Markup+(business)\">www.google.com/search?q=Markup+(business)</a></p>\n", + "example": 624, + "start_line": 9247, + "end_line": 9260, + "section": "Autolinks (extension)", + "extensions": [ + "autolink" + ] + }, + { + "markdown": "www.google.com/search?q=(business))+ok\n", + "html": "<p><a href=\"http://www.google.com/search?q=(business))+ok\">www.google.com/search?q=(business))+ok</a></p>\n", + "example": 625, + "start_line": 9266, + "end_line": 9270, + "section": "Autolinks (extension)", + "extensions": [ + "autolink" + ] + }, + { + "markdown": "www.google.com/search?q=commonmark&hl=en\n\nwww.google.com/search?q=commonmark&hl;\n", + "html": "<p><a href=\"http://www.google.com/search?q=commonmark&hl=en\">www.google.com/search?q=commonmark&hl=en</a></p>\n<p><a href=\"http://www.google.com/search?q=commonmark\">www.google.com/search?q=commonmark</a>&hl;</p>\n", + "example": 626, + "start_line": 9277, + "end_line": 9284, + "section": "Autolinks (extension)", + "extensions": [ + "autolink" + ] + }, + { + "markdown": "www.commonmark.org/he<lp\n", + "html": "<p><a href=\"http://www.commonmark.org/he\">www.commonmark.org/he</a><lp</p>\n", + "example": 627, + "start_line": 9288, + "end_line": 9292, + "section": "Autolinks (extension)", + "extensions": [ + "autolink" + ] + }, + { + "markdown": "http://commonmark.org\n\n(Visit https://encrypted.google.com/search?q=Markup+(business))\n\nAnonymous FTP is available at ftp://foo.bar.baz.\n", + "html": "<p><a href=\"http://commonmark.org\">http://commonmark.org</a></p>\n<p>(Visit <a href=\"https://encrypted.google.com/search?q=Markup+(business)\">https://encrypted.google.com/search?q=Markup+(business)</a>)</p>\n<p>Anonymous FTP is available at <a href=\"ftp://foo.bar.baz\">ftp://foo.bar.baz</a>.</p>\n", + "example": 628, + "start_line": 9299, + "end_line": 9309, + "section": "Autolinks (extension)", + "extensions": [ + "autolink" + ] + }, + { + "markdown": "foo@bar.baz\n", + "html": "<p><a href=\"mailto:foo@bar.baz\">foo@bar.baz</a></p>\n", + "example": 629, + "start_line": 9325, + "end_line": 9329, + "section": "Autolinks (extension)", + "extensions": [ + "autolink" + ] + }, + { + "markdown": "hello@mail+xyz.example isn't valid, but hello+xyz@mail.example is.\n", + "html": "<p>hello@mail+xyz.example isn't valid, but <a href=\"mailto:hello+xyz@mail.example\">hello+xyz@mail.example</a> is.</p>\n", + "example": 630, + "start_line": 9333, + "end_line": 9337, + "section": "Autolinks (extension)", + "extensions": [ + "autolink" + ] + }, + { + "markdown": "a.b-c_d@a.b\n\na.b-c_d@a.b.\n\na.b-c_d@a.b-\n\na.b-c_d@a.b_\n", + "html": "<p><a href=\"mailto:a.b-c_d@a.b\">a.b-c_d@a.b</a></p>\n<p><a href=\"mailto:a.b-c_d@a.b\">a.b-c_d@a.b</a>.</p>\n<p>a.b-c_d@a.b-</p>\n<p>a.b-c_d@a.b_</p>\n", + "example": 631, + "start_line": 9343, + "end_line": 9356, + "section": "Autolinks (extension)", + "extensions": [ + "autolink" + ] + }, + { + "markdown": "<a><bab><c2c>\n", + "html": "<p><a><bab><c2c></p>\n", + "example": 632, + "start_line": 9434, + "end_line": 9438, + "section": "Raw HTML", + "extensions": [] + }, + { + "markdown": "<a/><b2/>\n", + "html": "<p><a/><b2/></p>\n", + "example": 633, + "start_line": 9443, + "end_line": 9447, + "section": "Raw HTML", + "extensions": [] + }, + { + "markdown": "<a /><b2\ndata=\"foo\" >\n", + "html": "<p><a /><b2\ndata=\"foo\" ></p>\n", + "example": 634, + "start_line": 9452, + "end_line": 9458, + "section": "Raw HTML", + "extensions": [] + }, + { + "markdown": "<a foo=\"bar\" bam = 'baz <em>\"</em>'\n_boolean zoop:33=zoop:33 />\n", + "html": "<p><a foo=\"bar\" bam = 'baz <em>\"</em>'\n_boolean zoop:33=zoop:33 /></p>\n", + "example": 635, + "start_line": 9463, + "end_line": 9469, + "section": "Raw HTML", + "extensions": [] + }, + { + "markdown": "Foo <responsive-image src=\"foo.jpg\" />\n", + "html": "<p>Foo <responsive-image src=\"foo.jpg\" /></p>\n", + "example": 636, + "start_line": 9474, + "end_line": 9478, + "section": "Raw HTML", + "extensions": [] + }, + { + "markdown": "<33> <__>\n", + "html": "<p><33> <__></p>\n", + "example": 637, + "start_line": 9483, + "end_line": 9487, + "section": "Raw HTML", + "extensions": [] + }, + { + "markdown": "<a h*#ref=\"hi\">\n", + "html": "<p><a h*#ref="hi"></p>\n", + "example": 638, + "start_line": 9492, + "end_line": 9496, + "section": "Raw HTML", + "extensions": [] + }, + { + "markdown": "<a href=\"hi'> <a href=hi'>\n", + "html": "<p><a href="hi'> <a href=hi'></p>\n", + "example": 639, + "start_line": 9501, + "end_line": 9505, + "section": "Raw HTML", + "extensions": [] + }, + { + "markdown": "< a><\nfoo><bar/ >\n<foo bar=baz\nbim!bop />\n", + "html": "<p>< a><\nfoo><bar/ >\n<foo bar=baz\nbim!bop /></p>\n", + "example": 640, + "start_line": 9510, + "end_line": 9520, + "section": "Raw HTML", + "extensions": [] + }, + { + "markdown": "<a href='bar'title=title>\n", + "html": "<p><a href='bar'title=title></p>\n", + "example": 641, + "start_line": 9525, + "end_line": 9529, + "section": "Raw HTML", + "extensions": [] + }, + { + "markdown": "</a></foo >\n", + "html": "<p></a></foo ></p>\n", + "example": 642, + "start_line": 9534, + "end_line": 9538, + "section": "Raw HTML", + "extensions": [] + }, + { + "markdown": "</a href=\"foo\">\n", + "html": "<p></a href="foo"></p>\n", + "example": 643, + "start_line": 9543, + "end_line": 9547, + "section": "Raw HTML", + "extensions": [] + }, + { + "markdown": "foo <!-- this is a --\ncomment - with hyphens -->\n", + "html": "<p>foo <!-- this is a --\ncomment - with hyphens --></p>\n", + "example": 644, + "start_line": 9552, + "end_line": 9558, + "section": "Raw HTML", + "extensions": [] + }, + { + "markdown": "foo <!--> foo -->\n\nfoo <!---> foo -->\n", + "html": "<p>foo <!--> foo --></p>\n<p>foo <!---> foo --></p>\n", + "example": 645, + "start_line": 9560, + "end_line": 9567, + "section": "Raw HTML", + "extensions": [] + }, + { + "markdown": "foo <?php echo $a; ?>\n", + "html": "<p>foo <?php echo $a; ?></p>\n", + "example": 646, + "start_line": 9572, + "end_line": 9576, + "section": "Raw HTML", + "extensions": [] + }, + { + "markdown": "foo <!ELEMENT br EMPTY>\n", + "html": "<p>foo <!ELEMENT br EMPTY></p>\n", + "example": 647, + "start_line": 9581, + "end_line": 9585, + "section": "Raw HTML", + "extensions": [] + }, + { + "markdown": "foo <![CDATA[>&<]]>\n", + "html": "<p>foo <![CDATA[>&<]]></p>\n", + "example": 648, + "start_line": 9590, + "end_line": 9594, + "section": "Raw HTML", + "extensions": [] + }, + { + "markdown": "foo <a href=\"ö\">\n", + "html": "<p>foo <a href=\"ö\"></p>\n", + "example": 649, + "start_line": 9600, + "end_line": 9604, + "section": "Raw HTML", + "extensions": [] + }, + { + "markdown": "foo <a href=\"\\*\">\n", + "html": "<p>foo <a href=\"\\*\"></p>\n", + "example": 650, + "start_line": 9609, + "end_line": 9613, + "section": "Raw HTML", + "extensions": [] + }, + { + "markdown": "<a href=\"\\\"\">\n", + "html": "<p><a href="""></p>\n", + "example": 651, + "start_line": 9616, + "end_line": 9620, + "section": "Raw HTML", + "extensions": [] + }, + { + "markdown": "<strong> <title> <style> <em>\n\n<blockquote>\n <xmp> is disallowed. <XMP> is also disallowed.\n</blockquote>\n", + "html": "<p><strong> <title> <style> <em></p>\n<blockquote>\n <xmp> is disallowed. <XMP> is also disallowed.\n</blockquote>\n", + "example": 652, + "start_line": 9647, + "end_line": 9658, + "section": "Disallowed Raw HTML (extension)", + "extensions": [ + "tagfilter" + ] + }, + { + "markdown": "foo \nbaz\n", + "html": "<p>foo<br />\nbaz</p>\n", + "example": 653, + "start_line": 9669, + "end_line": 9675, + "section": "Hard line breaks", + "extensions": [] + }, + { + "markdown": "foo\\\nbaz\n", + "html": "<p>foo<br />\nbaz</p>\n", + "example": 654, + "start_line": 9681, + "end_line": 9687, + "section": "Hard line breaks", + "extensions": [] + }, + { + "markdown": "foo \nbaz\n", + "html": "<p>foo<br />\nbaz</p>\n", + "example": 655, + "start_line": 9692, + "end_line": 9698, + "section": "Hard line breaks", + "extensions": [] + }, + { + "markdown": "foo \n bar\n", + "html": "<p>foo<br />\nbar</p>\n", + "example": 656, + "start_line": 9703, + "end_line": 9709, + "section": "Hard line breaks", + "extensions": [] + }, + { + "markdown": "foo\\\n bar\n", + "html": "<p>foo<br />\nbar</p>\n", + "example": 657, + "start_line": 9712, + "end_line": 9718, + "section": "Hard line breaks", + "extensions": [] + }, + { + "markdown": "*foo \nbar*\n", + "html": "<p><em>foo<br />\nbar</em></p>\n", + "example": 658, + "start_line": 9724, + "end_line": 9730, + "section": "Hard line breaks", + "extensions": [] + }, + { + "markdown": "*foo\\\nbar*\n", + "html": "<p><em>foo<br />\nbar</em></p>\n", + "example": 659, + "start_line": 9733, + "end_line": 9739, + "section": "Hard line breaks", + "extensions": [] + }, + { + "markdown": "`code \nspan`\n", + "html": "<p><code>code span</code></p>\n", + "example": 660, + "start_line": 9744, + "end_line": 9749, + "section": "Hard line breaks", + "extensions": [] + }, + { + "markdown": "`code\\\nspan`\n", + "html": "<p><code>code\\ span</code></p>\n", + "example": 661, + "start_line": 9752, + "end_line": 9757, + "section": "Hard line breaks", + "extensions": [] + }, + { + "markdown": "<a href=\"foo \nbar\">\n", + "html": "<p><a href=\"foo \nbar\"></p>\n", + "example": 662, + "start_line": 9762, + "end_line": 9768, + "section": "Hard line breaks", + "extensions": [] + }, + { + "markdown": "<a href=\"foo\\\nbar\">\n", + "html": "<p><a href=\"foo\\\nbar\"></p>\n", + "example": 663, + "start_line": 9771, + "end_line": 9777, + "section": "Hard line breaks", + "extensions": [] + }, + { + "markdown": "foo\\\n", + "html": "<p>foo\\</p>\n", + "example": 664, + "start_line": 9784, + "end_line": 9788, + "section": "Hard line breaks", + "extensions": [] + }, + { + "markdown": "foo \n", + "html": "<p>foo</p>\n", + "example": 665, + "start_line": 9791, + "end_line": 9795, + "section": "Hard line breaks", + "extensions": [] + }, + { + "markdown": "### foo\\\n", + "html": "<h3>foo\\</h3>\n", + "example": 666, + "start_line": 9798, + "end_line": 9802, + "section": "Hard line breaks", + "extensions": [] + }, + { + "markdown": "### foo \n", + "html": "<h3>foo</h3>\n", + "example": 667, + "start_line": 9805, + "end_line": 9809, + "section": "Hard line breaks", + "extensions": [] + }, + { + "markdown": "foo\nbaz\n", + "html": "<p>foo\nbaz</p>\n", + "example": 668, + "start_line": 9820, + "end_line": 9826, + "section": "Soft line breaks", + "extensions": [] + }, + { + "markdown": "foo \n baz\n", + "html": "<p>foo\nbaz</p>\n", + "example": 669, + "start_line": 9832, + "end_line": 9838, + "section": "Soft line breaks", + "extensions": [] + }, + { + "markdown": "hello $.;'there\n", + "html": "<p>hello $.;'there</p>\n", + "example": 670, + "start_line": 9852, + "end_line": 9856, + "section": "Textual content", + "extensions": [] + }, + { + "markdown": "Foo \u03c7\u03c1\u1fc6\u03bd\n", + "html": "<p>Foo \u03c7\u03c1\u1fc6\u03bd</p>\n", + "example": 671, + "start_line": 9859, + "end_line": 9863, + "section": "Textual content", + "extensions": [] + }, + { + "markdown": "Multiple spaces\n", + "html": "<p>Multiple spaces</p>\n", + "example": 672, + "start_line": 9868, + "end_line": 9872, + "section": "Textual content", + "extensions": [] + } +] \ No newline at end of file diff --git a/pkgs/markdown/tool/stats.dart b/pkgs/markdown/tool/stats.dart new file mode 100644 index 000000000..67b1d394d --- /dev/null +++ b/pkgs/markdown/tool/stats.dart @@ -0,0 +1,266 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:async'; +import 'dart:collection'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:args/args.dart'; +import 'package:collection/collection.dart'; +import 'package:path/path.dart' as p; + +import '../tool/expected_output.dart'; +import 'stats_lib.dart'; + +final _configs = List<Config>.unmodifiable([ + Config.commonMarkConfig, + Config.gfmConfig, +]); + +Future<void> main(List<String> args) async { + final parser = ArgParser() + ..addOption( + 'section', + help: 'Restrict tests to one section, provided after the option.', + ) + ..addFlag( + 'raw', + help: 'raw JSON format', + negatable: false, + ) + ..addFlag( + 'update-files', + help: 'Update stats files in $toolDir', + negatable: false, + ) + ..addFlag( + 'verbose', + help: 'Print details for failures and errors.', + negatable: false, + ) + ..addFlag( + 'verbose-loose', + help: 'Print details for "loose" matches.', + negatable: false, + ) + ..addOption('flavor', allowed: _configs.map((c) => c.prefix)) + ..addFlag('help', negatable: false); + + ArgResults options; + + try { + options = parser.parse(args); + } on FormatException catch (e) { + stderr.writeln(e); + print(parser.usage); + exitCode = 64; // unix standard improper usage + return; + } + + if (options['help'] as bool) { + print(parser.usage); + return; + } + + final specifiedSection = options['section'] as String?; + final raw = options['raw'] as bool; + final verbose = options['verbose'] as bool; + final verboseLooseMatch = options['verbose-loose'] as bool; + final updateFiles = options['update-files'] as bool; + + if (updateFiles && (raw || verbose || (specifiedSection != null))) { + stderr.writeln('The `update-files` flag must be used by itself'); + print(parser.usage); + exitCode = 64; // unix standard improper usage + return; + } + + var testPrefix = options['flavor'] as String?; + if (!updateFiles) { + testPrefix = _configs.first.prefix; + } + + final testPrefixes = + testPrefix == null ? _configs.map((c) => c.prefix) : <String>[testPrefix]; + + for (final testPrefix in testPrefixes) { + await _processConfig( + testPrefix, + raw, + updateFiles, + verbose, + specifiedSection, + verboseLooseMatch, + ); + } +} + +final _sectionNameReplace = RegExp(r'[ \)\(]+'); + +String _unitOutput(Iterable<DataCase> cases) => cases.map((dataCase) => ''' +>>> ${dataCase.front_matter} +${dataCase.input}<<< +${dataCase.expectedOutput}''').join(); + +/// Set this to `true` and rerun `--update-files` to ease finding easy strict +/// fixes. +const _improveStrict = false; + +Future<void> _processConfig( + String testPrefix, + bool raw, + bool updateFiles, + bool verbose, + String? specifiedSection, + bool verboseLooseMatch, +) async { + final config = _configs.singleWhere((c) => c.prefix == testPrefix); + + final sections = loadCommonMarkSections(testPrefix); + + final scores = SplayTreeMap<String, SplayTreeMap<int, CompareLevel>>( + compareAsciiLowerCaseNatural); + + for (final entry in sections.entries) { + if (specifiedSection != null && entry.key != specifiedSection) { + continue; + } + + final units = <DataCase>[]; + + for (final e in entry.value) { + final result = compareResult( + config, + e, + verboseFail: verbose, + verboseLooseMatch: verboseLooseMatch, + extensions: e.extensions, + ); + + units.add(DataCase( + front_matter: result.testCase.toString(), + input: result.testCase.markdown, + expectedOutput: + (_improveStrict && result.compareLevel == CompareLevel.loose) + ? result.testCase.html + : result.result!, + )); + + final nestedMap = scores.putIfAbsent( + entry.key, + SplayTreeMap<int, CompareLevel>.new, + ); + nestedMap[e.example] = result.compareLevel; + } + + if (updateFiles && units.isNotEmpty) { + var fileName = + entry.key.toLowerCase().replaceAll(_sectionNameReplace, '_'); + while (fileName.endsWith('_')) { + fileName = fileName.substring(0, fileName.length - 1); + } + fileName = '$fileName.unit'; + File(p.join('test', testPrefix, fileName)) + ..createSync(recursive: true) + ..writeAsStringSync(_unitOutput(units)); + } + } + + if (raw || updateFiles) { + await _printRaw(testPrefix, scores, updateFiles); + } + + if (!raw || updateFiles) { + await _printFriendly(testPrefix, scores, updateFiles); + } +} + +Object? _convert(Object? obj) { + if (obj is CompareLevel) { + return obj.name; + } + if (obj is Map) { + return obj + .map<String, Object?>((key, value) => MapEntry(key.toString(), value)); + } + return obj; +} + +Future<void> _printRaw( + String testPrefix, + Map<String, Map<int, CompareLevel>> scores, + bool updateFiles, +) async { + IOSink sink; + if (updateFiles) { + final file = getStatsFile(testPrefix); + print('Updating ${file.path}'); + sink = file.openWrite(); + } else { + sink = stdout; + } + + const encoder = JsonEncoder.withIndent(' ', _convert); + try { + sink.writeln(encoder.convert(scores)); + // ignore: avoid_catching_errors + } on JsonUnsupportedObjectError catch (e) { + stderr.writeln(e.cause); + stderr.writeln(e.unsupportedObject.runtimeType); + rethrow; + } + + await sink.flush(); + await sink.close(); +} + +String _pct(int value, int total, String section) => + '${value.toString().padLeft(4)} ' + 'of ${total.toString().padLeft(4)} ' + '– ${(100 * value / total).toStringAsFixed(1).padLeft(5)}% $section'; + +Future<void> _printFriendly( + String testPrefix, + SplayTreeMap<String, SplayTreeMap<int, CompareLevel>> scores, + bool updateFiles, +) async { + var totalValid = 0; + var totalStrict = 0; + var totalExamples = 0; + + IOSink sink; + if (updateFiles) { + final path = p.join(toolDir, '${testPrefix}_stats.txt'); + print('Updating $path'); + final file = File(path); + sink = file.openWrite(); + } else { + sink = stdout; + } + + scores.forEach((section, Map<int, CompareLevel> map) { + final total = map.values.length; + totalExamples += total; + + final sectionStrictCount = + map.values.where((val) => val == CompareLevel.strict).length; + + final sectionLooseCount = + map.values.where((val) => val == CompareLevel.loose).length; + + final sectionValidCount = sectionStrictCount + sectionLooseCount; + + totalStrict += sectionStrictCount; + totalValid += sectionValidCount; + + sink.writeln(_pct(sectionValidCount, total, section)); + }); + + sink.writeln(_pct(totalValid, totalExamples, 'TOTAL')); + sink.writeln(_pct(totalStrict, totalValid, 'TOTAL Strict')); + + await sink.flush(); + await sink.close(); +} diff --git a/pkgs/markdown/tool/stats_lib.dart b/pkgs/markdown/tool/stats_lib.dart new file mode 100644 index 000000000..5ff63218e --- /dev/null +++ b/pkgs/markdown/tool/stats_lib.dart @@ -0,0 +1,276 @@ +// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:convert'; +import 'dart:io'; +import 'dart:mirrors'; + +import 'package:html/dom.dart' show Element; +import 'package:html/parser.dart' show parseFragment; +import 'package:markdown/markdown.dart' + show + AutolinkExtensionSyntax, + BlockSyntax, + InlineSyntax, + StrikethroughSyntax, + TableSyntax, + markdownToHtml; +import 'package:path/path.dart' as p; + +import '../test/util.dart'; + +// Locate the "tool" directory. Use mirrors so that this works with the test +// package, which loads this suite into an isolate. +String get toolDir { + final path = (reflect(loadCommonMarkSections) as ClosureMirror) + .function + .location! + .sourceUri + .path; + + return p.dirname(path); +} + +File getStatsFile(String prefix) => + File(p.join(toolDir, '${prefix}_stats.json')); + +Map<String, List<CommonMarkTestCase>> loadCommonMarkSections( + String testPrefix) { + final testFile = File(p.join(toolDir, '${testPrefix}_tests.json')); + final testsJson = testFile.readAsStringSync(); + + final testArray = jsonDecode(testsJson) as List; + + final sections = <String, List<CommonMarkTestCase>>{}; + + for (final exampleMap in testArray) { + final exampleTest = + CommonMarkTestCase.fromJson(exampleMap as Map<String, dynamic>); + + final sectionList = + sections.putIfAbsent(exampleTest.section, () => <CommonMarkTestCase>[]); + + sectionList.add(exampleTest); + } + + return sections; +} + +class Config { + static final Config commonMarkConfig = Config._( + 'common_mark', + 'https://spec.commonmark.org/0.30/', + ); + static final Config gfmConfig = Config._( + 'gfm', + 'https://github.github.com/gfm/', + ); + + final String prefix; + final String baseUrl; + + Config._(this.prefix, this.baseUrl); +} + +class CommonMarkTestCase { + final String markdown; + final String section; + final int example; + final String html; + final int startLine; + final int endLine; + final Set<String> extensions; + + CommonMarkTestCase( + this.example, + this.section, + this.startLine, + this.endLine, + this.markdown, + this.html, + this.extensions, + ); + + factory CommonMarkTestCase.fromJson(Map<String, dynamic> json) { + return CommonMarkTestCase( + json['example'] as int, + json['section'] as String /*!*/, + json['start_line'] as int, + json['end_line'] as int, + json['markdown'] as String /*!*/, + json['html'] as String, + json['extensions'] == null + ? const {} + : Set.from(json['extensions'] as List), + ); + } + + @override + String toString() => '$section - $example'; +} + +enum CompareLevel { strict, loose, fail, error } + +class CompareResult { + final CompareLevel compareLevel; + final CommonMarkTestCase testCase; + final String? result; + + CompareResult(this.testCase, this.result, this.compareLevel); +} + +CompareResult compareResult( + Config config, + CommonMarkTestCase testCase, { + bool throwOnError = false, + bool verboseFail = false, + bool verboseLooseMatch = false, + Set<String> extensions = const {}, +}) { + var enabletagfilter = false; + + String output; + final inlineSyntaxes = <InlineSyntax>[]; + final blockSyntaxes = <BlockSyntax>[]; + + for (final extension in extensions) { + switch (extension) { + case 'autolink': + inlineSyntaxes.add(AutolinkExtensionSyntax()); + break; + case 'strikethrough': + inlineSyntaxes.add(StrikethroughSyntax()); + break; + case 'table': + blockSyntaxes.add(const TableSyntax()); + break; + case 'tagfilter': + enabletagfilter = true; + break; + default: + throw UnimplementedError('Unimplemented extension "$extension"'); + } + } + + try { + output = markdownToHtml( + testCase.markdown, + inlineSyntaxes: inlineSyntaxes, + blockSyntaxes: blockSyntaxes, + enableTagfilter: enabletagfilter, + ); + } catch (err, stackTrace) { + if (throwOnError) { + rethrow; + } + if (verboseFail) { + _printVerboseFailure( + config.baseUrl, + 'ERROR', + testCase, + 'Thrown: $err\n$stackTrace', + ); + } + + return CompareResult(testCase, null, CompareLevel.error); + } + + if (testCase.html == output) { + return CompareResult(testCase, output, CompareLevel.strict); + } + + final expectedParsed = parseFragment(testCase.html); + final actual = parseFragment(output); + + final looseMatch = _compareHtml(expectedParsed.children, actual.children); + + if (!looseMatch && verboseFail) { + _printVerboseFailure(config.baseUrl, 'FAIL', testCase, output); + } + + if (looseMatch && verboseLooseMatch) { + _printVerboseFailure(config.baseUrl, 'LOOSE', testCase, output); + } + + return CompareResult( + testCase, + output, + looseMatch ? CompareLevel.loose : CompareLevel.fail, + ); +} + +String _indent(String s) => + s.splitMapJoin('\n', onNonMatch: (n) => ' ${whitespaceColor(n)}'); + +void _printVerboseFailure( + String baseUrl, + String message, + CommonMarkTestCase testCase, + String actual, +) { + print('$message: $baseUrl#example-${testCase.example} ' + '@ ${testCase.section}'); + print('input:'); + print(_indent(testCase.markdown)); + print('expected:'); + print(_indent(testCase.html)); + print('actual:'); + print(_indent(actual)); + print('-----------------------'); +} + +/// Compare two DOM trees for equality. +bool _compareHtml( + List<Element> expectedElements, + List<Element> actualElements, +) { + if (expectedElements.length != actualElements.length) { + return false; + } + + for (var childNum = 0; childNum < expectedElements.length; childNum++) { + final expected = expectedElements[childNum]; + final actual = actualElements[childNum]; + + if (expected.runtimeType != actual.runtimeType) { + return false; + } + + if (expected.localName != actual.localName) { + return false; + } + + if (expected.attributes.length != actual.attributes.length) { + return false; + } + + final expectedAttrKeys = expected.attributes.keys.toList(); + expectedAttrKeys.sort(); + + final actualAttrKeys = actual.attributes.keys.toList(); + actualAttrKeys.sort(); + + for (var attrNum = 0; attrNum < actualAttrKeys.length; attrNum++) { + final expectedAttrKey = expectedAttrKeys[attrNum]; + final actualAttrKey = actualAttrKeys[attrNum]; + + if (expectedAttrKey != actualAttrKey) { + return false; + } + + if (expected.attributes[expectedAttrKey] != + actual.attributes[actualAttrKey]) { + return false; + } + } + + final childrenEqual = _compareHtml(expected.children, actual.children); + + if (!childrenEqual) { + return false; + } + } + + return true; +} diff --git a/pkgs/markdown/tool/update-gh-pages.sh b/pkgs/markdown/tool/update-gh-pages.sh new file mode 100755 index 000000000..97762ad9e --- /dev/null +++ b/pkgs/markdown/tool/update-gh-pages.sh @@ -0,0 +1,13 @@ +# Echo every command being run. +set +x + +# Fail fast if a command fails. +set -e + +dart pub global activate peanut + +peanut -d example + +echo Now push updated gh-pages branch with: +echo +echo ' git push origin --set-upstream gh-pages' diff --git a/pkgs/markdown/tool/update_blns.dart b/pkgs/markdown/tool/update_blns.dart new file mode 100644 index 000000000..fbdabcaf4 --- /dev/null +++ b/pkgs/markdown/tool/update_blns.dart @@ -0,0 +1,33 @@ +import 'dart:async'; +import 'dart:io'; + +import 'update_shared.dart'; + +const _blnsJsonRawUrl = + 'https://github.com/minimaxir/big-list-of-naughty-strings/raw/master/blns.json'; +const _blnsFilePath = 'test/blns.dart'; + +Future<void> main() async { + final json = (await downloadJson(_blnsJsonRawUrl) as List).cast<String>(); + final blnsContent = StringBuffer(''' +// GENERATED FILE. DO NOT EDIT. +// +// This file was generated from big-list-of-naughty-strings's JSON file: +// $_blnsJsonRawUrl +// at ${DateTime.now()} by the script, tool/update_blns.dart. + +// ignore_for_file: text_direction_code_point_in_literal, use_raw_strings +// ignore_for_file: lines_longer_than_80_chars + +'''); + blnsContent.writeln('const blns = <String>['); + for (final str in json) { + final escaped = str + .replaceAll(r'\', r'\\') + .replaceAll("'", r"\'") + .replaceAll(r'$', r'\$'); + blnsContent.writeln(" '$escaped',"); + } + blnsContent.writeln('];'); + File(_blnsFilePath).writeAsStringSync(blnsContent.toString()); +} diff --git a/pkgs/markdown/tool/update_case_folding.dart b/pkgs/markdown/tool/update_case_folding.dart new file mode 100644 index 000000000..e53f70b4b --- /dev/null +++ b/pkgs/markdown/tool/update_case_folding.dart @@ -0,0 +1,51 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:convert'; +import 'dart:io'; + +import 'package:path/path.dart' as p; + +// Generates and updates unicode case folding map. +// Here only extract status C + F capital letters. +void main() { + // Downloaded from http://www.unicode.org/Public/14.0.0/ucd/CaseFolding.txt + final file = File('${p.current}/tool/case_folding.txt'); + + final result = <String, String>{}; + + for (final line in file.readAsLinesSync()) { + if (line.startsWith('#') || + line.trim().isEmpty || + !line.contains('CAPITAL LETTER')) { + continue; + } + + final content = line.substring(0, line.indexOf('#')); + final match = + RegExp(r'([0-9A-F]{1,6});\s+[CF];\s+(.+);').firstMatch(content); + if (match == null) { + continue; + } + + final key = String.fromCharCode(int.parse(match[1]!, radix: 16)); + final value = match[2]!.split(RegExp('[ ]+')).map((e) { + return String.fromCharCode(int.parse(e, radix: 16)); + }).join(); + result[key] = value; + } + + final outputPath = '${p.current}/lib/src/assets/case_folding.dart'; + final stringMap = const JsonEncoder.withIndent(' ').convert(result); + final output = ''' +// Generated file. do not edit. +// +// Source: tool/case_folding.txt +// Script: tool/update_case_folding.dart +// ignore_for_file: prefer_single_quotes + +const caseFoldingMap = $stringMap; +'''; + File(outputPath).writeAsStringSync(output); +} diff --git a/pkgs/markdown/tool/update_emojis.dart b/pkgs/markdown/tool/update_emojis.dart new file mode 100644 index 000000000..0b2b8a9a5 --- /dev/null +++ b/pkgs/markdown/tool/update_emojis.dart @@ -0,0 +1,56 @@ +// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:async'; +import 'dart:io'; + +import 'update_shared.dart'; + +// update_github_emojis.dart now generates the emoji list using the GitHub API +// to retrieve the emoji list. It uses this emoji source as a source to keep +// binary compatibility with the Unicode sequences for each emoji found here. +const _emojisJsonRawUrl = + 'https://raw.githubusercontent.com/muan/emojilib/v2.4.0/emojis.json'; +const _emojisFilePath = 'lib/src/legacy_emojis.dart'; + +Future<void> main() async { + final json = + (await downloadJson(_emojisJsonRawUrl) as Map<String, dynamic>).map( + (String alias, dynamic info) => + MapEntry(alias, info as Map<String, dynamic>), + ); + final emojisContent = StringBuffer(''' +// GENERATED FILE. DO NOT EDIT. +// +// This file was generated from emojilib's emoji data file: +// $_emojisJsonRawUrl +// at ${DateTime.now()} by the script, tool/update_emojis.dart. + +'''); + emojisContent.writeln('const emojis = <String, String>{'); + var emojiCount = 0; + final ignored = <String>[]; + // Dump in sorted order now to facilitate comparison with new GitHub emoji. + final sortedKeys = json.keys.toList()..sort(); + for (final alias in sortedKeys) { + final info = json[alias] as Map<String, dynamic>; + if (info['char'] != null) { + emojisContent.writeln(" '$alias': '${info['char']}',"); + emojiCount++; + } else { + ignored.add(alias); + } + } + emojisContent.writeln('};'); + File(_emojisFilePath).writeAsStringSync(emojisContent.toString()); + print( + 'WARNING: This updates only the LEGACY emoji - to update the active ' + 'emoji recognized by the markdown package, ' + 'execute `update_github_emojis.dart`.', + ); + print( + 'Wrote data to $_emojisFilePath for $emojiCount emoji, ' + 'ignoring ${ignored.length}: ${ignored.join(', ')}.', + ); +} diff --git a/pkgs/markdown/tool/update_entities.dart b/pkgs/markdown/tool/update_entities.dart new file mode 100644 index 000000000..2d114bd54 --- /dev/null +++ b/pkgs/markdown/tool/update_entities.dart @@ -0,0 +1,39 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:convert'; +import 'dart:io'; +import 'package:path/path.dart' as p; + +/// Generates and updates HTML entities. +void main() { + // Original file: https://html.spec.whatwg.org/entities.json + final file = File('${p.current}/tool/entities.json'); + final json = file.readAsStringSync(); + final map = Map<String, Map<String, dynamic>>.from(jsonDecode(json) as Map); + + final result = <String, String>{}; + for (final name in map.keys) { + if (name.endsWith(';')) { + final value = map[name]!['characters'] as String; + result[name] = value; + } + } + + final outputPath = '${p.current}/lib/src/assets/html_entities.dart'; + final stringMap = const JsonEncoder.withIndent(' ') + .convert(result) + .replaceAll(r'"$"', r'r"$"') + .replaceAll(r'"\\"', r'r"\"'); + final output = ''' +// Generated file. do not edit. +// +// Source: tool/entities.json +// Script: tool/update_entities.dart +// ignore_for_file: prefer_single_quotes + +const htmlEntitiesMap = $stringMap; +'''; + File(outputPath).writeAsStringSync(output); +} diff --git a/pkgs/markdown/tool/update_github_emojis.dart b/pkgs/markdown/tool/update_github_emojis.dart new file mode 100644 index 000000000..fb07ac51d --- /dev/null +++ b/pkgs/markdown/tool/update_github_emojis.dart @@ -0,0 +1,348 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:async'; +import 'dart:io'; + +import 'package:args/args.dart'; +import 'package:markdown/src/legacy_emojis.dart' as legacy; + +import 'update_shared.dart'; + +/// Regular expression to parse unicode from GitHub emoji API output filenames. +RegExp gitHubEmojiUnicodeFromFilenamePattern = + RegExp(r'.*unicode\/([A-Fa-f0-9\-]+)\.png'); + +/// URL for GitHub's emoji API. We reconcile with our legacy emoji so that +/// we don't change or break anything. +/// There are essentially only TWO (2) emoji that change and the +/// legacy emoji is still available with an alternate name. +/// The 'beetle' emoji changes from `🐞` to `🪲`, +/// legacy available as 'lady_beetle'. +/// The 'cricket' emoji changes from `🏏` to `🦗`, +/// legacy available as 'cricket_game'. +/// (if the -g flag us used to force using the GitHub Unicode sequences for the +/// emoji then additionally the 'email' emoji changes from '✉️' to '📧'). +const _emojisJsonRawUrl = 'https://api.github.com/emojis'; +const _emojisFilePath = 'lib/src/emojis.dart'; + +/// Reference to emoji map within legacy_emojis.dart +const legacyEmojis = legacy.emojis; + +/// AUTO GENERATED by `reconcile_emojis.dart` - this only needed to be done ONCE +/// during the reconciliation process with the legacy emoji. +/// This array is ONLY USED when the --useGitHubUnicodes option is used to +/// minimize the visual differences in the output emoji. +const legacyEmojisUsedVariationModifier = { + '263a', + '2600', + '2601', + '2744', + '2708', + '260e', + '2702', + '2712', + '270f', + '2764', + 'd83c-de37', + '2734', + '3299', + '3297', + 'd83c-dd70', + 'd83c-dd71', + 'd83c-dd7e', + '2668', + '203c', + '2049', + '303d', + '26a0', + '267b', + '2747', + '2733', + '24c2', + 'd83c-de02', + 'd83c-dd7f', + '23cf', + '25b6', + '25c0', + '27a1', + '2b05', + '2b06', + '2b07', + '2197', + '2198', + '2199', + '2196', + '2195', + '2194', + '21aa', + '21a9', + '2934', + '2935', + '2139', + '3030', + '2714', + '2716', + '00a9', + '00ae', + '2122', + '2611', + '25aa', + '25ab', + '25fc', + '25fb', + '2660', + '2663', + '2665', + '2666', +}; + +/// Special replacement character '�' +const errorSpecialReplacement = '\u{FFFD}'; + +const useOfGitHubUnicodeSequencesWarning = ''' +IMPORTANT NOTE: The use of the --useGitHubUnicodes switch will force using +GitHub Unicode sequences. +This option is essentially here only for completeness, not for +release use. +The slight visual differences of some emoji might also be another +reason using --useGitHubUnicodes should be considered a *Breaking Change*. + +Some test will fail because of the different Unicode sequences +and the emojis.unit file would need to be updated to contain the new +expected GitHub versions of the Unicode sequences of the emoji in order +for the tests to pass. +'''; + +/// The GitHub API URL will return a JSON map of all emoji in the form of +/// `{ 'shortcode':'emojifilename' ... }`. +/// The filenames are simply a list of all of the hex string of the +/// *essential* Unicode codepoints representing the emoji. +/// These sequences exclude the Unicode join zero width (0x200D) and +/// variation select (0xFE0F) modifiers. (We will need to add these in to +/// build our actually Unicode strings representing the emoji). +/// Multiple Unicode codepoints are separated by '-'. +/// Examples filenames (single and double code point examples): +/// - "https://github.githubassets.com/images/icons/emoji/unicode/1f643.png?v8" +/// - "https://github.githubassets.com/images/icons/emoji/unicode/1f1fa-1f1fe.png?v8" +/// - "https://github.githubassets.com/images/icons/emoji/unicode/1f469-1f469-1f467-1f466.png?v8" +/// NOTE: Some filenames will be GitHub 'custom' emoji that have +/// no Unicode equivalent and these will not have hex codepoints, +/// only the GitHub custom name. +/// We will ignore these (there are only a 19 and they are mostly pixel art +/// from the old Doom game). +/// Example GitHub custom emoji filename: +/// - "https://github.githubassets.com/images/icons/emoji/godmode.png?v8", +String parseGitHubFilenameIntoUnicodeString(String emojiFilename) { + const variationSelector = 0xFE0F; + const zeroWidthJoiner = 0x200D; + + try { + final rawHexList = gitHubEmojiUnicodeFromFilenamePattern + .firstMatch(emojiFilename) + ?.group(1); + if (rawHexList == null) { + // This is a GitHub custom emoji and it is represented by a PNG image only + // and there is no equivalent Unicode. We have to ignore. + return ''; + } + var legacyUsedVariationCode = false; + if (legacyEmojisUsedVariationModifier.contains(rawHexList)) { + legacyUsedVariationCode = true; + } + final rawCodePointsHex = rawHexList + .split('-') + .map((hexstr) => int.parse(hexstr, radix: 16)) + .toList(); + final codePointsHex = <int>[]; + + if (legacyUsedVariationCode) { + // Just add single variation selector. + codePointsHex.addAll(rawCodePointsHex); + codePointsHex.add(variationSelector); + } else { + // Now insert the join zero width and + // variation select modifying Unicode chars. + for (var i = 0; i < rawCodePointsHex.length; i++) { + final codePointAtIndex = rawCodePointsHex[i]; + codePointsHex.add(codePointAtIndex); + if (i < (rawCodePointsHex.length - 1)) { + codePointsHex.add(variationSelector); + // # and 0-9 don't use Zero Width Joiner. + if (codePointAtIndex == 0x23 || + (codePointAtIndex >= 0x30 && codePointAtIndex <= 0x39)) { + // Don't add Zero Width Joiner. + } else { + codePointsHex.add(zeroWidthJoiner); + } + } + } + } + return String.fromCharCodes(codePointsHex); + } catch (e) { + print( + 'Invalid/Non-Conformant emoji filename encountered "$emojiFilename"!'); + return errorSpecialReplacement; + } +} + +Future<void> main(List<String> args) async { + final parser = ArgParser() + ..addFlag('help', + abbr: 'h', negatable: false, help: 'Print help text and exit.') + ..addFlag('useGitHubUnicodes', + abbr: 'g', + negatable: false, + help: 'Use the GitHub Unicode sequences instead of legacy sequences.') + ..addFlag('visualizeDifferentUnicodes', + abbr: 'v', + negatable: false, + help: 'Visualize any Unicode sequence differences.') + ..addOption('dumpMarkdownShortCodes', + abbr: 's', + defaultsTo: 'missing', + allowed: ['plain', 'tooltip'], + allowedHelp: { + 'plain': 'just shortcode', + 'tooltip': + '(shortcode with a link to provide emoji name in tooltips)', + }, + help: 'Outputs all emoji shortcodes to stdout which can be used ' + 'in markdown to show and tests all emoji.'); + late final ArgResults results; + + try { + results = parser.parse(args); + } catch (e) { + print(e); + printUsage(parser); + return; + } + + if (results['help'] as bool) { + printUsage(parser); + return; + } + + var totalEmojiWithDifferentUnicodeSequences = 0; + final useLegacyUnicodeSequences = !(results['useGitHubUnicodes'] as bool); + final visualizeUnicodeDiffs = results['visualizeDifferentUnicodes'] as bool; + + final shortCodes = + (results['dumpMarkdownShortCodes'] as String).toLowerCase(); + final dumpMarkdownShortCodes = shortCodes == 'plain'; + final dumpMarkdownToolTipShortCodes = shortCodes == 'tooltip'; + + if (!useLegacyUnicodeSequences) { + // Issue warning of the implications of using + // full GitHub emoji Unicode sequences. + print(useOfGitHubUnicodeSequencesWarning); + } + if (visualizeUnicodeDiffs) { + print( + 'The following emoji have different Unicode sequences ' + 'from those of legacy versions:', + ); + } + final shortcodeToEmoji = + (await downloadJson(_emojisJsonRawUrl) as Map<String, dynamic>).map( + (String alias, dynamic filename) => MapEntry( + alias, + parseGitHubFilenameIntoUnicodeString(filename as String), + ), + ); + + // Now before we proceed we need to 'mix in' any legacy emoji alias shortcodes + // that are missing from the GitHub emoji list. + legacyEmojis.forEach((String shortCodeAlias, String emojiUnicode) { + if (!shortcodeToEmoji.containsKey(shortCodeAlias)) { + shortcodeToEmoji[shortCodeAlias] = emojiUnicode; + } + }); + + final emojisContent = StringBuffer(''' +// GENERATED FILE. DO NOT EDIT. +// +// This file was generated from GitHub's emoji API list endpoint: +// $_emojisJsonRawUrl +// at ${DateTime.now()} by the script, tool/update_github_emojis.dart. + +'''); + emojisContent.writeln('const emojis = <String, String>{'); + var emojiCount = 0; + final ignored = <String>[]; + final errored = <String>[]; + // Dump in sorted order now to facilitate comparison with new GitHub emoji. + final sortedKeys = shortcodeToEmoji.keys.toList()..sort(); + for (final shortCodeAlias in sortedKeys) { + var emojiUnicode = shortcodeToEmoji[shortCodeAlias]!; + if (useLegacyUnicodeSequences && + legacyEmojis.containsKey(shortCodeAlias) && + shortCodeAlias != 'cricket' && + shortCodeAlias != 'beetle') { + emojiUnicode = legacyEmojis[ + shortCodeAlias]!; // Use legacy Unicode string if available. + } + if (legacyEmojis.containsKey(shortCodeAlias) && + emojiUnicode != legacyEmojis[shortCodeAlias]) { + totalEmojiWithDifferentUnicodeSequences++; + if (visualizeUnicodeDiffs) { + print( + '$emojiUnicode was ${legacyEmojis[shortCodeAlias]} ' + ':$shortCodeAlias:', + ); + } + } + if (emojiUnicode != errorSpecialReplacement && emojiUnicode.isNotEmpty) { + emojisContent.writeln(" '$shortCodeAlias': '$emojiUnicode',"); + if (dumpMarkdownShortCodes) { + print(':$shortCodeAlias:'); + } else if (dumpMarkdownToolTipShortCodes) { + print('[:$shortCodeAlias:](## ":$shortCodeAlias: emoji")'); + } + emojiCount++; + } else { + if (emojiUnicode == errorSpecialReplacement) { + errored.add(shortCodeAlias); + } else { + ignored.add(shortCodeAlias); + } + } + } + emojisContent.writeln('};'); + File(_emojisFilePath).writeAsStringSync(emojisContent.toString()); + + if (dumpMarkdownShortCodes) { + // We are outputing the markdown to stdout, and presumably it + // is being captured, so we exit now to exclude the summary + // report from being included in the emoji markdown we have + // been outputing. + return; + } + + print('''Wrote data to $_emojisFilePath for $emojiCount emoji, +$totalEmojiWithDifferentUnicodeSequences emoji's Unicode sequences differ from legacy versions${!visualizeUnicodeDiffs ? " (run with -v flag to visualize)" : ""}, +ignoring ${ignored.length}: ${ignored.join(', ')}, +errored: ${errored.length} ${errored.join(', ')}.'''); +} + +void printUsage(ArgParser parser) { + print('''Usage: update_emojis.dart [--useGitHubUnicodes | -l] + +By default, the legacy Unicode sequences are used (for +maximum visual compatability with the legacy emoji). +The --useGitHubUnicodes flag can be used so that the +Unicode sequences from GitHub are used for emoji's that +existed within the legacy set. This will result in very slight visual +differences for some emoji, but it will result in many more +binary differences when comparing legacy_emoji.dart to emoji.dart. +$useOfGitHubUnicodeSequencesWarning + +The --visualizeDifferentUnicodes flag can be used to visually +verify that any different Unicode sequences produce the same +emoji. + +${parser.usage} +'''); +} diff --git a/pkgs/markdown/tool/update_shared.dart b/pkgs/markdown/tool/update_shared.dart new file mode 100644 index 000000000..6992cd58a --- /dev/null +++ b/pkgs/markdown/tool/update_shared.dart @@ -0,0 +1,21 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:convert'; +import 'dart:io'; + +Future<Object?> downloadJson(String uri) async { + final client = HttpClient(); + try { + final request = await client.getUrl(Uri.parse(uri)); + final response = await request.close(); + + return response + .transform(utf8.decoder) + .transform(const JsonDecoder()) + .single; + } finally { + client.close(); + } +}