@markup-carve/carve-grammars 0.1.2
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/LICENSE +21 -0
- package/README.md +240 -0
- package/highlightjs/carve.js +537 -0
- package/highlightjs/carve.mjs +25 -0
- package/package.json +119 -0
- package/prism/carve.js +471 -0
- package/shiki/carve.css +46 -0
- package/shiki/index.js +188 -0
- package/textmate/carve.tmLanguage.json +1023 -0
- package/tiptap/carve-kit.js +507 -0
- package/tiptap/extensions/carve-abbreviation.js +79 -0
- package/tiptap/extensions/carve-definition-list.js +270 -0
- package/tiptap/extensions/carve-delete.js +54 -0
- package/tiptap/extensions/carve-div.js +188 -0
- package/tiptap/extensions/carve-embed.js +248 -0
- package/tiptap/extensions/carve-footnote-definition.js +81 -0
- package/tiptap/extensions/carve-footnote.js +76 -0
- package/tiptap/extensions/carve-insert.js +54 -0
- package/tiptap/extensions/carve-keymap.js +71 -0
- package/tiptap/extensions/carve-math.js +82 -0
- package/tiptap/extensions/carve-mention.js +44 -0
- package/tiptap/extensions/carve-span.js +101 -0
- package/tiptap/extensions/carve-tabs.js +158 -0
- package/tiptap/extensions/index.js +14 -0
- package/tiptap/index.js +53 -0
- package/tiptap/serializer.js +686 -0
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Carve language definition for highlight.js
|
|
3
|
+
*
|
|
4
|
+
* Carve is a Djot-derived markup language with distinct inline delimiters:
|
|
5
|
+
* emphasis is /text/ (not _text_), underline is _text_, strikethrough is
|
|
6
|
+
* ~text~ (Djot uses ~ for subscript), subscript is ,text, and highlight is
|
|
7
|
+
* =text= (Djot uses {=text=}). Strong (*text*), superscript (^text^),
|
|
8
|
+
* insert ({+text+}) and delete ({-text-}) match Djot.
|
|
9
|
+
*
|
|
10
|
+
* This file is a UMD module so it works in every documented integration:
|
|
11
|
+
*
|
|
12
|
+
* - ESM: `import carve from 'carve-grammars/highlightjs/carve.js'` (resolved to
|
|
13
|
+
* the carve.mjs shim via the package `exports` map), then
|
|
14
|
+
* `hljs.registerLanguage('carve', carve)`.
|
|
15
|
+
* - Classic `<script src=".../highlightjs/carve.js">` after highlight.js: it
|
|
16
|
+
* self-registers against the global `hljs` (and exposes `globalThis.carveHljs`).
|
|
17
|
+
* - CommonJS contexts that load this file as CommonJS get the factory on
|
|
18
|
+
* `module.exports`.
|
|
19
|
+
*
|
|
20
|
+
* A top-level `export default` is intentionally NOT used: that would be a
|
|
21
|
+
* syntax error when the file is loaded as a classic browser script.
|
|
22
|
+
*
|
|
23
|
+
* @see https://github.com/markup-carve/carve for the Carve specification
|
|
24
|
+
*/
|
|
25
|
+
(function (root, factory) {
|
|
26
|
+
var carve = factory();
|
|
27
|
+
if (typeof module === 'object' && module.exports) {
|
|
28
|
+
module.exports = carve;
|
|
29
|
+
}
|
|
30
|
+
if (root) {
|
|
31
|
+
// Exposed for the ESM shim (carve.mjs) and for classic <script> use.
|
|
32
|
+
root.carveHljs = carve;
|
|
33
|
+
if (root.hljs && typeof root.hljs.registerLanguage === 'function') {
|
|
34
|
+
root.hljs.registerLanguage('carve', carve);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}(typeof globalThis !== 'undefined' ? globalThis : this, function () {
|
|
38
|
+
'use strict';
|
|
39
|
+
/**
|
|
40
|
+
* @param {object} [hljs] - the highlight.js instance (unused, kept for the
|
|
41
|
+
* standard language-definition signature).
|
|
42
|
+
* @returns {object} a highlight.js language definition.
|
|
43
|
+
*/
|
|
44
|
+
return function carve(hljs) {
|
|
45
|
+
// Block attributes: {.class #id key=value} or boolean {reversed}
|
|
46
|
+
// Excludes special inline syntax like {= {+ {- {%
|
|
47
|
+
// The payload is STRICT (spec PART 9 S14): a class/id/key identifier may not
|
|
48
|
+
// start with a digit, so `{2=v}` stays literal text rather than scoping as
|
|
49
|
+
// an attribute block. An unquoted value may contain dots and colons.
|
|
50
|
+
const ATTR_ITEM = /(?:[.#][A-Za-z_][\w-]*|[A-Za-z_][\w:-]*(?:=(?:"(?:[^"\\\n]|\\.)*"|'(?:[^'\\\n]|\\.)*'|[^\s"'{}]+))?)/.source;
|
|
51
|
+
// Forced intraword family (PART 9 S22). Content may contain the delimiter
|
|
52
|
+
// (`{/a/b/}` is <em>a/b</em>), so the run ends at the closing `X}`. These
|
|
53
|
+
// must precede ATTRIBUTE, or `{_path_}` reads as a boolean attribute.
|
|
54
|
+
const FORCED_STRONG = { className: 'strong', begin: /\{\*(?=\S)/, end: /\*\}/, relevance: 5 };
|
|
55
|
+
const FORCED_EMPHASIS = { className: 'emphasis', begin: /\{\/(?=\S)/, end: /\/\}/, relevance: 5 };
|
|
56
|
+
const FORCED_UNDERLINE = { className: 'emphasis', begin: /\{_(?=\S)/, end: /_\}/, relevance: 5 };
|
|
57
|
+
const FORCED_STRIKE = { className: 'deletion', begin: /\{~(?=\S)(?!.*~>)/, end: /~\}/, relevance: 5 };
|
|
58
|
+
|
|
59
|
+
const ATTRIBUTE_EMPTY = {
|
|
60
|
+
className: 'attr',
|
|
61
|
+
// Valid only glued to a preceding `]` (`[x]{}`); a bare `{}` is literal.
|
|
62
|
+
begin: /(?<=\])\{\s*\}/,
|
|
63
|
+
relevance: 5,
|
|
64
|
+
};
|
|
65
|
+
const ATTRIBUTE = {
|
|
66
|
+
className: 'attr',
|
|
67
|
+
begin: new RegExp('\\{\\s*' + ATTR_ITEM + '(?:\\s+' + ATTR_ITEM + ')*\\s*\\}'),
|
|
68
|
+
relevance: 5,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Headings: # to ######
|
|
72
|
+
const HEADING = {
|
|
73
|
+
className: 'section',
|
|
74
|
+
begin: /^#{1,6}\s/,
|
|
75
|
+
end: /$/,
|
|
76
|
+
relevance: 10,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// Emphasis (Carve): /text/ - the begin guard avoids URLs and paths
|
|
80
|
+
// (a/b, ://); the end is a closing slash not followed by word char/slash.
|
|
81
|
+
const EMPHASIS = {
|
|
82
|
+
className: 'emphasis',
|
|
83
|
+
begin: /(?<![\w:/])\/(?=\S)/,
|
|
84
|
+
end: /\/(?![\w/])/,
|
|
85
|
+
relevance: 0,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Underline (Carve): _text_ - not in the middle of words
|
|
89
|
+
const UNDERLINE = {
|
|
90
|
+
className: 'emphasis',
|
|
91
|
+
begin: /(?<!\w)_(?!\s)/,
|
|
92
|
+
end: /_(?!\w)/,
|
|
93
|
+
relevance: 0,
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// Strong: *text* - not in the middle of words, can contain emphasis.
|
|
97
|
+
// Excludes *[ which is abbreviation-definition syntax.
|
|
98
|
+
const STRONG = {
|
|
99
|
+
className: 'strong',
|
|
100
|
+
begin: /(?<!\w)\*(?![\s\[])/,
|
|
101
|
+
end: /\*(?!\w)/,
|
|
102
|
+
relevance: 0,
|
|
103
|
+
contains: [EMPHASIS, UNDERLINE],
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// Highlight (Carve): =text= (single-char; intraword as {=text=})
|
|
107
|
+
const HIGHLIGHT = {
|
|
108
|
+
className: 'addition',
|
|
109
|
+
begin: /(?<![=\w])=(?=\S)/,
|
|
110
|
+
end: /=(?![=\w])/,
|
|
111
|
+
relevance: 3,
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// Insert: {+text+}
|
|
115
|
+
const INSERT = {
|
|
116
|
+
className: 'addition',
|
|
117
|
+
begin: /\{\+/,
|
|
118
|
+
end: /\+\}/,
|
|
119
|
+
relevance: 5,
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// Delete: {-text-}
|
|
123
|
+
const DELETE = {
|
|
124
|
+
className: 'deletion',
|
|
125
|
+
begin: /\{-/,
|
|
126
|
+
end: /-\}/,
|
|
127
|
+
relevance: 5,
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// Strikethrough (Carve): ~text~ (Djot uses ~ for subscript instead)
|
|
131
|
+
const STRIKETHROUGH = {
|
|
132
|
+
className: 'deletion',
|
|
133
|
+
begin: /(?<!\w)~(?=\S)/,
|
|
134
|
+
end: /~(?!\w)/,
|
|
135
|
+
relevance: 2,
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// Subscript (Carve): braced-only `{,text,}` - a bare `,` is literal text.
|
|
139
|
+
const SUBSCRIPT = {
|
|
140
|
+
className: 'built_in',
|
|
141
|
+
begin: /\{,(?=\S)/,
|
|
142
|
+
end: /,\}/,
|
|
143
|
+
relevance: 3,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// Superscript (Carve): braced-only `{^text^}` - a bare `^` is literal text.
|
|
147
|
+
const SUPERSCRIPT = {
|
|
148
|
+
className: 'built_in',
|
|
149
|
+
begin: /\{\^(?=\S)/,
|
|
150
|
+
end: /\^\}/,
|
|
151
|
+
relevance: 3,
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// Math: $$`...`$$ (display) and $`...`$ (inline). Must precede the inline
|
|
155
|
+
// code modes - the leading $ keeps them from matching, but order is clearer.
|
|
156
|
+
const MATH_DISPLAY = {
|
|
157
|
+
className: 'string',
|
|
158
|
+
begin: /\$\$`+/,
|
|
159
|
+
end: /`+\$\$/,
|
|
160
|
+
relevance: 5,
|
|
161
|
+
};
|
|
162
|
+
const MATH_INLINE = {
|
|
163
|
+
className: 'string',
|
|
164
|
+
begin: /\$`+/,
|
|
165
|
+
end: /`+\$/,
|
|
166
|
+
relevance: 5,
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// Inline code: `code` or ``code``. highlight.js has no begin->end
|
|
170
|
+
// backreference to match fence widths, so handle the two common widths
|
|
171
|
+
// explicitly - double backticks first, so an embedded single backtick
|
|
172
|
+
// (``a ` b``) does not close the span early.
|
|
173
|
+
const INLINE_CODE_DOUBLE = {
|
|
174
|
+
className: 'code',
|
|
175
|
+
begin: /``/,
|
|
176
|
+
end: /``/,
|
|
177
|
+
relevance: 0,
|
|
178
|
+
};
|
|
179
|
+
const INLINE_CODE_SINGLE = {
|
|
180
|
+
className: 'code',
|
|
181
|
+
begin: /`/,
|
|
182
|
+
end: /`/,
|
|
183
|
+
relevance: 0,
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// Inline links: [text](url) with optional trailing attributes
|
|
187
|
+
const LINK = {
|
|
188
|
+
className: 'link',
|
|
189
|
+
begin: /\[[^\]]*\]\([^)]*\)(\{[^}]+\})?/,
|
|
190
|
+
relevance: 5,
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
// Autolinks: <https://...> or <mailto:...>
|
|
194
|
+
const AUTOLINK = {
|
|
195
|
+
className: 'link',
|
|
196
|
+
begin: /<(?:https?:\/\/|mailto:)[^>]+>/,
|
|
197
|
+
relevance: 5,
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// Email autolinks: <user@example.com>
|
|
201
|
+
const EMAIL_AUTOLINK = {
|
|
202
|
+
className: 'link',
|
|
203
|
+
begin: /<[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}>/,
|
|
204
|
+
relevance: 5,
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
// Images:  with optional trailing attributes
|
|
208
|
+
const IMAGE = {
|
|
209
|
+
className: 'link',
|
|
210
|
+
begin: /!\[[^\]]*\]\([^)]*\)(\{[^}]+\})?/,
|
|
211
|
+
relevance: 5,
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
// Reference links: [text][ref] with optional trailing attributes
|
|
215
|
+
const REFERENCE_LINK = {
|
|
216
|
+
className: 'link',
|
|
217
|
+
begin: /\[[^\]]+\]\[[^\]]*\](\{[^}]+\})?/,
|
|
218
|
+
relevance: 5,
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
// Spans with attributes: [text]{.class} or [text]{#id}
|
|
222
|
+
const SPAN = {
|
|
223
|
+
className: 'string',
|
|
224
|
+
// Only the bracket run; the trailing `{...}` is left to ATTRIBUTE so it
|
|
225
|
+
// scopes as an attribute block rather than vanishing into the span.
|
|
226
|
+
begin: /\[[^\]]+\](?=\{)/,
|
|
227
|
+
relevance: 5,
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// Reference definitions: [ref]: url
|
|
231
|
+
const REFERENCE_DEF = {
|
|
232
|
+
className: 'symbol',
|
|
233
|
+
begin: /^\[[^\]^\]]+\]:/,
|
|
234
|
+
end: /$/,
|
|
235
|
+
relevance: 10,
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// Footnote references: [^note]
|
|
239
|
+
const FOOTNOTE_REF = {
|
|
240
|
+
className: 'symbol',
|
|
241
|
+
begin: /\[\^[^\]]+\]/,
|
|
242
|
+
relevance: 5,
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
// Citations (Tier-2 §22): [@key], [+@key], [@key, p.10], [@a; @b]
|
|
246
|
+
// A bracket whose content holds at least one `@key` with no trailing
|
|
247
|
+
// `(url)`, `[ref]`, or `{attrs}` suffix. The negative lookahead is handled
|
|
248
|
+
// by position in the contains array (SPAN and REFERENCE_LINK are checked
|
|
249
|
+
// first to claim those suffixed forms).
|
|
250
|
+
const CITATION = {
|
|
251
|
+
className: 'symbol',
|
|
252
|
+
begin: /\[\+?(?:[^\]@]*@[A-Za-z0-9_][A-Za-z0-9_.:#$%&+?<>~\/-]*[^\]]*)\](?!\(|\[|\{)/,
|
|
253
|
+
relevance: 8,
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// Code callouts (Tier-2 §10): <n> markers trailing a code-fence line or
|
|
257
|
+
// leading a callout-list item.
|
|
258
|
+
const CODE_CALLOUT = {
|
|
259
|
+
className: 'symbol',
|
|
260
|
+
begin: /<\d+>/,
|
|
261
|
+
relevance: 5,
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
// Footnote definitions: [^note]: content
|
|
265
|
+
const FOOTNOTE_DEF = {
|
|
266
|
+
className: 'symbol',
|
|
267
|
+
begin: /^\[\^[^\]]+\]:/,
|
|
268
|
+
end: /$/,
|
|
269
|
+
relevance: 10,
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
// Abbreviation definitions: *[ABBR]: text
|
|
273
|
+
const ABBREVIATION_DEF = {
|
|
274
|
+
className: 'symbol',
|
|
275
|
+
begin: /^\*\[[^\]]+\]:/,
|
|
276
|
+
end: /$/,
|
|
277
|
+
relevance: 10,
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// Blockquotes: > text
|
|
281
|
+
const BLOCKQUOTE = {
|
|
282
|
+
className: 'quote',
|
|
283
|
+
begin: /^>/,
|
|
284
|
+
end: /$/,
|
|
285
|
+
relevance: 0,
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
// Horizontal rules: --- or *** or ___
|
|
289
|
+
const HORIZONTAL_RULE = {
|
|
290
|
+
className: 'meta',
|
|
291
|
+
begin: /^(-{3,}|\*{3,}|_{3,})$/,
|
|
292
|
+
relevance: 10,
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
// Bullet list items: - or *
|
|
296
|
+
const LIST_BULLET = {
|
|
297
|
+
className: 'bullet',
|
|
298
|
+
// A marker line may carry several markers (`- - A`, corpus 103).
|
|
299
|
+
begin: /^[ \t]*(?:[-*][ \t]+)*[-*](?=\s)/,
|
|
300
|
+
relevance: 0,
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
// Numbered list items: decimal (1.), alpha (a. A.), roman (i. I.)
|
|
304
|
+
const LIST_NUMBER = {
|
|
305
|
+
className: 'bullet',
|
|
306
|
+
begin: /^[ \t]*(\d+[.)]|[a-zA-Z][.)]|[ivxlcdmIVXLCDM]+[.)])(?=\s)/,
|
|
307
|
+
relevance: 0,
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
// Task list items: - [ ] or - [x]
|
|
311
|
+
const TASK_LIST = {
|
|
312
|
+
className: 'bullet',
|
|
313
|
+
begin: /^[ \t]*[-*]\s\[[ xX_]\]/,
|
|
314
|
+
relevance: 5,
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
// Definition list terms: : term
|
|
318
|
+
const DEFINITION_TERM = {
|
|
319
|
+
className: 'title',
|
|
320
|
+
begin: /^: /,
|
|
321
|
+
end: /$/,
|
|
322
|
+
relevance: 5,
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
// Code fence opening: ``` or ~~~ with optional language
|
|
326
|
+
const CODE_FENCE_START = {
|
|
327
|
+
className: 'keyword',
|
|
328
|
+
begin: /^[`~]{3,}\s*[a-zA-Z]*$/,
|
|
329
|
+
relevance: 10,
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
// Code fence closing: ``` or ~~~
|
|
333
|
+
const CODE_FENCE_END = {
|
|
334
|
+
className: 'keyword',
|
|
335
|
+
begin: /^[`~]{3,}$/,
|
|
336
|
+
relevance: 10,
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
// Div block opening: ::: with optional type, "title", [label], or the
|
|
340
|
+
// | / \ layout tokens. Strict shapes only - unquoted or curly-quoted
|
|
341
|
+
// trailing text is a paragraph, not a fence, and must not highlight.
|
|
342
|
+
const DIV_BLOCK_START = {
|
|
343
|
+
className: 'keyword',
|
|
344
|
+
begin: /^:{3,}(?:[ \t]*(?:\||\\)|[ \t]*[a-zA-Z_][\w-]*(?:[ \t]+"[^"\n]*")?(?:[ \t]+\[[^\]\n]*\])?|[ \t]*\[[^\]\n]*\])?[ \t]*$/,
|
|
345
|
+
relevance: 10,
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
// Div block closing: :::
|
|
349
|
+
const DIV_BLOCK_END = {
|
|
350
|
+
className: 'keyword',
|
|
351
|
+
begin: /^:{3,}$/,
|
|
352
|
+
relevance: 10,
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
// Inline comments: {% comment %}
|
|
356
|
+
// Carve comments: `%%` to end of line, a `%%%` fenced block, and the
|
|
357
|
+
// CriticMarkup comment `{# ... #}`. (The previous rule here matched
|
|
358
|
+
// `{% ... %}`, which is Jinja/Liquid syntax and does not exist in Carve.)
|
|
359
|
+
const LINE_COMMENT = {
|
|
360
|
+
className: 'comment',
|
|
361
|
+
begin: /(?:^|(?<=\s))%%(?!%)/,
|
|
362
|
+
end: /$/,
|
|
363
|
+
relevance: 5,
|
|
364
|
+
};
|
|
365
|
+
const BLOCK_COMMENT = {
|
|
366
|
+
className: 'comment',
|
|
367
|
+
begin: /^%%%\s*$/,
|
|
368
|
+
end: /^%%%\s*$/,
|
|
369
|
+
relevance: 10,
|
|
370
|
+
};
|
|
371
|
+
const CRITIC_SUB = {
|
|
372
|
+
className: 'meta',
|
|
373
|
+
// The `~>` arrow is what distinguishes a substitution from a forced
|
|
374
|
+
// strikethrough (`{~gone~}`), so it is required here.
|
|
375
|
+
begin: /\{~(?=[^}\n]*~>)/,
|
|
376
|
+
end: /~\}/,
|
|
377
|
+
relevance: 10,
|
|
378
|
+
};
|
|
379
|
+
const CRITIC_COMMENT = {
|
|
380
|
+
className: 'comment',
|
|
381
|
+
// The closing `#}` is required, or this would swallow an attribute
|
|
382
|
+
// block whose id comes first (`{#id .class}`).
|
|
383
|
+
begin: /\{#(?=[^}\n]*#\})/,
|
|
384
|
+
end: /#\}/,
|
|
385
|
+
relevance: 5,
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
// Mentions and tags: @name / #name (a heading `#` is line-anchored and is
|
|
389
|
+
// matched earlier, so an inline `#tag` is unambiguous).
|
|
390
|
+
const MENTION = {
|
|
391
|
+
className: 'symbol',
|
|
392
|
+
begin: /(?<![\w@])@[A-Za-z0-9][\w-]*(?:\.[\w-]+)*/,
|
|
393
|
+
relevance: 5,
|
|
394
|
+
};
|
|
395
|
+
const TAG = {
|
|
396
|
+
className: 'symbol',
|
|
397
|
+
begin: /(?<![\w#])#[A-Za-z0-9][\w-]*(?:\.[\w-]+)*/,
|
|
398
|
+
relevance: 5,
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
// Table separator: |---|---|
|
|
402
|
+
const TABLE_SEPARATOR = {
|
|
403
|
+
className: 'meta',
|
|
404
|
+
begin: /^\|[-:| ]+\|$/,
|
|
405
|
+
relevance: 5,
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
// Line blocks: | text (for poetry) - must precede TABLE_ROW
|
|
409
|
+
const LINE_BLOCK = {
|
|
410
|
+
className: 'string',
|
|
411
|
+
begin: /^\| /,
|
|
412
|
+
end: /$/,
|
|
413
|
+
relevance: 3,
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
// Table rows: | cell | cell |
|
|
417
|
+
const TABLE_ROW = {
|
|
418
|
+
className: 'string',
|
|
419
|
+
begin: /^\|/,
|
|
420
|
+
end: /\|(\{[^}]*\})?$/,
|
|
421
|
+
relevance: 2,
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
// Captions: ^ caption text
|
|
425
|
+
const CAPTION = {
|
|
426
|
+
className: 'title',
|
|
427
|
+
begin: /^\^ /,
|
|
428
|
+
end: /$/,
|
|
429
|
+
relevance: 5,
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
// Raw format marker: {=html} or {=latex}
|
|
433
|
+
const RAW_FORMAT = {
|
|
434
|
+
className: 'meta',
|
|
435
|
+
begin: /\{=[a-zA-Z]+\}/,
|
|
436
|
+
relevance: 5,
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
// Escaped characters: \* \[ etc
|
|
440
|
+
const ESCAPE = {
|
|
441
|
+
className: 'symbol',
|
|
442
|
+
begin: /\\[!"#$%&'()*+,.\/:;<=>?@\[\\\]^_`{|}~-]/,
|
|
443
|
+
relevance: 0,
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
// Hard line break: \ at end of line
|
|
447
|
+
const HARD_BREAK = {
|
|
448
|
+
className: 'meta',
|
|
449
|
+
begin: /\\$/,
|
|
450
|
+
relevance: 2,
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
// Symbol shortcodes (e.g. emoji): :name: (parser shape - name starts
|
|
454
|
+
// alphanumeric, then word chars, `+` or `-`; no whitespace, so
|
|
455
|
+
// `a : b : c` stays text)
|
|
456
|
+
const SYMBOL = {
|
|
457
|
+
className: 'symbol',
|
|
458
|
+
begin: /(?<!\w):[A-Za-z0-9+-][\w+-]*:/,
|
|
459
|
+
relevance: 0,
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
return {
|
|
463
|
+
name: 'Carve',
|
|
464
|
+
aliases: ['carve'],
|
|
465
|
+
case_insensitive: false,
|
|
466
|
+
contains: [
|
|
467
|
+
// NOTE: front matter is intentionally NOT highlighted. It is valid
|
|
468
|
+
// only at the very top of the document, but highlight.js has no
|
|
469
|
+
// document-start anchor, so a `^---$` begin would also match a bare
|
|
470
|
+
// `---` horizontal rule mid-document and swallow everything up to
|
|
471
|
+
// the next `---`. The horizontal-rule rule below handles `---`
|
|
472
|
+
// lines instead. (Prism anchors front matter via `^` with no `m`
|
|
473
|
+
// flag; see prism/carve.js.)
|
|
474
|
+
|
|
475
|
+
// Block-level elements (order matters - more specific first)
|
|
476
|
+
HEADING,
|
|
477
|
+
CODE_FENCE_START,
|
|
478
|
+
CODE_FENCE_END,
|
|
479
|
+
DIV_BLOCK_START,
|
|
480
|
+
DIV_BLOCK_END,
|
|
481
|
+
HORIZONTAL_RULE,
|
|
482
|
+
TABLE_SEPARATOR,
|
|
483
|
+
LINE_BLOCK, // Must be before TABLE_ROW (both start with |)
|
|
484
|
+
TABLE_ROW,
|
|
485
|
+
BLOCKQUOTE,
|
|
486
|
+
CAPTION,
|
|
487
|
+
TASK_LIST, // Must be before LIST_BULLET
|
|
488
|
+
LIST_BULLET,
|
|
489
|
+
LIST_NUMBER,
|
|
490
|
+
DEFINITION_TERM,
|
|
491
|
+
FOOTNOTE_DEF, // Must be before REFERENCE_DEF
|
|
492
|
+
ABBREVIATION_DEF, // Must be before REFERENCE_DEF (*[ABBR]: vs [ref]:)
|
|
493
|
+
REFERENCE_DEF,
|
|
494
|
+
|
|
495
|
+
// Inline elements (order matters - more specific first)
|
|
496
|
+
FOOTNOTE_REF,
|
|
497
|
+
IMAGE, // Must be before LINK (starts with !)
|
|
498
|
+
SPAN, // Must be before LINK ([text]{attr} vs [text](url))
|
|
499
|
+
REFERENCE_LINK, // Must be before LINK ([text][ref] vs [text](url))
|
|
500
|
+
CITATION, // Must be after SPAN/REF_LINK (no (url)/[ref]/{attr} tail)
|
|
501
|
+
CODE_CALLOUT, // <n> callout markers
|
|
502
|
+
SYMBOL, // :name: shortcodes
|
|
503
|
+
LINK,
|
|
504
|
+
AUTOLINK,
|
|
505
|
+
EMAIL_AUTOLINK,
|
|
506
|
+
RAW_FORMAT, // {=html} - must be before INSERT/DELETE braces
|
|
507
|
+
INSERT, // {+text+}
|
|
508
|
+
DELETE, // {-text-}
|
|
509
|
+
BLOCK_COMMENT, // %%% fence - before LINE_COMMENT
|
|
510
|
+
LINE_COMMENT, // %% to end of line
|
|
511
|
+
CRITIC_SUB, // {~old~>new~} - before FORCED_STRIKE
|
|
512
|
+
CRITIC_COMMENT, // {# ... #} - must be before ATTRIBUTE
|
|
513
|
+
MENTION,
|
|
514
|
+
TAG,
|
|
515
|
+
HIGHLIGHT, // =text=
|
|
516
|
+
SUBSCRIPT, // ,text,
|
|
517
|
+
SUPERSCRIPT, // ^text^
|
|
518
|
+
STRONG,
|
|
519
|
+
EMPHASIS, // /text/
|
|
520
|
+
UNDERLINE, // _text_
|
|
521
|
+
STRIKETHROUGH, // ~text~
|
|
522
|
+
MATH_DISPLAY, // $$`...`$$ - before inline code (leading $)
|
|
523
|
+
MATH_INLINE, // $`...`$
|
|
524
|
+
INLINE_CODE_DOUBLE, // ``code`` - before single
|
|
525
|
+
INLINE_CODE_SINGLE, // `code`
|
|
526
|
+
FORCED_STRONG,
|
|
527
|
+
FORCED_EMPHASIS,
|
|
528
|
+
FORCED_UNDERLINE,
|
|
529
|
+
FORCED_STRIKE,
|
|
530
|
+
ATTRIBUTE_EMPTY,
|
|
531
|
+
ATTRIBUTE,
|
|
532
|
+
ESCAPE,
|
|
533
|
+
HARD_BREAK,
|
|
534
|
+
],
|
|
535
|
+
};
|
|
536
|
+
};
|
|
537
|
+
}));
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESM entry for the Carve highlight.js grammar.
|
|
3
|
+
*
|
|
4
|
+
* The grammar itself lives in the UMD file `carve.js` (so it can also load as a
|
|
5
|
+
* classic `<script>` or via CommonJS). This shim runs that module for its side
|
|
6
|
+
* effect - which assigns `globalThis.carveHljs` - and re-exports the language
|
|
7
|
+
* factory as the default export, so ESM consumers get the documented:
|
|
8
|
+
*
|
|
9
|
+
* ```js
|
|
10
|
+
* import hljs from 'highlight.js';
|
|
11
|
+
* import carve from 'carve-grammars/highlightjs/carve.js';
|
|
12
|
+
* hljs.registerLanguage('carve', carve);
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* (The package `exports` map routes the ESM `import` of `./highlightjs/carve.js`
|
|
16
|
+
* to this file.)
|
|
17
|
+
*
|
|
18
|
+
* @module carve-grammars/highlightjs/carve
|
|
19
|
+
*/
|
|
20
|
+
import './carve.js';
|
|
21
|
+
|
|
22
|
+
/** @type {(hljs?: object) => object} */
|
|
23
|
+
const carve = globalThis.carveHljs;
|
|
24
|
+
|
|
25
|
+
export default carve;
|
package/package.json
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@markup-carve/carve-grammars",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Grammars for the Carve markup language: Tiptap editor kit + serializer, plus Prism, highlight.js and TextMate syntax-highlighting grammars",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "tiptap/index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "node tests/coverage-test.js && node tests/snapshot-test.js && node tests/roundtrip-test.js && node tests/serializer-test.js && node tests/tabs-roundtrip-test.js && node tests/parse-test.js && node tests/grammar-test.js && node tests/shiki-test.js && node tests/engine-sweep-test.js && node tests/textmate-sweep-test.js",
|
|
9
|
+
"test:coverage": "node tests/coverage-test.js",
|
|
10
|
+
"test:snapshot": "node tests/snapshot-test.js",
|
|
11
|
+
"test:roundtrip": "node tests/roundtrip-test.js",
|
|
12
|
+
"snapshots:update": "UPDATE_SNAPSHOTS=1 node tests/snapshot-test.js"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/markup-carve/carve-grammars.git"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"carve",
|
|
20
|
+
"tiptap",
|
|
21
|
+
"prosemirror",
|
|
22
|
+
"wysiwyg",
|
|
23
|
+
"serializer",
|
|
24
|
+
"markup",
|
|
25
|
+
"syntax-highlighting",
|
|
26
|
+
"prism",
|
|
27
|
+
"prismjs",
|
|
28
|
+
"highlight.js",
|
|
29
|
+
"hljs"
|
|
30
|
+
],
|
|
31
|
+
"author": "markup-carve",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/markup-carve/carve-grammars/issues"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/markup-carve/carve-grammars#readme",
|
|
37
|
+
"files": [
|
|
38
|
+
"tiptap/",
|
|
39
|
+
"prism/",
|
|
40
|
+
"highlightjs/",
|
|
41
|
+
"shiki/",
|
|
42
|
+
"textmate/",
|
|
43
|
+
"README.md",
|
|
44
|
+
"LICENSE"
|
|
45
|
+
],
|
|
46
|
+
"exports": {
|
|
47
|
+
".": "./tiptap/index.js",
|
|
48
|
+
"./tiptap": "./tiptap/index.js",
|
|
49
|
+
"./tiptap/*": "./tiptap/*",
|
|
50
|
+
"./prism/carve.js": "./prism/carve.js",
|
|
51
|
+
"./prism/*": "./prism/*",
|
|
52
|
+
"./highlightjs/carve.js": {
|
|
53
|
+
"import": "./highlightjs/carve.mjs",
|
|
54
|
+
"default": "./highlightjs/carve.js"
|
|
55
|
+
},
|
|
56
|
+
"./highlightjs/*": "./highlightjs/*",
|
|
57
|
+
"./shiki": "./shiki/index.js",
|
|
58
|
+
"./shiki/carve.css": "./shiki/carve.css",
|
|
59
|
+
"./textmate/carve.tmLanguage.json": "./textmate/carve.tmLanguage.json"
|
|
60
|
+
},
|
|
61
|
+
"peerDependencies": {
|
|
62
|
+
"@shikijs/themes": "^2 || ^3",
|
|
63
|
+
"@tiptap/core": "^2",
|
|
64
|
+
"@tiptap/extension-underline": "^2",
|
|
65
|
+
"@tiptap/starter-kit": "^2",
|
|
66
|
+
"highlight.js": "^11",
|
|
67
|
+
"prismjs": "^1"
|
|
68
|
+
},
|
|
69
|
+
"peerDependenciesMeta": {
|
|
70
|
+
"@tiptap/core": {
|
|
71
|
+
"optional": true
|
|
72
|
+
},
|
|
73
|
+
"@tiptap/starter-kit": {
|
|
74
|
+
"optional": true
|
|
75
|
+
},
|
|
76
|
+
"@tiptap/extension-underline": {
|
|
77
|
+
"optional": true
|
|
78
|
+
},
|
|
79
|
+
"prismjs": {
|
|
80
|
+
"optional": true
|
|
81
|
+
},
|
|
82
|
+
"highlight.js": {
|
|
83
|
+
"optional": true
|
|
84
|
+
},
|
|
85
|
+
"@shikijs/themes": {
|
|
86
|
+
"optional": true
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"devDependencies": {
|
|
90
|
+
"@markup-carve/carve": "github:markup-carve/carve-js",
|
|
91
|
+
"@shikijs/themes": "^3.13.0",
|
|
92
|
+
"@tiptap/core": "^2.27.2",
|
|
93
|
+
"@tiptap/extension-bullet-list": "^2.27.2",
|
|
94
|
+
"@tiptap/extension-code-block": "^2.27.2",
|
|
95
|
+
"@tiptap/extension-hard-break": "^2.27.2",
|
|
96
|
+
"@tiptap/extension-highlight": "^2.27.2",
|
|
97
|
+
"@tiptap/extension-image": "^2.27.2",
|
|
98
|
+
"@tiptap/extension-link": "^2.27.2",
|
|
99
|
+
"@tiptap/extension-list-item": "^2.27.2",
|
|
100
|
+
"@tiptap/extension-subscript": "^2.27.2",
|
|
101
|
+
"@tiptap/extension-superscript": "^2.27.2",
|
|
102
|
+
"@tiptap/extension-table": "^2.27.2",
|
|
103
|
+
"@tiptap/extension-table-cell": "^2.27.2",
|
|
104
|
+
"@tiptap/extension-table-header": "^2.27.2",
|
|
105
|
+
"@tiptap/extension-table-row": "^2.27.2",
|
|
106
|
+
"@tiptap/extension-task-item": "^2.27.2",
|
|
107
|
+
"@tiptap/extension-task-list": "^2.27.2",
|
|
108
|
+
"@tiptap/extension-underline": "^2.27.2",
|
|
109
|
+
"@tiptap/pm": "^2.27.2",
|
|
110
|
+
"@tiptap/starter-kit": "^2.27.2",
|
|
111
|
+
"happy-dom": "^20.10.6",
|
|
112
|
+
"highlight.js": "^11.11.1",
|
|
113
|
+
"prismjs": "^1.30.0",
|
|
114
|
+
"shiki": "^4.3.1"
|
|
115
|
+
},
|
|
116
|
+
"publishConfig": {
|
|
117
|
+
"access": "public"
|
|
118
|
+
}
|
|
119
|
+
}
|