UNPKG

8.06 kBJavaScriptView Raw
1(function (Prism) {
2 // We don't allow for pipes inside parentheses
3 // to not break table pattern |(. foo |). bar |
4 var modifierRegex = /\([^|()\n]+\)|\[[^\]\n]+\]|\{[^}\n]+\}/.source;
5 // Opening and closing parentheses which are not a modifier
6 // This pattern is necessary to prevent exponential backtracking
7 var parenthesesRegex = /\)|\((?![^|()\n]+\))/.source;
8 /**
9 * @param {string} source
10 * @param {string} [flags]
11 */
12 function withModifier(source, flags) {
13 return RegExp(
14 source
15 .replace(/<MOD>/g, function () { return '(?:' + modifierRegex + ')'; })
16 .replace(/<PAR>/g, function () { return '(?:' + parenthesesRegex + ')'; }),
17 flags || '');
18 }
19
20 var modifierTokens = {
21 'css': {
22 pattern: /\{[^{}]+\}/,
23 inside: {
24 rest: Prism.languages.css
25 }
26 },
27 'class-id': {
28 pattern: /(\()[^()]+(?=\))/,
29 lookbehind: true,
30 alias: 'attr-value'
31 },
32 'lang': {
33 pattern: /(\[)[^\[\]]+(?=\])/,
34 lookbehind: true,
35 alias: 'attr-value'
36 },
37 // Anything else is punctuation (the first pattern is for row/col spans inside tables)
38 'punctuation': /[\\\/]\d+|\S/
39 };
40
41
42 var textile = Prism.languages.textile = Prism.languages.extend('markup', {
43 'phrase': {
44 pattern: /(^|\r|\n)\S[\s\S]*?(?=$|\r?\n\r?\n|\r\r)/,
45 lookbehind: true,
46 inside: {
47
48 // h1. Header 1
49 'block-tag': {
50 pattern: withModifier(/^[a-z]\w*(?:<MOD>|<PAR>|[<>=])*\./.source),
51 inside: {
52 'modifier': {
53 pattern: withModifier(/(^[a-z]\w*)(?:<MOD>|<PAR>|[<>=])+(?=\.)/.source),
54 lookbehind: true,
55 inside: modifierTokens
56 },
57 'tag': /^[a-z]\w*/,
58 'punctuation': /\.$/
59 }
60 },
61
62 // # List item
63 // * List item
64 'list': {
65 pattern: withModifier(/^[*#]+<MOD>*\s+\S.*/.source, 'm'),
66 inside: {
67 'modifier': {
68 pattern: withModifier(/(^[*#]+)<MOD>+/.source),
69 lookbehind: true,
70 inside: modifierTokens
71 },
72 'punctuation': /^[*#]+/
73 }
74 },
75
76 // | cell | cell | cell |
77 'table': {
78 // Modifiers can be applied to the row: {color:red}.|1|2|3|
79 // or the cell: |{color:red}.1|2|3|
80 pattern: withModifier(/^(?:(?:<MOD>|<PAR>|[<>=^~])+\.\s*)?(?:\|(?:(?:<MOD>|<PAR>|[<>=^~_]|[\\/]\d+)+\.|(?!(?:<MOD>|<PAR>|[<>=^~_]|[\\/]\d+)+\.))[^|]*)+\|/.source, 'm'),
81 inside: {
82 'modifier': {
83 // Modifiers for rows after the first one are
84 // preceded by a pipe and a line feed
85 pattern: withModifier(/(^|\|(?:\r?\n|\r)?)(?:<MOD>|<PAR>|[<>=^~_]|[\\/]\d+)+(?=\.)/.source),
86 lookbehind: true,
87 inside: modifierTokens
88 },
89 'punctuation': /\||^\./
90 }
91 },
92
93 'inline': {
94 // eslint-disable-next-line regexp/no-super-linear-backtracking
95 pattern: withModifier(/(^|[^a-zA-Z\d])(\*\*|__|\?\?|[*_%@+\-^~])<MOD>*.+?\2(?![a-zA-Z\d])/.source),
96 lookbehind: true,
97 inside: {
98 // Note: superscripts and subscripts are not handled specifically
99
100 // *bold*, **bold**
101 'bold': {
102 // eslint-disable-next-line regexp/no-super-linear-backtracking
103 pattern: withModifier(/(^(\*\*?)<MOD>*).+?(?=\2)/.source),
104 lookbehind: true
105 },
106
107 // _italic_, __italic__
108 'italic': {
109 // eslint-disable-next-line regexp/no-super-linear-backtracking
110 pattern: withModifier(/(^(__?)<MOD>*).+?(?=\2)/.source),
111 lookbehind: true
112 },
113
114 // ??cite??
115 'cite': {
116 // eslint-disable-next-line regexp/no-super-linear-backtracking
117 pattern: withModifier(/(^\?\?<MOD>*).+?(?=\?\?)/.source),
118 lookbehind: true,
119 alias: 'string'
120 },
121
122 // @code@
123 'code': {
124 // eslint-disable-next-line regexp/no-super-linear-backtracking
125 pattern: withModifier(/(^@<MOD>*).+?(?=@)/.source),
126 lookbehind: true,
127 alias: 'keyword'
128 },
129
130 // +inserted+
131 'inserted': {
132 // eslint-disable-next-line regexp/no-super-linear-backtracking
133 pattern: withModifier(/(^\+<MOD>*).+?(?=\+)/.source),
134 lookbehind: true
135 },
136
137 // -deleted-
138 'deleted': {
139 // eslint-disable-next-line regexp/no-super-linear-backtracking
140 pattern: withModifier(/(^-<MOD>*).+?(?=-)/.source),
141 lookbehind: true
142 },
143
144 // %span%
145 'span': {
146 // eslint-disable-next-line regexp/no-super-linear-backtracking
147 pattern: withModifier(/(^%<MOD>*).+?(?=%)/.source),
148 lookbehind: true
149 },
150
151 'modifier': {
152 pattern: withModifier(/(^\*\*|__|\?\?|[*_%@+\-^~])<MOD>+/.source),
153 lookbehind: true,
154 inside: modifierTokens
155 },
156 'punctuation': /[*_%?@+\-^~]+/
157 }
158 },
159
160 // [alias]http://example.com
161 'link-ref': {
162 pattern: /^\[[^\]]+\]\S+$/m,
163 inside: {
164 'string': {
165 pattern: /(^\[)[^\]]+(?=\])/,
166 lookbehind: true
167 },
168 'url': {
169 pattern: /(^\])\S+$/,
170 lookbehind: true
171 },
172 'punctuation': /[\[\]]/
173 }
174 },
175
176 // "text":http://example.com
177 // "text":link-ref
178 'link': {
179 // eslint-disable-next-line regexp/no-super-linear-backtracking
180 pattern: withModifier(/"<MOD>*[^"]+":.+?(?=[^\w/]?(?:\s|$))/.source),
181 inside: {
182 'text': {
183 // eslint-disable-next-line regexp/no-super-linear-backtracking
184 pattern: withModifier(/(^"<MOD>*)[^"]+(?=")/.source),
185 lookbehind: true
186 },
187 'modifier': {
188 pattern: withModifier(/(^")<MOD>+/.source),
189 lookbehind: true,
190 inside: modifierTokens
191 },
192 'url': {
193 pattern: /(:).+/,
194 lookbehind: true
195 },
196 'punctuation': /[":]/
197 }
198 },
199
200 // !image.jpg!
201 // !image.jpg(Title)!:http://example.com
202 'image': {
203 pattern: withModifier(/!(?:<MOD>|<PAR>|[<>=])*(?![<>=])[^!\s()]+(?:\([^)]+\))?!(?::.+?(?=[^\w/]?(?:\s|$)))?/.source),
204 inside: {
205 'source': {
206 pattern: withModifier(/(^!(?:<MOD>|<PAR>|[<>=])*)(?![<>=])[^!\s()]+(?:\([^)]+\))?(?=!)/.source),
207 lookbehind: true,
208 alias: 'url'
209 },
210 'modifier': {
211 pattern: withModifier(/(^!)(?:<MOD>|<PAR>|[<>=])+/.source),
212 lookbehind: true,
213 inside: modifierTokens
214 },
215 'url': {
216 pattern: /(:).+/,
217 lookbehind: true
218 },
219 'punctuation': /[!:]/
220 }
221 },
222
223 // Footnote[1]
224 'footnote': {
225 pattern: /\b\[\d+\]/,
226 alias: 'comment',
227 inside: {
228 'punctuation': /\[|\]/
229 }
230 },
231
232 // CSS(Cascading Style Sheet)
233 'acronym': {
234 pattern: /\b[A-Z\d]+\([^)]+\)/,
235 inside: {
236 'comment': {
237 pattern: /(\()[^()]+(?=\))/,
238 lookbehind: true
239 },
240 'punctuation': /[()]/
241 }
242 },
243
244 // Prism(C)
245 'mark': {
246 pattern: /\b\((?:C|R|TM)\)/,
247 alias: 'comment',
248 inside: {
249 'punctuation': /[()]/
250 }
251 }
252 }
253 }
254 });
255
256 var phraseInside = textile['phrase'].inside;
257 var nestedPatterns = {
258 'inline': phraseInside['inline'],
259 'link': phraseInside['link'],
260 'image': phraseInside['image'],
261 'footnote': phraseInside['footnote'],
262 'acronym': phraseInside['acronym'],
263 'mark': phraseInside['mark']
264 };
265
266 // Only allow alpha-numeric HTML tags, not XML tags
267 textile.tag.pattern = /<\/?(?!\d)[a-z0-9]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i;
268
269 // Allow some nesting
270 var phraseInlineInside = phraseInside['inline'].inside;
271 phraseInlineInside['bold'].inside = nestedPatterns;
272 phraseInlineInside['italic'].inside = nestedPatterns;
273 phraseInlineInside['inserted'].inside = nestedPatterns;
274 phraseInlineInside['deleted'].inside = nestedPatterns;
275 phraseInlineInside['span'].inside = nestedPatterns;
276
277 // Allow some styles inside table cells
278 var phraseTableInside = phraseInside['table'].inside;
279 phraseTableInside['inline'] = nestedPatterns['inline'];
280 phraseTableInside['link'] = nestedPatterns['link'];
281 phraseTableInside['image'] = nestedPatterns['image'];
282 phraseTableInside['footnote'] = nestedPatterns['footnote'];
283 phraseTableInside['acronym'] = nestedPatterns['acronym'];
284 phraseTableInside['mark'] = nestedPatterns['mark'];
285
286}(Prism));