fix: resolve TypeScript errors in frontend build
This commit is contained in:
8
node_modules/prosemirror-markdown/.tern-project
generated
vendored
Normal file
8
node_modules/prosemirror-markdown/.tern-project
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"libs": ["browser"],
|
||||
"plugins": {
|
||||
"node": {},
|
||||
"complete_strings": {},
|
||||
"es_modules": {}
|
||||
}
|
||||
}
|
||||
311
node_modules/prosemirror-markdown/CHANGELOG.md
generated
vendored
Normal file
311
node_modules/prosemirror-markdown/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,311 @@
|
||||
## 1.13.4 (2026-02-04)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix a regression that caused the serializer to crash when a block ends in a hard break.
|
||||
|
||||
## 1.13.3 (2026-01-20)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Properly move trailing whitespace out of marks when they end in a hard break node.
|
||||
|
||||
## 1.13.2 (2025-03-18)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Add a `code` flag to the code mark.
|
||||
|
||||
## 1.13.1 (2024-09-26)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix a type error caused by use of an older markdown-it type package.
|
||||
|
||||
## 1.13.0 (2024-05-20)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix the type of `MarkdownParser.parse` to be non-nullable. Add a strict option to MarkdownSerializer
|
||||
|
||||
### New features
|
||||
|
||||
The new `strict` option to `MarkdownSerializer` makes it possible to make the serializer ignore node and mark types it doesn't know.
|
||||
|
||||
## 1.12.0 (2023-12-11)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Block-level markup inside a heading is no longer escaped by the serializer.
|
||||
|
||||
Do not backslash-escape a `+` at the start of line when it isn't followed by a space. Upgrade to markdown-it 14
|
||||
|
||||
### New features
|
||||
|
||||
`MarkdownSerializerState.renderInline` now takes a parameter that controls whether block-level markup should be escaped.
|
||||
|
||||
Upgrade to markdown-it version 14, which provides ES modules.
|
||||
|
||||
## 1.11.2 (2023-08-04)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix some unnecessary escapes for period characters in Markdown serialization.
|
||||
|
||||
Only escape `#` signs if they would otherwise create a heading. Add a test for headings in list items
|
||||
|
||||
Fix a bug in `MarkdownSerializer` that broken expelling of whitespace from marks when the mark spanned multiple nodes.
|
||||
|
||||
## 1.11.1 (2023-06-30)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Allow any blocks as first child of list items to align with what Markdown itself does.
|
||||
|
||||
Add parse rules that clear `strong` and `em` marks when inline CSS resets it.
|
||||
|
||||
## 1.11.0 (2023-05-17)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Make sure blank lines at the end of code blocks are properly serialized.
|
||||
|
||||
Convert soft breaks (single newlines) in Markdown to spaces, rather than newlines in the ProseMirror document, because newlines tend to behave awkwardly in the editor.
|
||||
|
||||
Fix a bug that cause the object passed as configuration to `MarkdownSerializer` to be mutated. Add release note
|
||||
|
||||
Include CommonJS type declarations in the package to please new TypeScript resolution settings.
|
||||
|
||||
### New features
|
||||
|
||||
A new option to `MarkdownSerializer` allows client code to configure which node type should be treated as hard breaks during mark serialization. Remove the extra left bracket
|
||||
|
||||
## 1.10.1 (2022-10-28)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Don't treat the empty string the same as `null` in `wrapBlock`'s `firstDelim` argument. Check content of code blocks for any sequence of backticks
|
||||
|
||||
Use longer sequences of backticks when serializing a code block that contains three or more backticks in a row.
|
||||
|
||||
## 1.10.0 (2022-10-05)
|
||||
|
||||
### New features
|
||||
|
||||
You can now pass an optional markdown-it environment object to .
|
||||
|
||||
## 1.9.4 (2022-08-19)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Don't escape colon characters at the start of a line.
|
||||
|
||||
Escape parentheses in images and links.
|
||||
|
||||
Allow links to wrap emphasis markers when serializing Markdown.
|
||||
|
||||
## 1.9.3 (2022-07-05)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Make sure '\!' characters in front of links are escaped.
|
||||
|
||||
## 1.9.2 (2022-07-04)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Don't escape characters in autolinks.
|
||||
|
||||
Fix a bug that caused the serializer to not escape start-of-line markup when inside a list.
|
||||
|
||||
## 1.9.1 (2022-06-02)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix a bug where inline nodes with content would reset the marks in their parent node during Markdown parsing.
|
||||
|
||||
## 1.9.0 (2022-05-30)
|
||||
|
||||
### New features
|
||||
|
||||
Include TypeScript type declarations.
|
||||
|
||||
## 1.8.0 (2022-03-14)
|
||||
|
||||
### New features
|
||||
|
||||
`MarkdownSerializer` now takes an `escapeExtraCharacters` option that can be used to control backslash-escaping behavior. Fix types for new option
|
||||
|
||||
## 1.7.1 (2022-02-16)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Avoid escaping underscores surrounded by word characters.
|
||||
|
||||
## 1.7.0 (2022-01-06)
|
||||
|
||||
### New features
|
||||
|
||||
Upgrade markdown-it to version 12.
|
||||
|
||||
## 1.6.2 (2022-01-04)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix a bug where URL text in links and images was overzealously escaped.
|
||||
|
||||
## 1.6.1 (2021-12-16)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix a bug where `MarkdownParser.parse` could return null when the parsed content doesn't fit the schema.
|
||||
|
||||
Make sure underscores are escaped when serializing to Markdown.
|
||||
|
||||
## 1.6.0 (2021-09-21)
|
||||
|
||||
### New features
|
||||
|
||||
`MarkdownParser.tokenizer` is now public, for easier creation of parsers that base on other parsers.
|
||||
|
||||
## 1.5.2 (2021-09-03)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Serializing to Markdown now properly escapes '>' characters at the start of the line.
|
||||
|
||||
## 1.5.1 (2021-01-06)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
The Markdown parser will now correctly set the `tight` attribute on list nodes.
|
||||
|
||||
## 1.5.0 (2020-07-17)
|
||||
|
||||
### New features
|
||||
|
||||
Markdown parse specs can now be specified as `noCloseToken`, which will cause the parser to treat them as a single token, rather than a pair of `_open`/`_close` tokens.
|
||||
|
||||
## 1.4.5 (2020-05-14)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Don't allow hard_break nodes in headings.
|
||||
|
||||
## 1.4.4 (2019-12-19)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix issue that broke parsing ordered lists with a starting number other than 1.
|
||||
|
||||
## 1.4.3 (2019-12-17)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Don't use short-hand angle bracket syntax when outputting self-linking URLs that are relative.
|
||||
|
||||
## 1.4.2 (2019-11-20)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Rename ES module files to use a .js extension, since Webpack gets confused by .mjs
|
||||
|
||||
## 1.4.1 (2019-11-19)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
The file referred to in the package's `module` field now is compiled down to ES5.
|
||||
|
||||
## 1.4.0 (2019-11-08)
|
||||
|
||||
### New features
|
||||
|
||||
Add a `module` field to package json file.
|
||||
|
||||
## 1.3.2 (2019-10-30)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Code blocks in the schema no longer allow marks inside them.
|
||||
|
||||
Code blocks are now parsed with `preserveWhiteSpace: full`, preventing removal of newline characters.
|
||||
|
||||
## 1.3.1 (2019-06-08)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix a bug that could occur when parsing multiple adjacent pieces of text with the same style.
|
||||
|
||||
## 1.3.0 (2019-01-22)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Inline code containing backticks is now serialized wrapped in the appropriate amount of backticks.
|
||||
|
||||
### New features
|
||||
|
||||
The serializer now serializes links whose target is the same as their text content using \< \> syntax.
|
||||
|
||||
Mark opening and close string callbacks now get passed the mark's context (parent fragment and index).
|
||||
|
||||
## 1.2.2 (2018-11-22)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Hard breaks at the end of an emphasized or strong mark are no longer serialized to invalid Markdown text.
|
||||
|
||||
## 1.2.1 (2018-10-19)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fixes a bug where inline mark delimiters were serialized incorrectly (the closing and opening marks were swapped, which was only noticeable when they are different).
|
||||
|
||||
## 1.2.0 (2018-10-08)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fixes an issue where the Markdown serializer would escape special characters in inline code.
|
||||
|
||||
### New features
|
||||
|
||||
Upgrade the markdown-it dependency to version 8.
|
||||
|
||||
## 1.1.1 (2018-07-08)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix bug that caused superfluous backslashes to be inserted at the start of some lines when serializing to Markdown.
|
||||
|
||||
## 1.1.0 (2018-06-20)
|
||||
|
||||
### New features
|
||||
|
||||
You can now override the handling of softbreak tokens in a custom handler.
|
||||
|
||||
## 1.0.4 (2018-04-17)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix crash when serializing marks with line breaks inside of them.
|
||||
|
||||
## 1.0.3 (2018-01-10)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix dependency version range for prosemirror-model.
|
||||
|
||||
## 1.0.2 (2017-12-07)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Code blocks are always wrapped in triple backticks when serializing, to avoid parsing corner cases around indented code blocks.
|
||||
|
||||
## 1.0.1 (2017-11-05)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Link marks are now non-inclusive (typing after them produces non-linked text).
|
||||
|
||||
## 1.0.0 (2017-10-13)
|
||||
|
||||
First stable release.
|
||||
100
node_modules/prosemirror-markdown/CONTRIBUTING.md
generated
vendored
Normal file
100
node_modules/prosemirror-markdown/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
# How to contribute
|
||||
|
||||
- [Getting help](#getting-help)
|
||||
- [Submitting bug reports](#submitting-bug-reports)
|
||||
- [Contributing code](#contributing-code)
|
||||
|
||||
## Getting help
|
||||
|
||||
Community discussion, questions, and informal bug reporting is done on the
|
||||
[discuss.ProseMirror forum](http://discuss.prosemirror.net).
|
||||
|
||||
## Submitting bug reports
|
||||
|
||||
Report bugs on the
|
||||
[GitHub issue tracker](http://github.com/prosemirror/prosemirror/issues).
|
||||
Before reporting a bug, please read these pointers.
|
||||
|
||||
- The issue tracker is for *bugs*, not requests for help. Questions
|
||||
should be asked on the [forum](http://discuss.prosemirror.net).
|
||||
|
||||
- Include information about the version of the code that exhibits the
|
||||
problem. For browser-related issues, include the browser and browser
|
||||
version on which the problem occurred.
|
||||
|
||||
- Mention very precisely what went wrong. "X is broken" is not a good
|
||||
bug report. What did you expect to happen? What happened instead?
|
||||
Describe the exact steps a maintainer has to take to make the
|
||||
problem occur. A screencast can be useful, but is no substitute for
|
||||
a textual description.
|
||||
|
||||
- A great way to make it easy to reproduce your problem, if it can not
|
||||
be trivially reproduced on the website demos, is to submit a script
|
||||
that triggers the issue.
|
||||
|
||||
## Contributing code
|
||||
|
||||
- Make sure you have a [GitHub Account](https://github.com/signup/free)
|
||||
|
||||
- Fork the relevant repository
|
||||
([how to fork a repo](https://help.github.com/articles/fork-a-repo))
|
||||
|
||||
- Create a local checkout of the code. You can use the
|
||||
[main repository](https://github.com/prosemirror/prosemirror) to
|
||||
easily check out all core modules.
|
||||
|
||||
- Make your changes, and commit them
|
||||
|
||||
- Follow the code style of the rest of the project (see below). Run
|
||||
`npm run lint` (in the main repository checkout) to make sure that
|
||||
the linter is happy.
|
||||
|
||||
- If your changes are easy to test or likely to regress, add tests in
|
||||
the relevant `test/` directory. Either put them in an existing
|
||||
`test-*.js` file, if they fit there, or add a new file.
|
||||
|
||||
- Make sure all tests pass. Run `npm run test` to verify tests pass
|
||||
(you will need Node.js v6+).
|
||||
|
||||
- Submit a pull request ([how to create a pull request](https://help.github.com/articles/fork-a-repo)).
|
||||
Don't put more than one feature/fix in a single pull request.
|
||||
|
||||
By contributing code to ProseMirror you
|
||||
|
||||
- Agree to license the contributed code under the project's [MIT
|
||||
license](https://github.com/ProseMirror/prosemirror/blob/master/LICENSE).
|
||||
|
||||
- Confirm that you have the right to contribute and license the code
|
||||
in question. (Either you hold all rights on the code, or the rights
|
||||
holder has explicitly granted the right to use it like this,
|
||||
through a compatible open source license or through a direct
|
||||
agreement with you.)
|
||||
|
||||
### Coding standards
|
||||
|
||||
- ES6 syntax, targeting an ES5 runtime (i.e. don't use library
|
||||
elements added by ES6, don't use ES7/ES.next syntax).
|
||||
|
||||
- 2 spaces per indentation level, no tabs.
|
||||
|
||||
- No semicolons except when necessary.
|
||||
|
||||
- Follow the surrounding code when it comes to spacing, brace
|
||||
placement, etc.
|
||||
|
||||
- Brace-less single-statement bodies are encouraged (whenever they
|
||||
don't impact readability).
|
||||
|
||||
- [getdocs](https://github.com/marijnh/getdocs)-style doc comments
|
||||
above items that are part of the public API.
|
||||
|
||||
- When documenting non-public items, you can put the type after a
|
||||
single colon, so that getdocs doesn't pick it up and add it to the
|
||||
API reference.
|
||||
|
||||
- The linter (`npm run lint`) complains about unused variables and
|
||||
functions. Prefix their names with an underscore to muffle it.
|
||||
|
||||
- ProseMirror does *not* follow JSHint or JSLint prescribed style.
|
||||
Patches that try to 'fix' code to pass one of these linters will not
|
||||
be accepted.
|
||||
19
node_modules/prosemirror-markdown/LICENSE
generated
vendored
Normal file
19
node_modules/prosemirror-markdown/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (C) 2015-2017 by Marijn Haverbeke <marijn@haverbeke.berlin> and others
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
276
node_modules/prosemirror-markdown/README.md
generated
vendored
Normal file
276
node_modules/prosemirror-markdown/README.md
generated
vendored
Normal file
@@ -0,0 +1,276 @@
|
||||
<h1>prosemirror-markdown</h1>
|
||||
<p>[ <a href="http://prosemirror.net"><strong>WEBSITE</strong></a> | <a href="https://github.com/prosemirror/prosemirror-markdown/issues"><strong>ISSUES</strong></a> | <a href="https://discuss.prosemirror.net"><strong>FORUM</strong></a> | <a href="https://gitter.im/ProseMirror/prosemirror"><strong>GITTER</strong></a> ]</p>
|
||||
<p>This is a (non-core) module for <a href="http://prosemirror.net">ProseMirror</a>.
|
||||
ProseMirror is a well-behaved rich semantic content editor based on
|
||||
contentEditable, with support for collaborative editing and custom
|
||||
document schemas.</p>
|
||||
<p>This module implements a ProseMirror
|
||||
<a href="https://prosemirror.net/docs/guide/#schema">schema</a> that corresponds to
|
||||
the document schema used by <a href="http://commonmark.org/">CommonMark</a>, and
|
||||
a parser and serializer to convert between ProseMirror documents in
|
||||
that schema and CommonMark/Markdown text.</p>
|
||||
<p>This code is released under an
|
||||
<a href="https://github.com/prosemirror/prosemirror/tree/master/LICENSE">MIT license</a>.
|
||||
There's a <a href="http://discuss.prosemirror.net">forum</a> for general
|
||||
discussion and support requests, and the
|
||||
<a href="https://github.com/prosemirror/prosemirror/issues">Github bug tracker</a>
|
||||
is the place to report issues.</p>
|
||||
<p>We aim to be an inclusive, welcoming community. To make that explicit,
|
||||
we have a <a href="http://contributor-covenant.org/version/1/1/0/">code of
|
||||
conduct</a> that applies
|
||||
to communication around the project.</p>
|
||||
<h2>Documentation</h2>
|
||||
<dl>
|
||||
<dt id="schema">
|
||||
<code><strong><a href="#schema">schema</a></strong>: <span class="type">Schema</span><<span class="string">"doc"</span> | <span class="string">"paragraph"</span> | <span class="string">"blockquote"</span> | <span class="string">"horizontal_rule"</span> | <span class="string">"heading"</span> | <span class="string">"code_block"</span> | <span class="string">"ordered_list"</span> | <span class="string">"bullet_list"</span> | <span class="string">"list_item"</span> | <span class="string">"text"</span> | <span class="string">"image"</span> | <span class="string">"hard_break"</span>, <span class="string">"em"</span> | <span class="string">"strong"</span> | <span class="string">"link"</span> | <span class="string">"code"</span>></code></dt>
|
||||
|
||||
<dd><p>Document schema for the data model used by CommonMark.</p>
|
||||
</dd>
|
||||
<dt id="MarkdownParser">
|
||||
<h4>
|
||||
<code><span class=keyword>class</span></code>
|
||||
<a href="#MarkdownParser">MarkdownParser</a></h4>
|
||||
</dt>
|
||||
|
||||
<dd><p>A configuration of a Markdown parser. Such a parser uses
|
||||
<a href="https://github.com/markdown-it/markdown-it">markdown-it</a> to
|
||||
tokenize a file, and then runs the custom rules it is given over
|
||||
the tokens to create a ProseMirror document tree.</p>
|
||||
<dl><dt id="MarkdownParser.constructor">
|
||||
<code><span class=keyword>new</span> <strong><a href="#MarkdownParser.constructor">MarkdownParser</a></strong>(<a id="MarkdownParser.constructor^schema" href="#MarkdownParser.constructor^schema"><span class=param>schema</span></a>: <span class="type">Schema</span>, <a id="MarkdownParser.constructor^tokenizer" href="#MarkdownParser.constructor^tokenizer"><span class=param>tokenizer</span></a>: <span class="type">any</span>, <a id="MarkdownParser.constructor^tokens" href="#MarkdownParser.constructor^tokens"><span class=param>tokens</span></a>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object"><span class="type">Object</span></a><<a href="#ParseSpec"><span class="type">ParseSpec</span></a>>)</code></dt>
|
||||
|
||||
<dd><p>Create a parser with the given configuration. You can configure
|
||||
the markdown-it parser to parse the dialect you want, and provide
|
||||
a description of the ProseMirror entities those tokens map to in
|
||||
the <code>tokens</code> object, which maps token names to descriptions of
|
||||
what to do with them. Such a description is an object, and may
|
||||
have the following properties:</p>
|
||||
</dd><dt id="MarkdownParser.schema">
|
||||
<code><strong><a href="#MarkdownParser.schema">schema</a></strong>: <span class="type">Schema</span></code></dt>
|
||||
|
||||
<dd><p>The parser's document schema.</p>
|
||||
</dd><dt id="MarkdownParser.tokenizer">
|
||||
<code><strong><a href="#MarkdownParser.tokenizer">tokenizer</a></strong>: <span class="type">any</span></code></dt>
|
||||
|
||||
<dd><p>This parser's markdown-it tokenizer.</p>
|
||||
</dd><dt id="MarkdownParser.tokens">
|
||||
<code><strong><a href="#MarkdownParser.tokens">tokens</a></strong>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object"><span class="type">Object</span></a><<a href="#ParseSpec"><span class="type">ParseSpec</span></a>></code></dt>
|
||||
|
||||
<dd><p>The value of the <code>tokens</code> object used to construct this
|
||||
parser. Can be useful to copy and modify to base other parsers
|
||||
on.</p>
|
||||
</dd><dt id="MarkdownParser.parse">
|
||||
<code><strong><a href="#MarkdownParser.parse">parse</a></strong>(<a id="MarkdownParser.parse^text" href="#MarkdownParser.parse^text"><span class=param>text</span></a>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"><span class="prim">string</span></a>) → <span class="type">any</span></code></dt>
|
||||
|
||||
<dd><p>Parse a string as <a href="http://commonmark.org/">CommonMark</a> markup,
|
||||
and create a ProseMirror document as prescribed by this parser's
|
||||
rules.</p>
|
||||
</dd></dl>
|
||||
|
||||
</dd>
|
||||
<dt id="ParseSpec">
|
||||
<h4>
|
||||
<code><span class=keyword>interface</span></code>
|
||||
<a href="#ParseSpec">ParseSpec</a></h4>
|
||||
</dt>
|
||||
|
||||
<dd><p>Object type used to specify how Markdown tokens should be parsed.</p>
|
||||
<dl><dt id="ParseSpec.node">
|
||||
<code><strong><a href="#ParseSpec.node">node</a></strong>⁠?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"><span class="prim">string</span></a></code></dt>
|
||||
|
||||
<dd><p>This token maps to a single node, whose type can be looked up
|
||||
in the schema under the given name. Exactly one of <code>node</code>,
|
||||
<code>block</code>, or <code>mark</code> must be set.</p>
|
||||
</dd><dt id="ParseSpec.block">
|
||||
<code><strong><a href="#ParseSpec.block">block</a></strong>⁠?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"><span class="prim">string</span></a></code></dt>
|
||||
|
||||
<dd><p>This token (unless <code>noCloseToken</code> is true) comes in <code>_open</code>
|
||||
and <code>_close</code> variants (which are appended to the base token
|
||||
name provides a the object property), and wraps a block of
|
||||
content. The block should be wrapped in a node of the type
|
||||
named to by the property's value. If the token does not have
|
||||
<code>_open</code> or <code>_close</code>, use the <code>noCloseToken</code> option.</p>
|
||||
</dd><dt id="ParseSpec.mark">
|
||||
<code><strong><a href="#ParseSpec.mark">mark</a></strong>⁠?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"><span class="prim">string</span></a></code></dt>
|
||||
|
||||
<dd><p>This token (again, unless <code>noCloseToken</code> is true) also comes
|
||||
in <code>_open</code> and <code>_close</code> variants, but should add a mark
|
||||
(named by the value) to its content, rather than wrapping it
|
||||
in a node.</p>
|
||||
</dd><dt id="ParseSpec.attrs">
|
||||
<code><strong><a href="#ParseSpec.attrs">attrs</a></strong>⁠?: <span class="type">Attrs</span></code></dt>
|
||||
|
||||
<dd><p>Attributes for the node or mark. When <code>getAttrs</code> is provided,
|
||||
it takes precedence.</p>
|
||||
</dd><dt id="ParseSpec.getAttrs">
|
||||
<code><strong><a href="#ParseSpec.getAttrs">getAttrs</a></strong>⁠?: <span class=fn>fn</span>(<a id="ParseSpec.getAttrs^token" href="#ParseSpec.getAttrs^token"><span class=param>token</span></a>: <span class="type">any</span>, <a id="ParseSpec.getAttrs^tokenStream" href="#ParseSpec.getAttrs^tokenStream"><span class=param>tokenStream</span></a>: <span class="type">any</span>[], <a id="ParseSpec.getAttrs^index" href="#ParseSpec.getAttrs^index"><span class=param>index</span></a>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number"><span class="prim">number</span></a>) → <span class="type">Attrs</span></code></dt>
|
||||
|
||||
<dd><p>A function used to compute the attributes for the node or mark
|
||||
that takes a <a href="https://markdown-it.github.io/markdown-it/#Token">markdown-it
|
||||
token</a> and
|
||||
returns an attribute object.</p>
|
||||
</dd><dt id="ParseSpec.noCloseToken">
|
||||
<code><strong><a href="#ParseSpec.noCloseToken">noCloseToken</a></strong>⁠?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean"><span class="prim">boolean</span></a></code></dt>
|
||||
|
||||
<dd><p>Indicates that the <a href="https://markdown-it.github.io/markdown-it/#Token">markdown-it
|
||||
token</a> has
|
||||
no <code>_open</code> or <code>_close</code> for the nodes. This defaults to <code>true</code>
|
||||
for <code>code_inline</code>, <code>code_block</code> and <code>fence</code>.</p>
|
||||
</dd><dt id="ParseSpec.ignore">
|
||||
<code><strong><a href="#ParseSpec.ignore">ignore</a></strong>⁠?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean"><span class="prim">boolean</span></a></code></dt>
|
||||
|
||||
<dd><p>When true, ignore content for the matched token.</p>
|
||||
</dd></dl>
|
||||
|
||||
</dd>
|
||||
<dt id="defaultMarkdownParser">
|
||||
<code><strong><a href="#defaultMarkdownParser">defaultMarkdownParser</a></strong>: <a href="#MarkdownParser"><span class="type">MarkdownParser</span></a></code></dt>
|
||||
|
||||
<dd><p>A parser parsing unextended <a href="http://commonmark.org/">CommonMark</a>,
|
||||
without inline HTML, and producing a document in the basic schema.</p>
|
||||
</dd>
|
||||
<dt id="MarkdownSerializer">
|
||||
<h4>
|
||||
<code><span class=keyword>class</span></code>
|
||||
<a href="#MarkdownSerializer">MarkdownSerializer</a></h4>
|
||||
</dt>
|
||||
|
||||
<dd><p>A specification for serializing a ProseMirror document as
|
||||
Markdown/CommonMark text.</p>
|
||||
<dl><dt id="MarkdownSerializer.constructor">
|
||||
<code><span class=keyword>new</span> <strong><a href="#MarkdownSerializer.constructor">MarkdownSerializer</a></strong>(<a id="MarkdownSerializer.constructor^nodes" href="#MarkdownSerializer.constructor^nodes"><span class=param>nodes</span></a>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object"><span class="type">Object</span></a><<span class=fn>fn</span>(<a id="MarkdownSerializer.constructor^nodes^state" href="#MarkdownSerializer.constructor^nodes^state"><span class=param>state</span></a>: <a href="#MarkdownSerializerState"><span class="type">MarkdownSerializerState</span></a>, <a id="MarkdownSerializer.constructor^nodes^node" href="#MarkdownSerializer.constructor^nodes^node"><span class=param>node</span></a>: <span class="type">Node</span>, <a id="MarkdownSerializer.constructor^nodes^parent" href="#MarkdownSerializer.constructor^nodes^parent"><span class=param>parent</span></a>: <span class="type">Node</span>, <a id="MarkdownSerializer.constructor^nodes^index" href="#MarkdownSerializer.constructor^nodes^index"><span class=param>index</span></a>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number"><span class="prim">number</span></a>)>, <a id="MarkdownSerializer.constructor^marks" href="#MarkdownSerializer.constructor^marks"><span class=param>marks</span></a>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object"><span class="type">Object</span></a><<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object"><span class="type">Object</span></a>>, <a id="MarkdownSerializer.constructor^options" href="#MarkdownSerializer.constructor^options"><span class=param>options</span></a>⁠?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object"><span class="type">Object</span></a><span class=defaultvalue> = {}</span>)</code></dt>
|
||||
|
||||
<dd><p>Construct a serializer with the given configuration. The <code>nodes</code>
|
||||
object should map node names in a given schema to function that
|
||||
take a serializer state and such a node, and serialize the node.</p>
|
||||
<dl><dt id="MarkdownSerializer.constructor^options">
|
||||
<code><strong><a href="#MarkdownSerializer.constructor^options">options</a></strong></code></dt>
|
||||
|
||||
<dd><dl><dt id="MarkdownSerializer.constructor^options.escapeExtraCharacters">
|
||||
<code><strong><a href="#MarkdownSerializer.constructor^options.escapeExtraCharacters">escapeExtraCharacters</a></strong>⁠?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp"><span class="type">RegExp</span></a></code></dt>
|
||||
|
||||
<dd><p>Extra characters can be added for escaping. This is passed
|
||||
directly to String.replace(), and the matching characters are
|
||||
preceded by a backslash.</p>
|
||||
</dd></dl></dd></dl></dd><dt id="MarkdownSerializer.nodes">
|
||||
<code><strong><a href="#MarkdownSerializer.nodes">nodes</a></strong>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object"><span class="type">Object</span></a><<span class=fn>fn</span>(<a id="MarkdownSerializer.nodes^state" href="#MarkdownSerializer.nodes^state"><span class=param>state</span></a>: <a href="#MarkdownSerializerState"><span class="type">MarkdownSerializerState</span></a>, <a id="MarkdownSerializer.nodes^node" href="#MarkdownSerializer.nodes^node"><span class=param>node</span></a>: <span class="type">Node</span>, <a id="MarkdownSerializer.nodes^parent" href="#MarkdownSerializer.nodes^parent"><span class=param>parent</span></a>: <span class="type">Node</span>, <a id="MarkdownSerializer.nodes^index" href="#MarkdownSerializer.nodes^index"><span class=param>index</span></a>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number"><span class="prim">number</span></a>)></code></dt>
|
||||
|
||||
<dd><p>The node serializer functions for this serializer.</p>
|
||||
</dd><dt id="MarkdownSerializer.marks">
|
||||
<code><strong><a href="#MarkdownSerializer.marks">marks</a></strong>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object"><span class="type">Object</span></a><<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object"><span class="type">Object</span></a>></code></dt>
|
||||
|
||||
<dd><p>The mark serializer info.</p>
|
||||
</dd><dt id="MarkdownSerializer.options">
|
||||
<code><strong><a href="#MarkdownSerializer.options">options</a></strong>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object"><span class="type">Object</span></a></code></dt>
|
||||
|
||||
<dd><dl><dt id="MarkdownSerializer.options.escapeExtraCharacters">
|
||||
<code><strong><a href="#MarkdownSerializer.options.escapeExtraCharacters">escapeExtraCharacters</a></strong>⁠?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp"><span class="type">RegExp</span></a></code></dt>
|
||||
|
||||
<dd><p>Extra characters can be added for escaping. This is passed
|
||||
directly to String.replace(), and the matching characters are
|
||||
preceded by a backslash.</p>
|
||||
</dd></dl></dd><dt id="MarkdownSerializer.serialize">
|
||||
<code><strong><a href="#MarkdownSerializer.serialize">serialize</a></strong>(<a id="MarkdownSerializer.serialize^content" href="#MarkdownSerializer.serialize^content"><span class=param>content</span></a>: <span class="type">Node</span>, <a id="MarkdownSerializer.serialize^options" href="#MarkdownSerializer.serialize^options"><span class=param>options</span></a>⁠?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object"><span class="type">Object</span></a><span class=defaultvalue> = {}</span>) → <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"><span class="prim">string</span></a></code></dt>
|
||||
|
||||
<dd><p>Serialize the content of the given node to
|
||||
<a href="http://commonmark.org/">CommonMark</a>.</p>
|
||||
<dl><dt id="MarkdownSerializer.serialize^options">
|
||||
<code><strong><a href="#MarkdownSerializer.serialize^options">options</a></strong></code></dt>
|
||||
|
||||
<dd><dl><dt id="MarkdownSerializer.serialize^options.tightLists">
|
||||
<code><strong><a href="#MarkdownSerializer.serialize^options.tightLists">tightLists</a></strong>⁠?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean"><span class="prim">boolean</span></a></code></dt>
|
||||
|
||||
<dd><p>Whether to render lists in a tight style. This can be overridden
|
||||
on a node level by specifying a tight attribute on the node.
|
||||
Defaults to false.</p>
|
||||
</dd></dl></dd></dl></dd></dl>
|
||||
|
||||
</dd>
|
||||
<dt id="MarkdownSerializerState">
|
||||
<h4>
|
||||
<code><span class=keyword>class</span></code>
|
||||
<a href="#MarkdownSerializerState">MarkdownSerializerState</a></h4>
|
||||
</dt>
|
||||
|
||||
<dd><p>This is an object used to track state and expose
|
||||
methods related to markdown serialization. Instances are passed to
|
||||
node and mark serialization methods (see <code>toMarkdown</code>).</p>
|
||||
<dl><dt id="MarkdownSerializerState.options">
|
||||
<code><strong><a href="#MarkdownSerializerState.options">options</a></strong>: {<span class=prop>tightLists</span>⁠?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean"><span class="prim">boolean</span></a>, <span class=prop>escapeExtraCharacters</span>⁠?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp"><span class="type">RegExp</span></a>}</code></dt>
|
||||
|
||||
<dd><p>The options passed to the serializer.</p>
|
||||
</dd><dt id="MarkdownSerializerState.wrapBlock">
|
||||
<code><strong><a href="#MarkdownSerializerState.wrapBlock">wrapBlock</a></strong>(<a id="MarkdownSerializerState.wrapBlock^delim" href="#MarkdownSerializerState.wrapBlock^delim"><span class=param>delim</span></a>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"><span class="prim">string</span></a>, <a id="MarkdownSerializerState.wrapBlock^firstDelim" href="#MarkdownSerializerState.wrapBlock^firstDelim"><span class=param>firstDelim</span></a>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"><span class="prim">string</span></a>, <a id="MarkdownSerializerState.wrapBlock^node" href="#MarkdownSerializerState.wrapBlock^node"><span class=param>node</span></a>: <span class="type">Node</span>, <a id="MarkdownSerializerState.wrapBlock^f" href="#MarkdownSerializerState.wrapBlock^f"><span class=param>f</span></a>: <span class=fn>fn</span>())</code></dt>
|
||||
|
||||
<dd><p>Render a block, prefixing each line with <code>delim</code>, and the first
|
||||
line in <code>firstDelim</code>. <code>node</code> should be the node that is closed at
|
||||
the end of the block, and <code>f</code> is a function that renders the
|
||||
content of the block.</p>
|
||||
</dd><dt id="MarkdownSerializerState.ensureNewLine">
|
||||
<code><strong><a href="#MarkdownSerializerState.ensureNewLine">ensureNewLine</a></strong>()</code></dt>
|
||||
|
||||
<dd><p>Ensure the current content ends with a newline.</p>
|
||||
</dd><dt id="MarkdownSerializerState.write">
|
||||
<code><strong><a href="#MarkdownSerializerState.write">write</a></strong>(<a id="MarkdownSerializerState.write^content" href="#MarkdownSerializerState.write^content"><span class=param>content</span></a>⁠?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"><span class="prim">string</span></a>)</code></dt>
|
||||
|
||||
<dd><p>Prepare the state for writing output (closing closed paragraphs,
|
||||
adding delimiters, and so on), and then optionally add content
|
||||
(unescaped) to the output.</p>
|
||||
</dd><dt id="MarkdownSerializerState.closeBlock">
|
||||
<code><strong><a href="#MarkdownSerializerState.closeBlock">closeBlock</a></strong>(<a id="MarkdownSerializerState.closeBlock^node" href="#MarkdownSerializerState.closeBlock^node"><span class=param>node</span></a>: <span class="type">Node</span>)</code></dt>
|
||||
|
||||
<dd><p>Close the block for the given node.</p>
|
||||
</dd><dt id="MarkdownSerializerState.text">
|
||||
<code><strong><a href="#MarkdownSerializerState.text">text</a></strong>(<a id="MarkdownSerializerState.text^text" href="#MarkdownSerializerState.text^text"><span class=param>text</span></a>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"><span class="prim">string</span></a>, <a id="MarkdownSerializerState.text^escape" href="#MarkdownSerializerState.text^escape"><span class=param>escape</span></a>⁠?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean"><span class="prim">boolean</span></a><span class=defaultvalue> = true</span>)</code></dt>
|
||||
|
||||
<dd><p>Add the given text to the document. When escape is not <code>false</code>,
|
||||
it will be escaped.</p>
|
||||
</dd><dt id="MarkdownSerializerState.render">
|
||||
<code><strong><a href="#MarkdownSerializerState.render">render</a></strong>(<a id="MarkdownSerializerState.render^node" href="#MarkdownSerializerState.render^node"><span class=param>node</span></a>: <span class="type">Node</span>, <a id="MarkdownSerializerState.render^parent" href="#MarkdownSerializerState.render^parent"><span class=param>parent</span></a>: <span class="type">Node</span>, <a id="MarkdownSerializerState.render^index" href="#MarkdownSerializerState.render^index"><span class=param>index</span></a>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number"><span class="prim">number</span></a>)</code></dt>
|
||||
|
||||
<dd><p>Render the given node as a block.</p>
|
||||
</dd><dt id="MarkdownSerializerState.renderContent">
|
||||
<code><strong><a href="#MarkdownSerializerState.renderContent">renderContent</a></strong>(<a id="MarkdownSerializerState.renderContent^parent" href="#MarkdownSerializerState.renderContent^parent"><span class=param>parent</span></a>: <span class="type">Node</span>)</code></dt>
|
||||
|
||||
<dd><p>Render the contents of <code>parent</code> as block nodes.</p>
|
||||
</dd><dt id="MarkdownSerializerState.renderInline">
|
||||
<code><strong><a href="#MarkdownSerializerState.renderInline">renderInline</a></strong>(<a id="MarkdownSerializerState.renderInline^parent" href="#MarkdownSerializerState.renderInline^parent"><span class=param>parent</span></a>: <span class="type">Node</span>)</code></dt>
|
||||
|
||||
<dd><p>Render the contents of <code>parent</code> as inline content.</p>
|
||||
</dd><dt id="MarkdownSerializerState.renderList">
|
||||
<code><strong><a href="#MarkdownSerializerState.renderList">renderList</a></strong>(<a id="MarkdownSerializerState.renderList^node" href="#MarkdownSerializerState.renderList^node"><span class=param>node</span></a>: <span class="type">Node</span>, <a id="MarkdownSerializerState.renderList^delim" href="#MarkdownSerializerState.renderList^delim"><span class=param>delim</span></a>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"><span class="prim">string</span></a>, <a id="MarkdownSerializerState.renderList^firstDelim" href="#MarkdownSerializerState.renderList^firstDelim"><span class=param>firstDelim</span></a>: <span class=fn>fn</span>(<a id="MarkdownSerializerState.renderList^firstDelim^index" href="#MarkdownSerializerState.renderList^firstDelim^index"><span class=param>index</span></a>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number"><span class="prim">number</span></a>) → <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"><span class="prim">string</span></a>)</code></dt>
|
||||
|
||||
<dd><p>Render a node's content as a list. <code>delim</code> should be the extra
|
||||
indentation added to all lines except the first in an item,
|
||||
<code>firstDelim</code> is a function going from an item index to a
|
||||
delimiter for the first line of the item.</p>
|
||||
</dd><dt id="MarkdownSerializerState.esc">
|
||||
<code><strong><a href="#MarkdownSerializerState.esc">esc</a></strong>(<a id="MarkdownSerializerState.esc^str" href="#MarkdownSerializerState.esc^str"><span class=param>str</span></a>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"><span class="prim">string</span></a>, <a id="MarkdownSerializerState.esc^startOfLine" href="#MarkdownSerializerState.esc^startOfLine"><span class=param>startOfLine</span></a>⁠?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean"><span class="prim">boolean</span></a><span class=defaultvalue> = false</span>) → <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"><span class="prim">string</span></a></code></dt>
|
||||
|
||||
<dd><p>Escape the given string so that it can safely appear in Markdown
|
||||
content. If <code>startOfLine</code> is true, also escape characters that
|
||||
have special meaning only at the start of the line.</p>
|
||||
</dd><dt id="MarkdownSerializerState.repeat">
|
||||
<code><strong><a href="#MarkdownSerializerState.repeat">repeat</a></strong>(<a id="MarkdownSerializerState.repeat^str" href="#MarkdownSerializerState.repeat^str"><span class=param>str</span></a>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"><span class="prim">string</span></a>, <a id="MarkdownSerializerState.repeat^n" href="#MarkdownSerializerState.repeat^n"><span class=param>n</span></a>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number"><span class="prim">number</span></a>) → <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"><span class="prim">string</span></a></code></dt>
|
||||
|
||||
<dd><p>Repeat the given string <code>n</code> times.</p>
|
||||
</dd><dt id="MarkdownSerializerState.markString">
|
||||
<code><strong><a href="#MarkdownSerializerState.markString">markString</a></strong>(<a id="MarkdownSerializerState.markString^mark" href="#MarkdownSerializerState.markString^mark"><span class=param>mark</span></a>: <span class="type">Mark</span>, <a id="MarkdownSerializerState.markString^open" href="#MarkdownSerializerState.markString^open"><span class=param>open</span></a>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean"><span class="prim">boolean</span></a>, <a id="MarkdownSerializerState.markString^parent" href="#MarkdownSerializerState.markString^parent"><span class=param>parent</span></a>: <span class="type">Node</span>, <a id="MarkdownSerializerState.markString^index" href="#MarkdownSerializerState.markString^index"><span class=param>index</span></a>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number"><span class="prim">number</span></a>) → <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"><span class="prim">string</span></a></code></dt>
|
||||
|
||||
<dd><p>Get the markdown string for a given opening or closing mark.</p>
|
||||
</dd><dt id="MarkdownSerializerState.getEnclosingWhitespace">
|
||||
<code><strong><a href="#MarkdownSerializerState.getEnclosingWhitespace">getEnclosingWhitespace</a></strong>(<a id="MarkdownSerializerState.getEnclosingWhitespace^text" href="#MarkdownSerializerState.getEnclosingWhitespace^text"><span class=param>text</span></a>: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"><span class="prim">string</span></a>) → {<span class=prop>leading</span>⁠?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"><span class="prim">string</span></a>, <span class=prop>trailing</span>⁠?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"><span class="prim">string</span></a>}</code></dt>
|
||||
|
||||
<dd><p>Get leading and trailing whitespace from a string. Values of
|
||||
leading or trailing property of the return object will be undefined
|
||||
if there is no match.</p>
|
||||
</dd></dl>
|
||||
|
||||
</dd>
|
||||
<dt id="defaultMarkdownSerializer">
|
||||
<code><strong><a href="#defaultMarkdownSerializer">defaultMarkdownSerializer</a></strong>: <a href="#MarkdownSerializer"><span class="type">MarkdownSerializer</span></a></code></dt>
|
||||
|
||||
<dd><p>A serializer for the <a href="#schema">basic schema</a>.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
966
node_modules/prosemirror-markdown/dist/index.cjs
generated
vendored
Normal file
966
node_modules/prosemirror-markdown/dist/index.cjs
generated
vendored
Normal file
@@ -0,0 +1,966 @@
|
||||
'use strict';
|
||||
|
||||
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
||||
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
||||
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
||||
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
||||
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
||||
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
||||
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
|
||||
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
||||
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
|
||||
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
|
||||
var prosemirrorModel = require('prosemirror-model');
|
||||
var MarkdownIt = require('markdown-it');
|
||||
var schema = new prosemirrorModel.Schema({
|
||||
nodes: {
|
||||
doc: {
|
||||
content: "block+"
|
||||
},
|
||||
paragraph: {
|
||||
content: "inline*",
|
||||
group: "block",
|
||||
parseDOM: [{
|
||||
tag: "p"
|
||||
}],
|
||||
toDOM: function toDOM() {
|
||||
return ["p", 0];
|
||||
}
|
||||
},
|
||||
blockquote: {
|
||||
content: "block+",
|
||||
group: "block",
|
||||
parseDOM: [{
|
||||
tag: "blockquote"
|
||||
}],
|
||||
toDOM: function toDOM() {
|
||||
return ["blockquote", 0];
|
||||
}
|
||||
},
|
||||
horizontal_rule: {
|
||||
group: "block",
|
||||
parseDOM: [{
|
||||
tag: "hr"
|
||||
}],
|
||||
toDOM: function toDOM() {
|
||||
return ["div", ["hr"]];
|
||||
}
|
||||
},
|
||||
heading: {
|
||||
attrs: {
|
||||
level: {
|
||||
"default": 1
|
||||
}
|
||||
},
|
||||
content: "(text | image)*",
|
||||
group: "block",
|
||||
defining: true,
|
||||
parseDOM: [{
|
||||
tag: "h1",
|
||||
attrs: {
|
||||
level: 1
|
||||
}
|
||||
}, {
|
||||
tag: "h2",
|
||||
attrs: {
|
||||
level: 2
|
||||
}
|
||||
}, {
|
||||
tag: "h3",
|
||||
attrs: {
|
||||
level: 3
|
||||
}
|
||||
}, {
|
||||
tag: "h4",
|
||||
attrs: {
|
||||
level: 4
|
||||
}
|
||||
}, {
|
||||
tag: "h5",
|
||||
attrs: {
|
||||
level: 5
|
||||
}
|
||||
}, {
|
||||
tag: "h6",
|
||||
attrs: {
|
||||
level: 6
|
||||
}
|
||||
}],
|
||||
toDOM: function toDOM(node) {
|
||||
return ["h" + node.attrs.level, 0];
|
||||
}
|
||||
},
|
||||
code_block: {
|
||||
content: "text*",
|
||||
group: "block",
|
||||
code: true,
|
||||
defining: true,
|
||||
marks: "",
|
||||
attrs: {
|
||||
params: {
|
||||
"default": ""
|
||||
}
|
||||
},
|
||||
parseDOM: [{
|
||||
tag: "pre",
|
||||
preserveWhitespace: "full",
|
||||
getAttrs: function getAttrs(node) {
|
||||
return {
|
||||
params: node.getAttribute("data-params") || ""
|
||||
};
|
||||
}
|
||||
}],
|
||||
toDOM: function toDOM(node) {
|
||||
return ["pre", node.attrs.params ? {
|
||||
"data-params": node.attrs.params
|
||||
} : {}, ["code", 0]];
|
||||
}
|
||||
},
|
||||
ordered_list: {
|
||||
content: "list_item+",
|
||||
group: "block",
|
||||
attrs: {
|
||||
order: {
|
||||
"default": 1
|
||||
},
|
||||
tight: {
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
parseDOM: [{
|
||||
tag: "ol",
|
||||
getAttrs: function getAttrs(dom) {
|
||||
return {
|
||||
order: dom.hasAttribute("start") ? +dom.getAttribute("start") : 1,
|
||||
tight: dom.hasAttribute("data-tight")
|
||||
};
|
||||
}
|
||||
}],
|
||||
toDOM: function toDOM(node) {
|
||||
return ["ol", {
|
||||
start: node.attrs.order == 1 ? null : node.attrs.order,
|
||||
"data-tight": node.attrs.tight ? "true" : null
|
||||
}, 0];
|
||||
}
|
||||
},
|
||||
bullet_list: {
|
||||
content: "list_item+",
|
||||
group: "block",
|
||||
attrs: {
|
||||
tight: {
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
parseDOM: [{
|
||||
tag: "ul",
|
||||
getAttrs: function getAttrs(dom) {
|
||||
return {
|
||||
tight: dom.hasAttribute("data-tight")
|
||||
};
|
||||
}
|
||||
}],
|
||||
toDOM: function toDOM(node) {
|
||||
return ["ul", {
|
||||
"data-tight": node.attrs.tight ? "true" : null
|
||||
}, 0];
|
||||
}
|
||||
},
|
||||
list_item: {
|
||||
content: "block+",
|
||||
defining: true,
|
||||
parseDOM: [{
|
||||
tag: "li"
|
||||
}],
|
||||
toDOM: function toDOM() {
|
||||
return ["li", 0];
|
||||
}
|
||||
},
|
||||
text: {
|
||||
group: "inline"
|
||||
},
|
||||
image: {
|
||||
inline: true,
|
||||
attrs: {
|
||||
src: {},
|
||||
alt: {
|
||||
"default": null
|
||||
},
|
||||
title: {
|
||||
"default": null
|
||||
}
|
||||
},
|
||||
group: "inline",
|
||||
draggable: true,
|
||||
parseDOM: [{
|
||||
tag: "img[src]",
|
||||
getAttrs: function getAttrs(dom) {
|
||||
return {
|
||||
src: dom.getAttribute("src"),
|
||||
title: dom.getAttribute("title"),
|
||||
alt: dom.getAttribute("alt")
|
||||
};
|
||||
}
|
||||
}],
|
||||
toDOM: function toDOM(node) {
|
||||
return ["img", node.attrs];
|
||||
}
|
||||
},
|
||||
hard_break: {
|
||||
inline: true,
|
||||
group: "inline",
|
||||
selectable: false,
|
||||
parseDOM: [{
|
||||
tag: "br"
|
||||
}],
|
||||
toDOM: function toDOM() {
|
||||
return ["br"];
|
||||
}
|
||||
}
|
||||
},
|
||||
marks: {
|
||||
em: {
|
||||
parseDOM: [{
|
||||
tag: "i"
|
||||
}, {
|
||||
tag: "em"
|
||||
}, {
|
||||
style: "font-style=italic"
|
||||
}, {
|
||||
style: "font-style=normal",
|
||||
clearMark: function clearMark(m) {
|
||||
return m.type.name == "em";
|
||||
}
|
||||
}],
|
||||
toDOM: function toDOM() {
|
||||
return ["em"];
|
||||
}
|
||||
},
|
||||
strong: {
|
||||
parseDOM: [{
|
||||
tag: "strong"
|
||||
}, {
|
||||
tag: "b",
|
||||
getAttrs: function getAttrs(node) {
|
||||
return node.style.fontWeight != "normal" && null;
|
||||
}
|
||||
}, {
|
||||
style: "font-weight=400",
|
||||
clearMark: function clearMark(m) {
|
||||
return m.type.name == "strong";
|
||||
}
|
||||
}, {
|
||||
style: "font-weight",
|
||||
getAttrs: function getAttrs(value) {
|
||||
return /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null;
|
||||
}
|
||||
}],
|
||||
toDOM: function toDOM() {
|
||||
return ["strong"];
|
||||
}
|
||||
},
|
||||
link: {
|
||||
attrs: {
|
||||
href: {},
|
||||
title: {
|
||||
"default": null
|
||||
}
|
||||
},
|
||||
inclusive: false,
|
||||
parseDOM: [{
|
||||
tag: "a[href]",
|
||||
getAttrs: function getAttrs(dom) {
|
||||
return {
|
||||
href: dom.getAttribute("href"),
|
||||
title: dom.getAttribute("title")
|
||||
};
|
||||
}
|
||||
}],
|
||||
toDOM: function toDOM(node) {
|
||||
return ["a", node.attrs];
|
||||
}
|
||||
},
|
||||
code: {
|
||||
code: true,
|
||||
parseDOM: [{
|
||||
tag: "code"
|
||||
}],
|
||||
toDOM: function toDOM() {
|
||||
return ["code"];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
function maybeMerge(a, b) {
|
||||
if (a.isText && b.isText && prosemirrorModel.Mark.sameSet(a.marks, b.marks)) return a.withText(a.text + b.text);
|
||||
}
|
||||
var MarkdownParseState = function () {
|
||||
function MarkdownParseState(schema, tokenHandlers) {
|
||||
_classCallCheck(this, MarkdownParseState);
|
||||
this.schema = schema;
|
||||
this.tokenHandlers = tokenHandlers;
|
||||
this.stack = [{
|
||||
type: schema.topNodeType,
|
||||
attrs: null,
|
||||
content: [],
|
||||
marks: prosemirrorModel.Mark.none
|
||||
}];
|
||||
}
|
||||
_createClass(MarkdownParseState, [{
|
||||
key: "top",
|
||||
value: function top() {
|
||||
return this.stack[this.stack.length - 1];
|
||||
}
|
||||
}, {
|
||||
key: "push",
|
||||
value: function push(elt) {
|
||||
if (this.stack.length) this.top().content.push(elt);
|
||||
}
|
||||
}, {
|
||||
key: "addText",
|
||||
value: function addText(text) {
|
||||
if (!text) return;
|
||||
var top = this.top(),
|
||||
nodes = top.content,
|
||||
last = nodes[nodes.length - 1];
|
||||
var node = this.schema.text(text, top.marks),
|
||||
merged;
|
||||
if (last && (merged = maybeMerge(last, node))) nodes[nodes.length - 1] = merged;else nodes.push(node);
|
||||
}
|
||||
}, {
|
||||
key: "openMark",
|
||||
value: function openMark(mark) {
|
||||
var top = this.top();
|
||||
top.marks = mark.addToSet(top.marks);
|
||||
}
|
||||
}, {
|
||||
key: "closeMark",
|
||||
value: function closeMark(mark) {
|
||||
var top = this.top();
|
||||
top.marks = mark.removeFromSet(top.marks);
|
||||
}
|
||||
}, {
|
||||
key: "parseTokens",
|
||||
value: function parseTokens(toks) {
|
||||
for (var i = 0; i < toks.length; i++) {
|
||||
var tok = toks[i];
|
||||
var handler = this.tokenHandlers[tok.type];
|
||||
if (!handler) throw new Error("Token type `" + tok.type + "` not supported by Markdown parser");
|
||||
handler(this, tok, toks, i);
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: "addNode",
|
||||
value: function addNode(type, attrs, content) {
|
||||
var top = this.top();
|
||||
var node = type.createAndFill(attrs, content, top ? top.marks : []);
|
||||
if (!node) return null;
|
||||
this.push(node);
|
||||
return node;
|
||||
}
|
||||
}, {
|
||||
key: "openNode",
|
||||
value: function openNode(type, attrs) {
|
||||
this.stack.push({
|
||||
type: type,
|
||||
attrs: attrs,
|
||||
content: [],
|
||||
marks: prosemirrorModel.Mark.none
|
||||
});
|
||||
}
|
||||
}, {
|
||||
key: "closeNode",
|
||||
value: function closeNode() {
|
||||
var info = this.stack.pop();
|
||||
return this.addNode(info.type, info.attrs, info.content);
|
||||
}
|
||||
}]);
|
||||
return MarkdownParseState;
|
||||
}();
|
||||
function attrs(spec, token, tokens, i) {
|
||||
if (spec.getAttrs) return spec.getAttrs(token, tokens, i);else if (spec.attrs instanceof Function) return spec.attrs(token);else return spec.attrs;
|
||||
}
|
||||
function noCloseToken(spec, type) {
|
||||
return spec.noCloseToken || type == "code_inline" || type == "code_block" || type == "fence";
|
||||
}
|
||||
function withoutTrailingNewline(str) {
|
||||
return str[str.length - 1] == "\n" ? str.slice(0, str.length - 1) : str;
|
||||
}
|
||||
function noOp() {}
|
||||
function tokenHandlers(schema, tokens) {
|
||||
var handlers = Object.create(null);
|
||||
var _loop = function _loop() {
|
||||
var spec = tokens[type];
|
||||
if (spec.block) {
|
||||
var nodeType = schema.nodeType(spec.block);
|
||||
if (noCloseToken(spec, type)) {
|
||||
handlers[type] = function (state, tok, tokens, i) {
|
||||
state.openNode(nodeType, attrs(spec, tok, tokens, i));
|
||||
state.addText(withoutTrailingNewline(tok.content));
|
||||
state.closeNode();
|
||||
};
|
||||
} else {
|
||||
handlers[type + "_open"] = function (state, tok, tokens, i) {
|
||||
return state.openNode(nodeType, attrs(spec, tok, tokens, i));
|
||||
};
|
||||
handlers[type + "_close"] = function (state) {
|
||||
return state.closeNode();
|
||||
};
|
||||
}
|
||||
} else if (spec.node) {
|
||||
var _nodeType = schema.nodeType(spec.node);
|
||||
handlers[type] = function (state, tok, tokens, i) {
|
||||
return state.addNode(_nodeType, attrs(spec, tok, tokens, i));
|
||||
};
|
||||
} else if (spec.mark) {
|
||||
var markType = schema.marks[spec.mark];
|
||||
if (noCloseToken(spec, type)) {
|
||||
handlers[type] = function (state, tok, tokens, i) {
|
||||
state.openMark(markType.create(attrs(spec, tok, tokens, i)));
|
||||
state.addText(withoutTrailingNewline(tok.content));
|
||||
state.closeMark(markType);
|
||||
};
|
||||
} else {
|
||||
handlers[type + "_open"] = function (state, tok, tokens, i) {
|
||||
return state.openMark(markType.create(attrs(spec, tok, tokens, i)));
|
||||
};
|
||||
handlers[type + "_close"] = function (state) {
|
||||
return state.closeMark(markType);
|
||||
};
|
||||
}
|
||||
} else if (spec.ignore) {
|
||||
if (noCloseToken(spec, type)) {
|
||||
handlers[type] = noOp;
|
||||
} else {
|
||||
handlers[type + "_open"] = noOp;
|
||||
handlers[type + "_close"] = noOp;
|
||||
}
|
||||
} else {
|
||||
throw new RangeError("Unrecognized parsing spec " + JSON.stringify(spec));
|
||||
}
|
||||
};
|
||||
for (var type in tokens) {
|
||||
_loop();
|
||||
}
|
||||
handlers.text = function (state, tok) {
|
||||
return state.addText(tok.content);
|
||||
};
|
||||
handlers.inline = function (state, tok) {
|
||||
return state.parseTokens(tok.children);
|
||||
};
|
||||
handlers.softbreak = handlers.softbreak || function (state) {
|
||||
return state.addText(" ");
|
||||
};
|
||||
return handlers;
|
||||
}
|
||||
var MarkdownParser = function () {
|
||||
function MarkdownParser(schema, tokenizer, tokens) {
|
||||
_classCallCheck(this, MarkdownParser);
|
||||
this.schema = schema;
|
||||
this.tokenizer = tokenizer;
|
||||
this.tokens = tokens;
|
||||
this.tokenHandlers = tokenHandlers(schema, tokens);
|
||||
}
|
||||
_createClass(MarkdownParser, [{
|
||||
key: "parse",
|
||||
value: function parse(text) {
|
||||
var markdownEnv = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
||||
var state = new MarkdownParseState(this.schema, this.tokenHandlers),
|
||||
doc;
|
||||
state.parseTokens(this.tokenizer.parse(text, markdownEnv));
|
||||
do {
|
||||
doc = state.closeNode();
|
||||
} while (state.stack.length);
|
||||
return doc || this.schema.topNodeType.createAndFill();
|
||||
}
|
||||
}]);
|
||||
return MarkdownParser;
|
||||
}();
|
||||
function listIsTight(tokens, i) {
|
||||
while (++i < tokens.length) if (tokens[i].type != "list_item_open") return tokens[i].hidden;
|
||||
return false;
|
||||
}
|
||||
var defaultMarkdownParser = new MarkdownParser(schema, MarkdownIt("commonmark", {
|
||||
html: false
|
||||
}), {
|
||||
blockquote: {
|
||||
block: "blockquote"
|
||||
},
|
||||
paragraph: {
|
||||
block: "paragraph"
|
||||
},
|
||||
list_item: {
|
||||
block: "list_item"
|
||||
},
|
||||
bullet_list: {
|
||||
block: "bullet_list",
|
||||
getAttrs: function getAttrs(_, tokens, i) {
|
||||
return {
|
||||
tight: listIsTight(tokens, i)
|
||||
};
|
||||
}
|
||||
},
|
||||
ordered_list: {
|
||||
block: "ordered_list",
|
||||
getAttrs: function getAttrs(tok, tokens, i) {
|
||||
return {
|
||||
order: +tok.attrGet("start") || 1,
|
||||
tight: listIsTight(tokens, i)
|
||||
};
|
||||
}
|
||||
},
|
||||
heading: {
|
||||
block: "heading",
|
||||
getAttrs: function getAttrs(tok) {
|
||||
return {
|
||||
level: +tok.tag.slice(1)
|
||||
};
|
||||
}
|
||||
},
|
||||
code_block: {
|
||||
block: "code_block",
|
||||
noCloseToken: true
|
||||
},
|
||||
fence: {
|
||||
block: "code_block",
|
||||
getAttrs: function getAttrs(tok) {
|
||||
return {
|
||||
params: tok.info || ""
|
||||
};
|
||||
},
|
||||
noCloseToken: true
|
||||
},
|
||||
hr: {
|
||||
node: "horizontal_rule"
|
||||
},
|
||||
image: {
|
||||
node: "image",
|
||||
getAttrs: function getAttrs(tok) {
|
||||
return {
|
||||
src: tok.attrGet("src"),
|
||||
title: tok.attrGet("title") || null,
|
||||
alt: tok.children[0] && tok.children[0].content || null
|
||||
};
|
||||
}
|
||||
},
|
||||
hardbreak: {
|
||||
node: "hard_break"
|
||||
},
|
||||
em: {
|
||||
mark: "em"
|
||||
},
|
||||
strong: {
|
||||
mark: "strong"
|
||||
},
|
||||
link: {
|
||||
mark: "link",
|
||||
getAttrs: function getAttrs(tok) {
|
||||
return {
|
||||
href: tok.attrGet("href"),
|
||||
title: tok.attrGet("title") || null
|
||||
};
|
||||
}
|
||||
},
|
||||
code_inline: {
|
||||
mark: "code",
|
||||
noCloseToken: true
|
||||
}
|
||||
});
|
||||
var blankMark = {
|
||||
open: "",
|
||||
close: "",
|
||||
mixable: true
|
||||
};
|
||||
var MarkdownSerializer = function () {
|
||||
function MarkdownSerializer(nodes, marks) {
|
||||
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
||||
_classCallCheck(this, MarkdownSerializer);
|
||||
this.nodes = nodes;
|
||||
this.marks = marks;
|
||||
this.options = options;
|
||||
}
|
||||
_createClass(MarkdownSerializer, [{
|
||||
key: "serialize",
|
||||
value: function serialize(content) {
|
||||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
||||
options = Object.assign({}, this.options, options);
|
||||
var state = new MarkdownSerializerState(this.nodes, this.marks, options);
|
||||
state.renderContent(content);
|
||||
return state.out;
|
||||
}
|
||||
}]);
|
||||
return MarkdownSerializer;
|
||||
}();
|
||||
var defaultMarkdownSerializer = new MarkdownSerializer({
|
||||
blockquote: function blockquote(state, node) {
|
||||
state.wrapBlock("> ", null, node, function () {
|
||||
return state.renderContent(node);
|
||||
});
|
||||
},
|
||||
code_block: function code_block(state, node) {
|
||||
var backticks = node.textContent.match(/`{3,}/gm);
|
||||
var fence = backticks ? backticks.sort().slice(-1)[0] + "`" : "```";
|
||||
state.write(fence + (node.attrs.params || "") + "\n");
|
||||
state.text(node.textContent, false);
|
||||
state.write("\n");
|
||||
state.write(fence);
|
||||
state.closeBlock(node);
|
||||
},
|
||||
heading: function heading(state, node) {
|
||||
state.write(state.repeat("#", node.attrs.level) + " ");
|
||||
state.renderInline(node, false);
|
||||
state.closeBlock(node);
|
||||
},
|
||||
horizontal_rule: function horizontal_rule(state, node) {
|
||||
state.write(node.attrs.markup || "---");
|
||||
state.closeBlock(node);
|
||||
},
|
||||
bullet_list: function bullet_list(state, node) {
|
||||
state.renderList(node, " ", function () {
|
||||
return (node.attrs.bullet || "*") + " ";
|
||||
});
|
||||
},
|
||||
ordered_list: function ordered_list(state, node) {
|
||||
var start = node.attrs.order || 1;
|
||||
var maxW = String(start + node.childCount - 1).length;
|
||||
var space = state.repeat(" ", maxW + 2);
|
||||
state.renderList(node, space, function (i) {
|
||||
var nStr = String(start + i);
|
||||
return state.repeat(" ", maxW - nStr.length) + nStr + ". ";
|
||||
});
|
||||
},
|
||||
list_item: function list_item(state, node) {
|
||||
state.renderContent(node);
|
||||
},
|
||||
paragraph: function paragraph(state, node) {
|
||||
state.renderInline(node);
|
||||
state.closeBlock(node);
|
||||
},
|
||||
image: function image(state, node) {
|
||||
state.write("]/g, "\\$&") + (node.attrs.title ? ' "' + node.attrs.title.replace(/"/g, '\\"') + '"' : "") + ")");
|
||||
},
|
||||
hard_break: function hard_break(state, node, parent, index) {
|
||||
for (var i = index + 1; i < parent.childCount; i++) if (parent.child(i).type != node.type) {
|
||||
state.write("\\\n");
|
||||
return;
|
||||
}
|
||||
},
|
||||
text: function text(state, node) {
|
||||
state.text(node.text, !state.inAutolink);
|
||||
}
|
||||
}, {
|
||||
em: {
|
||||
open: "*",
|
||||
close: "*",
|
||||
mixable: true,
|
||||
expelEnclosingWhitespace: true
|
||||
},
|
||||
strong: {
|
||||
open: "**",
|
||||
close: "**",
|
||||
mixable: true,
|
||||
expelEnclosingWhitespace: true
|
||||
},
|
||||
link: {
|
||||
open: function open(state, mark, parent, index) {
|
||||
state.inAutolink = isPlainURL(mark, parent, index);
|
||||
return state.inAutolink ? "<" : "[";
|
||||
},
|
||||
close: function close(state, mark, parent, index) {
|
||||
var inAutolink = state.inAutolink;
|
||||
state.inAutolink = undefined;
|
||||
return inAutolink ? ">" : "](" + mark.attrs.href.replace(/[\(\)"]/g, "\\$&") + (mark.attrs.title ? " \"".concat(mark.attrs.title.replace(/"/g, '\\"'), "\"") : "") + ")";
|
||||
},
|
||||
mixable: true
|
||||
},
|
||||
code: {
|
||||
open: function open(_state, _mark, parent, index) {
|
||||
return backticksFor(parent.child(index), -1);
|
||||
},
|
||||
close: function close(_state, _mark, parent, index) {
|
||||
return backticksFor(parent.child(index - 1), 1);
|
||||
},
|
||||
escape: false
|
||||
}
|
||||
});
|
||||
function backticksFor(node, side) {
|
||||
var ticks = /`+/g,
|
||||
m,
|
||||
len = 0;
|
||||
if (node.isText) while (m = ticks.exec(node.text)) len = Math.max(len, m[0].length);
|
||||
var result = len > 0 && side > 0 ? " `" : "`";
|
||||
for (var i = 0; i < len; i++) result += "`";
|
||||
if (len > 0 && side < 0) result += " ";
|
||||
return result;
|
||||
}
|
||||
function isPlainURL(link, parent, index) {
|
||||
if (link.attrs.title || !/^\w+:/.test(link.attrs.href)) return false;
|
||||
var content = parent.child(index);
|
||||
if (!content.isText || content.text != link.attrs.href || content.marks[content.marks.length - 1] != link) return false;
|
||||
return index == parent.childCount - 1 || !link.isInSet(parent.child(index + 1).marks);
|
||||
}
|
||||
var MarkdownSerializerState = function () {
|
||||
function MarkdownSerializerState(nodes, marks, options) {
|
||||
_classCallCheck(this, MarkdownSerializerState);
|
||||
this.nodes = nodes;
|
||||
this.marks = marks;
|
||||
this.options = options;
|
||||
this.delim = "";
|
||||
this.out = "";
|
||||
this.closed = null;
|
||||
this.inAutolink = undefined;
|
||||
this.atBlockStart = false;
|
||||
this.inTightList = false;
|
||||
if (typeof this.options.tightLists == "undefined") this.options.tightLists = false;
|
||||
if (typeof this.options.hardBreakNodeName == "undefined") this.options.hardBreakNodeName = "hard_break";
|
||||
}
|
||||
_createClass(MarkdownSerializerState, [{
|
||||
key: "flushClose",
|
||||
value: function flushClose() {
|
||||
var size = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 2;
|
||||
if (this.closed) {
|
||||
if (!this.atBlank()) this.out += "\n";
|
||||
if (size > 1) {
|
||||
var delimMin = this.delim;
|
||||
var trim = /\s+$/.exec(delimMin);
|
||||
if (trim) delimMin = delimMin.slice(0, delimMin.length - trim[0].length);
|
||||
for (var i = 1; i < size; i++) this.out += delimMin + "\n";
|
||||
}
|
||||
this.closed = null;
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: "getMark",
|
||||
value: function getMark(name) {
|
||||
var info = this.marks[name];
|
||||
if (!info) {
|
||||
if (this.options.strict !== false) throw new Error("Mark type `".concat(name, "` not supported by Markdown renderer"));
|
||||
info = blankMark;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
}, {
|
||||
key: "wrapBlock",
|
||||
value: function wrapBlock(delim, firstDelim, node, f) {
|
||||
var old = this.delim;
|
||||
this.write(firstDelim != null ? firstDelim : delim);
|
||||
this.delim += delim;
|
||||
f();
|
||||
this.delim = old;
|
||||
this.closeBlock(node);
|
||||
}
|
||||
}, {
|
||||
key: "atBlank",
|
||||
value: function atBlank() {
|
||||
return /(^|\n)$/.test(this.out);
|
||||
}
|
||||
}, {
|
||||
key: "ensureNewLine",
|
||||
value: function ensureNewLine() {
|
||||
if (!this.atBlank()) this.out += "\n";
|
||||
}
|
||||
}, {
|
||||
key: "write",
|
||||
value: function write(content) {
|
||||
this.flushClose();
|
||||
if (this.delim && this.atBlank()) this.out += this.delim;
|
||||
if (content) this.out += content;
|
||||
}
|
||||
}, {
|
||||
key: "closeBlock",
|
||||
value: function closeBlock(node) {
|
||||
this.closed = node;
|
||||
}
|
||||
}, {
|
||||
key: "text",
|
||||
value: function text(_text) {
|
||||
var escape = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
||||
var lines = _text.split("\n");
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
this.write();
|
||||
if (!escape && lines[i][0] == "[" && /(^|[^\\])\!$/.test(this.out)) this.out = this.out.slice(0, this.out.length - 1) + "\\!";
|
||||
this.out += escape ? this.esc(lines[i], this.atBlockStart) : lines[i];
|
||||
if (i != lines.length - 1) this.out += "\n";
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: "render",
|
||||
value: function render(node, parent, index) {
|
||||
if (this.nodes[node.type.name]) {
|
||||
this.nodes[node.type.name](this, node, parent, index);
|
||||
} else {
|
||||
if (this.options.strict !== false) {
|
||||
throw new Error("Token type `" + node.type.name + "` not supported by Markdown renderer");
|
||||
} else if (!node.type.isLeaf) {
|
||||
if (node.type.inlineContent) this.renderInline(node);else this.renderContent(node);
|
||||
if (node.isBlock) this.closeBlock(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: "renderContent",
|
||||
value: function renderContent(parent) {
|
||||
var _this = this;
|
||||
parent.forEach(function (node, _, i) {
|
||||
return _this.render(node, parent, i);
|
||||
});
|
||||
}
|
||||
}, {
|
||||
key: "renderInline",
|
||||
value: function renderInline(parent) {
|
||||
var _this2 = this;
|
||||
var fromBlockStart = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
||||
this.atBlockStart = fromBlockStart;
|
||||
var active = [],
|
||||
trailing = "";
|
||||
var progress = function progress(node, offset, index) {
|
||||
var marks = node ? node.marks : [];
|
||||
if (node && node.type.name === _this2.options.hardBreakNodeName) marks = marks.filter(function (m) {
|
||||
if (index + 1 == parent.childCount) return false;
|
||||
var next = parent.child(index + 1);
|
||||
return m.isInSet(next.marks) && (!next.isText || /\S/.test(next.text));
|
||||
});
|
||||
var leading = trailing;
|
||||
trailing = "";
|
||||
if (node && node.isText && marks.some(function (mark) {
|
||||
var info = _this2.getMark(mark.type.name);
|
||||
return info && info.expelEnclosingWhitespace && !mark.isInSet(active);
|
||||
})) {
|
||||
var _exec = /^(\s*)(.*)$/m.exec(node.text),
|
||||
_exec2 = _slicedToArray(_exec, 3),
|
||||
_ = _exec2[0],
|
||||
lead = _exec2[1],
|
||||
rest = _exec2[2];
|
||||
if (lead) {
|
||||
leading += lead;
|
||||
node = rest ? node.withText(rest) : null;
|
||||
if (!node) marks = active;
|
||||
}
|
||||
}
|
||||
if (node && node.isText && marks.some(function (mark) {
|
||||
var info = _this2.getMark(mark.type.name);
|
||||
return info && info.expelEnclosingWhitespace && !_this2.isMarkAhead(parent, index + 1, mark);
|
||||
})) {
|
||||
var _exec3 = /^(.*?)(\s*)$/m.exec(node.text),
|
||||
_exec4 = _slicedToArray(_exec3, 3),
|
||||
_2 = _exec4[0],
|
||||
_rest = _exec4[1],
|
||||
trail = _exec4[2];
|
||||
if (trail) {
|
||||
trailing = trail;
|
||||
node = _rest ? node.withText(_rest) : null;
|
||||
if (!node) marks = active;
|
||||
}
|
||||
}
|
||||
var inner = marks.length ? marks[marks.length - 1] : null;
|
||||
var noEsc = inner && _this2.getMark(inner.type.name).escape === false;
|
||||
var len = marks.length - (noEsc ? 1 : 0);
|
||||
outer: for (var i = 0; i < len; i++) {
|
||||
var mark = marks[i];
|
||||
if (!_this2.getMark(mark.type.name).mixable) break;
|
||||
for (var j = 0; j < active.length; j++) {
|
||||
var other = active[j];
|
||||
if (!_this2.getMark(other.type.name).mixable) break;
|
||||
if (mark.eq(other)) {
|
||||
if (i > j) marks = marks.slice(0, j).concat(mark).concat(marks.slice(j, i)).concat(marks.slice(i + 1, len));else if (j > i) marks = marks.slice(0, i).concat(marks.slice(i + 1, j)).concat(mark).concat(marks.slice(j, len));
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
var keep = 0;
|
||||
while (keep < Math.min(active.length, len) && marks[keep].eq(active[keep])) ++keep;
|
||||
while (keep < active.length) _this2.text(_this2.markString(active.pop(), false, parent, index), false);
|
||||
if (leading) _this2.text(leading);
|
||||
if (node) {
|
||||
while (active.length < len) {
|
||||
var add = marks[active.length];
|
||||
active.push(add);
|
||||
_this2.text(_this2.markString(add, true, parent, index), false);
|
||||
_this2.atBlockStart = false;
|
||||
}
|
||||
if (noEsc && node.isText) _this2.text(_this2.markString(inner, true, parent, index) + node.text + _this2.markString(inner, false, parent, index + 1), false);else _this2.render(node, parent, index);
|
||||
_this2.atBlockStart = false;
|
||||
}
|
||||
if ((node === null || node === void 0 ? void 0 : node.isText) && node.nodeSize > 0) {
|
||||
_this2.atBlockStart = false;
|
||||
}
|
||||
};
|
||||
parent.forEach(progress);
|
||||
progress(null, 0, parent.childCount);
|
||||
this.atBlockStart = false;
|
||||
}
|
||||
}, {
|
||||
key: "renderList",
|
||||
value: function renderList(node, delim, firstDelim) {
|
||||
var _this3 = this;
|
||||
if (this.closed && this.closed.type == node.type) this.flushClose(3);else if (this.inTightList) this.flushClose(1);
|
||||
var isTight = typeof node.attrs.tight != "undefined" ? node.attrs.tight : this.options.tightLists;
|
||||
var prevTight = this.inTightList;
|
||||
this.inTightList = isTight;
|
||||
node.forEach(function (child, _, i) {
|
||||
if (i && isTight) _this3.flushClose(1);
|
||||
_this3.wrapBlock(delim, firstDelim(i), node, function () {
|
||||
return _this3.render(child, node, i);
|
||||
});
|
||||
});
|
||||
this.inTightList = prevTight;
|
||||
}
|
||||
}, {
|
||||
key: "esc",
|
||||
value: function esc(str) {
|
||||
var startOfLine = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
||||
str = str.replace(/[`*\\~\[\]_]/g, function (m, i) {
|
||||
return m == "_" && i > 0 && i + 1 < str.length && str[i - 1].match(/\w/) && str[i + 1].match(/\w/) ? m : "\\" + m;
|
||||
});
|
||||
if (startOfLine) str = str.replace(/^(\+[ ]|[\-*>])/, "\\$&").replace(/^(\s*)(#{1,6})(\s|$)/, '$1\\$2$3').replace(/^(\s*\d+)\.\s/, "$1\\. ");
|
||||
if (this.options.escapeExtraCharacters) str = str.replace(this.options.escapeExtraCharacters, "\\$&");
|
||||
return str;
|
||||
}
|
||||
}, {
|
||||
key: "quote",
|
||||
value: function quote(str) {
|
||||
var wrap = str.indexOf('"') == -1 ? '""' : str.indexOf("'") == -1 ? "''" : "()";
|
||||
return wrap[0] + str + wrap[1];
|
||||
}
|
||||
}, {
|
||||
key: "repeat",
|
||||
value: function repeat(str, n) {
|
||||
var out = "";
|
||||
for (var i = 0; i < n; i++) out += str;
|
||||
return out;
|
||||
}
|
||||
}, {
|
||||
key: "markString",
|
||||
value: function markString(mark, open, parent, index) {
|
||||
var info = this.getMark(mark.type.name);
|
||||
var value = open ? info.open : info.close;
|
||||
return typeof value == "string" ? value : value(this, mark, parent, index);
|
||||
}
|
||||
}, {
|
||||
key: "getEnclosingWhitespace",
|
||||
value: function getEnclosingWhitespace(text) {
|
||||
return {
|
||||
leading: (text.match(/^(\s+)/) || [undefined])[0],
|
||||
trailing: (text.match(/(\s+)$/) || [undefined])[0]
|
||||
};
|
||||
}
|
||||
}, {
|
||||
key: "isMarkAhead",
|
||||
value: function isMarkAhead(parent, index, mark) {
|
||||
for (;; index++) {
|
||||
if (index >= parent.childCount) return false;
|
||||
var next = parent.child(index);
|
||||
if (next.type.name != this.options.hardBreakNodeName) return mark.isInSet(next.marks);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}]);
|
||||
return MarkdownSerializerState;
|
||||
}();
|
||||
exports.MarkdownParser = MarkdownParser;
|
||||
exports.MarkdownSerializer = MarkdownSerializer;
|
||||
exports.MarkdownSerializerState = MarkdownSerializerState;
|
||||
exports.defaultMarkdownParser = defaultMarkdownParser;
|
||||
exports.defaultMarkdownSerializer = defaultMarkdownSerializer;
|
||||
exports.schema = schema;
|
||||
335
node_modules/prosemirror-markdown/dist/index.d.cts
generated
vendored
Normal file
335
node_modules/prosemirror-markdown/dist/index.d.cts
generated
vendored
Normal file
@@ -0,0 +1,335 @@
|
||||
import { Schema, Attrs, Node, Mark } from 'prosemirror-model';
|
||||
import MarkdownIt from 'markdown-it';
|
||||
import Token from 'markdown-it/lib/token.mjs';
|
||||
|
||||
/**
|
||||
Document schema for the data model used by CommonMark.
|
||||
*/
|
||||
declare const schema: Schema<"blockquote" | "image" | "text" | "paragraph" | "code_block" | "doc" | "horizontal_rule" | "heading" | "ordered_list" | "bullet_list" | "list_item" | "hard_break", "link" | "code" | "em" | "strong">;
|
||||
|
||||
/**
|
||||
Object type used to specify how Markdown tokens should be parsed.
|
||||
*/
|
||||
interface ParseSpec {
|
||||
/**
|
||||
This token maps to a single node, whose type can be looked up
|
||||
in the schema under the given name. Exactly one of `node`,
|
||||
`block`, or `mark` must be set.
|
||||
*/
|
||||
node?: string;
|
||||
/**
|
||||
This token (unless `noCloseToken` is true) comes in `_open`
|
||||
and `_close` variants (which are appended to the base token
|
||||
name provides a the object property), and wraps a block of
|
||||
content. The block should be wrapped in a node of the type
|
||||
named to by the property's value. If the token does not have
|
||||
`_open` or `_close`, use the `noCloseToken` option.
|
||||
*/
|
||||
block?: string;
|
||||
/**
|
||||
This token (again, unless `noCloseToken` is true) also comes
|
||||
in `_open` and `_close` variants, but should add a mark
|
||||
(named by the value) to its content, rather than wrapping it
|
||||
in a node.
|
||||
*/
|
||||
mark?: string;
|
||||
/**
|
||||
Attributes for the node or mark. When `getAttrs` is provided,
|
||||
it takes precedence.
|
||||
*/
|
||||
attrs?: Attrs | null;
|
||||
/**
|
||||
A function used to compute the attributes for the node or mark
|
||||
that takes a [markdown-it
|
||||
token](https://markdown-it.github.io/markdown-it/#Token) and
|
||||
returns an attribute object.
|
||||
*/
|
||||
getAttrs?: (token: Token, tokenStream: Token[], index: number) => Attrs | null;
|
||||
/**
|
||||
Indicates that the [markdown-it
|
||||
token](https://markdown-it.github.io/markdown-it/#Token) has
|
||||
no `_open` or `_close` for the nodes. This defaults to `true`
|
||||
for `code_inline`, `code_block` and `fence`.
|
||||
*/
|
||||
noCloseToken?: boolean;
|
||||
/**
|
||||
When true, ignore content for the matched token.
|
||||
*/
|
||||
ignore?: boolean;
|
||||
}
|
||||
/**
|
||||
A configuration of a Markdown parser. Such a parser uses
|
||||
[markdown-it](https://github.com/markdown-it/markdown-it) to
|
||||
tokenize a file, and then runs the custom rules it is given over
|
||||
the tokens to create a ProseMirror document tree.
|
||||
*/
|
||||
declare class MarkdownParser {
|
||||
/**
|
||||
The parser's document schema.
|
||||
*/
|
||||
readonly schema: Schema;
|
||||
/**
|
||||
This parser's markdown-it tokenizer.
|
||||
*/
|
||||
readonly tokenizer: MarkdownIt;
|
||||
/**
|
||||
The value of the `tokens` object used to construct this
|
||||
parser. Can be useful to copy and modify to base other parsers
|
||||
on.
|
||||
*/
|
||||
readonly tokens: {
|
||||
[name: string]: ParseSpec;
|
||||
};
|
||||
/**
|
||||
Create a parser with the given configuration. You can configure
|
||||
the markdown-it parser to parse the dialect you want, and provide
|
||||
a description of the ProseMirror entities those tokens map to in
|
||||
the `tokens` object, which maps token names to descriptions of
|
||||
what to do with them. Such a description is an object, and may
|
||||
have the following properties:
|
||||
*/
|
||||
constructor(
|
||||
/**
|
||||
The parser's document schema.
|
||||
*/
|
||||
schema: Schema,
|
||||
/**
|
||||
This parser's markdown-it tokenizer.
|
||||
*/
|
||||
tokenizer: MarkdownIt,
|
||||
/**
|
||||
The value of the `tokens` object used to construct this
|
||||
parser. Can be useful to copy and modify to base other parsers
|
||||
on.
|
||||
*/
|
||||
tokens: {
|
||||
[name: string]: ParseSpec;
|
||||
});
|
||||
/**
|
||||
Parse a string as [CommonMark](http://commonmark.org/) markup,
|
||||
and create a ProseMirror document as prescribed by this parser's
|
||||
rules.
|
||||
|
||||
The second argument, when given, is passed through to the
|
||||
[Markdown
|
||||
parser](https://markdown-it.github.io/markdown-it/#MarkdownIt.parse).
|
||||
*/
|
||||
parse(text: string, markdownEnv?: Object): Node;
|
||||
}
|
||||
/**
|
||||
A parser parsing unextended [CommonMark](http://commonmark.org/),
|
||||
without inline HTML, and producing a document in the basic schema.
|
||||
*/
|
||||
declare const defaultMarkdownParser: MarkdownParser;
|
||||
|
||||
type MarkSerializerSpec = {
|
||||
/**
|
||||
The string that should appear before a piece of content marked
|
||||
by this mark, either directly or as a function that returns an
|
||||
appropriate string.
|
||||
*/
|
||||
open: string | ((state: MarkdownSerializerState, mark: Mark, parent: Node, index: number) => string);
|
||||
/**
|
||||
The string that should appear after a piece of content marked by
|
||||
this mark.
|
||||
*/
|
||||
close: string | ((state: MarkdownSerializerState, mark: Mark, parent: Node, index: number) => string);
|
||||
/**
|
||||
When `true`, this indicates that the order in which the mark's
|
||||
opening and closing syntax appears relative to other mixable
|
||||
marks can be varied. (For example, you can say `**a *b***` and
|
||||
`*a **b***`, but not `` `a *b*` ``.)
|
||||
*/
|
||||
mixable?: boolean;
|
||||
/**
|
||||
When enabled, causes the serializer to move enclosing whitespace
|
||||
from inside the marks to outside the marks. This is necessary
|
||||
for emphasis marks as CommonMark does not permit enclosing
|
||||
whitespace inside emphasis marks, see:
|
||||
http:spec.commonmark.org/0.26/#example-330
|
||||
*/
|
||||
expelEnclosingWhitespace?: boolean;
|
||||
/**
|
||||
Can be set to `false` to disable character escaping in a mark. A
|
||||
non-escaping mark has to have the highest precedence (must
|
||||
always be the innermost mark).
|
||||
*/
|
||||
escape?: boolean;
|
||||
};
|
||||
/**
|
||||
A specification for serializing a ProseMirror document as
|
||||
Markdown/CommonMark text.
|
||||
*/
|
||||
declare class MarkdownSerializer {
|
||||
/**
|
||||
The node serializer functions for this serializer.
|
||||
*/
|
||||
readonly nodes: {
|
||||
[node: string]: (state: MarkdownSerializerState, node: Node, parent: Node, index: number) => void;
|
||||
};
|
||||
/**
|
||||
The mark serializer info.
|
||||
*/
|
||||
readonly marks: {
|
||||
[mark: string]: MarkSerializerSpec;
|
||||
};
|
||||
readonly options: {
|
||||
/**
|
||||
Extra characters can be added for escaping. This is passed
|
||||
directly to String.replace(), and the matching characters are
|
||||
preceded by a backslash.
|
||||
*/
|
||||
escapeExtraCharacters?: RegExp;
|
||||
/**
|
||||
Specify the node name of hard breaks.
|
||||
Defaults to "hard_break"
|
||||
*/
|
||||
hardBreakNodeName?: string;
|
||||
/**
|
||||
By default, the serializer raises an error when it finds a
|
||||
node or mark type for which no serializer is defined. Set
|
||||
this to `false` to make it just ignore such elements,
|
||||
rendering only their content.
|
||||
*/
|
||||
strict?: boolean;
|
||||
};
|
||||
/**
|
||||
Construct a serializer with the given configuration. The `nodes`
|
||||
object should map node names in a given schema to function that
|
||||
take a serializer state and such a node, and serialize the node.
|
||||
*/
|
||||
constructor(
|
||||
/**
|
||||
The node serializer functions for this serializer.
|
||||
*/
|
||||
nodes: {
|
||||
[node: string]: (state: MarkdownSerializerState, node: Node, parent: Node, index: number) => void;
|
||||
},
|
||||
/**
|
||||
The mark serializer info.
|
||||
*/
|
||||
marks: {
|
||||
[mark: string]: MarkSerializerSpec;
|
||||
}, options?: {
|
||||
/**
|
||||
Extra characters can be added for escaping. This is passed
|
||||
directly to String.replace(), and the matching characters are
|
||||
preceded by a backslash.
|
||||
*/
|
||||
escapeExtraCharacters?: RegExp;
|
||||
/**
|
||||
Specify the node name of hard breaks.
|
||||
Defaults to "hard_break"
|
||||
*/
|
||||
hardBreakNodeName?: string;
|
||||
/**
|
||||
By default, the serializer raises an error when it finds a
|
||||
node or mark type for which no serializer is defined. Set
|
||||
this to `false` to make it just ignore such elements,
|
||||
rendering only their content.
|
||||
*/
|
||||
strict?: boolean;
|
||||
});
|
||||
/**
|
||||
Serialize the content of the given node to
|
||||
[CommonMark](http://commonmark.org/).
|
||||
*/
|
||||
serialize(content: Node, options?: {
|
||||
/**
|
||||
Whether to render lists in a tight style. This can be overridden
|
||||
on a node level by specifying a tight attribute on the node.
|
||||
Defaults to false.
|
||||
*/
|
||||
tightLists?: boolean;
|
||||
}): string;
|
||||
}
|
||||
/**
|
||||
A serializer for the [basic schema](https://prosemirror.net/docs/ref/#schema).
|
||||
*/
|
||||
declare const defaultMarkdownSerializer: MarkdownSerializer;
|
||||
/**
|
||||
This is an object used to track state and expose
|
||||
methods related to markdown serialization. Instances are passed to
|
||||
node and mark serialization methods (see `toMarkdown`).
|
||||
*/
|
||||
declare class MarkdownSerializerState {
|
||||
/**
|
||||
The options passed to the serializer.
|
||||
*/
|
||||
readonly options: {
|
||||
tightLists?: boolean;
|
||||
escapeExtraCharacters?: RegExp;
|
||||
hardBreakNodeName?: string;
|
||||
strict?: boolean;
|
||||
};
|
||||
/**
|
||||
Render a block, prefixing each line with `delim`, and the first
|
||||
line in `firstDelim`. `node` should be the node that is closed at
|
||||
the end of the block, and `f` is a function that renders the
|
||||
content of the block.
|
||||
*/
|
||||
wrapBlock(delim: string, firstDelim: string | null, node: Node, f: () => void): void;
|
||||
/**
|
||||
Ensure the current content ends with a newline.
|
||||
*/
|
||||
ensureNewLine(): void;
|
||||
/**
|
||||
Prepare the state for writing output (closing closed paragraphs,
|
||||
adding delimiters, and so on), and then optionally add content
|
||||
(unescaped) to the output.
|
||||
*/
|
||||
write(content?: string): void;
|
||||
/**
|
||||
Close the block for the given node.
|
||||
*/
|
||||
closeBlock(node: Node): void;
|
||||
/**
|
||||
Add the given text to the document. When escape is not `false`,
|
||||
it will be escaped.
|
||||
*/
|
||||
text(text: string, escape?: boolean): void;
|
||||
/**
|
||||
Render the given node as a block.
|
||||
*/
|
||||
render(node: Node, parent: Node, index: number): void;
|
||||
/**
|
||||
Render the contents of `parent` as block nodes.
|
||||
*/
|
||||
renderContent(parent: Node): void;
|
||||
/**
|
||||
Render the contents of `parent` as inline content.
|
||||
*/
|
||||
renderInline(parent: Node, fromBlockStart?: boolean): void;
|
||||
/**
|
||||
Render a node's content as a list. `delim` should be the extra
|
||||
indentation added to all lines except the first in an item,
|
||||
`firstDelim` is a function going from an item index to a
|
||||
delimiter for the first line of the item.
|
||||
*/
|
||||
renderList(node: Node, delim: string, firstDelim: (index: number) => string): void;
|
||||
/**
|
||||
Escape the given string so that it can safely appear in Markdown
|
||||
content. If `startOfLine` is true, also escape characters that
|
||||
have special meaning only at the start of the line.
|
||||
*/
|
||||
esc(str: string, startOfLine?: boolean): string;
|
||||
/**
|
||||
Repeat the given string `n` times.
|
||||
*/
|
||||
repeat(str: string, n: number): string;
|
||||
/**
|
||||
Get the markdown string for a given opening or closing mark.
|
||||
*/
|
||||
markString(mark: Mark, open: boolean, parent: Node, index: number): string;
|
||||
/**
|
||||
Get leading and trailing whitespace from a string. Values of
|
||||
leading or trailing property of the return object will be undefined
|
||||
if there is no match.
|
||||
*/
|
||||
getEnclosingWhitespace(text: string): {
|
||||
leading?: string;
|
||||
trailing?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export { MarkdownParser, MarkdownSerializer, MarkdownSerializerState, type ParseSpec, defaultMarkdownParser, defaultMarkdownSerializer, schema };
|
||||
335
node_modules/prosemirror-markdown/dist/index.d.ts
generated
vendored
Normal file
335
node_modules/prosemirror-markdown/dist/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,335 @@
|
||||
import { Schema, Attrs, Node, Mark } from 'prosemirror-model';
|
||||
import MarkdownIt from 'markdown-it';
|
||||
import Token from 'markdown-it/lib/token.mjs';
|
||||
|
||||
/**
|
||||
Document schema for the data model used by CommonMark.
|
||||
*/
|
||||
declare const schema: Schema<"blockquote" | "image" | "text" | "paragraph" | "code_block" | "doc" | "horizontal_rule" | "heading" | "ordered_list" | "bullet_list" | "list_item" | "hard_break", "link" | "code" | "em" | "strong">;
|
||||
|
||||
/**
|
||||
Object type used to specify how Markdown tokens should be parsed.
|
||||
*/
|
||||
interface ParseSpec {
|
||||
/**
|
||||
This token maps to a single node, whose type can be looked up
|
||||
in the schema under the given name. Exactly one of `node`,
|
||||
`block`, or `mark` must be set.
|
||||
*/
|
||||
node?: string;
|
||||
/**
|
||||
This token (unless `noCloseToken` is true) comes in `_open`
|
||||
and `_close` variants (which are appended to the base token
|
||||
name provides a the object property), and wraps a block of
|
||||
content. The block should be wrapped in a node of the type
|
||||
named to by the property's value. If the token does not have
|
||||
`_open` or `_close`, use the `noCloseToken` option.
|
||||
*/
|
||||
block?: string;
|
||||
/**
|
||||
This token (again, unless `noCloseToken` is true) also comes
|
||||
in `_open` and `_close` variants, but should add a mark
|
||||
(named by the value) to its content, rather than wrapping it
|
||||
in a node.
|
||||
*/
|
||||
mark?: string;
|
||||
/**
|
||||
Attributes for the node or mark. When `getAttrs` is provided,
|
||||
it takes precedence.
|
||||
*/
|
||||
attrs?: Attrs | null;
|
||||
/**
|
||||
A function used to compute the attributes for the node or mark
|
||||
that takes a [markdown-it
|
||||
token](https://markdown-it.github.io/markdown-it/#Token) and
|
||||
returns an attribute object.
|
||||
*/
|
||||
getAttrs?: (token: Token, tokenStream: Token[], index: number) => Attrs | null;
|
||||
/**
|
||||
Indicates that the [markdown-it
|
||||
token](https://markdown-it.github.io/markdown-it/#Token) has
|
||||
no `_open` or `_close` for the nodes. This defaults to `true`
|
||||
for `code_inline`, `code_block` and `fence`.
|
||||
*/
|
||||
noCloseToken?: boolean;
|
||||
/**
|
||||
When true, ignore content for the matched token.
|
||||
*/
|
||||
ignore?: boolean;
|
||||
}
|
||||
/**
|
||||
A configuration of a Markdown parser. Such a parser uses
|
||||
[markdown-it](https://github.com/markdown-it/markdown-it) to
|
||||
tokenize a file, and then runs the custom rules it is given over
|
||||
the tokens to create a ProseMirror document tree.
|
||||
*/
|
||||
declare class MarkdownParser {
|
||||
/**
|
||||
The parser's document schema.
|
||||
*/
|
||||
readonly schema: Schema;
|
||||
/**
|
||||
This parser's markdown-it tokenizer.
|
||||
*/
|
||||
readonly tokenizer: MarkdownIt;
|
||||
/**
|
||||
The value of the `tokens` object used to construct this
|
||||
parser. Can be useful to copy and modify to base other parsers
|
||||
on.
|
||||
*/
|
||||
readonly tokens: {
|
||||
[name: string]: ParseSpec;
|
||||
};
|
||||
/**
|
||||
Create a parser with the given configuration. You can configure
|
||||
the markdown-it parser to parse the dialect you want, and provide
|
||||
a description of the ProseMirror entities those tokens map to in
|
||||
the `tokens` object, which maps token names to descriptions of
|
||||
what to do with them. Such a description is an object, and may
|
||||
have the following properties:
|
||||
*/
|
||||
constructor(
|
||||
/**
|
||||
The parser's document schema.
|
||||
*/
|
||||
schema: Schema,
|
||||
/**
|
||||
This parser's markdown-it tokenizer.
|
||||
*/
|
||||
tokenizer: MarkdownIt,
|
||||
/**
|
||||
The value of the `tokens` object used to construct this
|
||||
parser. Can be useful to copy and modify to base other parsers
|
||||
on.
|
||||
*/
|
||||
tokens: {
|
||||
[name: string]: ParseSpec;
|
||||
});
|
||||
/**
|
||||
Parse a string as [CommonMark](http://commonmark.org/) markup,
|
||||
and create a ProseMirror document as prescribed by this parser's
|
||||
rules.
|
||||
|
||||
The second argument, when given, is passed through to the
|
||||
[Markdown
|
||||
parser](https://markdown-it.github.io/markdown-it/#MarkdownIt.parse).
|
||||
*/
|
||||
parse(text: string, markdownEnv?: Object): Node;
|
||||
}
|
||||
/**
|
||||
A parser parsing unextended [CommonMark](http://commonmark.org/),
|
||||
without inline HTML, and producing a document in the basic schema.
|
||||
*/
|
||||
declare const defaultMarkdownParser: MarkdownParser;
|
||||
|
||||
type MarkSerializerSpec = {
|
||||
/**
|
||||
The string that should appear before a piece of content marked
|
||||
by this mark, either directly or as a function that returns an
|
||||
appropriate string.
|
||||
*/
|
||||
open: string | ((state: MarkdownSerializerState, mark: Mark, parent: Node, index: number) => string);
|
||||
/**
|
||||
The string that should appear after a piece of content marked by
|
||||
this mark.
|
||||
*/
|
||||
close: string | ((state: MarkdownSerializerState, mark: Mark, parent: Node, index: number) => string);
|
||||
/**
|
||||
When `true`, this indicates that the order in which the mark's
|
||||
opening and closing syntax appears relative to other mixable
|
||||
marks can be varied. (For example, you can say `**a *b***` and
|
||||
`*a **b***`, but not `` `a *b*` ``.)
|
||||
*/
|
||||
mixable?: boolean;
|
||||
/**
|
||||
When enabled, causes the serializer to move enclosing whitespace
|
||||
from inside the marks to outside the marks. This is necessary
|
||||
for emphasis marks as CommonMark does not permit enclosing
|
||||
whitespace inside emphasis marks, see:
|
||||
http:spec.commonmark.org/0.26/#example-330
|
||||
*/
|
||||
expelEnclosingWhitespace?: boolean;
|
||||
/**
|
||||
Can be set to `false` to disable character escaping in a mark. A
|
||||
non-escaping mark has to have the highest precedence (must
|
||||
always be the innermost mark).
|
||||
*/
|
||||
escape?: boolean;
|
||||
};
|
||||
/**
|
||||
A specification for serializing a ProseMirror document as
|
||||
Markdown/CommonMark text.
|
||||
*/
|
||||
declare class MarkdownSerializer {
|
||||
/**
|
||||
The node serializer functions for this serializer.
|
||||
*/
|
||||
readonly nodes: {
|
||||
[node: string]: (state: MarkdownSerializerState, node: Node, parent: Node, index: number) => void;
|
||||
};
|
||||
/**
|
||||
The mark serializer info.
|
||||
*/
|
||||
readonly marks: {
|
||||
[mark: string]: MarkSerializerSpec;
|
||||
};
|
||||
readonly options: {
|
||||
/**
|
||||
Extra characters can be added for escaping. This is passed
|
||||
directly to String.replace(), and the matching characters are
|
||||
preceded by a backslash.
|
||||
*/
|
||||
escapeExtraCharacters?: RegExp;
|
||||
/**
|
||||
Specify the node name of hard breaks.
|
||||
Defaults to "hard_break"
|
||||
*/
|
||||
hardBreakNodeName?: string;
|
||||
/**
|
||||
By default, the serializer raises an error when it finds a
|
||||
node or mark type for which no serializer is defined. Set
|
||||
this to `false` to make it just ignore such elements,
|
||||
rendering only their content.
|
||||
*/
|
||||
strict?: boolean;
|
||||
};
|
||||
/**
|
||||
Construct a serializer with the given configuration. The `nodes`
|
||||
object should map node names in a given schema to function that
|
||||
take a serializer state and such a node, and serialize the node.
|
||||
*/
|
||||
constructor(
|
||||
/**
|
||||
The node serializer functions for this serializer.
|
||||
*/
|
||||
nodes: {
|
||||
[node: string]: (state: MarkdownSerializerState, node: Node, parent: Node, index: number) => void;
|
||||
},
|
||||
/**
|
||||
The mark serializer info.
|
||||
*/
|
||||
marks: {
|
||||
[mark: string]: MarkSerializerSpec;
|
||||
}, options?: {
|
||||
/**
|
||||
Extra characters can be added for escaping. This is passed
|
||||
directly to String.replace(), and the matching characters are
|
||||
preceded by a backslash.
|
||||
*/
|
||||
escapeExtraCharacters?: RegExp;
|
||||
/**
|
||||
Specify the node name of hard breaks.
|
||||
Defaults to "hard_break"
|
||||
*/
|
||||
hardBreakNodeName?: string;
|
||||
/**
|
||||
By default, the serializer raises an error when it finds a
|
||||
node or mark type for which no serializer is defined. Set
|
||||
this to `false` to make it just ignore such elements,
|
||||
rendering only their content.
|
||||
*/
|
||||
strict?: boolean;
|
||||
});
|
||||
/**
|
||||
Serialize the content of the given node to
|
||||
[CommonMark](http://commonmark.org/).
|
||||
*/
|
||||
serialize(content: Node, options?: {
|
||||
/**
|
||||
Whether to render lists in a tight style. This can be overridden
|
||||
on a node level by specifying a tight attribute on the node.
|
||||
Defaults to false.
|
||||
*/
|
||||
tightLists?: boolean;
|
||||
}): string;
|
||||
}
|
||||
/**
|
||||
A serializer for the [basic schema](https://prosemirror.net/docs/ref/#schema).
|
||||
*/
|
||||
declare const defaultMarkdownSerializer: MarkdownSerializer;
|
||||
/**
|
||||
This is an object used to track state and expose
|
||||
methods related to markdown serialization. Instances are passed to
|
||||
node and mark serialization methods (see `toMarkdown`).
|
||||
*/
|
||||
declare class MarkdownSerializerState {
|
||||
/**
|
||||
The options passed to the serializer.
|
||||
*/
|
||||
readonly options: {
|
||||
tightLists?: boolean;
|
||||
escapeExtraCharacters?: RegExp;
|
||||
hardBreakNodeName?: string;
|
||||
strict?: boolean;
|
||||
};
|
||||
/**
|
||||
Render a block, prefixing each line with `delim`, and the first
|
||||
line in `firstDelim`. `node` should be the node that is closed at
|
||||
the end of the block, and `f` is a function that renders the
|
||||
content of the block.
|
||||
*/
|
||||
wrapBlock(delim: string, firstDelim: string | null, node: Node, f: () => void): void;
|
||||
/**
|
||||
Ensure the current content ends with a newline.
|
||||
*/
|
||||
ensureNewLine(): void;
|
||||
/**
|
||||
Prepare the state for writing output (closing closed paragraphs,
|
||||
adding delimiters, and so on), and then optionally add content
|
||||
(unescaped) to the output.
|
||||
*/
|
||||
write(content?: string): void;
|
||||
/**
|
||||
Close the block for the given node.
|
||||
*/
|
||||
closeBlock(node: Node): void;
|
||||
/**
|
||||
Add the given text to the document. When escape is not `false`,
|
||||
it will be escaped.
|
||||
*/
|
||||
text(text: string, escape?: boolean): void;
|
||||
/**
|
||||
Render the given node as a block.
|
||||
*/
|
||||
render(node: Node, parent: Node, index: number): void;
|
||||
/**
|
||||
Render the contents of `parent` as block nodes.
|
||||
*/
|
||||
renderContent(parent: Node): void;
|
||||
/**
|
||||
Render the contents of `parent` as inline content.
|
||||
*/
|
||||
renderInline(parent: Node, fromBlockStart?: boolean): void;
|
||||
/**
|
||||
Render a node's content as a list. `delim` should be the extra
|
||||
indentation added to all lines except the first in an item,
|
||||
`firstDelim` is a function going from an item index to a
|
||||
delimiter for the first line of the item.
|
||||
*/
|
||||
renderList(node: Node, delim: string, firstDelim: (index: number) => string): void;
|
||||
/**
|
||||
Escape the given string so that it can safely appear in Markdown
|
||||
content. If `startOfLine` is true, also escape characters that
|
||||
have special meaning only at the start of the line.
|
||||
*/
|
||||
esc(str: string, startOfLine?: boolean): string;
|
||||
/**
|
||||
Repeat the given string `n` times.
|
||||
*/
|
||||
repeat(str: string, n: number): string;
|
||||
/**
|
||||
Get the markdown string for a given opening or closing mark.
|
||||
*/
|
||||
markString(mark: Mark, open: boolean, parent: Node, index: number): string;
|
||||
/**
|
||||
Get leading and trailing whitespace from a string. Values of
|
||||
leading or trailing property of the return object will be undefined
|
||||
if there is no match.
|
||||
*/
|
||||
getEnclosingWhitespace(text: string): {
|
||||
leading?: string;
|
||||
trailing?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export { MarkdownParser, MarkdownSerializer, MarkdownSerializerState, type ParseSpec, defaultMarkdownParser, defaultMarkdownSerializer, schema };
|
||||
878
node_modules/prosemirror-markdown/dist/index.js
generated
vendored
Normal file
878
node_modules/prosemirror-markdown/dist/index.js
generated
vendored
Normal file
@@ -0,0 +1,878 @@
|
||||
import { Schema, Mark } from 'prosemirror-model';
|
||||
import MarkdownIt from 'markdown-it';
|
||||
|
||||
/**
|
||||
Document schema for the data model used by CommonMark.
|
||||
*/
|
||||
const schema = new Schema({
|
||||
nodes: {
|
||||
doc: {
|
||||
content: "block+"
|
||||
},
|
||||
paragraph: {
|
||||
content: "inline*",
|
||||
group: "block",
|
||||
parseDOM: [{ tag: "p" }],
|
||||
toDOM() { return ["p", 0]; }
|
||||
},
|
||||
blockquote: {
|
||||
content: "block+",
|
||||
group: "block",
|
||||
parseDOM: [{ tag: "blockquote" }],
|
||||
toDOM() { return ["blockquote", 0]; }
|
||||
},
|
||||
horizontal_rule: {
|
||||
group: "block",
|
||||
parseDOM: [{ tag: "hr" }],
|
||||
toDOM() { return ["div", ["hr"]]; }
|
||||
},
|
||||
heading: {
|
||||
attrs: { level: { default: 1 } },
|
||||
content: "(text | image)*",
|
||||
group: "block",
|
||||
defining: true,
|
||||
parseDOM: [{ tag: "h1", attrs: { level: 1 } },
|
||||
{ tag: "h2", attrs: { level: 2 } },
|
||||
{ tag: "h3", attrs: { level: 3 } },
|
||||
{ tag: "h4", attrs: { level: 4 } },
|
||||
{ tag: "h5", attrs: { level: 5 } },
|
||||
{ tag: "h6", attrs: { level: 6 } }],
|
||||
toDOM(node) { return ["h" + node.attrs.level, 0]; }
|
||||
},
|
||||
code_block: {
|
||||
content: "text*",
|
||||
group: "block",
|
||||
code: true,
|
||||
defining: true,
|
||||
marks: "",
|
||||
attrs: { params: { default: "" } },
|
||||
parseDOM: [{ tag: "pre", preserveWhitespace: "full", getAttrs: node => ({ params: node.getAttribute("data-params") || "" }) }],
|
||||
toDOM(node) { return ["pre", node.attrs.params ? { "data-params": node.attrs.params } : {}, ["code", 0]]; }
|
||||
},
|
||||
ordered_list: {
|
||||
content: "list_item+",
|
||||
group: "block",
|
||||
attrs: { order: { default: 1 }, tight: { default: false } },
|
||||
parseDOM: [{ tag: "ol", getAttrs(dom) {
|
||||
return { order: dom.hasAttribute("start") ? +dom.getAttribute("start") : 1,
|
||||
tight: dom.hasAttribute("data-tight") };
|
||||
} }],
|
||||
toDOM(node) {
|
||||
return ["ol", { start: node.attrs.order == 1 ? null : node.attrs.order,
|
||||
"data-tight": node.attrs.tight ? "true" : null }, 0];
|
||||
}
|
||||
},
|
||||
bullet_list: {
|
||||
content: "list_item+",
|
||||
group: "block",
|
||||
attrs: { tight: { default: false } },
|
||||
parseDOM: [{ tag: "ul", getAttrs: dom => ({ tight: dom.hasAttribute("data-tight") }) }],
|
||||
toDOM(node) { return ["ul", { "data-tight": node.attrs.tight ? "true" : null }, 0]; }
|
||||
},
|
||||
list_item: {
|
||||
content: "block+",
|
||||
defining: true,
|
||||
parseDOM: [{ tag: "li" }],
|
||||
toDOM() { return ["li", 0]; }
|
||||
},
|
||||
text: {
|
||||
group: "inline"
|
||||
},
|
||||
image: {
|
||||
inline: true,
|
||||
attrs: {
|
||||
src: {},
|
||||
alt: { default: null },
|
||||
title: { default: null }
|
||||
},
|
||||
group: "inline",
|
||||
draggable: true,
|
||||
parseDOM: [{ tag: "img[src]", getAttrs(dom) {
|
||||
return {
|
||||
src: dom.getAttribute("src"),
|
||||
title: dom.getAttribute("title"),
|
||||
alt: dom.getAttribute("alt")
|
||||
};
|
||||
} }],
|
||||
toDOM(node) { return ["img", node.attrs]; }
|
||||
},
|
||||
hard_break: {
|
||||
inline: true,
|
||||
group: "inline",
|
||||
selectable: false,
|
||||
parseDOM: [{ tag: "br" }],
|
||||
toDOM() { return ["br"]; }
|
||||
}
|
||||
},
|
||||
marks: {
|
||||
em: {
|
||||
parseDOM: [
|
||||
{ tag: "i" }, { tag: "em" },
|
||||
{ style: "font-style=italic" },
|
||||
{ style: "font-style=normal", clearMark: m => m.type.name == "em" }
|
||||
],
|
||||
toDOM() { return ["em"]; }
|
||||
},
|
||||
strong: {
|
||||
parseDOM: [
|
||||
{ tag: "strong" },
|
||||
{ tag: "b", getAttrs: node => node.style.fontWeight != "normal" && null },
|
||||
{ style: "font-weight=400", clearMark: m => m.type.name == "strong" },
|
||||
{ style: "font-weight", getAttrs: value => /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null }
|
||||
],
|
||||
toDOM() { return ["strong"]; }
|
||||
},
|
||||
link: {
|
||||
attrs: {
|
||||
href: {},
|
||||
title: { default: null }
|
||||
},
|
||||
inclusive: false,
|
||||
parseDOM: [{ tag: "a[href]", getAttrs(dom) {
|
||||
return { href: dom.getAttribute("href"), title: dom.getAttribute("title") };
|
||||
} }],
|
||||
toDOM(node) { return ["a", node.attrs]; }
|
||||
},
|
||||
code: {
|
||||
code: true,
|
||||
parseDOM: [{ tag: "code" }],
|
||||
toDOM() { return ["code"]; }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
function maybeMerge(a, b) {
|
||||
if (a.isText && b.isText && Mark.sameSet(a.marks, b.marks))
|
||||
return a.withText(a.text + b.text);
|
||||
}
|
||||
// Object used to track the context of a running parse.
|
||||
class MarkdownParseState {
|
||||
constructor(schema, tokenHandlers) {
|
||||
this.schema = schema;
|
||||
this.tokenHandlers = tokenHandlers;
|
||||
this.stack = [{ type: schema.topNodeType, attrs: null, content: [], marks: Mark.none }];
|
||||
}
|
||||
top() {
|
||||
return this.stack[this.stack.length - 1];
|
||||
}
|
||||
push(elt) {
|
||||
if (this.stack.length)
|
||||
this.top().content.push(elt);
|
||||
}
|
||||
// Adds the given text to the current position in the document,
|
||||
// using the current marks as styling.
|
||||
addText(text) {
|
||||
if (!text)
|
||||
return;
|
||||
let top = this.top(), nodes = top.content, last = nodes[nodes.length - 1];
|
||||
let node = this.schema.text(text, top.marks), merged;
|
||||
if (last && (merged = maybeMerge(last, node)))
|
||||
nodes[nodes.length - 1] = merged;
|
||||
else
|
||||
nodes.push(node);
|
||||
}
|
||||
// Adds the given mark to the set of active marks.
|
||||
openMark(mark) {
|
||||
let top = this.top();
|
||||
top.marks = mark.addToSet(top.marks);
|
||||
}
|
||||
// Removes the given mark from the set of active marks.
|
||||
closeMark(mark) {
|
||||
let top = this.top();
|
||||
top.marks = mark.removeFromSet(top.marks);
|
||||
}
|
||||
parseTokens(toks) {
|
||||
for (let i = 0; i < toks.length; i++) {
|
||||
let tok = toks[i];
|
||||
let handler = this.tokenHandlers[tok.type];
|
||||
if (!handler)
|
||||
throw new Error("Token type `" + tok.type + "` not supported by Markdown parser");
|
||||
handler(this, tok, toks, i);
|
||||
}
|
||||
}
|
||||
// Add a node at the current position.
|
||||
addNode(type, attrs, content) {
|
||||
let top = this.top();
|
||||
let node = type.createAndFill(attrs, content, top ? top.marks : []);
|
||||
if (!node)
|
||||
return null;
|
||||
this.push(node);
|
||||
return node;
|
||||
}
|
||||
// Wrap subsequent content in a node of the given type.
|
||||
openNode(type, attrs) {
|
||||
this.stack.push({ type: type, attrs: attrs, content: [], marks: Mark.none });
|
||||
}
|
||||
// Close and return the node that is currently on top of the stack.
|
||||
closeNode() {
|
||||
let info = this.stack.pop();
|
||||
return this.addNode(info.type, info.attrs, info.content);
|
||||
}
|
||||
}
|
||||
function attrs(spec, token, tokens, i) {
|
||||
if (spec.getAttrs)
|
||||
return spec.getAttrs(token, tokens, i);
|
||||
// For backwards compatibility when `attrs` is a Function
|
||||
else if (spec.attrs instanceof Function)
|
||||
return spec.attrs(token);
|
||||
else
|
||||
return spec.attrs;
|
||||
}
|
||||
// Code content is represented as a single token with a `content`
|
||||
// property in Markdown-it.
|
||||
function noCloseToken(spec, type) {
|
||||
return spec.noCloseToken || type == "code_inline" || type == "code_block" || type == "fence";
|
||||
}
|
||||
function withoutTrailingNewline(str) {
|
||||
return str[str.length - 1] == "\n" ? str.slice(0, str.length - 1) : str;
|
||||
}
|
||||
function noOp() { }
|
||||
function tokenHandlers(schema, tokens) {
|
||||
let handlers = Object.create(null);
|
||||
for (let type in tokens) {
|
||||
let spec = tokens[type];
|
||||
if (spec.block) {
|
||||
let nodeType = schema.nodeType(spec.block);
|
||||
if (noCloseToken(spec, type)) {
|
||||
handlers[type] = (state, tok, tokens, i) => {
|
||||
state.openNode(nodeType, attrs(spec, tok, tokens, i));
|
||||
state.addText(withoutTrailingNewline(tok.content));
|
||||
state.closeNode();
|
||||
};
|
||||
}
|
||||
else {
|
||||
handlers[type + "_open"] = (state, tok, tokens, i) => state.openNode(nodeType, attrs(spec, tok, tokens, i));
|
||||
handlers[type + "_close"] = state => state.closeNode();
|
||||
}
|
||||
}
|
||||
else if (spec.node) {
|
||||
let nodeType = schema.nodeType(spec.node);
|
||||
handlers[type] = (state, tok, tokens, i) => state.addNode(nodeType, attrs(spec, tok, tokens, i));
|
||||
}
|
||||
else if (spec.mark) {
|
||||
let markType = schema.marks[spec.mark];
|
||||
if (noCloseToken(spec, type)) {
|
||||
handlers[type] = (state, tok, tokens, i) => {
|
||||
state.openMark(markType.create(attrs(spec, tok, tokens, i)));
|
||||
state.addText(withoutTrailingNewline(tok.content));
|
||||
state.closeMark(markType);
|
||||
};
|
||||
}
|
||||
else {
|
||||
handlers[type + "_open"] = (state, tok, tokens, i) => state.openMark(markType.create(attrs(spec, tok, tokens, i)));
|
||||
handlers[type + "_close"] = state => state.closeMark(markType);
|
||||
}
|
||||
}
|
||||
else if (spec.ignore) {
|
||||
if (noCloseToken(spec, type)) {
|
||||
handlers[type] = noOp;
|
||||
}
|
||||
else {
|
||||
handlers[type + "_open"] = noOp;
|
||||
handlers[type + "_close"] = noOp;
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new RangeError("Unrecognized parsing spec " + JSON.stringify(spec));
|
||||
}
|
||||
}
|
||||
handlers.text = (state, tok) => state.addText(tok.content);
|
||||
handlers.inline = (state, tok) => state.parseTokens(tok.children);
|
||||
handlers.softbreak = handlers.softbreak || (state => state.addText(" "));
|
||||
return handlers;
|
||||
}
|
||||
/**
|
||||
A configuration of a Markdown parser. Such a parser uses
|
||||
[markdown-it](https://github.com/markdown-it/markdown-it) to
|
||||
tokenize a file, and then runs the custom rules it is given over
|
||||
the tokens to create a ProseMirror document tree.
|
||||
*/
|
||||
class MarkdownParser {
|
||||
/**
|
||||
Create a parser with the given configuration. You can configure
|
||||
the markdown-it parser to parse the dialect you want, and provide
|
||||
a description of the ProseMirror entities those tokens map to in
|
||||
the `tokens` object, which maps token names to descriptions of
|
||||
what to do with them. Such a description is an object, and may
|
||||
have the following properties:
|
||||
*/
|
||||
constructor(
|
||||
/**
|
||||
The parser's document schema.
|
||||
*/
|
||||
schema,
|
||||
/**
|
||||
This parser's markdown-it tokenizer.
|
||||
*/
|
||||
tokenizer,
|
||||
/**
|
||||
The value of the `tokens` object used to construct this
|
||||
parser. Can be useful to copy and modify to base other parsers
|
||||
on.
|
||||
*/
|
||||
tokens) {
|
||||
this.schema = schema;
|
||||
this.tokenizer = tokenizer;
|
||||
this.tokens = tokens;
|
||||
this.tokenHandlers = tokenHandlers(schema, tokens);
|
||||
}
|
||||
/**
|
||||
Parse a string as [CommonMark](http://commonmark.org/) markup,
|
||||
and create a ProseMirror document as prescribed by this parser's
|
||||
rules.
|
||||
|
||||
The second argument, when given, is passed through to the
|
||||
[Markdown
|
||||
parser](https://markdown-it.github.io/markdown-it/#MarkdownIt.parse).
|
||||
*/
|
||||
parse(text, markdownEnv = {}) {
|
||||
let state = new MarkdownParseState(this.schema, this.tokenHandlers), doc;
|
||||
state.parseTokens(this.tokenizer.parse(text, markdownEnv));
|
||||
do {
|
||||
doc = state.closeNode();
|
||||
} while (state.stack.length);
|
||||
return doc || this.schema.topNodeType.createAndFill();
|
||||
}
|
||||
}
|
||||
function listIsTight(tokens, i) {
|
||||
while (++i < tokens.length)
|
||||
if (tokens[i].type != "list_item_open")
|
||||
return tokens[i].hidden;
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
A parser parsing unextended [CommonMark](http://commonmark.org/),
|
||||
without inline HTML, and producing a document in the basic schema.
|
||||
*/
|
||||
const defaultMarkdownParser = new MarkdownParser(schema, MarkdownIt("commonmark", { html: false }), {
|
||||
blockquote: { block: "blockquote" },
|
||||
paragraph: { block: "paragraph" },
|
||||
list_item: { block: "list_item" },
|
||||
bullet_list: { block: "bullet_list", getAttrs: (_, tokens, i) => ({ tight: listIsTight(tokens, i) }) },
|
||||
ordered_list: { block: "ordered_list", getAttrs: (tok, tokens, i) => ({
|
||||
order: +tok.attrGet("start") || 1,
|
||||
tight: listIsTight(tokens, i)
|
||||
}) },
|
||||
heading: { block: "heading", getAttrs: tok => ({ level: +tok.tag.slice(1) }) },
|
||||
code_block: { block: "code_block", noCloseToken: true },
|
||||
fence: { block: "code_block", getAttrs: tok => ({ params: tok.info || "" }), noCloseToken: true },
|
||||
hr: { node: "horizontal_rule" },
|
||||
image: { node: "image", getAttrs: tok => ({
|
||||
src: tok.attrGet("src"),
|
||||
title: tok.attrGet("title") || null,
|
||||
alt: tok.children[0] && tok.children[0].content || null
|
||||
}) },
|
||||
hardbreak: { node: "hard_break" },
|
||||
em: { mark: "em" },
|
||||
strong: { mark: "strong" },
|
||||
link: { mark: "link", getAttrs: tok => ({
|
||||
href: tok.attrGet("href"),
|
||||
title: tok.attrGet("title") || null
|
||||
}) },
|
||||
code_inline: { mark: "code", noCloseToken: true }
|
||||
});
|
||||
|
||||
const blankMark = { open: "", close: "", mixable: true };
|
||||
/**
|
||||
A specification for serializing a ProseMirror document as
|
||||
Markdown/CommonMark text.
|
||||
*/
|
||||
class MarkdownSerializer {
|
||||
/**
|
||||
Construct a serializer with the given configuration. The `nodes`
|
||||
object should map node names in a given schema to function that
|
||||
take a serializer state and such a node, and serialize the node.
|
||||
*/
|
||||
constructor(
|
||||
/**
|
||||
The node serializer functions for this serializer.
|
||||
*/
|
||||
nodes,
|
||||
/**
|
||||
The mark serializer info.
|
||||
*/
|
||||
marks, options = {}) {
|
||||
this.nodes = nodes;
|
||||
this.marks = marks;
|
||||
this.options = options;
|
||||
}
|
||||
/**
|
||||
Serialize the content of the given node to
|
||||
[CommonMark](http://commonmark.org/).
|
||||
*/
|
||||
serialize(content, options = {}) {
|
||||
options = Object.assign({}, this.options, options);
|
||||
let state = new MarkdownSerializerState(this.nodes, this.marks, options);
|
||||
state.renderContent(content);
|
||||
return state.out;
|
||||
}
|
||||
}
|
||||
/**
|
||||
A serializer for the [basic schema](https://prosemirror.net/docs/ref/#schema).
|
||||
*/
|
||||
const defaultMarkdownSerializer = new MarkdownSerializer({
|
||||
blockquote(state, node) {
|
||||
state.wrapBlock("> ", null, node, () => state.renderContent(node));
|
||||
},
|
||||
code_block(state, node) {
|
||||
// Make sure the front matter fences are longer than any dash sequence within it
|
||||
const backticks = node.textContent.match(/`{3,}/gm);
|
||||
const fence = backticks ? (backticks.sort().slice(-1)[0] + "`") : "```";
|
||||
state.write(fence + (node.attrs.params || "") + "\n");
|
||||
state.text(node.textContent, false);
|
||||
// Add a newline to the current content before adding closing marker
|
||||
state.write("\n");
|
||||
state.write(fence);
|
||||
state.closeBlock(node);
|
||||
},
|
||||
heading(state, node) {
|
||||
state.write(state.repeat("#", node.attrs.level) + " ");
|
||||
state.renderInline(node, false);
|
||||
state.closeBlock(node);
|
||||
},
|
||||
horizontal_rule(state, node) {
|
||||
state.write(node.attrs.markup || "---");
|
||||
state.closeBlock(node);
|
||||
},
|
||||
bullet_list(state, node) {
|
||||
state.renderList(node, " ", () => (node.attrs.bullet || "*") + " ");
|
||||
},
|
||||
ordered_list(state, node) {
|
||||
let start = node.attrs.order || 1;
|
||||
let maxW = String(start + node.childCount - 1).length;
|
||||
let space = state.repeat(" ", maxW + 2);
|
||||
state.renderList(node, space, i => {
|
||||
let nStr = String(start + i);
|
||||
return state.repeat(" ", maxW - nStr.length) + nStr + ". ";
|
||||
});
|
||||
},
|
||||
list_item(state, node) {
|
||||
state.renderContent(node);
|
||||
},
|
||||
paragraph(state, node) {
|
||||
state.renderInline(node);
|
||||
state.closeBlock(node);
|
||||
},
|
||||
image(state, node) {
|
||||
state.write("]/g, "\\$&") +
|
||||
(node.attrs.title ? ' "' + node.attrs.title.replace(/"/g, '\\"') + '"' : "") + ")");
|
||||
},
|
||||
hard_break(state, node, parent, index) {
|
||||
for (let i = index + 1; i < parent.childCount; i++)
|
||||
if (parent.child(i).type != node.type) {
|
||||
state.write("\\\n");
|
||||
return;
|
||||
}
|
||||
},
|
||||
text(state, node) {
|
||||
state.text(node.text, !state.inAutolink);
|
||||
}
|
||||
}, {
|
||||
em: { open: "*", close: "*", mixable: true, expelEnclosingWhitespace: true },
|
||||
strong: { open: "**", close: "**", mixable: true, expelEnclosingWhitespace: true },
|
||||
link: {
|
||||
open(state, mark, parent, index) {
|
||||
state.inAutolink = isPlainURL(mark, parent, index);
|
||||
return state.inAutolink ? "<" : "[";
|
||||
},
|
||||
close(state, mark, parent, index) {
|
||||
let { inAutolink } = state;
|
||||
state.inAutolink = undefined;
|
||||
return inAutolink ? ">"
|
||||
: "](" + mark.attrs.href.replace(/[\(\)"]/g, "\\$&") + (mark.attrs.title ? ` "${mark.attrs.title.replace(/"/g, '\\"')}"` : "") + ")";
|
||||
},
|
||||
mixable: true
|
||||
},
|
||||
code: { open(_state, _mark, parent, index) { return backticksFor(parent.child(index), -1); },
|
||||
close(_state, _mark, parent, index) { return backticksFor(parent.child(index - 1), 1); },
|
||||
escape: false }
|
||||
});
|
||||
function backticksFor(node, side) {
|
||||
let ticks = /`+/g, m, len = 0;
|
||||
if (node.isText)
|
||||
while (m = ticks.exec(node.text))
|
||||
len = Math.max(len, m[0].length);
|
||||
let result = len > 0 && side > 0 ? " `" : "`";
|
||||
for (let i = 0; i < len; i++)
|
||||
result += "`";
|
||||
if (len > 0 && side < 0)
|
||||
result += " ";
|
||||
return result;
|
||||
}
|
||||
function isPlainURL(link, parent, index) {
|
||||
if (link.attrs.title || !/^\w+:/.test(link.attrs.href))
|
||||
return false;
|
||||
let content = parent.child(index);
|
||||
if (!content.isText || content.text != link.attrs.href || content.marks[content.marks.length - 1] != link)
|
||||
return false;
|
||||
return index == parent.childCount - 1 || !link.isInSet(parent.child(index + 1).marks);
|
||||
}
|
||||
/**
|
||||
This is an object used to track state and expose
|
||||
methods related to markdown serialization. Instances are passed to
|
||||
node and mark serialization methods (see `toMarkdown`).
|
||||
*/
|
||||
class MarkdownSerializerState {
|
||||
/**
|
||||
@internal
|
||||
*/
|
||||
constructor(
|
||||
/**
|
||||
@internal
|
||||
*/
|
||||
nodes,
|
||||
/**
|
||||
@internal
|
||||
*/
|
||||
marks,
|
||||
/**
|
||||
The options passed to the serializer.
|
||||
*/
|
||||
options) {
|
||||
this.nodes = nodes;
|
||||
this.marks = marks;
|
||||
this.options = options;
|
||||
/**
|
||||
@internal
|
||||
*/
|
||||
this.delim = "";
|
||||
/**
|
||||
@internal
|
||||
*/
|
||||
this.out = "";
|
||||
/**
|
||||
@internal
|
||||
*/
|
||||
this.closed = null;
|
||||
/**
|
||||
@internal
|
||||
*/
|
||||
this.inAutolink = undefined;
|
||||
/**
|
||||
@internal
|
||||
*/
|
||||
this.atBlockStart = false;
|
||||
/**
|
||||
@internal
|
||||
*/
|
||||
this.inTightList = false;
|
||||
if (typeof this.options.tightLists == "undefined")
|
||||
this.options.tightLists = false;
|
||||
if (typeof this.options.hardBreakNodeName == "undefined")
|
||||
this.options.hardBreakNodeName = "hard_break";
|
||||
}
|
||||
/**
|
||||
@internal
|
||||
*/
|
||||
flushClose(size = 2) {
|
||||
if (this.closed) {
|
||||
if (!this.atBlank())
|
||||
this.out += "\n";
|
||||
if (size > 1) {
|
||||
let delimMin = this.delim;
|
||||
let trim = /\s+$/.exec(delimMin);
|
||||
if (trim)
|
||||
delimMin = delimMin.slice(0, delimMin.length - trim[0].length);
|
||||
for (let i = 1; i < size; i++)
|
||||
this.out += delimMin + "\n";
|
||||
}
|
||||
this.closed = null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
@internal
|
||||
*/
|
||||
getMark(name) {
|
||||
let info = this.marks[name];
|
||||
if (!info) {
|
||||
if (this.options.strict !== false)
|
||||
throw new Error(`Mark type \`${name}\` not supported by Markdown renderer`);
|
||||
info = blankMark;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
/**
|
||||
Render a block, prefixing each line with `delim`, and the first
|
||||
line in `firstDelim`. `node` should be the node that is closed at
|
||||
the end of the block, and `f` is a function that renders the
|
||||
content of the block.
|
||||
*/
|
||||
wrapBlock(delim, firstDelim, node, f) {
|
||||
let old = this.delim;
|
||||
this.write(firstDelim != null ? firstDelim : delim);
|
||||
this.delim += delim;
|
||||
f();
|
||||
this.delim = old;
|
||||
this.closeBlock(node);
|
||||
}
|
||||
/**
|
||||
@internal
|
||||
*/
|
||||
atBlank() {
|
||||
return /(^|\n)$/.test(this.out);
|
||||
}
|
||||
/**
|
||||
Ensure the current content ends with a newline.
|
||||
*/
|
||||
ensureNewLine() {
|
||||
if (!this.atBlank())
|
||||
this.out += "\n";
|
||||
}
|
||||
/**
|
||||
Prepare the state for writing output (closing closed paragraphs,
|
||||
adding delimiters, and so on), and then optionally add content
|
||||
(unescaped) to the output.
|
||||
*/
|
||||
write(content) {
|
||||
this.flushClose();
|
||||
if (this.delim && this.atBlank())
|
||||
this.out += this.delim;
|
||||
if (content)
|
||||
this.out += content;
|
||||
}
|
||||
/**
|
||||
Close the block for the given node.
|
||||
*/
|
||||
closeBlock(node) {
|
||||
this.closed = node;
|
||||
}
|
||||
/**
|
||||
Add the given text to the document. When escape is not `false`,
|
||||
it will be escaped.
|
||||
*/
|
||||
text(text, escape = true) {
|
||||
let lines = text.split("\n");
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
this.write();
|
||||
// Escape exclamation marks in front of links
|
||||
if (!escape && lines[i][0] == "[" && /(^|[^\\])\!$/.test(this.out))
|
||||
this.out = this.out.slice(0, this.out.length - 1) + "\\!";
|
||||
this.out += escape ? this.esc(lines[i], this.atBlockStart) : lines[i];
|
||||
if (i != lines.length - 1)
|
||||
this.out += "\n";
|
||||
}
|
||||
}
|
||||
/**
|
||||
Render the given node as a block.
|
||||
*/
|
||||
render(node, parent, index) {
|
||||
if (this.nodes[node.type.name]) {
|
||||
this.nodes[node.type.name](this, node, parent, index);
|
||||
}
|
||||
else {
|
||||
if (this.options.strict !== false) {
|
||||
throw new Error("Token type `" + node.type.name + "` not supported by Markdown renderer");
|
||||
}
|
||||
else if (!node.type.isLeaf) {
|
||||
if (node.type.inlineContent)
|
||||
this.renderInline(node);
|
||||
else
|
||||
this.renderContent(node);
|
||||
if (node.isBlock)
|
||||
this.closeBlock(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
Render the contents of `parent` as block nodes.
|
||||
*/
|
||||
renderContent(parent) {
|
||||
parent.forEach((node, _, i) => this.render(node, parent, i));
|
||||
}
|
||||
/**
|
||||
Render the contents of `parent` as inline content.
|
||||
*/
|
||||
renderInline(parent, fromBlockStart = true) {
|
||||
this.atBlockStart = fromBlockStart;
|
||||
let active = [], trailing = "";
|
||||
let progress = (node, offset, index) => {
|
||||
let marks = node ? node.marks : [];
|
||||
// Remove marks from `hard_break` that are the last node inside
|
||||
// that mark to prevent parser edge cases with new lines just
|
||||
// before closing marks.
|
||||
if (node && node.type.name === this.options.hardBreakNodeName)
|
||||
marks = marks.filter(m => {
|
||||
if (index + 1 == parent.childCount)
|
||||
return false;
|
||||
let next = parent.child(index + 1);
|
||||
return m.isInSet(next.marks) && (!next.isText || /\S/.test(next.text));
|
||||
});
|
||||
let leading = trailing;
|
||||
trailing = "";
|
||||
// If whitespace has to be expelled from the node, adjust
|
||||
// leading and trailing accordingly.
|
||||
if (node && node.isText && marks.some(mark => {
|
||||
let info = this.getMark(mark.type.name);
|
||||
return info && info.expelEnclosingWhitespace && !mark.isInSet(active);
|
||||
})) {
|
||||
let [_, lead, rest] = /^(\s*)(.*)$/m.exec(node.text);
|
||||
if (lead) {
|
||||
leading += lead;
|
||||
node = rest ? node.withText(rest) : null;
|
||||
if (!node)
|
||||
marks = active;
|
||||
}
|
||||
}
|
||||
if (node && node.isText && marks.some(mark => {
|
||||
let info = this.getMark(mark.type.name);
|
||||
return info && info.expelEnclosingWhitespace && !this.isMarkAhead(parent, index + 1, mark);
|
||||
})) {
|
||||
let [_, rest, trail] = /^(.*?)(\s*)$/m.exec(node.text);
|
||||
if (trail) {
|
||||
trailing = trail;
|
||||
node = rest ? node.withText(rest) : null;
|
||||
if (!node)
|
||||
marks = active;
|
||||
}
|
||||
}
|
||||
let inner = marks.length ? marks[marks.length - 1] : null;
|
||||
let noEsc = inner && this.getMark(inner.type.name).escape === false;
|
||||
let len = marks.length - (noEsc ? 1 : 0);
|
||||
// Try to reorder 'mixable' marks, such as em and strong, which
|
||||
// in Markdown may be opened and closed in different order, so
|
||||
// that order of the marks for the token matches the order in
|
||||
// active.
|
||||
outer: for (let i = 0; i < len; i++) {
|
||||
let mark = marks[i];
|
||||
if (!this.getMark(mark.type.name).mixable)
|
||||
break;
|
||||
for (let j = 0; j < active.length; j++) {
|
||||
let other = active[j];
|
||||
if (!this.getMark(other.type.name).mixable)
|
||||
break;
|
||||
if (mark.eq(other)) {
|
||||
if (i > j)
|
||||
marks = marks.slice(0, j).concat(mark).concat(marks.slice(j, i)).concat(marks.slice(i + 1, len));
|
||||
else if (j > i)
|
||||
marks = marks.slice(0, i).concat(marks.slice(i + 1, j)).concat(mark).concat(marks.slice(j, len));
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Find the prefix of the mark set that didn't change
|
||||
let keep = 0;
|
||||
while (keep < Math.min(active.length, len) && marks[keep].eq(active[keep]))
|
||||
++keep;
|
||||
// Close the marks that need to be closed
|
||||
while (keep < active.length)
|
||||
this.text(this.markString(active.pop(), false, parent, index), false);
|
||||
// Output any previously expelled trailing whitespace outside the marks
|
||||
if (leading)
|
||||
this.text(leading);
|
||||
// Open the marks that need to be opened
|
||||
if (node) {
|
||||
while (active.length < len) {
|
||||
let add = marks[active.length];
|
||||
active.push(add);
|
||||
this.text(this.markString(add, true, parent, index), false);
|
||||
this.atBlockStart = false;
|
||||
}
|
||||
// Render the node. Special case code marks, since their content
|
||||
// may not be escaped.
|
||||
if (noEsc && node.isText)
|
||||
this.text(this.markString(inner, true, parent, index) + node.text +
|
||||
this.markString(inner, false, parent, index + 1), false);
|
||||
else
|
||||
this.render(node, parent, index);
|
||||
this.atBlockStart = false;
|
||||
}
|
||||
// After the first non-empty text node is rendered, the end of output
|
||||
// is no longer at block start.
|
||||
//
|
||||
// FIXME: If a non-text node writes something to the output for this
|
||||
// block, the end of output is also no longer at block start. But how
|
||||
// can we detect that?
|
||||
if ((node === null || node === void 0 ? void 0 : node.isText) && node.nodeSize > 0) {
|
||||
this.atBlockStart = false;
|
||||
}
|
||||
};
|
||||
parent.forEach(progress);
|
||||
progress(null, 0, parent.childCount);
|
||||
this.atBlockStart = false;
|
||||
}
|
||||
/**
|
||||
Render a node's content as a list. `delim` should be the extra
|
||||
indentation added to all lines except the first in an item,
|
||||
`firstDelim` is a function going from an item index to a
|
||||
delimiter for the first line of the item.
|
||||
*/
|
||||
renderList(node, delim, firstDelim) {
|
||||
if (this.closed && this.closed.type == node.type)
|
||||
this.flushClose(3);
|
||||
else if (this.inTightList)
|
||||
this.flushClose(1);
|
||||
let isTight = typeof node.attrs.tight != "undefined" ? node.attrs.tight : this.options.tightLists;
|
||||
let prevTight = this.inTightList;
|
||||
this.inTightList = isTight;
|
||||
node.forEach((child, _, i) => {
|
||||
if (i && isTight)
|
||||
this.flushClose(1);
|
||||
this.wrapBlock(delim, firstDelim(i), node, () => this.render(child, node, i));
|
||||
});
|
||||
this.inTightList = prevTight;
|
||||
}
|
||||
/**
|
||||
Escape the given string so that it can safely appear in Markdown
|
||||
content. If `startOfLine` is true, also escape characters that
|
||||
have special meaning only at the start of the line.
|
||||
*/
|
||||
esc(str, startOfLine = false) {
|
||||
str = str.replace(/[`*\\~\[\]_]/g, (m, i) => m == "_" && i > 0 && i + 1 < str.length && str[i - 1].match(/\w/) && str[i + 1].match(/\w/) ? m : "\\" + m);
|
||||
if (startOfLine)
|
||||
str = str.replace(/^(\+[ ]|[\-*>])/, "\\$&").replace(/^(\s*)(#{1,6})(\s|$)/, '$1\\$2$3').replace(/^(\s*\d+)\.\s/, "$1\\. ");
|
||||
if (this.options.escapeExtraCharacters)
|
||||
str = str.replace(this.options.escapeExtraCharacters, "\\$&");
|
||||
return str;
|
||||
}
|
||||
/**
|
||||
@internal
|
||||
*/
|
||||
quote(str) {
|
||||
let wrap = str.indexOf('"') == -1 ? '""' : str.indexOf("'") == -1 ? "''" : "()";
|
||||
return wrap[0] + str + wrap[1];
|
||||
}
|
||||
/**
|
||||
Repeat the given string `n` times.
|
||||
*/
|
||||
repeat(str, n) {
|
||||
let out = "";
|
||||
for (let i = 0; i < n; i++)
|
||||
out += str;
|
||||
return out;
|
||||
}
|
||||
/**
|
||||
Get the markdown string for a given opening or closing mark.
|
||||
*/
|
||||
markString(mark, open, parent, index) {
|
||||
let info = this.getMark(mark.type.name);
|
||||
let value = open ? info.open : info.close;
|
||||
return typeof value == "string" ? value : value(this, mark, parent, index);
|
||||
}
|
||||
/**
|
||||
Get leading and trailing whitespace from a string. Values of
|
||||
leading or trailing property of the return object will be undefined
|
||||
if there is no match.
|
||||
*/
|
||||
getEnclosingWhitespace(text) {
|
||||
return {
|
||||
leading: (text.match(/^(\s+)/) || [undefined])[0],
|
||||
trailing: (text.match(/(\s+)$/) || [undefined])[0]
|
||||
};
|
||||
}
|
||||
/**
|
||||
@internal
|
||||
*/
|
||||
isMarkAhead(parent, index, mark) {
|
||||
for (;; index++) {
|
||||
if (index >= parent.childCount)
|
||||
return false;
|
||||
let next = parent.child(index);
|
||||
if (next.type.name != this.options.hardBreakNodeName)
|
||||
return mark.isInSet(next.marks);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { MarkdownParser, MarkdownSerializer, MarkdownSerializerState, defaultMarkdownParser, defaultMarkdownSerializer, schema };
|
||||
40
node_modules/prosemirror-markdown/package.json
generated
vendored
Normal file
40
node_modules/prosemirror-markdown/package.json
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "prosemirror-markdown",
|
||||
"version": "1.13.4",
|
||||
"description": "ProseMirror Markdown integration",
|
||||
"type": "module",
|
||||
"main": "dist/index.cjs",
|
||||
"module": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"exports": {
|
||||
"import": "./dist/index.js",
|
||||
"require": "./dist/index.cjs"
|
||||
},
|
||||
"sideEffects": false,
|
||||
"license": "MIT",
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "Marijn Haverbeke",
|
||||
"email": "marijn@haverbeke.berlin",
|
||||
"web": "http://marijnhaverbeke.nl"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/prosemirror/prosemirror-markdown.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"markdown-it": "^14.0.0",
|
||||
"prosemirror-model": "^1.25.0",
|
||||
"@types/markdown-it": "^14.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@prosemirror/buildhelper": "^0.1.5",
|
||||
"prosemirror-test-builder": "^1.0.0",
|
||||
"punycode": "^1.4.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "pm-runtests",
|
||||
"prepare": "pm-buildhelper src/index.ts"
|
||||
}
|
||||
}
|
||||
42
node_modules/prosemirror-markdown/src/README.md
generated
vendored
Normal file
42
node_modules/prosemirror-markdown/src/README.md
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
# prosemirror-markdown
|
||||
|
||||
[ [**WEBSITE**](http://prosemirror.net) | [**ISSUES**](https://github.com/prosemirror/prosemirror-markdown/issues) | [**FORUM**](https://discuss.prosemirror.net) | [**GITTER**](https://gitter.im/ProseMirror/prosemirror) ]
|
||||
|
||||
This is a (non-core) module for [ProseMirror](http://prosemirror.net).
|
||||
ProseMirror is a well-behaved rich semantic content editor based on
|
||||
contentEditable, with support for collaborative editing and custom
|
||||
document schemas.
|
||||
|
||||
This module implements a ProseMirror
|
||||
[schema](https://prosemirror.net/docs/guide/#schema) that corresponds to
|
||||
the document schema used by [CommonMark](http://commonmark.org/), and
|
||||
a parser and serializer to convert between ProseMirror documents in
|
||||
that schema and CommonMark/Markdown text.
|
||||
|
||||
This code is released under an
|
||||
[MIT license](https://github.com/prosemirror/prosemirror/tree/master/LICENSE).
|
||||
There's a [forum](http://discuss.prosemirror.net) for general
|
||||
discussion and support requests, and the
|
||||
[Github bug tracker](https://github.com/prosemirror/prosemirror/issues)
|
||||
is the place to report issues.
|
||||
|
||||
We aim to be an inclusive, welcoming community. To make that explicit,
|
||||
we have a [code of
|
||||
conduct](http://contributor-covenant.org/version/1/1/0/) that applies
|
||||
to communication around the project.
|
||||
|
||||
## Documentation
|
||||
|
||||
@schema
|
||||
|
||||
@MarkdownParser
|
||||
|
||||
@ParseSpec
|
||||
|
||||
@defaultMarkdownParser
|
||||
|
||||
@MarkdownSerializer
|
||||
|
||||
@MarkdownSerializerState
|
||||
|
||||
@defaultMarkdownSerializer
|
||||
272
node_modules/prosemirror-markdown/src/from_markdown.ts
generated
vendored
Normal file
272
node_modules/prosemirror-markdown/src/from_markdown.ts
generated
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
// @ts-ignore
|
||||
import MarkdownIt from "markdown-it"
|
||||
import Token from "markdown-it/lib/token.mjs"
|
||||
import {schema} from "./schema"
|
||||
import {Mark, MarkType, Node, Attrs, Schema, NodeType} from "prosemirror-model"
|
||||
|
||||
function maybeMerge(a: Node, b: Node): Node | undefined {
|
||||
if (a.isText && b.isText && Mark.sameSet(a.marks, b.marks))
|
||||
return (a as any).withText(a.text! + b.text!)
|
||||
}
|
||||
|
||||
// Object used to track the context of a running parse.
|
||||
class MarkdownParseState {
|
||||
stack: {type: NodeType, attrs: Attrs | null, content: Node[], marks: readonly Mark[]}[]
|
||||
|
||||
constructor(
|
||||
readonly schema: Schema,
|
||||
readonly tokenHandlers: {[token: string]: (stat: MarkdownParseState, token: Token, tokens: Token[], i: number) => void}
|
||||
) {
|
||||
this.stack = [{type: schema.topNodeType, attrs: null, content: [], marks: Mark.none}]
|
||||
}
|
||||
|
||||
top() {
|
||||
return this.stack[this.stack.length - 1]
|
||||
}
|
||||
|
||||
push(elt: Node) {
|
||||
if (this.stack.length) this.top().content.push(elt)
|
||||
}
|
||||
|
||||
// Adds the given text to the current position in the document,
|
||||
// using the current marks as styling.
|
||||
addText(text: string) {
|
||||
if (!text) return
|
||||
let top = this.top(), nodes = top.content, last = nodes[nodes.length - 1]
|
||||
let node = this.schema.text(text, top.marks), merged
|
||||
if (last && (merged = maybeMerge(last, node))) nodes[nodes.length - 1] = merged
|
||||
else nodes.push(node)
|
||||
}
|
||||
|
||||
// Adds the given mark to the set of active marks.
|
||||
openMark(mark: Mark) {
|
||||
let top = this.top()
|
||||
top.marks = mark.addToSet(top.marks)
|
||||
}
|
||||
|
||||
// Removes the given mark from the set of active marks.
|
||||
closeMark(mark: MarkType) {
|
||||
let top = this.top()
|
||||
top.marks = mark.removeFromSet(top.marks)
|
||||
}
|
||||
|
||||
parseTokens(toks: Token[]) {
|
||||
for (let i = 0; i < toks.length; i++) {
|
||||
let tok = toks[i]
|
||||
let handler = this.tokenHandlers[tok.type]
|
||||
if (!handler)
|
||||
throw new Error("Token type `" + tok.type + "` not supported by Markdown parser")
|
||||
handler(this, tok, toks, i)
|
||||
}
|
||||
}
|
||||
|
||||
// Add a node at the current position.
|
||||
addNode(type: NodeType, attrs: Attrs | null, content?: readonly Node[]) {
|
||||
let top = this.top()
|
||||
let node = type.createAndFill(attrs, content, top ? top.marks : [])
|
||||
if (!node) return null
|
||||
this.push(node)
|
||||
return node
|
||||
}
|
||||
|
||||
// Wrap subsequent content in a node of the given type.
|
||||
openNode(type: NodeType, attrs: Attrs | null) {
|
||||
this.stack.push({type: type, attrs: attrs, content: [], marks: Mark.none})
|
||||
}
|
||||
|
||||
// Close and return the node that is currently on top of the stack.
|
||||
closeNode() {
|
||||
let info = this.stack.pop()!
|
||||
return this.addNode(info.type, info.attrs, info.content)
|
||||
}
|
||||
}
|
||||
|
||||
function attrs(spec: ParseSpec, token: Token, tokens: Token[], i: number) {
|
||||
if (spec.getAttrs) return spec.getAttrs(token, tokens, i)
|
||||
// For backwards compatibility when `attrs` is a Function
|
||||
else if (spec.attrs instanceof Function) return spec.attrs(token)
|
||||
else return spec.attrs
|
||||
}
|
||||
|
||||
// Code content is represented as a single token with a `content`
|
||||
// property in Markdown-it.
|
||||
function noCloseToken(spec: ParseSpec, type: string) {
|
||||
return spec.noCloseToken || type == "code_inline" || type == "code_block" || type == "fence"
|
||||
}
|
||||
|
||||
function withoutTrailingNewline(str: string) {
|
||||
return str[str.length - 1] == "\n" ? str.slice(0, str.length - 1) : str
|
||||
}
|
||||
|
||||
function noOp() {}
|
||||
|
||||
function tokenHandlers(schema: Schema, tokens: {[token: string]: ParseSpec}) {
|
||||
let handlers: {[token: string]: (stat: MarkdownParseState, token: Token, tokens: Token[], i: number) => void} =
|
||||
Object.create(null)
|
||||
for (let type in tokens) {
|
||||
let spec = tokens[type]
|
||||
if (spec.block) {
|
||||
let nodeType = schema.nodeType(spec.block)
|
||||
if (noCloseToken(spec, type)) {
|
||||
handlers[type] = (state, tok, tokens, i) => {
|
||||
state.openNode(nodeType, attrs(spec, tok, tokens, i))
|
||||
state.addText(withoutTrailingNewline(tok.content))
|
||||
state.closeNode()
|
||||
}
|
||||
} else {
|
||||
handlers[type + "_open"] = (state, tok, tokens, i) => state.openNode(nodeType, attrs(spec, tok, tokens, i))
|
||||
handlers[type + "_close"] = state => state.closeNode()
|
||||
}
|
||||
} else if (spec.node) {
|
||||
let nodeType = schema.nodeType(spec.node)
|
||||
handlers[type] = (state, tok, tokens, i) => state.addNode(nodeType, attrs(spec, tok, tokens, i))
|
||||
} else if (spec.mark) {
|
||||
let markType = schema.marks[spec.mark]
|
||||
if (noCloseToken(spec, type)) {
|
||||
handlers[type] = (state, tok, tokens, i) => {
|
||||
state.openMark(markType.create(attrs(spec, tok, tokens, i)))
|
||||
state.addText(withoutTrailingNewline(tok.content))
|
||||
state.closeMark(markType)
|
||||
}
|
||||
} else {
|
||||
handlers[type + "_open"] = (state, tok, tokens, i) => state.openMark(markType.create(attrs(spec, tok, tokens, i)))
|
||||
handlers[type + "_close"] = state => state.closeMark(markType)
|
||||
}
|
||||
} else if (spec.ignore) {
|
||||
if (noCloseToken(spec, type)) {
|
||||
handlers[type] = noOp
|
||||
} else {
|
||||
handlers[type + "_open"] = noOp
|
||||
handlers[type + "_close"] = noOp
|
||||
}
|
||||
} else {
|
||||
throw new RangeError("Unrecognized parsing spec " + JSON.stringify(spec))
|
||||
}
|
||||
}
|
||||
|
||||
handlers.text = (state, tok) => state.addText(tok.content)
|
||||
handlers.inline = (state, tok) => state.parseTokens(tok.children!)
|
||||
handlers.softbreak = handlers.softbreak || (state => state.addText(" "))
|
||||
|
||||
return handlers
|
||||
}
|
||||
|
||||
/// Object type used to specify how Markdown tokens should be parsed.
|
||||
export interface ParseSpec {
|
||||
/// This token maps to a single node, whose type can be looked up
|
||||
/// in the schema under the given name. Exactly one of `node`,
|
||||
/// `block`, or `mark` must be set.
|
||||
node?: string
|
||||
|
||||
/// This token (unless `noCloseToken` is true) comes in `_open`
|
||||
/// and `_close` variants (which are appended to the base token
|
||||
/// name provides a the object property), and wraps a block of
|
||||
/// content. The block should be wrapped in a node of the type
|
||||
/// named to by the property's value. If the token does not have
|
||||
/// `_open` or `_close`, use the `noCloseToken` option.
|
||||
block?: string
|
||||
|
||||
/// This token (again, unless `noCloseToken` is true) also comes
|
||||
/// in `_open` and `_close` variants, but should add a mark
|
||||
/// (named by the value) to its content, rather than wrapping it
|
||||
/// in a node.
|
||||
mark?: string
|
||||
|
||||
/// Attributes for the node or mark. When `getAttrs` is provided,
|
||||
/// it takes precedence.
|
||||
attrs?: Attrs | null
|
||||
|
||||
/// A function used to compute the attributes for the node or mark
|
||||
/// that takes a [markdown-it
|
||||
/// token](https://markdown-it.github.io/markdown-it/#Token) and
|
||||
/// returns an attribute object.
|
||||
getAttrs?: (token: Token, tokenStream: Token[], index: number) => Attrs | null
|
||||
|
||||
/// Indicates that the [markdown-it
|
||||
/// token](https://markdown-it.github.io/markdown-it/#Token) has
|
||||
/// no `_open` or `_close` for the nodes. This defaults to `true`
|
||||
/// for `code_inline`, `code_block` and `fence`.
|
||||
noCloseToken?: boolean
|
||||
|
||||
/// When true, ignore content for the matched token.
|
||||
ignore?: boolean
|
||||
}
|
||||
|
||||
/// A configuration of a Markdown parser. Such a parser uses
|
||||
/// [markdown-it](https://github.com/markdown-it/markdown-it) to
|
||||
/// tokenize a file, and then runs the custom rules it is given over
|
||||
/// the tokens to create a ProseMirror document tree.
|
||||
export class MarkdownParser {
|
||||
/// @internal
|
||||
tokenHandlers: {[token: string]: (stat: MarkdownParseState, token: Token, tokens: Token[], i: number) => void}
|
||||
|
||||
/// Create a parser with the given configuration. You can configure
|
||||
/// the markdown-it parser to parse the dialect you want, and provide
|
||||
/// a description of the ProseMirror entities those tokens map to in
|
||||
/// the `tokens` object, which maps token names to descriptions of
|
||||
/// what to do with them. Such a description is an object, and may
|
||||
/// have the following properties:
|
||||
constructor(
|
||||
/// The parser's document schema.
|
||||
readonly schema: Schema,
|
||||
/// This parser's markdown-it tokenizer.
|
||||
readonly tokenizer: MarkdownIt,
|
||||
/// The value of the `tokens` object used to construct this
|
||||
/// parser. Can be useful to copy and modify to base other parsers
|
||||
/// on.
|
||||
readonly tokens: {[name: string]: ParseSpec}
|
||||
) {
|
||||
this.tokenHandlers = tokenHandlers(schema, tokens)
|
||||
}
|
||||
|
||||
/// Parse a string as [CommonMark](http://commonmark.org/) markup,
|
||||
/// and create a ProseMirror document as prescribed by this parser's
|
||||
/// rules.
|
||||
///
|
||||
/// The second argument, when given, is passed through to the
|
||||
/// [Markdown
|
||||
/// parser](https://markdown-it.github.io/markdown-it/#MarkdownIt.parse).
|
||||
parse(text: string, markdownEnv: Object = {}) {
|
||||
let state = new MarkdownParseState(this.schema, this.tokenHandlers), doc
|
||||
state.parseTokens(this.tokenizer.parse(text, markdownEnv))
|
||||
do { doc = state.closeNode() } while (state.stack.length)
|
||||
return doc || this.schema.topNodeType.createAndFill()!
|
||||
}
|
||||
}
|
||||
|
||||
function listIsTight(tokens: readonly Token[], i: number) {
|
||||
while (++i < tokens.length)
|
||||
if (tokens[i].type != "list_item_open") return tokens[i].hidden
|
||||
return false
|
||||
}
|
||||
|
||||
/// A parser parsing unextended [CommonMark](http://commonmark.org/),
|
||||
/// without inline HTML, and producing a document in the basic schema.
|
||||
export const defaultMarkdownParser = new MarkdownParser(schema, MarkdownIt("commonmark", {html: false}), {
|
||||
blockquote: {block: "blockquote"},
|
||||
paragraph: {block: "paragraph"},
|
||||
list_item: {block: "list_item"},
|
||||
bullet_list: {block: "bullet_list", getAttrs: (_, tokens, i) => ({tight: listIsTight(tokens, i)})},
|
||||
ordered_list: {block: "ordered_list", getAttrs: (tok, tokens, i) => ({
|
||||
order: +tok.attrGet("start")! || 1,
|
||||
tight: listIsTight(tokens, i)
|
||||
})},
|
||||
heading: {block: "heading", getAttrs: tok => ({level: +tok.tag.slice(1)})},
|
||||
code_block: {block: "code_block", noCloseToken: true},
|
||||
fence: {block: "code_block", getAttrs: tok => ({params: tok.info || ""}), noCloseToken: true},
|
||||
hr: {node: "horizontal_rule"},
|
||||
image: {node: "image", getAttrs: tok => ({
|
||||
src: tok.attrGet("src"),
|
||||
title: tok.attrGet("title") || null,
|
||||
alt: tok.children![0] && tok.children![0].content || null
|
||||
})},
|
||||
hardbreak: {node: "hard_break"},
|
||||
|
||||
em: {mark: "em"},
|
||||
strong: {mark: "strong"},
|
||||
link: {mark: "link", getAttrs: tok => ({
|
||||
href: tok.attrGet("href"),
|
||||
title: tok.attrGet("title") || null
|
||||
})},
|
||||
code_inline: {mark: "code", noCloseToken: true}
|
||||
})
|
||||
5
node_modules/prosemirror-markdown/src/index.ts
generated
vendored
Normal file
5
node_modules/prosemirror-markdown/src/index.ts
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
// Defines a parser and serializer for [CommonMark](http://commonmark.org/) text.
|
||||
|
||||
export {schema} from "./schema"
|
||||
export {defaultMarkdownParser, MarkdownParser, ParseSpec} from "./from_markdown"
|
||||
export {MarkdownSerializer, defaultMarkdownSerializer, MarkdownSerializerState} from "./to_markdown"
|
||||
156
node_modules/prosemirror-markdown/src/schema.ts
generated
vendored
Normal file
156
node_modules/prosemirror-markdown/src/schema.ts
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
import {Schema, MarkSpec} from "prosemirror-model"
|
||||
|
||||
/// Document schema for the data model used by CommonMark.
|
||||
export const schema = new Schema({
|
||||
nodes: {
|
||||
doc: {
|
||||
content: "block+"
|
||||
},
|
||||
|
||||
paragraph: {
|
||||
content: "inline*",
|
||||
group: "block",
|
||||
parseDOM: [{tag: "p"}],
|
||||
toDOM() { return ["p", 0] }
|
||||
},
|
||||
|
||||
blockquote: {
|
||||
content: "block+",
|
||||
group: "block",
|
||||
parseDOM: [{tag: "blockquote"}],
|
||||
toDOM() { return ["blockquote", 0] }
|
||||
},
|
||||
|
||||
horizontal_rule: {
|
||||
group: "block",
|
||||
parseDOM: [{tag: "hr"}],
|
||||
toDOM() { return ["div", ["hr"]] }
|
||||
},
|
||||
|
||||
heading: {
|
||||
attrs: {level: {default: 1}},
|
||||
content: "(text | image)*",
|
||||
group: "block",
|
||||
defining: true,
|
||||
parseDOM: [{tag: "h1", attrs: {level: 1}},
|
||||
{tag: "h2", attrs: {level: 2}},
|
||||
{tag: "h3", attrs: {level: 3}},
|
||||
{tag: "h4", attrs: {level: 4}},
|
||||
{tag: "h5", attrs: {level: 5}},
|
||||
{tag: "h6", attrs: {level: 6}}],
|
||||
toDOM(node) { return ["h" + node.attrs.level, 0] }
|
||||
},
|
||||
|
||||
code_block: {
|
||||
content: "text*",
|
||||
group: "block",
|
||||
code: true,
|
||||
defining: true,
|
||||
marks: "",
|
||||
attrs: {params: {default: ""}},
|
||||
parseDOM: [{tag: "pre", preserveWhitespace: "full", getAttrs: node => (
|
||||
{params: (node as HTMLElement).getAttribute("data-params") || ""}
|
||||
)}],
|
||||
toDOM(node) { return ["pre", node.attrs.params ? {"data-params": node.attrs.params} : {}, ["code", 0]] }
|
||||
},
|
||||
|
||||
ordered_list: {
|
||||
content: "list_item+",
|
||||
group: "block",
|
||||
attrs: {order: {default: 1}, tight: {default: false}},
|
||||
parseDOM: [{tag: "ol", getAttrs(dom) {
|
||||
return {order: (dom as HTMLElement).hasAttribute("start") ? +(dom as HTMLElement).getAttribute("start")! : 1,
|
||||
tight: (dom as HTMLElement).hasAttribute("data-tight")}
|
||||
}}],
|
||||
toDOM(node) {
|
||||
return ["ol", {start: node.attrs.order == 1 ? null : node.attrs.order,
|
||||
"data-tight": node.attrs.tight ? "true" : null}, 0]
|
||||
}
|
||||
},
|
||||
|
||||
bullet_list: {
|
||||
content: "list_item+",
|
||||
group: "block",
|
||||
attrs: {tight: {default: false}},
|
||||
parseDOM: [{tag: "ul", getAttrs: dom => ({tight: (dom as HTMLElement).hasAttribute("data-tight")})}],
|
||||
toDOM(node) { return ["ul", {"data-tight": node.attrs.tight ? "true" : null}, 0] }
|
||||
},
|
||||
|
||||
list_item: {
|
||||
content: "block+",
|
||||
defining: true,
|
||||
parseDOM: [{tag: "li"}],
|
||||
toDOM() { return ["li", 0] }
|
||||
},
|
||||
|
||||
text: {
|
||||
group: "inline"
|
||||
},
|
||||
|
||||
image: {
|
||||
inline: true,
|
||||
attrs: {
|
||||
src: {},
|
||||
alt: {default: null},
|
||||
title: {default: null}
|
||||
},
|
||||
group: "inline",
|
||||
draggable: true,
|
||||
parseDOM: [{tag: "img[src]", getAttrs(dom) {
|
||||
return {
|
||||
src: (dom as HTMLElement).getAttribute("src"),
|
||||
title: (dom as HTMLElement).getAttribute("title"),
|
||||
alt: (dom as HTMLElement).getAttribute("alt")
|
||||
}
|
||||
}}],
|
||||
toDOM(node) { return ["img", node.attrs] }
|
||||
},
|
||||
|
||||
hard_break: {
|
||||
inline: true,
|
||||
group: "inline",
|
||||
selectable: false,
|
||||
parseDOM: [{tag: "br"}],
|
||||
toDOM() { return ["br"] }
|
||||
}
|
||||
},
|
||||
|
||||
marks: {
|
||||
em: {
|
||||
parseDOM: [
|
||||
{tag: "i"}, {tag: "em"},
|
||||
{style: "font-style=italic"},
|
||||
{style: "font-style=normal", clearMark: m => m.type.name == "em"}
|
||||
],
|
||||
toDOM() { return ["em"] }
|
||||
},
|
||||
|
||||
strong: {
|
||||
parseDOM: [
|
||||
{tag: "strong"},
|
||||
{tag: "b", getAttrs: node => node.style.fontWeight != "normal" && null},
|
||||
{style: "font-weight=400", clearMark: m => m.type.name == "strong"},
|
||||
{style: "font-weight", getAttrs: value => /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null}
|
||||
],
|
||||
toDOM() { return ["strong"] }
|
||||
} as MarkSpec,
|
||||
|
||||
link: {
|
||||
attrs: {
|
||||
href: {},
|
||||
title: {default: null}
|
||||
},
|
||||
inclusive: false,
|
||||
parseDOM: [{tag: "a[href]", getAttrs(dom) {
|
||||
return {href: (dom as HTMLElement).getAttribute("href"), title: dom.getAttribute("title")}
|
||||
}}],
|
||||
toDOM(node) { return ["a", node.attrs] }
|
||||
},
|
||||
|
||||
code: {
|
||||
code: true,
|
||||
parseDOM: [{tag: "code"}],
|
||||
toDOM() { return ["code"] }
|
||||
}
|
||||
}
|
||||
})
|
||||
483
node_modules/prosemirror-markdown/src/to_markdown.ts
generated
vendored
Normal file
483
node_modules/prosemirror-markdown/src/to_markdown.ts
generated
vendored
Normal file
@@ -0,0 +1,483 @@
|
||||
import {Node, Mark} from "prosemirror-model"
|
||||
|
||||
type MarkSerializerSpec = {
|
||||
/// The string that should appear before a piece of content marked
|
||||
/// by this mark, either directly or as a function that returns an
|
||||
/// appropriate string.
|
||||
open: string | ((state: MarkdownSerializerState, mark: Mark, parent: Node, index: number) => string),
|
||||
/// The string that should appear after a piece of content marked by
|
||||
/// this mark.
|
||||
close: string | ((state: MarkdownSerializerState, mark: Mark, parent: Node, index: number) => string),
|
||||
/// When `true`, this indicates that the order in which the mark's
|
||||
/// opening and closing syntax appears relative to other mixable
|
||||
/// marks can be varied. (For example, you can say `**a *b***` and
|
||||
/// `*a **b***`, but not `` `a *b*` ``.)
|
||||
mixable?: boolean,
|
||||
/// When enabled, causes the serializer to move enclosing whitespace
|
||||
/// from inside the marks to outside the marks. This is necessary
|
||||
/// for emphasis marks as CommonMark does not permit enclosing
|
||||
/// whitespace inside emphasis marks, see:
|
||||
/// http:///spec.commonmark.org/0.26/#example-330
|
||||
expelEnclosingWhitespace?: boolean,
|
||||
/// Can be set to `false` to disable character escaping in a mark. A
|
||||
/// non-escaping mark has to have the highest precedence (must
|
||||
/// always be the innermost mark).
|
||||
escape?: boolean
|
||||
}
|
||||
|
||||
const blankMark: MarkSerializerSpec = {open: "", close: "", mixable: true}
|
||||
|
||||
/// A specification for serializing a ProseMirror document as
|
||||
/// Markdown/CommonMark text.
|
||||
export class MarkdownSerializer {
|
||||
/// Construct a serializer with the given configuration. The `nodes`
|
||||
/// object should map node names in a given schema to function that
|
||||
/// take a serializer state and such a node, and serialize the node.
|
||||
constructor(
|
||||
/// The node serializer functions for this serializer.
|
||||
readonly nodes: {[node: string]: (state: MarkdownSerializerState, node: Node, parent: Node, index: number) => void},
|
||||
/// The mark serializer info.
|
||||
readonly marks: {[mark: string]: MarkSerializerSpec},
|
||||
readonly options: {
|
||||
/// Extra characters can be added for escaping. This is passed
|
||||
/// directly to String.replace(), and the matching characters are
|
||||
/// preceded by a backslash.
|
||||
escapeExtraCharacters?: RegExp,
|
||||
/// Specify the node name of hard breaks.
|
||||
/// Defaults to "hard_break"
|
||||
hardBreakNodeName?: string,
|
||||
/// By default, the serializer raises an error when it finds a
|
||||
/// node or mark type for which no serializer is defined. Set
|
||||
/// this to `false` to make it just ignore such elements,
|
||||
/// rendering only their content.
|
||||
strict?: boolean
|
||||
} = {}
|
||||
) {}
|
||||
|
||||
/// Serialize the content of the given node to
|
||||
/// [CommonMark](http://commonmark.org/).
|
||||
serialize(content: Node, options: {
|
||||
/// Whether to render lists in a tight style. This can be overridden
|
||||
/// on a node level by specifying a tight attribute on the node.
|
||||
/// Defaults to false.
|
||||
tightLists?: boolean
|
||||
} = {}) {
|
||||
options = Object.assign({}, this.options, options)
|
||||
let state = new MarkdownSerializerState(this.nodes, this.marks, options)
|
||||
state.renderContent(content)
|
||||
return state.out
|
||||
}
|
||||
}
|
||||
|
||||
/// A serializer for the [basic schema](#schema).
|
||||
export const defaultMarkdownSerializer = new MarkdownSerializer({
|
||||
blockquote(state, node) {
|
||||
state.wrapBlock("> ", null, node, () => state.renderContent(node))
|
||||
},
|
||||
code_block(state, node) {
|
||||
// Make sure the front matter fences are longer than any dash sequence within it
|
||||
const backticks = node.textContent.match(/`{3,}/gm)
|
||||
const fence = backticks ? (backticks.sort().slice(-1)[0] + "`") : "```"
|
||||
|
||||
state.write(fence + (node.attrs.params || "") + "\n")
|
||||
state.text(node.textContent, false)
|
||||
// Add a newline to the current content before adding closing marker
|
||||
state.write("\n")
|
||||
state.write(fence)
|
||||
state.closeBlock(node)
|
||||
},
|
||||
heading(state, node) {
|
||||
state.write(state.repeat("#", node.attrs.level) + " ")
|
||||
state.renderInline(node, false)
|
||||
state.closeBlock(node)
|
||||
},
|
||||
horizontal_rule(state, node) {
|
||||
state.write(node.attrs.markup || "---")
|
||||
state.closeBlock(node)
|
||||
},
|
||||
bullet_list(state, node) {
|
||||
state.renderList(node, " ", () => (node.attrs.bullet || "*") + " ")
|
||||
},
|
||||
ordered_list(state, node) {
|
||||
let start = node.attrs.order || 1
|
||||
let maxW = String(start + node.childCount - 1).length
|
||||
let space = state.repeat(" ", maxW + 2)
|
||||
state.renderList(node, space, i => {
|
||||
let nStr = String(start + i)
|
||||
return state.repeat(" ", maxW - nStr.length) + nStr + ". "
|
||||
})
|
||||
},
|
||||
list_item(state, node) {
|
||||
state.renderContent(node)
|
||||
},
|
||||
paragraph(state, node) {
|
||||
state.renderInline(node)
|
||||
state.closeBlock(node)
|
||||
},
|
||||
|
||||
image(state, node) {
|
||||
state.write("]/g, "\\$&") +
|
||||
(node.attrs.title ? ' "' + node.attrs.title.replace(/"/g, '\\"') + '"' : "") + ")")
|
||||
},
|
||||
hard_break(state, node, parent, index) {
|
||||
for (let i = index + 1; i < parent.childCount; i++)
|
||||
if (parent.child(i).type != node.type) {
|
||||
state.write("\\\n")
|
||||
return
|
||||
}
|
||||
},
|
||||
text(state, node) {
|
||||
state.text(node.text!, !state.inAutolink)
|
||||
}
|
||||
}, {
|
||||
em: {open: "*", close: "*", mixable: true, expelEnclosingWhitespace: true},
|
||||
strong: {open: "**", close: "**", mixable: true, expelEnclosingWhitespace: true},
|
||||
link: {
|
||||
open(state, mark, parent, index) {
|
||||
state.inAutolink = isPlainURL(mark, parent, index)
|
||||
return state.inAutolink ? "<" : "["
|
||||
},
|
||||
close(state, mark, parent, index) {
|
||||
let {inAutolink} = state
|
||||
state.inAutolink = undefined
|
||||
return inAutolink ? ">"
|
||||
: "](" + mark.attrs.href.replace(/[\(\)"]/g, "\\$&") + (mark.attrs.title ? ` "${mark.attrs.title.replace(/"/g, '\\"')}"` : "") + ")"
|
||||
},
|
||||
mixable: true
|
||||
},
|
||||
code: {open(_state, _mark, parent, index) { return backticksFor(parent.child(index), -1) },
|
||||
close(_state, _mark, parent, index) { return backticksFor(parent.child(index - 1), 1) },
|
||||
escape: false}
|
||||
})
|
||||
|
||||
function backticksFor(node: Node, side: number) {
|
||||
let ticks = /`+/g, m: RegExpExecArray | null, len = 0
|
||||
if (node.isText) while (m = ticks.exec(node.text!)) len = Math.max(len, m[0].length)
|
||||
let result = len > 0 && side > 0 ? " `" : "`"
|
||||
for (let i = 0; i < len; i++) result += "`"
|
||||
if (len > 0 && side < 0) result += " "
|
||||
return result
|
||||
}
|
||||
|
||||
function isPlainURL(link: Mark, parent: Node, index: number) {
|
||||
if (link.attrs.title || !/^\w+:/.test(link.attrs.href)) return false
|
||||
let content = parent.child(index)
|
||||
if (!content.isText || content.text != link.attrs.href || content.marks[content.marks.length - 1] != link) return false
|
||||
return index == parent.childCount - 1 || !link.isInSet(parent.child(index + 1).marks)
|
||||
}
|
||||
|
||||
/// This is an object used to track state and expose
|
||||
/// methods related to markdown serialization. Instances are passed to
|
||||
/// node and mark serialization methods (see `toMarkdown`).
|
||||
export class MarkdownSerializerState {
|
||||
/// @internal
|
||||
delim: string = ""
|
||||
/// @internal
|
||||
out: string = ""
|
||||
/// @internal
|
||||
closed: Node | null = null
|
||||
/// @internal
|
||||
inAutolink: boolean | undefined = undefined
|
||||
/// @internal
|
||||
atBlockStart: boolean = false
|
||||
/// @internal
|
||||
inTightList: boolean = false
|
||||
|
||||
/// @internal
|
||||
constructor(
|
||||
/// @internal
|
||||
readonly nodes: {[node: string]: (state: MarkdownSerializerState, node: Node, parent: Node, index: number) => void},
|
||||
/// @internal
|
||||
readonly marks: {[mark: string]: MarkSerializerSpec},
|
||||
/// The options passed to the serializer.
|
||||
readonly options: {tightLists?: boolean, escapeExtraCharacters?: RegExp, hardBreakNodeName?: string, strict?: boolean}
|
||||
) {
|
||||
if (typeof this.options.tightLists == "undefined")
|
||||
this.options.tightLists = false
|
||||
if (typeof this.options.hardBreakNodeName == "undefined")
|
||||
this.options.hardBreakNodeName = "hard_break"
|
||||
}
|
||||
|
||||
/// @internal
|
||||
flushClose(size: number = 2) {
|
||||
if (this.closed) {
|
||||
if (!this.atBlank()) this.out += "\n"
|
||||
if (size > 1) {
|
||||
let delimMin = this.delim
|
||||
let trim = /\s+$/.exec(delimMin)
|
||||
if (trim) delimMin = delimMin.slice(0, delimMin.length - trim[0].length)
|
||||
for (let i = 1; i < size; i++)
|
||||
this.out += delimMin + "\n"
|
||||
}
|
||||
this.closed = null
|
||||
}
|
||||
}
|
||||
|
||||
/// @internal
|
||||
getMark(name: string) {
|
||||
let info = this.marks[name]
|
||||
if (!info) {
|
||||
if (this.options.strict !== false)
|
||||
throw new Error(`Mark type \`${name}\` not supported by Markdown renderer`)
|
||||
info = blankMark
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
/// Render a block, prefixing each line with `delim`, and the first
|
||||
/// line in `firstDelim`. `node` should be the node that is closed at
|
||||
/// the end of the block, and `f` is a function that renders the
|
||||
/// content of the block.
|
||||
wrapBlock(delim: string, firstDelim: string | null, node: Node, f: () => void) {
|
||||
let old = this.delim
|
||||
this.write(firstDelim != null ? firstDelim : delim)
|
||||
this.delim += delim
|
||||
f()
|
||||
this.delim = old
|
||||
this.closeBlock(node)
|
||||
}
|
||||
|
||||
/// @internal
|
||||
atBlank() {
|
||||
return /(^|\n)$/.test(this.out)
|
||||
}
|
||||
|
||||
/// Ensure the current content ends with a newline.
|
||||
ensureNewLine() {
|
||||
if (!this.atBlank()) this.out += "\n"
|
||||
}
|
||||
|
||||
/// Prepare the state for writing output (closing closed paragraphs,
|
||||
/// adding delimiters, and so on), and then optionally add content
|
||||
/// (unescaped) to the output.
|
||||
write(content?: string) {
|
||||
this.flushClose()
|
||||
if (this.delim && this.atBlank())
|
||||
this.out += this.delim
|
||||
if (content) this.out += content
|
||||
}
|
||||
|
||||
/// Close the block for the given node.
|
||||
closeBlock(node: Node) {
|
||||
this.closed = node
|
||||
}
|
||||
|
||||
/// Add the given text to the document. When escape is not `false`,
|
||||
/// it will be escaped.
|
||||
text(text: string, escape = true) {
|
||||
let lines = text.split("\n")
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
this.write()
|
||||
// Escape exclamation marks in front of links
|
||||
if (!escape && lines[i][0] == "[" && /(^|[^\\])\!$/.test(this.out))
|
||||
this.out = this.out.slice(0, this.out.length - 1) + "\\!"
|
||||
this.out += escape ? this.esc(lines[i], this.atBlockStart) : lines[i]
|
||||
if (i != lines.length - 1) this.out += "\n"
|
||||
}
|
||||
}
|
||||
|
||||
/// Render the given node as a block.
|
||||
render(node: Node, parent: Node, index: number) {
|
||||
if (this.nodes[node.type.name]) {
|
||||
this.nodes[node.type.name](this, node, parent, index)
|
||||
} else {
|
||||
if (this.options.strict !== false) {
|
||||
throw new Error("Token type `" + node.type.name + "` not supported by Markdown renderer")
|
||||
} else if (!node.type.isLeaf) {
|
||||
if (node.type.inlineContent) this.renderInline(node)
|
||||
else this.renderContent(node)
|
||||
if (node.isBlock) this.closeBlock(node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Render the contents of `parent` as block nodes.
|
||||
renderContent(parent: Node) {
|
||||
parent.forEach((node, _, i) => this.render(node, parent, i))
|
||||
}
|
||||
|
||||
/// Render the contents of `parent` as inline content.
|
||||
renderInline(parent: Node, fromBlockStart = true) {
|
||||
this.atBlockStart = fromBlockStart
|
||||
let active: Mark[] = [], trailing = ""
|
||||
let progress = (node: Node | null, offset: number, index: number) => {
|
||||
let marks = node ? node.marks : []
|
||||
|
||||
// Remove marks from `hard_break` that are the last node inside
|
||||
// that mark to prevent parser edge cases with new lines just
|
||||
// before closing marks.
|
||||
if (node && node.type.name === this.options.hardBreakNodeName)
|
||||
marks = marks.filter(m => {
|
||||
if (index + 1 == parent.childCount) return false
|
||||
let next = parent.child(index + 1)
|
||||
return m.isInSet(next.marks) && (!next.isText || /\S/.test(next.text!))
|
||||
})
|
||||
|
||||
let leading = trailing
|
||||
trailing = ""
|
||||
// If whitespace has to be expelled from the node, adjust
|
||||
// leading and trailing accordingly.
|
||||
if (node && node.isText && marks.some(mark => {
|
||||
let info = this.getMark(mark.type.name)
|
||||
return info && info.expelEnclosingWhitespace && !mark.isInSet(active)
|
||||
})) {
|
||||
let [_, lead, rest] = /^(\s*)(.*)$/m.exec(node.text!)!
|
||||
if (lead) {
|
||||
leading += lead
|
||||
node = rest ? (node as any).withText(rest) : null
|
||||
if (!node) marks = active
|
||||
}
|
||||
}
|
||||
if (node && node.isText && marks.some(mark => {
|
||||
let info = this.getMark(mark.type.name)
|
||||
return info && info.expelEnclosingWhitespace && !this.isMarkAhead(parent, index + 1, mark)
|
||||
})) {
|
||||
let [_, rest, trail] = /^(.*?)(\s*)$/m.exec(node.text!)!
|
||||
if (trail) {
|
||||
trailing = trail
|
||||
node = rest ? (node as any).withText(rest) : null
|
||||
if (!node) marks = active
|
||||
}
|
||||
}
|
||||
let inner = marks.length ? marks[marks.length - 1] : null
|
||||
let noEsc = inner && this.getMark(inner.type.name).escape === false
|
||||
let len = marks.length - (noEsc ? 1 : 0)
|
||||
|
||||
// Try to reorder 'mixable' marks, such as em and strong, which
|
||||
// in Markdown may be opened and closed in different order, so
|
||||
// that order of the marks for the token matches the order in
|
||||
// active.
|
||||
outer: for (let i = 0; i < len; i++) {
|
||||
let mark = marks[i]
|
||||
if (!this.getMark(mark.type.name).mixable) break
|
||||
for (let j = 0; j < active.length; j++) {
|
||||
let other = active[j]
|
||||
if (!this.getMark(other.type.name).mixable) break
|
||||
if (mark.eq(other)) {
|
||||
if (i > j)
|
||||
marks = marks.slice(0, j).concat(mark).concat(marks.slice(j, i)).concat(marks.slice(i + 1, len))
|
||||
else if (j > i)
|
||||
marks = marks.slice(0, i).concat(marks.slice(i + 1, j)).concat(mark).concat(marks.slice(j, len))
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the prefix of the mark set that didn't change
|
||||
let keep = 0
|
||||
while (keep < Math.min(active.length, len) && marks[keep].eq(active[keep])) ++keep
|
||||
|
||||
// Close the marks that need to be closed
|
||||
while (keep < active.length)
|
||||
this.text(this.markString(active.pop()!, false, parent, index), false)
|
||||
|
||||
// Output any previously expelled trailing whitespace outside the marks
|
||||
if (leading) this.text(leading)
|
||||
|
||||
// Open the marks that need to be opened
|
||||
if (node) {
|
||||
while (active.length < len) {
|
||||
let add = marks[active.length]
|
||||
active.push(add)
|
||||
this.text(this.markString(add, true, parent, index), false)
|
||||
this.atBlockStart = false
|
||||
}
|
||||
|
||||
// Render the node. Special case code marks, since their content
|
||||
// may not be escaped.
|
||||
if (noEsc && node.isText)
|
||||
this.text(this.markString(inner!, true, parent, index) + node.text +
|
||||
this.markString(inner!, false, parent, index + 1), false)
|
||||
else
|
||||
this.render(node, parent, index)
|
||||
this.atBlockStart = false
|
||||
}
|
||||
|
||||
// After the first non-empty text node is rendered, the end of output
|
||||
// is no longer at block start.
|
||||
//
|
||||
// FIXME: If a non-text node writes something to the output for this
|
||||
// block, the end of output is also no longer at block start. But how
|
||||
// can we detect that?
|
||||
if (node?.isText && node.nodeSize > 0) {
|
||||
this.atBlockStart = false
|
||||
}
|
||||
}
|
||||
parent.forEach(progress)
|
||||
progress(null, 0, parent.childCount)
|
||||
this.atBlockStart = false
|
||||
}
|
||||
|
||||
/// Render a node's content as a list. `delim` should be the extra
|
||||
/// indentation added to all lines except the first in an item,
|
||||
/// `firstDelim` is a function going from an item index to a
|
||||
/// delimiter for the first line of the item.
|
||||
renderList(node: Node, delim: string, firstDelim: (index: number) => string) {
|
||||
if (this.closed && this.closed.type == node.type)
|
||||
this.flushClose(3)
|
||||
else if (this.inTightList)
|
||||
this.flushClose(1)
|
||||
|
||||
let isTight = typeof node.attrs.tight != "undefined" ? node.attrs.tight : this.options.tightLists
|
||||
let prevTight = this.inTightList
|
||||
this.inTightList = isTight
|
||||
node.forEach((child, _, i) => {
|
||||
if (i && isTight) this.flushClose(1)
|
||||
this.wrapBlock(delim, firstDelim(i), node, () => this.render(child, node, i))
|
||||
})
|
||||
this.inTightList = prevTight
|
||||
}
|
||||
|
||||
/// Escape the given string so that it can safely appear in Markdown
|
||||
/// content. If `startOfLine` is true, also escape characters that
|
||||
/// have special meaning only at the start of the line.
|
||||
esc(str: string, startOfLine = false) {
|
||||
str = str.replace(
|
||||
/[`*\\~\[\]_]/g,
|
||||
(m, i) => m == "_" && i > 0 && i + 1 < str.length && str[i-1].match(/\w/) && str[i+1].match(/\w/) ? m : "\\" + m
|
||||
)
|
||||
if (startOfLine) str = str.replace(/^(\+[ ]|[\-*>])/, "\\$&").replace(/^(\s*)(#{1,6})(\s|$)/, '$1\\$2$3').replace(/^(\s*\d+)\.\s/, "$1\\. ")
|
||||
if (this.options.escapeExtraCharacters) str = str.replace(this.options.escapeExtraCharacters, "\\$&")
|
||||
return str
|
||||
}
|
||||
|
||||
/// @internal
|
||||
quote(str: string) {
|
||||
let wrap = str.indexOf('"') == -1 ? '""' : str.indexOf("'") == -1 ? "''" : "()"
|
||||
return wrap[0] + str + wrap[1]
|
||||
}
|
||||
|
||||
/// Repeat the given string `n` times.
|
||||
repeat(str: string, n: number) {
|
||||
let out = ""
|
||||
for (let i = 0; i < n; i++) out += str
|
||||
return out
|
||||
}
|
||||
|
||||
/// Get the markdown string for a given opening or closing mark.
|
||||
markString(mark: Mark, open: boolean, parent: Node, index: number) {
|
||||
let info = this.getMark(mark.type.name)
|
||||
let value = open ? info.open : info.close
|
||||
return typeof value == "string" ? value : value(this, mark, parent, index)
|
||||
}
|
||||
|
||||
/// Get leading and trailing whitespace from a string. Values of
|
||||
/// leading or trailing property of the return object will be undefined
|
||||
/// if there is no match.
|
||||
getEnclosingWhitespace(text: string): {leading?: string, trailing?: string} {
|
||||
return {
|
||||
leading: (text.match(/^(\s+)/) || [undefined])[0],
|
||||
trailing: (text.match(/(\s+)$/) || [undefined])[0]
|
||||
}
|
||||
}
|
||||
|
||||
/// @internal
|
||||
isMarkAhead(parent: Node, index: number, mark: Mark) {
|
||||
for (;; index++) {
|
||||
if (index >= parent.childCount) return false
|
||||
let next = parent.child(index)
|
||||
if (next.type.name != this.options.hardBreakNodeName) return mark.isInSet(next.marks)
|
||||
index++
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user