shelving 1.51.0 → 1.51.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/markup/render.js +2 -2
- package/markup/rules.js +17 -19
- package/markup/types.d.ts +5 -7
- package/package.json +1 -1
package/markup/render.js
CHANGED
|
@@ -15,12 +15,12 @@ function renderString(content, options) {
|
|
|
15
15
|
let matchedRule = undefined;
|
|
16
16
|
let matchedResult = undefined;
|
|
17
17
|
for (const rule of options.rules) {
|
|
18
|
-
const { priority = 0, match, contexts } = rule;
|
|
18
|
+
const { priority = 0, match, regexp, contexts } = rule;
|
|
19
19
|
// Only apply this rule if both:
|
|
20
20
|
// 1. The priority is equal or higher to the current priority.
|
|
21
21
|
// 2. The rule is allowed in the current context.
|
|
22
22
|
if (priority >= matchedPriority && contexts.includes(options.context)) {
|
|
23
|
-
const result = match(content, options);
|
|
23
|
+
const result = match ? match(content, options) : regexp ? content.match(regexp) : null;
|
|
24
24
|
// If this matched and has an index (it might not if it's a `/g` global RegExp, which would be a mistake).
|
|
25
25
|
if (result && typeof result.index === "number") {
|
|
26
26
|
const index = result.index;
|
package/markup/rules.js
CHANGED
|
@@ -3,8 +3,6 @@ import { formatUrl, toURL, getLineRegExp, MATCH_LINE, getBlockRegExp, MATCH_BLOC
|
|
|
3
3
|
const BULLETS = "-*•+"; // Anything that can be a bullet (used for unordered lists and horizontal rules).
|
|
4
4
|
// Regular expressions.
|
|
5
5
|
const REPLACE_INDENT = /^ {1,2}/gm;
|
|
6
|
-
// Regular expression makers.
|
|
7
|
-
const getMatcher = regexp => content => content.match(regexp);
|
|
8
6
|
/**
|
|
9
7
|
* Headings are single line only (don't allow multiline).
|
|
10
8
|
* - 1-6 hashes then 1+ spaces, then the title.
|
|
@@ -12,7 +10,7 @@ const getMatcher = regexp => content => content.match(regexp);
|
|
|
12
10
|
* - Markdown's underline syntax is not supported (for simplification).
|
|
13
11
|
*/
|
|
14
12
|
export const HEADING_RULE = {
|
|
15
|
-
|
|
13
|
+
regexp: getLineRegExp(`(#{1,6}) +(${MATCH_LINE})`),
|
|
16
14
|
render: ([, prefix = "", children = ""]) => ({ type: `h${prefix.length}`, key: null, props: { children } }),
|
|
17
15
|
contexts: ["block"],
|
|
18
16
|
childContext: "inline",
|
|
@@ -25,7 +23,7 @@ export const HEADING_RULE = {
|
|
|
25
23
|
* - Might have infinite number of spaces between the characters.
|
|
26
24
|
*/
|
|
27
25
|
export const HORIZONTAL_RULE = {
|
|
28
|
-
|
|
26
|
+
regexp: getLineRegExp(`([${BULLETS}])(?: *\\1){2,}`),
|
|
29
27
|
render: () => ({ type: "hr", key: null, props: {} }),
|
|
30
28
|
contexts: ["block"],
|
|
31
29
|
};
|
|
@@ -38,7 +36,7 @@ export const HORIZONTAL_RULE = {
|
|
|
38
36
|
*/
|
|
39
37
|
const UNORDERED = `[${BULLETS}] +`; // Anything that can be a bullet (used for unordered lists and horizontal rules).
|
|
40
38
|
export const UNORDERED_LIST_RULE = {
|
|
41
|
-
|
|
39
|
+
regexp: getBlockRegExp(`${UNORDERED}(${MATCH_BLOCK})`),
|
|
42
40
|
render: ([, list = ""]) => {
|
|
43
41
|
const children = list.split(SPLIT_UL_ITEMS).map(mapUnorderedItem);
|
|
44
42
|
return { type: "ul", key: null, props: { children } };
|
|
@@ -58,7 +56,7 @@ const mapUnorderedItem = (item, key) => {
|
|
|
58
56
|
*/
|
|
59
57
|
const ORDERED = "[0-9]+[.):] +"; // Number for a numbered list (e.g. `1.` or `2)` or `3:`)
|
|
60
58
|
export const ORDERED_LIST_RULE = {
|
|
61
|
-
|
|
59
|
+
regexp: getBlockRegExp(`(${ORDERED}${MATCH_BLOCK})`),
|
|
62
60
|
render: ([, list = ""]) => {
|
|
63
61
|
const children = list.split(SPLIT_OL_ITEMS).map(mapOrderedItem);
|
|
64
62
|
return { type: "ol", key: null, props: { children } };
|
|
@@ -83,7 +81,7 @@ const mapOrderedItem = (item, key) => {
|
|
|
83
81
|
* - Quote indent symbol can be followed by zero or more spaces.
|
|
84
82
|
*/
|
|
85
83
|
export const BLOCKQUOTE_RULE = {
|
|
86
|
-
|
|
84
|
+
regexp: getLineRegExp(`(>${MATCH_LINE}(?:\\n>${MATCH_LINE})*)`),
|
|
87
85
|
render: ([, quote = ""]) => ({
|
|
88
86
|
type: "blockquote",
|
|
89
87
|
key: null,
|
|
@@ -102,7 +100,7 @@ const BLOCKQUOTE_LINES = /^>/gm;
|
|
|
102
100
|
*/
|
|
103
101
|
export const FENCED_CODE_RULE = {
|
|
104
102
|
// Matcher has its own end that only stops when it reaches a matching closing fence or the end of the string.
|
|
105
|
-
|
|
103
|
+
regexp: getBlockRegExp(`(\`{3,}|~{3,}) *(${MATCH_LINE})\\n(${MATCH_BLOCK})`, `\\n\\1\\n+|\\n\\1$|$`),
|
|
106
104
|
render: ([, , file, children]) => ({
|
|
107
105
|
type: "pre",
|
|
108
106
|
key: null,
|
|
@@ -121,7 +119,7 @@ export const FENCED_CODE_RULE = {
|
|
|
121
119
|
* - When ordering rules, paragraph should go after other "block" context elements (because it has a very generous capture).
|
|
122
120
|
*/
|
|
123
121
|
export const PARAGRAPH_RULE = {
|
|
124
|
-
|
|
122
|
+
regexp: getBlockRegExp(` *(${MATCH_BLOCK})`),
|
|
125
123
|
render: ([, children]) => ({ type: `p`, key: null, props: { children } }),
|
|
126
124
|
contexts: ["block"],
|
|
127
125
|
childContext: "inline",
|
|
@@ -137,8 +135,9 @@ export const PARAGRAPH_RULE = {
|
|
|
137
135
|
*/
|
|
138
136
|
export const LINK_MARKUP = {
|
|
139
137
|
// Custom matcher to check the URL against the allowed schemes.
|
|
138
|
+
regexp: /\[([^\]]*?)\]\(([^)]*?)\)/,
|
|
140
139
|
match: (content, { schemes, url: base }) => {
|
|
141
|
-
const matches = content.match(
|
|
140
|
+
const matches = content.match(LINK_MARKUP.regexp);
|
|
142
141
|
if (matches && typeof matches.index === "number") {
|
|
143
142
|
const [, title = "", href = ""] = matches;
|
|
144
143
|
const url = toURL(href, base);
|
|
@@ -157,7 +156,6 @@ export const LINK_MARKUP = {
|
|
|
157
156
|
contexts: ["inline", "list"],
|
|
158
157
|
childContext: "link",
|
|
159
158
|
};
|
|
160
|
-
const MATCH_LINK = /\[([^\]]*?)\]\(([^)]*?)\)/;
|
|
161
159
|
/**
|
|
162
160
|
* Autolinked URL starts with `http:` or `https:` and matches an unlimited number of non-space characters.
|
|
163
161
|
* - If followed by space and then text in `()` round or `[]` square brackets that will be used as the title, e.g. `http://google.com/maps (Google Maps)` or `http://google.com/maps [Google Maps]` (this syntax is from Todoist and maybe other things too).
|
|
@@ -167,8 +165,9 @@ const MATCH_LINK = /\[([^\]]*?)\]\(([^)]*?)\)/;
|
|
|
167
165
|
*/
|
|
168
166
|
export const AUTOLINK_RULE = {
|
|
169
167
|
// Custom matcher to check the URL against the allowed schemes.
|
|
168
|
+
regexp: /([a-zA-Z][a-zA-Z0-9-]*[a-zA-Z0-9]:\S+)(?: +(?:\(([^)]*?)\)|\[([^\]]*?)\]))?/,
|
|
170
169
|
match: (content, { schemes, url: base }) => {
|
|
171
|
-
const matches = content.match(
|
|
170
|
+
const matches = content.match(AUTOLINK_RULE.regexp);
|
|
172
171
|
if (matches && typeof matches.index === "number") {
|
|
173
172
|
const [, href = "", title1 = "", title2 = ""] = matches;
|
|
174
173
|
const url = toURL(href, base);
|
|
@@ -183,7 +182,6 @@ export const AUTOLINK_RULE = {
|
|
|
183
182
|
contexts: ["inline", "list"],
|
|
184
183
|
childContext: "link",
|
|
185
184
|
};
|
|
186
|
-
const MATCH_AUTOLINK = /([a-z][a-z0-9-]*[a-z0-9]:\S+)(?: +(?:\(([^)]*?)\)|\[([^\]]*?)\]))?/i;
|
|
187
185
|
/**
|
|
188
186
|
* Inline code.
|
|
189
187
|
* - Text surrounded by one or more "`" backtick tilde characters.
|
|
@@ -192,7 +190,7 @@ const MATCH_AUTOLINK = /([a-z][a-z0-9-]*[a-z0-9]:\S+)(?: +(?:\(([^)]*?)\)|\[([^\
|
|
|
192
190
|
* - Same as Markdown syntax.
|
|
193
191
|
*/
|
|
194
192
|
export const CODE_RULE = {
|
|
195
|
-
|
|
193
|
+
regexp: getWrapRegExp("`+", MATCH_BLOCK),
|
|
196
194
|
render: ([, , children]) => ({ type: "code", key: null, props: { children } }),
|
|
197
195
|
contexts: ["inline", "list"],
|
|
198
196
|
priority: 10, // Higher priority than other inlines so it matches first before e.g. `strong` or `em` (from CommonMark spec: "Code span backticks have higher precedence than any other inline constructs except HTML tags and autolinks.")
|
|
@@ -206,7 +204,7 @@ export const CODE_RULE = {
|
|
|
206
204
|
* - Different to Markdown: strong is always surrounded by `*asterisks*` and emphasis is always surrounded by `_underscores_` (strong isn't 'double emphasis').
|
|
207
205
|
*/
|
|
208
206
|
export const STRONG_MARKUP = {
|
|
209
|
-
|
|
207
|
+
regexp: getWrapRegExp("\\*+"),
|
|
210
208
|
render: ([, , children]) => ({ type: "strong", key: null, props: { children } }),
|
|
211
209
|
contexts: ["inline", "list", "link"],
|
|
212
210
|
childContext: "inline",
|
|
@@ -220,7 +218,7 @@ export const STRONG_MARKUP = {
|
|
|
220
218
|
* - Different to Markdown: strong is always surrounded by `*asterisks*` and emphasis is always surrounded by `_underscores_` (strong isn't 'double emphasis').
|
|
221
219
|
*/
|
|
222
220
|
export const EMPHASIS_RULE = {
|
|
223
|
-
|
|
221
|
+
regexp: getWrapRegExp("_+"),
|
|
224
222
|
render: ([, , children]) => ({ type: "em", key: null, props: { children } }),
|
|
225
223
|
contexts: ["inline", "list", "link"],
|
|
226
224
|
childContext: "inline",
|
|
@@ -234,7 +232,7 @@ export const EMPHASIS_RULE = {
|
|
|
234
232
|
* - Markdown doesn't have this.
|
|
235
233
|
*/
|
|
236
234
|
export const INSERT_RULE = {
|
|
237
|
-
|
|
235
|
+
regexp: getWrapRegExp("\\+\\++"),
|
|
238
236
|
render: ([, , children]) => ({ type: "ins", key: null, props: { children } }),
|
|
239
237
|
contexts: ["inline", "list", "link"],
|
|
240
238
|
childContext: "inline",
|
|
@@ -248,7 +246,7 @@ export const INSERT_RULE = {
|
|
|
248
246
|
* - Markdown doesn't have this.
|
|
249
247
|
*/
|
|
250
248
|
export const DELETE_RULE = {
|
|
251
|
-
|
|
249
|
+
regexp: getWrapRegExp("--+|~~+"),
|
|
252
250
|
render: ([, , children]) => ({ type: "del", key: null, props: { children } }),
|
|
253
251
|
contexts: ["inline", "list", "link"],
|
|
254
252
|
childContext: "inline",
|
|
@@ -262,7 +260,7 @@ export const DELETE_RULE = {
|
|
|
262
260
|
* - This works better with textareas that wrap text (since manually breaking up long lines is no longer necessary).
|
|
263
261
|
*/
|
|
264
262
|
export const LINEBREAK_RULE = {
|
|
265
|
-
|
|
263
|
+
regexp: /\n/,
|
|
266
264
|
render: () => ({ type: "br", key: null, props: {} }),
|
|
267
265
|
contexts: ["inline", "list", "link"],
|
|
268
266
|
childContext: "inline",
|
package/markup/types.d.ts
CHANGED
|
@@ -18,8 +18,10 @@ export declare type MarkupElementProps = {
|
|
|
18
18
|
export declare type MarkupNode = undefined | null | string | MarkupElement | MarkupNode[];
|
|
19
19
|
/** A single markup parsing rule. */
|
|
20
20
|
export declare type MarkupRule = {
|
|
21
|
-
/** RegExp
|
|
22
|
-
readonly
|
|
21
|
+
/** RegExp for matching this rule. */
|
|
22
|
+
readonly regexp: RegExp;
|
|
23
|
+
/** Custom matching function for this rule (overrides `regexp` if present. */
|
|
24
|
+
readonly match?: (content: string, options: MarkupOptions) => RegExpMatchArray | null | undefined | void;
|
|
23
25
|
/**
|
|
24
26
|
* Return a corresponding JSX element for the match.
|
|
25
27
|
* @param ...matches The matches from `match` RegExp (without the `0` zeroeth "whole match").
|
|
@@ -27,7 +29,7 @@ export declare type MarkupRule = {
|
|
|
27
29
|
* - The `key` property is not required (will be set automatically).
|
|
28
30
|
* - e.g. `{ type: "a", props: { href: "/example.html", className: "strong", children: "Children *can* include _syntax_" } }`
|
|
29
31
|
*/
|
|
30
|
-
readonly render:
|
|
32
|
+
readonly render: (matches: RegExpMatchArray, options: MarkupOptions) => MarkupElement;
|
|
31
33
|
/** Apply the rule only when in certain contexts, e.g. `["block", "inline", "list"]` */
|
|
32
34
|
readonly contexts: string[];
|
|
33
35
|
/** Context any string children returned from `render()` should be rendered with. */
|
|
@@ -42,8 +44,6 @@ export declare type MarkupRule = {
|
|
|
42
44
|
*/
|
|
43
45
|
readonly priority?: number;
|
|
44
46
|
};
|
|
45
|
-
export declare type MarkupRuleMatcher = (content: string, options: MarkupOptions) => RegExpMatchArray | null | undefined | void;
|
|
46
|
-
export declare type MarkupRuleRenderer = (matches: RegExpMatchArray, options: MarkupOptions) => MarkupElement;
|
|
47
47
|
/** A set of parse rules (as an object or array). */
|
|
48
48
|
export declare type MarkupRules = Iterable<MarkupRule>;
|
|
49
49
|
/** The current parsing options (represents the current state of the parsing). */
|
|
@@ -59,5 +59,3 @@ export declare type MarkupOptions = {
|
|
|
59
59
|
/** Valid URL schemes/protocols for links (including trailing commas), defaults to `[`http:`, `https:`]` */
|
|
60
60
|
readonly schemes: string[];
|
|
61
61
|
};
|
|
62
|
-
/** The create element function. */
|
|
63
|
-
export declare type MarkupElementCreator = (type: string, props?: MarkupElementProps | null) => MarkupElement;
|