pantsdown 2.2.2 → 2.2.4

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/src/lexer.ts CHANGED
@@ -3,423 +3,423 @@ import { Tokenizer } from "./tokenizer.ts";
3
3
  import { type Links, type SourceMap, type Token, type Tokens } from "./types.ts";
4
4
 
5
5
  export class Lexer {
6
- private tokenizer: Tokenizer;
7
- private inlineQueue: { src: string; tokens: Token[] }[];
8
- private links: Links = {};
9
-
10
- tokens: Token[] = [];
11
- footnoteTokens: Tokens["Footnote"][] = [];
12
- line = 1;
13
- state = {
14
- inLink: false,
15
- inRawBlock: false,
16
- top: true,
17
- };
18
-
19
- constructor() {
20
- this.tokenizer = new Tokenizer(this);
21
- this.inlineQueue = [];
22
- }
23
-
24
- /**
25
- * Preprocessing
26
- */
27
- lex(src: string) {
28
- // reset values from previous parse
29
- this.tokenizer.pendingHtmlClose = [];
30
- this.footnoteTokens = [];
31
- this.tokens = [];
32
- this.links = {};
33
- this.line = 1;
34
-
35
- src = src.replace(/\r\n|\r/g, "\n");
36
-
37
- this.blockTokens(src, this.tokens);
38
-
39
- for (const next of this.inlineQueue) {
40
- this.inlineTokens(next.src, next.tokens);
41
- }
42
- this.inlineQueue = [];
43
-
44
- const footnotesToken: Tokens["Footnotes"] = {
45
- type: "footnotes",
46
- raw: "",
47
- items: this.footnoteTokens,
48
- };
49
-
50
- this.tokens.push(footnotesToken);
51
-
52
- return this.tokens;
53
- }
54
-
55
- getSourceMap(rawToken: string): SourceMap | undefined {
56
- if (!this.state.top) return;
57
- const tokenLines = rawToken.split("\n");
58
- const sourceMap: SourceMap = [this.line, (this.line += tokenLines.length - 1)];
59
-
60
- while (tokenLines[tokenLines.length - 1] === "") {
61
- // token.raw sometimes includes newline chars at the end of the string
62
- // which we don't want to include in the sourceMap
63
- tokenLines.pop();
64
- sourceMap[1]--;
65
- }
66
-
67
- return sourceMap;
68
- }
69
-
70
- /**
71
- * Lexing
72
- */
73
- blockTokens(src: string, tokens: Token[]): Token[] {
74
- src = src.replace(/^( *)(\t+)/gm, (_, leading: string, tabs: string) => {
75
- return leading + " ".repeat(tabs.length);
76
- });
77
-
78
- let token: Token | undefined;
79
- let lastToken: Token | undefined;
80
- let cutSrc;
81
- let lastParagraphClipped;
82
-
83
- while (src) {
84
- // newline
85
- if ((token = this.tokenizer.space(src))) {
86
- src = src.substring(token.raw.length);
87
- if (token.raw.length === 1 && tokens.length > 0) {
88
- // if there's a single \n as a spacer, it's terminating the last line,
89
- // so move it there so that we don't get unecessary paragraph tags
90
- const last = tokens[tokens.length - 1];
91
- if (last) last.raw += "\n";
92
- } else {
93
- tokens.push(token);
94
- }
95
- continue;
96
- }
97
-
98
- // code
99
- if ((token = this.tokenizer.code(src))) {
100
- src = src.substring(token.raw.length);
101
- lastToken = tokens[tokens.length - 1];
102
- // An indented code block cannot interrupt a paragraph.
103
- if (lastToken && (lastToken.type === "paragraph" || lastToken.type === "text")) {
104
- lastToken.raw += "\n" + token.raw;
105
- lastToken.text += "\n" + token.text;
106
- const lastInline = this.inlineQueue[this.inlineQueue.length - 1];
107
- if (lastInline) lastInline.src = lastToken.text;
108
- } else {
109
- tokens.push(token);
110
- }
111
- continue;
112
- }
113
-
114
- // latexBlock
115
- if ((token = this.tokenizer.latexBlock(src))) {
116
- src = src.substring(token.raw.length);
117
- tokens.push(token);
118
- continue;
119
- }
120
-
121
- // fences
122
- if ((token = this.tokenizer.fences(src))) {
123
- src = src.substring(token.raw.length);
124
- tokens.push(token);
125
- continue;
126
- }
127
-
128
- // footnote
129
- if ((token = this.tokenizer.footnote(src))) {
130
- src = src.substring(token.raw.length);
131
- this.footnoteTokens.push(token);
132
- continue;
133
- }
134
-
135
- // heading
136
- if ((token = this.tokenizer.heading(src))) {
137
- src = src.substring(token.raw.length);
138
- tokens.push(token);
139
- continue;
140
- }
141
-
142
- // hr
143
- if ((token = this.tokenizer.hr(src))) {
144
- src = src.substring(token.raw.length);
145
- tokens.push(token);
146
- continue;
147
- }
148
-
149
- // blockquote
150
- if ((token = this.tokenizer.blockquote(src))) {
151
- src = src.substring(token.raw.length);
152
- tokens.push(token);
153
- continue;
154
- }
155
-
156
- // list
157
- if ((token = this.tokenizer.list(src))) {
158
- src = src.substring(token.raw.length);
159
- tokens.push(token);
160
- continue;
161
- }
162
-
163
- // html
164
- if ((token = this.tokenizer.html(src))) {
165
- src = src.substring(token.raw.length);
166
- tokens.push(token);
167
- continue;
168
- }
169
-
170
- // def
171
- if ((token = this.tokenizer.def(src))) {
172
- src = src.substring(token.raw.length);
173
- lastToken = tokens[tokens.length - 1];
174
- if (lastToken && (lastToken.type === "paragraph" || lastToken.type === "text")) {
175
- lastToken.raw += "\n" + token.raw;
176
- lastToken.text += "\n" + token.raw;
177
- const lastInline = this.inlineQueue[this.inlineQueue.length - 1];
178
- if (lastInline) lastInline.src = lastToken.text;
179
- } else {
180
- this.links[token.tag] ??= {
181
- href: token.href,
182
- title: token.title,
183
- };
184
- }
185
- continue;
186
- }
187
-
188
- // table (gfm)
189
- if ((token = this.tokenizer.table(src))) {
190
- src = src.substring(token.raw.length);
191
- tokens.push(token);
192
- continue;
193
- }
194
-
195
- // lheading
196
- if ((token = this.tokenizer.lheading(src))) {
197
- src = src.substring(token.raw.length);
198
- tokens.push(token);
199
- continue;
200
- }
201
-
202
- // top-level paragraph
203
- // prevent paragraph consuming extensions by clipping 'src' to extension start
204
- cutSrc = src;
205
- if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) {
206
- lastToken = tokens[tokens.length - 1];
207
- if (lastParagraphClipped && lastToken?.type === "paragraph") {
208
- lastToken.raw += "\n" + token.raw;
209
- lastToken.text += "\n" + token.text;
210
- this.inlineQueue.pop();
211
- const lastInline = this.inlineQueue[this.inlineQueue.length - 1];
212
- if (lastInline) lastInline.src = lastToken.text;
213
- } else {
214
- tokens.push(token);
215
- }
216
- lastParagraphClipped = cutSrc.length !== src.length;
217
- src = src.substring(token.raw.length);
218
- continue;
219
- }
220
-
221
- // text
222
- if ((token = this.tokenizer.text(src))) {
223
- src = src.substring(token.raw.length);
224
- lastToken = tokens[tokens.length - 1];
225
- if (lastToken?.type === "text") {
226
- lastToken.raw += "\n" + token.raw;
227
- lastToken.text += "\n" + token.text;
228
- this.inlineQueue.pop();
229
- const lastInline = this.inlineQueue[this.inlineQueue.length - 1];
230
- if (lastInline) lastInline.src = lastToken.text;
231
- } else {
232
- tokens.push(token);
233
- }
234
- continue;
235
- }
236
-
237
- if (src) {
238
- const errMsg = "Infinite loop on byte: " + String(src.charCodeAt(0));
239
- throw new Error(errMsg);
240
- }
241
- }
242
-
243
- this.state.top = true;
244
- return tokens;
245
- }
246
-
247
- inline(src: string, tokens: Token[] = []) {
248
- this.inlineQueue.push({ src, tokens });
249
- return tokens;
250
- }
251
-
252
- /**
253
- * Lexing/Compiling
254
- */
255
- inlineTokens(src: string, tokens: Token[] = []): Token[] {
256
- let token, lastToken, cutSrc;
257
-
258
- // String with links masked to avoid interference with em and strong
259
- let maskedSrc = src;
260
- let match;
261
- let keepPrevChar, prevChar;
262
-
263
- // Mask out reflinks
264
- const links = Object.keys(this.links);
265
- if (links.length > 0) {
266
- while ((match = inline.reflinkSearch.exec(maskedSrc)) != null) {
267
- if (links.includes(match[0].slice(match[0].lastIndexOf("[") + 1, -1))) {
268
- maskedSrc =
269
- maskedSrc.slice(0, match.index) +
270
- "[" +
271
- "a".repeat(match[0].length - 2) +
272
- "]" +
273
- maskedSrc.slice(inline.reflinkSearch.lastIndex);
274
- }
275
- }
276
- }
277
- // Mask out other blocks
278
- while ((match = inline.blockSkip.exec(maskedSrc)) != null) {
279
- maskedSrc =
280
- maskedSrc.slice(0, match.index) +
281
- "[" +
282
- "a".repeat(match[0].length - 2) +
283
- "]" +
284
- maskedSrc.slice(inline.blockSkip.lastIndex);
285
- }
286
-
287
- // Mask out escaped characters
288
- while ((match = inline.anyPunctuation.exec(maskedSrc)) != null) {
289
- maskedSrc =
290
- maskedSrc.slice(0, match.index) +
291
- "++" +
292
- maskedSrc.slice(inline.anyPunctuation.lastIndex);
293
- }
294
-
295
- while (src) {
296
- if (!keepPrevChar) {
297
- prevChar = "";
298
- }
299
- keepPrevChar = false;
300
-
301
- // latexInline (before escape to handle \(...\) syntax)
302
- if ((token = this.tokenizer.latexInline(src))) {
303
- src = src.substring(token.raw.length);
304
- tokens.push(token);
305
- continue;
306
- }
307
-
308
- // escape
309
- if ((token = this.tokenizer.escape(src))) {
310
- src = src.substring(token.raw.length);
311
- tokens.push(token);
312
- continue;
313
- }
314
-
315
- // tag
316
- if ((token = this.tokenizer.tag(src))) {
317
- src = src.substring(token.raw.length);
318
- lastToken = tokens[tokens.length - 1];
319
- if (lastToken && token.type === "text" && lastToken.type === "text") {
320
- lastToken.raw += token.raw;
321
- lastToken.text += token.text;
322
- } else {
323
- tokens.push(token);
324
- }
325
- continue;
326
- }
327
-
328
- // footnoteRef
329
- if ((token = this.tokenizer.footnoteRef(src))) {
330
- src = src.substring(token.raw.length);
331
- tokens.push(token);
332
- continue;
333
- }
334
-
335
- // link
336
- if ((token = this.tokenizer.link(src))) {
337
- src = src.substring(token.raw.length);
338
- tokens.push(token);
339
- continue;
340
- }
341
-
342
- // reflink, nolink
343
- if ((token = this.tokenizer.reflink(src, this.links))) {
344
- src = src.substring(token.raw.length);
345
- lastToken = tokens[tokens.length - 1];
346
- if (lastToken && token.type === "text" && lastToken.type === "text") {
347
- lastToken.raw += token.raw;
348
- lastToken.text += token.text;
349
- } else {
350
- tokens.push(token);
351
- }
352
- continue;
353
- }
354
-
355
- // em & strong
356
- if ((token = this.tokenizer.emStrong(src, maskedSrc, prevChar))) {
357
- src = src.substring(token.raw.length);
358
- tokens.push(token);
359
- continue;
360
- }
361
-
362
- // code
363
- if ((token = this.tokenizer.codespan(src))) {
364
- src = src.substring(token.raw.length);
365
- tokens.push(token);
366
- continue;
367
- }
368
-
369
- // br
370
- if ((token = this.tokenizer.br(src))) {
371
- src = src.substring(token.raw.length);
372
- tokens.push(token);
373
- continue;
374
- }
375
-
376
- // del (gfm)
377
- if ((token = this.tokenizer.del(src))) {
378
- src = src.substring(token.raw.length);
379
- tokens.push(token);
380
- continue;
381
- }
382
-
383
- // autolink
384
- if ((token = this.tokenizer.autolink(src))) {
385
- src = src.substring(token.raw.length);
386
- tokens.push(token);
387
- continue;
388
- }
389
-
390
- // url (gfm)
391
- if (!this.state.inLink && (token = this.tokenizer.url(src))) {
392
- src = src.substring(token.raw.length);
393
- tokens.push(token);
394
- continue;
395
- }
396
-
397
- // text
398
- // prevent inlineText consuming extensions by clipping 'src' to extension start
399
- cutSrc = src;
400
- if ((token = this.tokenizer.inlineText(cutSrc))) {
401
- src = src.substring(token.raw.length);
402
- if (!token.raw.endsWith("_")) {
403
- // Track prevChar before string of ____ started
404
- prevChar = token.raw.slice(-1);
405
- }
406
- keepPrevChar = true;
407
- lastToken = tokens[tokens.length - 1];
408
- if (lastToken?.type === "text") {
409
- lastToken.raw += token.raw;
410
- lastToken.text += token.text;
411
- } else {
412
- tokens.push(token);
413
- }
414
- continue;
415
- }
416
-
417
- if (src) {
418
- const errMsg = "Infinite loop on byte: " + String(src.charCodeAt(0));
419
- throw new Error(errMsg);
420
- }
421
- }
422
-
423
- return tokens;
424
- }
6
+ private tokenizer: Tokenizer;
7
+ private inlineQueue: { src: string; tokens: Token[] }[];
8
+ private links: Links = {};
9
+
10
+ tokens: Token[] = [];
11
+ footnoteTokens: Tokens["Footnote"][] = [];
12
+ line = 1;
13
+ state = {
14
+ inLink: false,
15
+ inRawBlock: false,
16
+ top: true,
17
+ };
18
+
19
+ constructor() {
20
+ this.tokenizer = new Tokenizer(this);
21
+ this.inlineQueue = [];
22
+ }
23
+
24
+ /**
25
+ * Preprocessing
26
+ */
27
+ lex(src: string) {
28
+ // reset values from previous parse
29
+ this.tokenizer.pendingHtmlClose = [];
30
+ this.footnoteTokens = [];
31
+ this.tokens = [];
32
+ this.links = {};
33
+ this.line = 1;
34
+
35
+ src = src.replace(/\r\n|\r/g, "\n");
36
+
37
+ this.blockTokens(src, this.tokens);
38
+
39
+ for (const next of this.inlineQueue) {
40
+ this.inlineTokens(next.src, next.tokens);
41
+ }
42
+ this.inlineQueue = [];
43
+
44
+ const footnotesToken: Tokens["Footnotes"] = {
45
+ type: "footnotes",
46
+ raw: "",
47
+ items: this.footnoteTokens,
48
+ };
49
+
50
+ this.tokens.push(footnotesToken);
51
+
52
+ return this.tokens;
53
+ }
54
+
55
+ getSourceMap(rawToken: string): SourceMap | undefined {
56
+ if (!this.state.top) return;
57
+ const tokenLines = rawToken.split("\n");
58
+ const sourceMap: SourceMap = [this.line, (this.line += tokenLines.length - 1)];
59
+
60
+ while (tokenLines[tokenLines.length - 1] === "") {
61
+ // token.raw sometimes includes newline chars at the end of the string
62
+ // which we don't want to include in the sourceMap
63
+ tokenLines.pop();
64
+ sourceMap[1]--;
65
+ }
66
+
67
+ return sourceMap;
68
+ }
69
+
70
+ /**
71
+ * Lexing
72
+ */
73
+ blockTokens(src: string, tokens: Token[]): Token[] {
74
+ src = src.replace(/^( *)(\t+)/gm, (_, leading: string, tabs: string) => {
75
+ return leading + " ".repeat(tabs.length);
76
+ });
77
+
78
+ let token: Token | undefined;
79
+ let lastToken: Token | undefined;
80
+ let cutSrc;
81
+ let lastParagraphClipped;
82
+
83
+ while (src) {
84
+ // newline
85
+ if ((token = this.tokenizer.space(src))) {
86
+ src = src.substring(token.raw.length);
87
+ if (token.raw.length === 1 && tokens.length > 0) {
88
+ // if there's a single \n as a spacer, it's terminating the last line,
89
+ // so move it there so that we don't get unecessary paragraph tags
90
+ const last = tokens[tokens.length - 1];
91
+ if (last) last.raw += "\n";
92
+ } else {
93
+ tokens.push(token);
94
+ }
95
+ continue;
96
+ }
97
+
98
+ // code
99
+ if ((token = this.tokenizer.code(src))) {
100
+ src = src.substring(token.raw.length);
101
+ lastToken = tokens[tokens.length - 1];
102
+ // An indented code block cannot interrupt a paragraph.
103
+ if (lastToken && (lastToken.type === "paragraph" || lastToken.type === "text")) {
104
+ lastToken.raw += "\n" + token.raw;
105
+ lastToken.text += "\n" + token.text;
106
+ const lastInline = this.inlineQueue[this.inlineQueue.length - 1];
107
+ if (lastInline) lastInline.src = lastToken.text;
108
+ } else {
109
+ tokens.push(token);
110
+ }
111
+ continue;
112
+ }
113
+
114
+ // latexBlock
115
+ if ((token = this.tokenizer.latexBlock(src))) {
116
+ src = src.substring(token.raw.length);
117
+ tokens.push(token);
118
+ continue;
119
+ }
120
+
121
+ // fences
122
+ if ((token = this.tokenizer.fences(src))) {
123
+ src = src.substring(token.raw.length);
124
+ tokens.push(token);
125
+ continue;
126
+ }
127
+
128
+ // footnote
129
+ if ((token = this.tokenizer.footnote(src))) {
130
+ src = src.substring(token.raw.length);
131
+ this.footnoteTokens.push(token);
132
+ continue;
133
+ }
134
+
135
+ // heading
136
+ if ((token = this.tokenizer.heading(src))) {
137
+ src = src.substring(token.raw.length);
138
+ tokens.push(token);
139
+ continue;
140
+ }
141
+
142
+ // hr
143
+ if ((token = this.tokenizer.hr(src))) {
144
+ src = src.substring(token.raw.length);
145
+ tokens.push(token);
146
+ continue;
147
+ }
148
+
149
+ // blockquote
150
+ if ((token = this.tokenizer.blockquote(src))) {
151
+ src = src.substring(token.raw.length);
152
+ tokens.push(token);
153
+ continue;
154
+ }
155
+
156
+ // list
157
+ if ((token = this.tokenizer.list(src))) {
158
+ src = src.substring(token.raw.length);
159
+ tokens.push(token);
160
+ continue;
161
+ }
162
+
163
+ // html
164
+ if ((token = this.tokenizer.html(src))) {
165
+ src = src.substring(token.raw.length);
166
+ tokens.push(token);
167
+ continue;
168
+ }
169
+
170
+ // def
171
+ if ((token = this.tokenizer.def(src))) {
172
+ src = src.substring(token.raw.length);
173
+ lastToken = tokens[tokens.length - 1];
174
+ if (lastToken && (lastToken.type === "paragraph" || lastToken.type === "text")) {
175
+ lastToken.raw += "\n" + token.raw;
176
+ lastToken.text += "\n" + token.raw;
177
+ const lastInline = this.inlineQueue[this.inlineQueue.length - 1];
178
+ if (lastInline) lastInline.src = lastToken.text;
179
+ } else {
180
+ this.links[token.tag] ??= {
181
+ href: token.href,
182
+ title: token.title,
183
+ };
184
+ }
185
+ continue;
186
+ }
187
+
188
+ // table (gfm)
189
+ if ((token = this.tokenizer.table(src))) {
190
+ src = src.substring(token.raw.length);
191
+ tokens.push(token);
192
+ continue;
193
+ }
194
+
195
+ // lheading
196
+ if ((token = this.tokenizer.lheading(src))) {
197
+ src = src.substring(token.raw.length);
198
+ tokens.push(token);
199
+ continue;
200
+ }
201
+
202
+ // top-level paragraph
203
+ // prevent paragraph consuming extensions by clipping 'src' to extension start
204
+ cutSrc = src;
205
+ if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) {
206
+ lastToken = tokens[tokens.length - 1];
207
+ if (lastParagraphClipped && lastToken?.type === "paragraph") {
208
+ lastToken.raw += "\n" + token.raw;
209
+ lastToken.text += "\n" + token.text;
210
+ this.inlineQueue.pop();
211
+ const lastInline = this.inlineQueue[this.inlineQueue.length - 1];
212
+ if (lastInline) lastInline.src = lastToken.text;
213
+ } else {
214
+ tokens.push(token);
215
+ }
216
+ lastParagraphClipped = cutSrc.length !== src.length;
217
+ src = src.substring(token.raw.length);
218
+ continue;
219
+ }
220
+
221
+ // text
222
+ if ((token = this.tokenizer.text(src))) {
223
+ src = src.substring(token.raw.length);
224
+ lastToken = tokens[tokens.length - 1];
225
+ if (lastToken?.type === "text") {
226
+ lastToken.raw += "\n" + token.raw;
227
+ lastToken.text += "\n" + token.text;
228
+ this.inlineQueue.pop();
229
+ const lastInline = this.inlineQueue[this.inlineQueue.length - 1];
230
+ if (lastInline) lastInline.src = lastToken.text;
231
+ } else {
232
+ tokens.push(token);
233
+ }
234
+ continue;
235
+ }
236
+
237
+ if (src) {
238
+ const errMsg = "Infinite loop on byte: " + String(src.charCodeAt(0));
239
+ throw new Error(errMsg);
240
+ }
241
+ }
242
+
243
+ this.state.top = true;
244
+ return tokens;
245
+ }
246
+
247
+ inline(src: string, tokens: Token[] = []) {
248
+ this.inlineQueue.push({ src, tokens });
249
+ return tokens;
250
+ }
251
+
252
+ /**
253
+ * Lexing/Compiling
254
+ */
255
+ inlineTokens(src: string, tokens: Token[] = []): Token[] {
256
+ let token, lastToken, cutSrc;
257
+
258
+ // String with links masked to avoid interference with em and strong
259
+ let maskedSrc = src;
260
+ let match;
261
+ let keepPrevChar, prevChar;
262
+
263
+ // Mask out reflinks
264
+ const links = Object.keys(this.links);
265
+ if (links.length > 0) {
266
+ while ((match = inline.reflinkSearch.exec(maskedSrc)) != null) {
267
+ if (links.includes(match[0].slice(match[0].lastIndexOf("[") + 1, -1))) {
268
+ maskedSrc =
269
+ maskedSrc.slice(0, match.index) +
270
+ "[" +
271
+ "a".repeat(match[0].length - 2) +
272
+ "]" +
273
+ maskedSrc.slice(inline.reflinkSearch.lastIndex);
274
+ }
275
+ }
276
+ }
277
+ // Mask out other blocks
278
+ while ((match = inline.blockSkip.exec(maskedSrc)) != null) {
279
+ maskedSrc =
280
+ maskedSrc.slice(0, match.index) +
281
+ "[" +
282
+ "a".repeat(match[0].length - 2) +
283
+ "]" +
284
+ maskedSrc.slice(inline.blockSkip.lastIndex);
285
+ }
286
+
287
+ // Mask out escaped characters
288
+ while ((match = inline.anyPunctuation.exec(maskedSrc)) != null) {
289
+ maskedSrc =
290
+ maskedSrc.slice(0, match.index) +
291
+ "++" +
292
+ maskedSrc.slice(inline.anyPunctuation.lastIndex);
293
+ }
294
+
295
+ while (src) {
296
+ if (!keepPrevChar) {
297
+ prevChar = "";
298
+ }
299
+ keepPrevChar = false;
300
+
301
+ // latexInline (before escape to handle \(...\) syntax)
302
+ if ((token = this.tokenizer.latexInline(src))) {
303
+ src = src.substring(token.raw.length);
304
+ tokens.push(token);
305
+ continue;
306
+ }
307
+
308
+ // escape
309
+ if ((token = this.tokenizer.escape(src))) {
310
+ src = src.substring(token.raw.length);
311
+ tokens.push(token);
312
+ continue;
313
+ }
314
+
315
+ // tag
316
+ if ((token = this.tokenizer.tag(src))) {
317
+ src = src.substring(token.raw.length);
318
+ lastToken = tokens[tokens.length - 1];
319
+ if (lastToken && token.type === "text" && lastToken.type === "text") {
320
+ lastToken.raw += token.raw;
321
+ lastToken.text += token.text;
322
+ } else {
323
+ tokens.push(token);
324
+ }
325
+ continue;
326
+ }
327
+
328
+ // footnoteRef
329
+ if ((token = this.tokenizer.footnoteRef(src))) {
330
+ src = src.substring(token.raw.length);
331
+ tokens.push(token);
332
+ continue;
333
+ }
334
+
335
+ // link
336
+ if ((token = this.tokenizer.link(src))) {
337
+ src = src.substring(token.raw.length);
338
+ tokens.push(token);
339
+ continue;
340
+ }
341
+
342
+ // reflink, nolink
343
+ if ((token = this.tokenizer.reflink(src, this.links))) {
344
+ src = src.substring(token.raw.length);
345
+ lastToken = tokens[tokens.length - 1];
346
+ if (lastToken && token.type === "text" && lastToken.type === "text") {
347
+ lastToken.raw += token.raw;
348
+ lastToken.text += token.text;
349
+ } else {
350
+ tokens.push(token);
351
+ }
352
+ continue;
353
+ }
354
+
355
+ // em & strong
356
+ if ((token = this.tokenizer.emStrong(src, maskedSrc, prevChar))) {
357
+ src = src.substring(token.raw.length);
358
+ tokens.push(token);
359
+ continue;
360
+ }
361
+
362
+ // code
363
+ if ((token = this.tokenizer.codespan(src))) {
364
+ src = src.substring(token.raw.length);
365
+ tokens.push(token);
366
+ continue;
367
+ }
368
+
369
+ // br
370
+ if ((token = this.tokenizer.br(src))) {
371
+ src = src.substring(token.raw.length);
372
+ tokens.push(token);
373
+ continue;
374
+ }
375
+
376
+ // del (gfm)
377
+ if ((token = this.tokenizer.del(src))) {
378
+ src = src.substring(token.raw.length);
379
+ tokens.push(token);
380
+ continue;
381
+ }
382
+
383
+ // autolink
384
+ if ((token = this.tokenizer.autolink(src))) {
385
+ src = src.substring(token.raw.length);
386
+ tokens.push(token);
387
+ continue;
388
+ }
389
+
390
+ // url (gfm)
391
+ if (!this.state.inLink && (token = this.tokenizer.url(src))) {
392
+ src = src.substring(token.raw.length);
393
+ tokens.push(token);
394
+ continue;
395
+ }
396
+
397
+ // text
398
+ // prevent inlineText consuming extensions by clipping 'src' to extension start
399
+ cutSrc = src;
400
+ if ((token = this.tokenizer.inlineText(cutSrc))) {
401
+ src = src.substring(token.raw.length);
402
+ if (!token.raw.endsWith("_")) {
403
+ // Track prevChar before string of ____ started
404
+ prevChar = token.raw.slice(-1);
405
+ }
406
+ keepPrevChar = true;
407
+ lastToken = tokens[tokens.length - 1];
408
+ if (lastToken?.type === "text") {
409
+ lastToken.raw += token.raw;
410
+ lastToken.text += token.text;
411
+ } else {
412
+ tokens.push(token);
413
+ }
414
+ continue;
415
+ }
416
+
417
+ if (src) {
418
+ const errMsg = "Infinite loop on byte: " + String(src.charCodeAt(0));
419
+ throw new Error(errMsg);
420
+ }
421
+ }
422
+
423
+ return tokens;
424
+ }
425
425
  }