Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
S
sfm-js
Manage
Activity
Members
Labels
Plan
Issues
2
Issue boards
Milestones
Iterations
Wiki
Requirements
Code
Merge requests
0
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
TransFem.org
sfm-js
Commits
a8ef16e8
Commit
a8ef16e8
authored
11 months ago
by
Septicake
Browse files
Options
Downloads
Patches
Plain Diff
Added documentation
parent
079b0dd6
No related branches found
No related tags found
2 merge requests
!9
Bump version to 0.24.6 and include recent changes
,
!3
Added documentation
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
src/internal/core/index.ts
+134
-0
134 additions, 0 deletions
src/internal/core/index.ts
src/internal/index.ts
+18
-0
18 additions, 0 deletions
src/internal/index.ts
src/internal/parser.ts
+253
-0
253 additions, 0 deletions
src/internal/parser.ts
with
405 additions
and
0 deletions
src/internal/core/index.ts
+
134
−
0
View file @
a8ef16e8
...
...
@@ -2,18 +2,37 @@
// Parsimmon-like stateful parser combinators
//
/**
* Holds the information from a successful parse.
*/
export
type
Success
<
T
>
=
{
success
:
true
;
value
:
T
;
index
:
number
;
};
/**
* Represents a failed parse.
*/
export
type
Failure
=
{
success
:
false
};
/**
* Possible results from a parse.
*/
export
type
Result
<
T
>
=
Success
<
T
>
|
Failure
;
/**
* The function used by a parser to determine if it succeeds or fails.
*/
export
type
ParserHandler
<
T
>
=
(
input
:
string
,
index
:
number
,
state
:
any
)
=>
Result
<
T
>
/**
* A function that always returns a parse success.
*
* @param index The index of the success.
* @param value The value of the success.
* @returns A {@link Success} object.
*/
export
function
success
<
T
>
(
index
:
number
,
value
:
T
):
Success
<
T
>
{
return
{
success
:
true
,
...
...
@@ -22,10 +41,18 @@ export function success<T>(index: number, value: T): Success<T> {
};
}
/**
* A function that always returns a parse failure.
*
* @returns A {@link Failure} object.
*/
export
function
failure
():
Failure
{
return
{
success
:
false
};
}
/**
* The parser class.
*/
export
class
Parser
<
T
>
{
public
name
?:
string
;
public
handler
:
ParserHandler
<
T
>
;
...
...
@@ -50,6 +77,13 @@ export class Parser<T> {
this
.
name
=
name
;
}
/**
* A function that maps the result of the parse with the provided function if successful, and returns a {@link Failure}
* otherwise.
*
* @param fn The function used to map the output of the parser.
* @returns The result of the parser mapped with `fn`.
*/
map
<
U
>
(
fn
:
(
value
:
T
)
=>
U
):
Parser
<
U
>
{
return
new
Parser
((
input
,
index
,
state
)
=>
{
const
result
=
this
.
handler
(
input
,
index
,
state
);
...
...
@@ -60,6 +94,11 @@ export class Parser<T> {
});
}
/**
* A function that returns the plaintext related to the {@link Success} and a {@link Failure} otherwise.
*
* @returns The plaintext related to the successful parse, and a {@link Failure} if the parse failed.
*/
text
():
Parser
<
string
>
{
return
new
Parser
((
input
,
index
,
state
)
=>
{
const
result
=
this
.
handler
(
input
,
index
,
state
);
...
...
@@ -71,6 +110,13 @@ export class Parser<T> {
});
}
/**
* A function that returns a {@link Parser} that must succeed at least of `min` times in order to return
* a {@link Success} and returns a {@link Failure} otherwise.
*
* @param min The minimum amount of times this parse must succeed to return a {@link Success}.
* @returns A Parser that returns a {@link Success} object it matches enough times, and a {@link Failure} otherwise.
*/
many
(
min
:
number
):
Parser
<
T
[]
>
{
return
new
Parser
((
input
,
index
,
state
)
=>
{
let
result
;
...
...
@@ -91,6 +137,13 @@ export class Parser<T> {
});
}
/**
* A function that checks if the supplied separator appears between this separator's value.
*
* @param separator The parser representing the separator that must appear between this parser's value.
* @param min The minimum amount of times the separator must appear.
* @returns A {@link Success} object if the minimum separator count is met, and a {@link Failure} otherwise.
*/
sep
(
separator
:
Parser
<
any
>
,
min
:
number
):
Parser
<
T
[]
>
{
if
(
min
<
1
)
{
throw
new
Error
(
'
"min" must be a value greater than or equal to 1.
'
);
...
...
@@ -104,6 +157,12 @@ export class Parser<T> {
]).
map
(
result
=>
[
result
[
0
],
...
result
[
1
]]);
}
/**
* A function that attempts to match this parser, but returns a {@link Success} object with the
* value `null` if it fails.
*
* @returns A {@link Success} object.
*/
option
<
T
>
():
Parser
<
T
|
null
>
{
return
alt
([
this
,
...
...
@@ -112,6 +171,12 @@ export class Parser<T> {
}
}
/**
* A function that returns a {@link Parser} that succeeds if it matches the supplied string.
*
* @param value The string that the returned {@link Parser} checks for.
* @returns A {@link Parser} that matches the supplied string.
*/
export
function
str
<
T
extends
string
>
(
value
:
T
):
Parser
<
T
>
{
return
new
Parser
((
input
,
index
,
_state
)
=>
{
if
((
input
.
length
-
index
)
<
value
.
length
)
{
...
...
@@ -124,6 +189,12 @@ export function str<T extends string>(value: T): Parser<T> {
});
}
/**
* A function that returns {@link Parser} that succeeds if the input matches the supplied regular expression.
*
* @param pattern The regular expression that the returned {@link Parser} tries to match.
* @returns A {@link Parser} that checks if the input matches the supplied regular expression.
*/
export
function
regexp
<
T
extends
RegExp
>
(
pattern
:
T
):
Parser
<
string
>
{
const
re
=
RegExp
(
`^(?:
${
pattern
.
source
}
)`
,
pattern
.
flags
);
return
new
Parser
((
input
,
index
,
_state
)
=>
{
...
...
@@ -136,6 +207,20 @@ export function regexp<T extends RegExp>(pattern: T): Parser<string> {
});
}
/**
* A function that returns a {@link Parser} that goes through the parsers provided, in order, and checks that they all
* succeed. A {@link Failure} object is returned if any of the parsers fails.
* The value in the {@link Success} returned by the parser varies depending on the value of `select`:
*
* If select is `null`, then the array of the results of the supplied parsers is returned, otherwise the value
* in the array at the specified index is returned.
*
* @param parsers The array of {@link Parser Parsers} that are checked to see if it succeeds.
* @param select The index of the result array that is returned.
* @returns A {@link Parser} that runs through the parsers in the order that they were provided and returns
* a value based on the state of `select` (the entire array if `null`, else the value held at the
* index specified by `select`).
*/
export
function
seq
(
parsers
:
Parser
<
any
>
[],
select
?:
number
):
Parser
<
any
>
{
return
new
Parser
((
input
,
index
,
state
)
=>
{
let
result
;
...
...
@@ -153,6 +238,15 @@ export function seq(parsers: Parser<any>[], select?: number): Parser<any> {
});
}
/**
* A function that returns a {@link Parser} that goes through the parsers provided, in order, and checks if each succeeds.
* If one fails, the next parser is tested, and this pattern is continued until the final parser is tested, at which point
* the parser will return a {@link Failure} if it still fails. If any of the parsers succeed, the resulting {@link Success}
* is returned immediately.
*
* @param parsers The {@link Parser Parsers} that should be used.
* @returns A {@link Parser} that returns the first {@link Success} from the supplied parsers.
*/
export
function
alt
(
parsers
:
Parser
<
any
>
[]):
Parser
<
any
>
{
return
new
Parser
((
input
,
index
,
state
)
=>
{
let
result
;
...
...
@@ -166,12 +260,24 @@ export function alt(parsers: Parser<any>[]): Parser<any> {
});
}
/**
* A function that returns a {@link Parser} that always succeeds, returning a {@link Success} object with the supplied value.
*
* @param value The value to be used in the returned {@link Success} object.
* @returns A {@link Parser} that always returns a {@link Success} with the specified value.
*/
function
succeeded
<
T
>
(
value
:
T
):
Parser
<
T
>
{
return
new
Parser
((
_input
,
index
,
_state
)
=>
{
return
success
(
index
,
value
);
});
}
/**
* A function that returns a {@link Parser} that inverts the result of the parser supplied.
*
* @param parser The {@link Parser} to be matched.
* @returns A {@link Success} with the value `null` if the parser fails, or a {@link Failure} if it succeeds.
*/
export
function
notMatch
(
parser
:
Parser
<
any
>
):
Parser
<
null
>
{
return
new
Parser
((
input
,
index
,
state
)
=>
{
const
result
=
parser
.
handler
(
input
,
index
,
state
);
...
...
@@ -181,6 +287,15 @@ export function notMatch(parser: Parser<any>): Parser<null> {
});
}
/**
* A function that returns a {@link Parser} that fails if `parserExcluded` succeeds, and returns the result of `parserIncluded`
* otherwise.
*
* @param parserIncluded The {@link Parser} that should succeed
* @param parserExcluded The {@link Parser} that should fail
* @returns A {@link Failure} object if `parserExcluded` succeeds, or if `parserIncluded` fails, and a {@link Success} object
* otherwise.
*/
export
function
difference
(
parserIncluded
:
Parser
<
any
>
,
parserExcluded
:
Parser
<
any
>
):
Parser
<
string
>
{
return
new
Parser
((
input
,
index
,
state
)
=>
{
const
exclude
=
parserExcluded
.
handler
(
input
,
index
,
state
);
...
...
@@ -193,11 +308,16 @@ export function difference(parserIncluded: Parser<any>, parserExcluded: Parser<a
});
}
/** A {@link Parser} that matches the carriage return character `\r`. */
export
const
cr
=
str
(
'
\r
'
);
/** A {@link Parser} that matches the line feed character `\n`. */
export
const
lf
=
str
(
'
\n
'
);
/** A {@link Parser} that matches the character sequence `\r\n`. */
export
const
crlf
=
str
(
'
\r\n
'
);
/** A {@link Parser} that matches for any valid new line sequences. */
export
const
newline
=
alt
([
crlf
,
cr
,
lf
]);
/** A {@link Parser} that succeeds so long as it is not at the end of the input string. */
export
const
char
=
new
Parser
((
input
,
index
,
_state
)
=>
{
if
((
input
.
length
-
index
)
<
1
)
{
return
failure
();
...
...
@@ -206,6 +326,10 @@ export const char = new Parser((input, index, _state) => {
return
success
(
index
+
1
,
value
);
});
/**
* A {@link Parser} that checks that the current position is the beginning of a line. For this parser to succeed,
* either the current index must be zero, or the previous character is a `\n` or `\r`.
*/
export
const
lineBegin
=
new
Parser
((
input
,
index
,
state
)
=>
{
if
(
index
===
0
)
{
return
success
(
index
,
null
);
...
...
@@ -219,6 +343,10 @@ export const lineBegin = new Parser((input, index, state) => {
return
failure
();
});
/**
* A {@link Parser} that checks that the current position is the end of a line. For this parser to succeed, either the current
* index must be equal to the input length, or the current character is a `\n` or `\r`.
*/
export
const
lineEnd
=
new
Parser
((
input
,
index
,
state
)
=>
{
if
(
index
===
input
.
length
)
{
return
success
(
index
,
null
);
...
...
@@ -232,6 +360,12 @@ export const lineEnd = new Parser((input, index, state) => {
return
failure
();
});
/**
* A function that lazily loads the supplied {@link Parser}
*
* @param fn The {@link Parser} that the returned parser should use.
* @returns A {@link Parser} that checks using the supplied parser's {@link Parser.handler}
*/
export
function
lazy
<
T
>
(
fn
:
()
=>
Parser
<
T
>
):
Parser
<
T
>
{
const
parser
:
Parser
<
T
>
=
new
Parser
((
input
,
index
,
state
)
=>
{
parser
.
handler
=
fn
().
handler
;
...
...
This diff is collapsed.
Click to expand it.
src/internal/index.ts
+
18
−
0
View file @
a8ef16e8
...
...
@@ -3,10 +3,21 @@ import { language } from './parser';
import
{
mergeText
}
from
'
./util
'
;
import
*
as
P
from
'
./core
'
;
/**
* A type representing the available options for the full parser.
*/
export
type
FullParserOpts
=
{
nestLimit
?:
number
;
};
/**
* A function that parses through the input plaintext with the full parser and returns the AST representing the
* result.
*
* @param input The input string to parse.
* @param opts The options used for the parsing.
* @returns An array of nodes representing the resulting styles.
*/
export
function
fullParser
(
input
:
string
,
opts
:
FullParserOpts
):
M
.
MfmNode
[]
{
const
result
=
language
.
fullParser
.
handler
(
input
,
0
,
{
nestLimit
:
(
opts
.
nestLimit
!=
null
)
?
opts
.
nestLimit
:
20
,
...
...
@@ -17,6 +28,13 @@ export function fullParser(input: string, opts: FullParserOpts): M.MfmNode[] {
return
mergeText
(
result
.
value
);
}
/**
* A function that parses through the input plaintext with the simple parser and returns the AST representing the
* result.
*
* @param input The input string to parse.
* @returns An array of simple nodes represennting the resulting styles.
*/
export
function
simpleParser
(
input
:
string
):
M
.
MfmSimpleNode
[]
{
const
result
=
language
.
simpleParser
.
handler
(
input
,
0
,
{
})
as
P
.
Success
<
any
>
;
return
mergeText
(
result
.
value
);
...
...
This diff is collapsed.
Click to expand it.
src/internal/parser.ts
+
253
−
0
View file @
a8ef16e8
...
...
@@ -12,10 +12,25 @@ import twemojiRegex from '@twemoji/parser/dist/lib/regex';
type
ArgPair
=
{
k
:
string
,
v
:
string
|
true
};
type
Args
=
Record
<
string
,
string
|
true
>
;
/** A {@link P.Parser Parser} that matches all whitespace characters other than ones representing new lines */
const
space
=
P
.
difference
(
P
.
regexp
(
/
\s
/
),
P
.
newline
);
/** A {@link P.Parser Parser} that matches all alphanumeric characters */
const
alphaAndNum
=
P
.
regexp
(
/
\p
{Letter}|
\p
{Number}/iu
);
/** A {@link P.Parser Parser} that matches any valid new line sequences */
const
newLine
=
P
.
alt
([
P
.
crlf
,
P
.
cr
,
P
.
lf
]);
/**
* A function that returns a {@link P.Parser Parser} which goes through the supplied parsers sequentially.
* If the first provided parser fails, a {@link P.Failure Failure} object is returned, the plaintext of the
* successfully parsed portion of the input if any other parsers fail, and an array of the values of the
* parsers' {@link P.Success Successes}.
*
* @param parsers The list of {@link P.Parser Parsers} to use.
* @returns A {@link P.Parser Parser} that goes through the supplied parsers sequentially and makes sure that each
* succeeds. If the first parser fails, a {@link P.Failure Failure} object is returned. If any other parser
* fails, the plaintext of the successfully parsed portion of the input text is returned. If all succeed,
* the array of each {@link P.Success Success'} value is returned.
*/
function
seqOrText
(
parsers
:
P
.
Parser
<
any
>
[]):
P
.
Parser
<
any
[]
|
string
>
{
return
new
P
.
Parser
<
any
[]
|
string
>
((
input
,
index
,
state
)
=>
{
const
accum
:
any
[]
=
[];
...
...
@@ -36,18 +51,34 @@ function seqOrText(parsers: P.Parser<any>[]): P.Parser<any[] | string> {
});
}
/**
* A {@link P.Parser Parser} that succeeds if the supplied state is not a link label.
*/
const
notLinkLabel
=
new
P
.
Parser
((
_input
,
index
,
state
)
=>
{
return
(
!
state
.
linkLabel
)
?
P
.
success
(
index
,
null
)
:
P
.
failure
();
});
/**
* A {@link P.Parser Parser} that succeeds if the current nest depth is less than the nest limit.
*/
const
nestable
=
new
P
.
Parser
((
_input
,
index
,
state
)
=>
{
return
(
state
.
depth
<
state
.
nestLimit
)
?
P
.
success
(
index
,
null
)
:
P
.
failure
();
});
/**
* A function that returns a {@link P.Parser Parser} that calls `parser` if it is possible to nest, and `fallback`
* otherwise.
*
* @param parser The {@link P.Parser Parser} that gets used if it is currently possible to nest.
* @param fallback The {@link P.Parser Parser} that gets used if it is not currently possible to nest.
* If `null`, {@link P.char} is used.
* @returns A {@link P.Parser Parser} that checks that it is possible to nest, returning the result of `parser` if it is,
* otherwise returning the result of `fallback`
*/
function
nest
<
T
>
(
parser
:
P
.
Parser
<
T
>
,
fallback
?:
P
.
Parser
<
string
>
):
P
.
Parser
<
T
|
string
>
{
// nesting limited? -> No: specified parser, Yes: fallback parser (default = P.char)
const
inner
=
P
.
alt
([
...
...
@@ -62,15 +93,37 @@ function nest<T>(parser: P.Parser<T>, fallback?: P.Parser<string>): P.Parser<T |
});
}
/**
* The collection of {@link P.Parser Parsers} representing the rules that make up SFM
*/
export
const
language
=
P
.
createLanguage
({
/**
* A {@link P.Parser Parser} that matches every SFM rule as many times as possible.
*
* @param r The rules of SFM
* @returns A {@link P.Parser Parser} that matches every rule as many times as possible
*/
fullParser
:
r
=>
{
return
r
.
full
.
many
(
0
);
},
/**
* A {@link P.Parser Parser} that matches {@link language.unicodeEmoji}, {@link language.emojiCode},
* and {@link language.text} as many times as possible
*
* @param r The rules of SFM
* @returns A {@link P.Parser Parser} that matches very few SFM rules as many times as possible.
*/
simpleParser
:
r
=>
{
return
r
.
simple
.
many
(
0
);
},
/**
* A {@link P.Parser Parser} that matches any SFM rule.
*
* @param r The rules of SFM
* @returns A {@link P.Parser Parser} that matches any rule.
*/
full
:
r
=>
{
return
P
.
alt
([
// Regexp
...
...
@@ -129,6 +182,13 @@ export const language = P.createLanguage({
]);
},
/**
* A {@link P.Parser Parser} that only matches {@link language.unicodeEmoji}, {@link language.emojiCode},
* and {@link language.text}.
*
* @param r The rules of SFM
* @returns A {@link P.Parser Parser} that matches very few SFM rules.
*/
simple
:
r
=>
{
return
P
.
alt
([
r
.
unicodeEmoji
,
// Regexp
...
...
@@ -137,6 +197,12 @@ export const language = P.createLanguage({
]);
},
/**
* A {@link P.Parser Parser} that only matches rules that can be done without disrupting text.
*
* @param r The rules of SFM
* @returns A {@link P.Parser Parser} that matches all inline rules.
*/
inline
:
r
=>
{
return
P
.
alt
([
// Regexp
...
...
@@ -185,6 +251,12 @@ export const language = P.createLanguage({
]);
},
/**
* A {@link P.Parser Parser} that matches single lines that begin with a `>` character.
*
* @param r The rules of SFM
* @returns The {@link P.Parser Parser} for this rule
*/
quote
:
r
=>
{
const
lines
:
P
.
Parser
<
string
[]
>
=
P
.
seq
([
P
.
str
(
'
>
'
),
...
...
@@ -222,6 +294,14 @@ export const language = P.createLanguage({
});
},
/**
* A {@link P.Parser Parser} that matches multi-line text that is surrounded by the ` ``` ` mark.
* Text directly after the opening mark decides the language that the syntax highlighting uses.
* The marks must be on their own lines.
*
* @param r The rules of SFM
* @returns The {@link P.Parser Parser} for this rule
*/
codeBlock
:
r
=>
{
const
mark
=
P
.
str
(
'
```
'
);
return
P
.
seq
([
...
...
@@ -242,6 +322,13 @@ export const language = P.createLanguage({
});
},
/**
* A {@link P.Parser Parser} that matches multi-line text that is opened with `\[` and closed with `\]`.
* The marks do not have to be on their own lines, nor do they need to be the first.
*
* @param r The rules of SFM
* @returns The {@link P.Parser Parser} for this rule
*/
mathBlock
:
r
=>
{
const
open
=
P
.
str
(
'
\\
[
'
);
const
close
=
P
.
str
(
'
\\
]
'
);
...
...
@@ -259,6 +346,14 @@ export const language = P.createLanguage({
});
},
/**
* A {@link P.Parser Parser} that matches multi-line text that is opened with `<center>` and closed with `</center>`.
* The marks do not have to be on their own lines.
* The opening mark must appear at the beginning of its line, and the closing mark must appear at the end of its line.
*
* @param r The rules of SFM
* @returns The {@link P.Parser Parser} for this rule
*/
centerTag
:
r
=>
{
const
open
=
P
.
str
(
'
<center>
'
);
const
close
=
P
.
str
(
'
</center>
'
);
...
...
@@ -277,6 +372,13 @@ export const language = P.createLanguage({
});
},
/**
* A {@link P.Parser Parser} that matches multi-line text that is surrounded with the `***` mark.
* The marks do not have to be on their own lines and have no restrictions on placement.
*
* @param r The rules of SFM
* @returns The {@link P.Parser Parser} for this rule
*/
big
:
r
=>
{
const
mark
=
P
.
str
(
'
***
'
);
return
seqOrText
([
...
...
@@ -289,6 +391,13 @@ export const language = P.createLanguage({
});
},
/**
* A {@link P.Parser Parser} that matches multi-line text that is surrounded with the `**` mark.
* The marks do not have to be on their own lines and have no restrictions on placement.
*
* @param r The rules of SFM
* @returns The {@link P.Parser Parser} for this rule
*/
boldAsta
:
r
=>
{
const
mark
=
P
.
str
(
'
**
'
);
return
seqOrText
([
...
...
@@ -301,6 +410,13 @@ export const language = P.createLanguage({
});
},
/**
* A {@link P.Parser Parser} that matches multi-line text that is opened with `<b>` and closed with `</b>`.
* The marks do not have to be on their own lines and have no restrictions on placement.
*
* @param r The rules of SFM
* @returns The {@link P.Parser Parser} for this rule
*/
boldTag
:
r
=>
{
const
open
=
P
.
str
(
'
<b>
'
);
const
close
=
P
.
str
(
'
</b>
'
);
...
...
@@ -314,6 +430,13 @@ export const language = P.createLanguage({
});
},
/**
* A {@link P.Parser Parser} that matches multi-line text that is surrounded with the `__` mark.
* The marks do not have to be on their own lines and have no restrictions on placement.
*
* @param r The rules of SFM
* @returns The {@link P.Parser Parser} for this rule
*/
boldUnder
:
r
=>
{
const
mark
=
P
.
str
(
'
__
'
);
return
P
.
seq
([
...
...
@@ -323,6 +446,13 @@ export const language = P.createLanguage({
]).
map
(
result
=>
M
.
BOLD
(
mergeText
(
result
[
1
]
as
string
[])));
},
/**
* A {@link P.Parser Parser} that matches multi-line text that is opened with `<small>` and closed with `</small>`.
* The marks do not have to be on their own lines and have no restrictions on placement.
*
* @param r The rules of SFM
* @returns The {@link P.Parser Parser} for this rule
*/
smallTag
:
r
=>
{
const
open
=
P
.
str
(
'
<small>
'
);
const
close
=
P
.
str
(
'
</small>
'
);
...
...
@@ -336,6 +466,13 @@ export const language = P.createLanguage({
});
},
/**
* A {@link P.Parser Parser} that matches multi-line text that is opened with `<i>` and closed with `</i>`.
* The marks do not have to be on their own lines and have no restrictions on placement.
*
* @param r The rules of SFM
* @returns The {@link P.Parser Parser} for this rule
*/
italicTag
:
r
=>
{
const
open
=
P
.
str
(
'
<i>
'
);
const
close
=
P
.
str
(
'
</i>
'
);
...
...
@@ -349,6 +486,13 @@ export const language = P.createLanguage({
});
},
/**
* A {@link P.Parser Parser} that matches multi-line text that is surrounded with the `*` mark.
* The marks do not have to be on their own lines and have no restrictions on placement.
*
* @param r The rules of SFM
* @returns The {@link P.Parser Parser} for this rule
*/
italicAsta
:
r
=>
{
const
mark
=
P
.
str
(
'
*
'
);
const
parser
=
P
.
seq
([
...
...
@@ -370,6 +514,13 @@ export const language = P.createLanguage({
});
},
/**
* A {@link P.Parser Parser} that matches multi-line text that is surrounded with the `_` mark.
* The marks do not have to be on their own lines and have no restrictions on placement.
*
* @param r The rules of SFM
* @returns The {@link P.Parser Parser} for this rule
*/
italicUnder
:
r
=>
{
const
mark
=
P
.
str
(
'
_
'
);
const
parser
=
P
.
seq
([
...
...
@@ -391,6 +542,13 @@ export const language = P.createLanguage({
});
},
/**
* A {@link P.Parser Parser} that matches multi-line text that is opened with `<s>` and closed with `</s>`.
* The marks do not have to be on their own lines and have no restrictions on placement.
*
* @param r The rules of SFM
* @returns The {@link P.Parser Parser} for this rule
*/
strikeTag
:
r
=>
{
const
open
=
P
.
str
(
'
<s>
'
);
const
close
=
P
.
str
(
'
</s>
'
);
...
...
@@ -404,6 +562,13 @@ export const language = P.createLanguage({
});
},
/**
* A {@link P.Parser Parser} that matches multi-line text that is surrounded with the `~~` mark.
* The marks do not have to be on their own lines and have no restrictions on placement.
*
* @param r The rules of SFM
* @returns The {@link P.Parser Parser} for this rule
*/
strikeWave
:
r
=>
{
const
mark
=
P
.
str
(
'
~~
'
);
return
seqOrText
([
...
...
@@ -416,11 +581,24 @@ export const language = P.createLanguage({
});
},
/**
* A {@link P.Parser Parser} that matches unicode emojis according to a regex.
*
* @param r The rules of SFM
* @returns The {@link P.Parser Parser} for this rule
*/
unicodeEmoji
:
r
=>
{
const
emoji
=
RegExp
(
twemojiRegex
.
source
);
return
P
.
regexp
(
emoji
).
map
(
content
=>
M
.
UNI_EMOJI
(
content
));
},
/**
* A {@link P.Parser Parser} that matches multi-line text that is opened with `<plain>` and closed with `</plain>`.
* The marks do not have to be on their own lines and have no restrictions on placement.
*
* @param r The rules of SFM
* @returns The {@link P.Parser Parser} for this rule
*/
plainTag
:
r
=>
{
const
open
=
P
.
str
(
'
<plain>
'
);
const
close
=
P
.
str
(
'
</plain>
'
);
...
...
@@ -483,6 +661,13 @@ export const language = P.createLanguage({
});
},
/**
* A {@link P.Parser Parser} that matches multi-line text that is surrounded with the `` ` `` mark.
* The marks do not have to be on their own lines and have no restrictions on placement.
*
* @param r The rules of SFM
* @returns The {@link P.Parser Parser} for this rule
*/
inlineCode
:
r
=>
{
const
mark
=
P
.
str
(
'
`
'
);
return
P
.
seq
([
...
...
@@ -495,6 +680,13 @@ export const language = P.createLanguage({
]).
map
(
result
=>
M
.
INLINE_CODE
(
result
[
1
].
join
(
''
)));
},
/**
* A {@link P.Parser Parser} that matches single-line text opened with `\(` and closed with `\)`.
* The marks must be on the same line, but have no other restrictions on placement.
*
* @param r The rules of SFM
* @returns The {@link P.Parser Parser} for this rule
*/
mathInline
:
r
=>
{
const
open
=
P
.
str
(
'
\\
(
'
);
const
close
=
P
.
str
(
'
\\
)
'
);
...
...
@@ -508,6 +700,14 @@ export const language = P.createLanguage({
]).
map
(
result
=>
M
.
MATH_INLINE
(
result
[
1
].
join
(
''
)));
},
/**
* A {@link P.Parser Parser} that matches user mentions, which all must begin with `@{username}`, but only have to be followed by
* `@{hostname}` if the user is on a different instance.
* The mention must be contained within one line, but it has no other restrictions on placement.
*
* @param r the rules of SFM
* @returns The {@link P.Parser Parser} for this rule
*/
mention
:
r
=>
{
const
parser
=
P
.
seq
([
notLinkLabel
,
...
...
@@ -574,6 +774,15 @@ export const language = P.createLanguage({
});
},
/**
* A {@link P.Parser Parser} that matches single word hashtags starting with the character `#`.
* The contents of the hashtag are limited to alphanumeric characters, but cannot be made up of exclusively numbers.
* There are some characters that must be closed with another in order for the parse to succeed.
* There are no restrictions on the placement of hashtags.
*
* @param r The rules of SFM
* @returns A {@link P.Parser Parser} for this rule
*/
hashtag
:
r
=>
{
const
mark
=
P
.
str
(
'
#
'
);
const
hashTagChar
=
P
.
seq
([
...
...
@@ -620,6 +829,14 @@ export const language = P.createLanguage({
});
},
/**
* A {@link P.Parser Parser} that matches single word emojis surrounded by the `:` mark.
* The marks must be on the same line, and alphanumeric characters cannot appear both in front
* of, and behind, the opening and closing marks respectively.
*
* @param r The rules of SFM
* @returns A {@link P.Parser Parser} for this rule
*/
emojiCode
:
r
=>
{
const
side
=
P
.
notMatch
(
P
.
regexp
(
/
[
a-z0-9
]
/i
));
const
mark
=
P
.
str
(
'
:
'
);
...
...
@@ -632,6 +849,16 @@ export const language = P.createLanguage({
],
2
).
map
(
name
=>
M
.
EMOJI_CODE
(
name
as
string
));
},
/**
* A {@link P.Parser Parser} that matches inline links, which are made up of the label and the url.
* The label must be opened with either `?[` for silent links or `[` for normal links and closed with `]`.
* The url must be opened with `(` and closed with `)`, and the contents of the url must follow either the
* {@link language.url} or {@link language.urlAlt} rules.
* The inline link must be on a single line, but has no other restrictions on placement.
*
* @param r The rules of SFM
* @returns A {@link P.Parser Parser} for this rule
*/
link
:
r
=>
{
const
labelInline
=
new
P
.
Parser
((
input
,
index
,
state
)
=>
{
state
.
linkLabel
=
true
;
...
...
@@ -659,6 +886,12 @@ export const language = P.createLanguage({
});
},
/**
* A {@link P.Parser Parser} that matches the standard format for urls.
*
* @param r The rules of SFM
* @returns A {@link P.Parser Parser} for this rule
*/
url
:
r
=>
{
const
urlChar
=
P
.
regexp
(
/
[
.,a-z0-9_
/
:%#@$&?!~=+-
]
/i
);
const
innerItem
:
P
.
Parser
<
any
>
=
P
.
lazy
(()
=>
P
.
alt
([
...
...
@@ -698,6 +931,12 @@ export const language = P.createLanguage({
});
},
/**
* A {@link P.Parser Parser} that matches an alternate form for urls, where it is opened with `<` and closed with `>`.
*
* @param r The rules of SFM
* @returns A {@link P.Parser Parser} for this rule
*/
urlAlt
:
r
=>
{
const
open
=
P
.
str
(
'
<
'
);
const
close
=
P
.
str
(
'
>
'
);
...
...
@@ -718,6 +957,14 @@ export const language = P.createLanguage({
});
},
/**
* A {@link P.Parser Parser} that matches single line text for a search query. The query must have either `[検索]` or
* `[search]` at the end of the line.
* The query and button must be on the same line and there can be nothing else on that line.
*
* @param r The rules of SFM
* @returns A {@link P.Parser Parser} for this rule
*/
search
:
r
=>
{
const
button
=
P
.
alt
([
P
.
regexp
(
/
\[(
検索|search
)\]
/i
),
...
...
@@ -742,5 +989,11 @@ export const language = P.createLanguage({
});
},
/**
* A rule that simply collects characters.
*
* @param r The rules of SFM
* @returns A {@link P.Parser Parser} for this rule
*/
text
:
r
=>
P
.
char
,
});
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment