@peaceroad/markdown-it-strong-ja 0.4.2 → 0.4.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/index.js CHANGED
@@ -1,14 +1,27 @@
1
+ // Character code constants
2
+ const CHAR_ASTERISK = 0x2A // *
3
+ const CHAR_UNDERSCORE = 0x5F // _
4
+ const CHAR_BACKSLASH = 0x5C // \
5
+ const CHAR_BACKTICK = 0x60 // `
6
+ const CHAR_DOLLAR = 0x24 // $
7
+ const CHAR_LT = 0x3C // <
8
+ const CHAR_GT = 0x3E // >
9
+ const CHAR_SLASH = 0x2F // /
10
+ const CHAR_SPACE = 0x20 // ' ' (space)
11
+
1
12
  const REG_ASTERISKS = /^\*+$/
2
13
  const REG_ATTRS = /{[^{}\n!@#%^&*()]+?}$/
3
14
  const REG_PUNCTUATION = /[!-/:-@[-`{-~ ]/
4
- const REG_JAPANESE = /[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF\uFF66-\uFF9F\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF01-\uFF60\uFFE0-\uFFE6]/ //漢字、ひらがな、カタカナ(半角含む)、全角英数字、絵文字、全角記号:/(?:[\p{Hiragana}\p{Katakana}\p{Han}]|[\uFF66-\uFF9F]|[A-Za-z0-9]|[\p{Emoji}]|[\uFF01-\uFF60\uFFE0-\uFFE6])/u;/(?:[\p{Hiragana}\p{Katakana}\p{Han}]|[\uFF66-\uFF9F]|[A-Za-z0-9]|[\p{Emoji}])/u
15
+ const REG_JAPANESE = /\p{Script=Hiragana}|\p{Script=Katakana}|\p{Script=Han}|\p{General_Category=Punctuation}|\p{General_Category=Symbol}|\p{General_Category=Format}|\p{Emoji}/u // ひらがな|カタカナ|漢字|句読点|記号|フォーマット文字|絵文字
16
+
17
+ const REG_MARKDOWN_HTML = /^\[[^\[\]]+\]\([^)]+\)$|^<([a-zA-Z][a-zA-Z0-9]*)[^>]*>([^<]+<\/\1>)$|^`[^`]+`$|^\$[^$]+\$$/ // for mixed-language context detection
5
18
 
6
19
  const hasBackslash = (state, start) => {
7
20
  let slashNum = 0
8
21
  let i = start - 1
9
22
  const src = state.src
10
23
  while(i >= 0) {
11
- if (src.charCodeAt(i) === 0x5C) { slashNum++; i--; continue }
24
+ if (src.charCodeAt(i) === CHAR_BACKSLASH) { slashNum++; i--; continue }
12
25
  break
13
26
  }
14
27
  return slashNum % 2 === 1
@@ -23,7 +36,6 @@ const setToken = (state, inlines, opt) => {
23
36
  }
24
37
  while (i < inlines.length) {
25
38
  let type = inlines[i].type
26
- //console.log(i, type)
27
39
  const tag = type.replace(/(?:_open|_close)$/, '')
28
40
 
29
41
  if (/_open$/.test(type)) {
@@ -40,9 +52,7 @@ const setToken = (state, inlines, opt) => {
40
52
  }
41
53
  if (type === 'text') {
42
54
  let content = src.slice(inlines[i].s, inlines[i].e + 1)
43
- //console.log('content: ' + content)
44
55
  if (REG_ASTERISKS.test(content)) {
45
- //console.log('asterisk process::')
46
56
  const asteriskToken = state.push(type, '', 0)
47
57
  asteriskToken.content = content
48
58
  i++
@@ -50,7 +60,6 @@ const setToken = (state, inlines, opt) => {
50
60
  }
51
61
  if (opt.mditAttrs && attrsIsText.val && i + 1 < inlines.length) {
52
62
  const hasImmediatelyAfterAsteriskClose = inlines[i+1].type === attrsIsText.tag + '_close'
53
- //console.log(hasImmediatelyAfterAsteriskClose, inlines[i+1].type, /^[\s\S]*{[^{}\n!@#%^&*()]+?}$/.test(content))
54
63
  if (hasImmediatelyAfterAsteriskClose && REG_ATTRS.test(content)) {
55
64
  const attrsToken = state.push(type, '', 0)
56
65
 
@@ -66,7 +75,6 @@ const setToken = (state, inlines, opt) => {
66
75
  backSlash += '\\'
67
76
  k++
68
77
  }
69
- //console.log(backSlashNum, backSlash)
70
78
  attrsToken.content = content.replace(/\\+{/, backSlash + '{')
71
79
  }
72
80
  } else {
@@ -79,8 +87,6 @@ const setToken = (state, inlines, opt) => {
79
87
  }
80
88
 
81
89
  const childTokens = state.md.parseInline(content, state.env)
82
- //console.log(childTokens)
83
- //console.log(childTokens[0].children)
84
90
  if (childTokens[0] && childTokens[0].children) {
85
91
  let j = 0
86
92
  while (j < childTokens[0].children.length) {
@@ -131,7 +137,7 @@ const pushInlines = (inlines, s, e, len, type, tag, tagType) => {
131
137
  ep: e,
132
138
  len: len,
133
139
  type: type,
134
- check: type === 'text' ? true : false,
140
+ check: type === 'text',
135
141
  }
136
142
  if (tag) inline.tag = [tag, tagType]
137
143
  inlines.push(inline)
@@ -141,16 +147,13 @@ const hasNextSymbol = (state, n, max, symbol, noMark) => {
141
147
  let nextSymbolPos = -1
142
148
  const src = state.src
143
149
  if (src.charCodeAt(n) === symbol && !hasBackslash(state, n)) {
144
- let i = n + 1
145
- let tempNoMark = noMark
146
- while (i < max) {
147
- tempNoMark += src[i]
150
+ for (let i = n + 1; i < max; i++) {
151
+ noMark += src[i]
148
152
  if (src.charCodeAt(i) === symbol && !hasBackslash(state, i)) {
149
153
  noMark += src.substring(n, i + 1)
150
154
  nextSymbolPos = i
151
155
  break
152
156
  }
153
- i++
154
157
  }
155
158
  }
156
159
  return [nextSymbolPos, noMark]
@@ -158,25 +161,34 @@ const hasNextSymbol = (state, n, max, symbol, noMark) => {
158
161
 
159
162
  const createInlines = (state, start, max, opt) => {
160
163
  const src = state.src
161
- const srcLen = max;
164
+ const srcLen = max
165
+ const htmlEnabled = state.md.options.html
162
166
  let n = start
163
167
  let inlines = []
164
168
  let noMark = ''
165
169
  let textStart = n
170
+
171
+ // Infinite loop prevention
172
+ const maxIterations = srcLen * 2 // Safe upper bound
173
+ let iterations = 0
174
+
166
175
  while (n < srcLen) {
167
- //console.log('n: ' + n + ', state.src[n]: ' + state.src[n] + ', noMark: ' + noMark)
168
- let nextSymbolPos = -1;
169
- [nextSymbolPos, noMark] = hasNextSymbol(state, n, srcLen, 0x60, noMark) // '`'
170
- if (nextSymbolPos !== -1) {
171
- if (nextSymbolPos === srcLen - 1) {
172
- pushInlines(inlines, textStart, nextSymbolPos, nextSymbolPos - textStart + 1, 'text')
173
- break
176
+ // Prevent infinite loops
177
+ iterations++
178
+ if (iterations > maxIterations) {
179
+ // Add remaining text as-is and exit safely
180
+ if (textStart < srcLen) {
181
+ pushInlines(inlines, textStart, srcLen - 1, srcLen - textStart, 'text')
174
182
  }
175
- n = nextSymbolPos + 1
176
- continue
183
+ break
177
184
  }
178
- if (opt.dollarMath) {
179
- [nextSymbolPos, noMark] = hasNextSymbol(state, n, srcLen, 0x24, noMark) // '$'
185
+
186
+ const currentChar = src.charCodeAt(n)
187
+ let nextSymbolPos = -1
188
+
189
+ // Inline code (backticks)
190
+ if (currentChar === CHAR_BACKTICK && !hasBackslash(state, n)) {
191
+ [nextSymbolPos, noMark] = hasNextSymbol(state, n, srcLen, CHAR_BACKTICK, noMark)
180
192
  if (nextSymbolPos !== -1) {
181
193
  if (nextSymbolPos === srcLen - 1) {
182
194
  pushInlines(inlines, textStart, nextSymbolPos, nextSymbolPos - textStart + 1, 'text')
@@ -187,58 +199,74 @@ const createInlines = (state, start, max, opt) => {
187
199
  }
188
200
  }
189
201
 
190
- if (state.md.options.html) {
191
- if (src.charCodeAt(n) === 0x3C && !hasBackslash(state, n)) { // '<'
192
- let i = n + 1
193
- while (i < srcLen) {
194
- if (src.charCodeAt(i) === 0x3E && !hasBackslash(state, i)) { // '>'
195
- if (noMark.length !== 0) {
196
- pushInlines(inlines, textStart, n - 1, n - textStart, 'text')
197
- noMark = ''
198
- }
199
- let tag = src.slice(n + 1, i)
200
- let tagType = ''
201
- if (/^\//.test(tag)) {
202
- tag = tag.slice(1)
203
- tagType = 'close'
204
- } else {
205
- tagType = 'open'
206
- }
207
- pushInlines(inlines, n, i, i - n + 1, 'html_inline', tag, tagType)
208
- textStart = i + 1
209
- break
202
+ // Inline math ($...$)
203
+ if (opt.dollarMath && currentChar === CHAR_DOLLAR && !hasBackslash(state, n)) {
204
+ [nextSymbolPos, noMark] = hasNextSymbol(state, n, srcLen, CHAR_DOLLAR, noMark)
205
+ if (nextSymbolPos !== -1) {
206
+ if (nextSymbolPos === srcLen - 1) {
207
+ pushInlines(inlines, textStart, nextSymbolPos, nextSymbolPos - textStart + 1, 'text')
208
+ break
209
+ }
210
+ n = nextSymbolPos + 1
211
+ continue
212
+ }
213
+ }
214
+
215
+ // HTML tags
216
+ if (htmlEnabled && currentChar === CHAR_LT && !hasBackslash(state, n)) {
217
+ let foundClosingTag = false
218
+ for (let i = n + 1; i < srcLen; i++) {
219
+ if (src.charCodeAt(i) === CHAR_GT && !hasBackslash(state, i)) {
220
+ if (noMark.length !== 0) {
221
+ pushInlines(inlines, textStart, n - 1, n - textStart, 'text')
222
+ noMark = ''
210
223
  }
211
- i++
224
+ let tag = src.slice(n + 1, i)
225
+ let tagType
226
+ if (tag.charCodeAt(0) === CHAR_SLASH) {
227
+ tag = tag.slice(1)
228
+ tagType = 'close'
229
+ } else {
230
+ tagType = 'open'
231
+ }
232
+ pushInlines(inlines, n, i, i - n + 1, 'html_inline', tag, tagType)
233
+ textStart = i + 1
234
+ n = i + 1
235
+ foundClosingTag = true
236
+ break
212
237
  }
213
- n = i + 1
238
+ }
239
+ if (foundClosingTag) {
214
240
  continue
215
241
  }
242
+ // If no closing tag found, treat as regular character to prevent infinite loops
216
243
  }
217
244
 
218
- if (src.charCodeAt(n) === 0x2A && !hasBackslash(state, n)) { // '*'
245
+ // Asterisk handling
246
+ if (currentChar === CHAR_ASTERISK && !hasBackslash(state, n)) {
219
247
  if (n !== 0 && noMark.length !== 0) {
220
248
  pushInlines(inlines, textStart, n - 1, n - textStart, 'text')
221
249
  noMark = ''
222
250
  }
223
251
  if (n === srcLen - 1) {
224
- pushInlines(inlines, n, n, 1 , '')
252
+ pushInlines(inlines, n, n, 1, '')
225
253
  break
226
254
  }
227
255
  let i = n + 1
228
- while (i < srcLen) {
229
- if (src.charCodeAt(i) === 0x2A) {
230
- if (i === srcLen - 1) pushInlines(inlines, n, i, i - n + 1 , '')
231
- i++
232
- continue
233
- }
234
- pushInlines(inlines, n, i - 1, i - n, '')
256
+ while (i < srcLen && src.charCodeAt(i) === CHAR_ASTERISK) {
257
+ i++
258
+ }
259
+ if (i === srcLen) {
260
+ pushInlines(inlines, n, i - 1, i - n, '')
261
+ } else {
262
+ pushInlines(inlines, n, i - 1, i - n, '')
235
263
  textStart = i
236
- break
237
264
  }
238
265
  n = i
239
266
  continue
240
267
  }
241
268
 
269
+ // Regular character
242
270
  noMark += src[n]
243
271
  if (n === srcLen - 1) {
244
272
  pushInlines(inlines, textStart, n, n - textStart + 1, 'text')
@@ -250,7 +278,6 @@ const createInlines = (state, start, max, opt) => {
250
278
  }
251
279
 
252
280
  const pushMark = (marks, opts) => {
253
- //binary search
254
281
  let left = 0, right = marks.length
255
282
  while (left < right) {
256
283
  const mid = (left + right) >> 1
@@ -264,28 +291,43 @@ const pushMark = (marks, opts) => {
264
291
  }
265
292
 
266
293
  const setStrong = (state, inlines, marks, n, memo, opt) => {
294
+ if (opt.disallowMixed === true) {
295
+ let i = n + 1
296
+ const inlinesLength = inlines.length
297
+ while (i < inlinesLength) {
298
+ if (inlines[i].len === 0 || inlines[i].check) { i++; continue }
299
+ if (inlines[i].type !== '') { i++; continue }
300
+
301
+ if (inlines[i].len > 1) {
302
+ const mixedCheck = checkMixedLanguagePattern(state, inlines, n, i, opt)
303
+ if (mixedCheck.shouldBlock) {
304
+ return [n, 0]
305
+ }
306
+ break
307
+ }
308
+ i++
309
+ }
310
+ }
311
+
267
312
  let i = n + 1
268
313
  let j = 0
269
314
  let nest = 0
270
- let insideTagsIsClose = 1 // 1: closed, 0: open still, -1: error
271
- while (i < inlines.length) {
272
- //console.log('[strong] i: ' + i + ', inlines[i].len: ' + inlines[i].len + ', inlines[i].type: ' + inlines[i].type)
315
+ let insideTagsIsClose = 1
316
+ const inlinesLength = inlines.length
317
+ while (i < inlinesLength) {
318
+ if (inlines[i].type !== '') { i++; continue }
273
319
  if (inlines[i].len === 0 || inlines[i].check) { i++; continue }
274
320
  if (inlines[i].type === 'html_inline') {
275
321
  inlines[i].check = true
276
322
  insideTagsIsClose = checkInsideTags(inlines, i, memo)
277
- //console.log(' nest: ' + nest + ', insideTagsIsClose: ' + insideTagsIsClose )
278
- if (insideTagsIsClose === -1) return n, nest
323
+ if (insideTagsIsClose === -1) return [n, nest]
279
324
  if (insideTagsIsClose === 0) { i++; continue }
280
325
  }
281
- if (inlines[i].type !== '') { i++; continue }
282
326
 
283
327
  nest = checkNest(inlines, marks, n, i)
284
- //console.log(' check nest: ' + nest)
285
- if (nest === -1) return n, nest
328
+ if (nest === -1) return [n, nest]
286
329
 
287
330
  if (inlines[i].len === 1 && inlines[n].len > 2) {
288
- //console.log(' check em inside strong:: i: ' + i)
289
331
  pushMark(marks, {
290
332
  nest: nest,
291
333
  s: inlines[n].ep,
@@ -307,32 +349,25 @@ const setStrong = (state, inlines, marks, n, memo, opt) => {
307
349
  inlines[i].len -= 1
308
350
  if (inlines[i].len > 0) inlines[i].sp += 1
309
351
  if (insideTagsIsClose === 1) {
310
- n, nest = setEm(state, inlines, marks, n, memo, opt)
352
+ const [newN, newNest] = setEm(state, inlines, marks, n, memo, opt)
353
+ n = newN
354
+ nest = newNest
311
355
  }
312
- //console.log(marks)
313
356
  }
314
- //console.log(' check len:: inlines[n].len: ' + inlines[n].len + ', inlines[i].len: ' + inlines[i].len)
315
357
  let strongNum = Math.trunc(Math.min(inlines[n].len, inlines[i].len) / 2)
316
358
 
317
359
  if (inlines[i].len > 1) {
318
- //console.log(' hasPunctuationOrNonJapanese: ' + hasPunctuationOrNonJapanese(state, inlines, n, i) + ', memo.inlineMarkEnd: ' + memo.inlineMarkEnd)
319
-
320
- if (hasPunctuationOrNonJapanese(state, inlines, n, i)) {
360
+ if (hasPunctuationOrNonJapanese(state, inlines, n, i, opt)) {
321
361
  if (memo.inlineMarkEnd) {
322
- //console.log('check nest em.')
323
- //console.log('~~~~~~~~~~~~~~~~~')
324
- marks.push(...createMarks(state, inlines, i, inlines.length - 1, memo, opt))
325
- //console.log('~~~~~~~~~~~~~~~~~')
362
+ marks.push(...createMarks(state, inlines, i, inlinesLength - 1, memo, opt))
326
363
  if (inlines[i].len === 0) { i++; continue }
327
364
  } else {
328
- return n, nest
365
+ return [n, nest]
329
366
  }
330
367
  }
331
- //console.log(' ===> strong normal push. n: ' + n + ', i: ' + i + ' , nest: ' + nest + ',strongNum: ' + strongNum)
332
368
 
333
369
  j = 0
334
370
  while (j < strongNum) {
335
- //console.log(' - j: ' + j + ', inlines[i].sp: ' + inlines[i].sp)
336
371
  pushMark(marks, {
337
372
  nest: nest + strongNum - 1 - j,
338
373
  s: inlines[n].ep - 1,
@@ -355,47 +390,40 @@ const setStrong = (state, inlines, marks, n, memo, opt) => {
355
390
  inlines[i].len -= 2
356
391
  j++
357
392
  }
358
- if (inlines[n].len === 0) return n, nest
393
+ if (inlines[n].len === 0) return [n, nest]
359
394
  }
360
395
 
361
396
  if (inlines[n].len === 1 && inlines[i].len > 0) {
362
- //console.log(' check em that warp strong.')
363
397
  nest++
364
- n, nest = setEm(state, inlines, marks, n, memo, opt, nest)
398
+ const [newN, newNest] = setEm(state, inlines, marks, n, memo, opt, nest)
399
+ n = newN
400
+ nest = newNest
365
401
  }
366
402
 
367
403
  i++
368
404
  }
369
405
 
370
406
  if (n == 0 && memo.inlineMarkEnd) {
371
- //console.log('check nest em(inlineMarkEnd).')
372
- //console.log('===============================')
373
- marks.push(...createMarks(state, inlines, n + 1 , inlines.length - 1, memo, opt))
374
- //console.log(marks)
375
- //console.log('===============================')
407
+ marks.push(...createMarks(state, inlines, n + 1, inlinesLength - 1, memo, opt))
376
408
  }
377
- return n, nest
409
+ return [n, nest]
378
410
  }
379
411
 
380
412
  const checkInsideTags = (inlines, i, memo) => {
381
- //console.log('isJumTag before::memo.htmlTags: ' + JSON.stringify(memo.htmlTags))
382
413
  if (inlines[i].tag === undefined) return 0
383
414
  const tagName = inlines[i].tag[0].toLowerCase()
384
415
  if (memo.htmlTags[tagName] === undefined) {
385
416
  memo.htmlTags[tagName] = 0
386
417
  }
387
- //console.log('memo.htmlTags: ' + JSON.stringify(memo.htmlTags) + ', inlines[i]: ' + JSON.stringify(inlines[i]) + ', inlines[i]')
388
418
  if (inlines[i].tag[1] === 'open') {
389
419
  memo.htmlTags[tagName] += 1
390
420
  }
391
421
  if (inlines[i].tag[1] === 'close') {
392
422
  memo.htmlTags[tagName] -= 1
393
423
  }
394
- //console.log(' i: ' + i + ', tagName: ' + tagName + ', memo.htmlTags[tagName]: ' + memo.htmlTags[tagName] + ', prevHtmlTags[tagName]: ' + prevHtmlTags[tagName])
395
424
  if (memo.htmlTags[tagName] < 0) {
396
425
  return -1
397
426
  }
398
- //console.log('isJumTag after::memo.htmlTags: ' + JSON.stringify(memo.htmlTags))
399
427
  const closeAllTags = Object.values(memo.htmlTags).every(val => val === 0)
400
428
  if (closeAllTags) return 1
401
429
  return 0
@@ -408,47 +436,107 @@ const isJapanese = (ch) => {
408
436
  return REG_JAPANESE.test(ch)
409
437
  }
410
438
 
411
- const hasPunctuationOrNonJapanese = (state, inlines, n, i) => {
439
+ const isEnglish = (ch) => {
440
+ if (!ch) return false
441
+ const code = ch.charCodeAt(0)
442
+ if ((code >= 65 && code <= 90) || (code >= 97 && code <= 122) || (code >= 48 && code <= 57)) {
443
+ return true
444
+ }
445
+ if (code < 128) {
446
+ return code === CHAR_SPACE || (code > 126)
447
+ }
448
+ return !REG_JAPANESE.test(ch) && !REG_PUNCTUATION.test(ch)
449
+ }
450
+
451
+ const checkMixedLanguagePattern = (state, inlines, n, i, opt) => {
452
+ const src = state.src
453
+ const openPrevChar = src[inlines[n].s - 1] || ''
454
+ const closeNextChar = src[inlines[i].e + 1] || ''
455
+
456
+ const isEnglishPrefix = isEnglish(openPrevChar)
457
+ const isEnglishSuffix = isEnglish(closeNextChar)
458
+ if (!isEnglishPrefix && !isEnglishSuffix) {
459
+ return { hasEnglishContext: false, hasMarkdownOrHtml: false, shouldBlock: false }
460
+ }
461
+
462
+ const contentBetween = src.slice(inlines[n].e + 1, inlines[i].s)
463
+ const hasMarkdownOrHtml = REG_MARKDOWN_HTML.test(contentBetween)
464
+
465
+ return {
466
+ hasEnglishContext: true,
467
+ hasMarkdownOrHtml,
468
+ shouldBlock: hasMarkdownOrHtml
469
+ }
470
+ }
471
+
472
+ const hasPunctuationOrNonJapanese = (state, inlines, n, i, opt) => {
412
473
  const src = state.src
413
474
  const openPrevChar = src[inlines[n].s - 1] || ''
414
- //const checkOpenPrevChar =
415
475
  const openNextChar = src[inlines[n].e + 1] || ''
416
476
  const checkOpenNextChar = isPunctuation(openNextChar)
417
477
  const closePrevChar = src[inlines[i].s - 1] || ''
418
478
  const checkClosePrevChar = isPunctuation(closePrevChar)
419
479
  const closeNextChar = src[inlines[i].e + 1] || ''
420
- const checkCloseNextChar = (isPunctuation(closeNextChar) || i === inlines.length - 1)
421
- if ((checkOpenNextChar || checkClosePrevChar) && !checkCloseNextChar && !(isJapanese(openPrevChar) || isJapanese(closeNextChar))) return true
422
- return false
480
+ const checkCloseNextChar = (isPunctuation(closeNextChar) || i === inlines.length - 1)
481
+
482
+ if (opt.disallowMixed === false) {
483
+ const openPrevChar = src[inlines[n].s - 1] || ''
484
+ const closeNextChar = src[inlines[i].e + 1] || ''
485
+
486
+ if (isEnglish(openPrevChar) || isEnglish(closeNextChar)) {
487
+ const contentBetween = src.slice(inlines[n].e + 1, inlines[i].s)
488
+ if (REG_MARKDOWN_HTML.test(contentBetween)) {
489
+ return false
490
+ }
491
+ }
492
+ }
493
+
494
+ const result = (checkOpenNextChar || checkClosePrevChar) && !checkCloseNextChar && !(isJapanese(openPrevChar) || isJapanese(closeNextChar))
495
+ return result
423
496
  }
424
497
 
425
498
  const setEm = (state, inlines, marks, n, memo, opt, sNest) => {
499
+ if (opt.disallowMixed === true && !sNest) {
500
+ let i = n + 1
501
+ const inlinesLength = inlines.length
502
+ while (i < inlinesLength) {
503
+ if (inlines[i].len === 0 || inlines[i].check) { i++; continue }
504
+ if (inlines[i].type !== '') { i++; continue }
505
+
506
+ if (inlines[i].len > 0) {
507
+ const mixedCheck = checkMixedLanguagePattern(state, inlines, n, i, opt)
508
+ if (mixedCheck.shouldBlock) {
509
+ return [n, 0]
510
+ }
511
+ break
512
+ }
513
+ i++
514
+ }
515
+ }
516
+
426
517
  let i = n + 1
427
518
  let nest = 0
428
519
  let strongPNum = 0
429
520
  let insideTagsIsClose = 1
430
- while (i < inlines.length) {
431
- //console.log('[em] i: ' + i + ', src: ' + state.src.slice(inlines[i].sp, inlines[i].ep + 1) + ', inlines[i]: ' + JSON.stringify(inlines[i]))
432
- //console.log(inlines[i].type, JSON.stringify(memo.htmlTags))
521
+ const inlinesLength = inlines.length
522
+ while (i < inlinesLength) {
433
523
  if (inlines[i].len === 0 || inlines[i].check) { i++; continue }
434
524
  if (!sNest && inlines[i].type === 'html_inline') {
435
525
  inlines.check = true
436
526
  insideTagsIsClose = checkInsideTags(inlines, i, memo)
437
- //console.log(' i: ' + i + ', insideTagsIsClose: ' + insideTagsIsClose)
438
- if (insideTagsIsClose === -1) return n, nest
527
+ if (insideTagsIsClose === -1) return [n, nest]
439
528
  if (insideTagsIsClose === 0) { i++; continue }
440
529
  }
441
530
  if (inlines[i].type !== '') { i++; continue }
442
531
 
443
532
  const emNum = Math.min(inlines[n].len, inlines[i].len)
444
533
 
445
- //console.log('sNest: ' + sNest + ', emNum: ' + emNum)
446
- if (!sNest && emNum !== 1) return n, sNest, memo
534
+ if (!sNest && emNum !== 1) return [n, sNest, memo]
447
535
 
448
536
  const hasMarkersAtStartAndEnd = (i) => {
449
537
  let flag = memo.inlineMarkStart
450
538
  if (!flag) return false
451
- inlines.length - 1 === i ? flag = true : flag = false
539
+ inlinesLength - 1 === i ? flag = true : flag = false
452
540
  if (!flag) return false
453
541
  inlines[i].len > 1 ? flag = true : flag = false
454
542
  return flag
@@ -464,30 +552,22 @@ const setEm = (state, inlines, marks, n, memo, opt, sNest) => {
464
552
  } else {
465
553
  nest = checkNest(inlines, marks, n, i)
466
554
  }
467
- //console.log(' nest: ' + nest + ', emNum: ' + emNum)
468
- if (nest === -1) return n, nest
555
+ if (nest === -1) return [n, nest]
469
556
 
470
557
  if (emNum === 1) {
471
- //console.log(' hasPunctuationOrNonJapanese: ' + hasPunctuationOrNonJapanese(state, inlines, n, i) + ', memo.inlineMarkEnd: ' + memo.inlineMarkEnd)
472
- if (hasPunctuationOrNonJapanese(state, inlines, n, i)) {
558
+ if (hasPunctuationOrNonJapanese(state, inlines, n, i, opt)) {
473
559
  if (memo.inlineMarkEnd) {
474
- //console.log('check nest em.')
475
- //console.log('~~~~~~~~~~~~~~~~~')
476
- marks.push(...createMarks(state, inlines, i, inlines.length - 1, memo, opt))
477
- //console.log('~~~~~~~~~~~~~~~~~')
560
+ marks.push(...createMarks(state, inlines, i, inlinesLength - 1, memo, opt))
478
561
 
479
562
  if (inlines[i].len === 0) { i++; continue }
480
563
  } else {
481
- return n, nest
564
+ return [n, nest]
482
565
  }
483
566
  }
484
- //console.log('inlines[i].len: ' + inlines[i].len)
485
- if (inlines[i].len < 1) { // memo.html
567
+ if (inlines[i].len < 1) {
486
568
  i++; continue;
487
569
  }
488
570
 
489
- //console.log(' ===> em Normal push. n: ' + n + ', i: ' + i + ', nest: ' + nest, ', strongPNum: ' + strongPNum)
490
- //console.log(inlines[n].ep, inlines[n].sp, inlines[n].s)
491
571
  pushMark(marks, {
492
572
  nest: nest,
493
573
  s: inlines[n].ep,
@@ -522,17 +602,15 @@ const setEm = (state, inlines, marks, n, memo, opt, sNest) => {
522
602
  inlines[i].ep -= 1
523
603
  }
524
604
  inlines[i].len -= 1
525
- //console.log(marks)
526
- if (inlines[n].len === 0) return n, nest
605
+ if (inlines[n].len === 0) return [n, nest]
527
606
  }
528
607
 
529
608
  i++
530
609
  }
531
- return n, nest
610
+ return [n, nest]
532
611
  }
533
612
 
534
613
  const setText = (inlines, marks, n, nest) => {
535
- //console.log('n: ' + n + ' [text]: inlines[n].len: ' + inlines[n].len)
536
614
  pushMark(marks, {
537
615
  nest: nest,
538
616
  s: inlines[n].sp,
@@ -551,10 +629,8 @@ const checkNest = (inlines, marks, n, i) => {
551
629
  let strongNest = 0
552
630
  let emNest = 0
553
631
  let j = 0
554
- //console.log(inlines)
555
- //console.log(marks)
556
- //console.log('n: ' + n + ', i: ' + i + ', inlines[n].s: ' + inlines[n].s + ', inlines[i].s: ' + inlines[i].s)
557
- while (j < marks.length) {
632
+ const marksLength = marks.length
633
+ while (j < marksLength) {
558
634
  if (marks[j].s <= inlines[n].s) {
559
635
  if (marks[j].type === 'strong_open') strongNest++
560
636
  if (marks[j].type === 'strong_close') strongNest--
@@ -565,21 +641,17 @@ const checkNest = (inlines, marks, n, i) => {
565
641
  }
566
642
  let parentNest = strongNest + emNest
567
643
  let parentCloseN = j
568
- //console.log('strongNest: ' + strongNest + ', emNest: ' + emNest + ', parentNest: ' + parentNest + ', parentCloseN: ' + parentCloseN)
569
- if (parentCloseN < marks.length) {
570
- while (parentCloseN < marks.length) {
644
+ if (parentCloseN < marksLength) {
645
+ while (parentCloseN < marksLength) {
571
646
  if (marks[parentCloseN].nest === parentNest) break
572
647
  parentCloseN++
573
648
  }
574
- //console.log('parentCloseN: ' + parentCloseN)
575
- if (parentCloseN > marks.length - 1) {
649
+ if (parentCloseN > marksLength - 1) {
576
650
  isRange = true
577
651
  } else {
578
- //console.log(marks[parentCloseN].s, i, inlines[i].s)
579
652
  if (marks[parentCloseN].s < inlines[i].s) isRange = false
580
653
  }
581
654
  }
582
- //console.log('isRange: ' + isRange)
583
655
 
584
656
  if (isRange) {
585
657
  nest = parentNest + 1
@@ -592,15 +664,20 @@ const checkNest = (inlines, marks, n, i) => {
592
664
  const createMarks = (state, inlines, start, end, memo, opt) => {
593
665
  let marks = []
594
666
  let n = start
667
+
595
668
  while (n < end) {
596
669
  if (inlines[n].type !== '') { n++; continue }
597
670
  let nest = 0
598
- //console.log('n: ' + n + ' ----- inlines:: src: ' + state.src.slice(inlines[n].sp, inlines[n].ep + 1) + ', inlines[n].sp: ' + inlines[n].sp + ', inlines[n].len: ' + inlines[n].len + ', memo.isEm: ' + memo.isEm)
671
+
599
672
  if (inlines[n].len > 1) {
600
- n, nest = setStrong(state, inlines, marks, n, memo, opt)
673
+ const [newN, newNest] = setStrong(state, inlines, marks, n, memo, opt)
674
+ n = newN
675
+ nest = newNest
601
676
  }
602
677
  if (inlines[n].len !== 0) {
603
- n, nest = setEm(state, inlines, marks, n, memo, opt)
678
+ const [newN2, newNest2] = setEm(state, inlines, marks, n, memo, opt)
679
+ n = newN2
680
+ nest = newNest2
604
681
  }
605
682
  if (inlines[n].len !== 0) {
606
683
  setText(inlines, marks, n, nest)
@@ -638,7 +715,7 @@ const strongJa = (state, silent, opt) => {
638
715
  const src = state.src
639
716
  let attributesSrc
640
717
  if (start > max) return false
641
- if (src.charCodeAt(start) !== 0x2A) return false
718
+ if (src.charCodeAt(start) !== CHAR_ASTERISK) return false
642
719
  if (hasBackslash(state, start)) return false
643
720
 
644
721
  if (opt.mditAttrs) {
@@ -659,36 +736,26 @@ const strongJa = (state, silent, opt) => {
659
736
  }
660
737
  }
661
738
 
662
- //console.log('state.src.length(max): ' + state.src.length + (state.src.length === max ? '' : '(' + max + ')') + ', start: ' + start + ', state.src: ' + state.src)
663
739
  let inlines = createInlines(state, start, max, opt)
664
- //console.log('inlines: ')
665
- //console.log(inlines)
666
740
 
667
741
  const memo = {
668
742
  html: state.md.options.html,
669
743
  htmlTags: {},
670
- inlineMarkStart: src.charCodeAt(0) === 0x2A ? true : false,
671
- inlineMarkEnd: src.charCodeAt(max - 1) === 0x2A ? true : false,
744
+ inlineMarkStart: src.charCodeAt(0) === CHAR_ASTERISK,
745
+ inlineMarkEnd: src.charCodeAt(max - 1) === CHAR_ASTERISK,
672
746
  }
673
747
 
674
748
  let marks = createMarks(state, inlines, 0, inlines.length, memo, opt)
675
- //console.log('marks: ')
676
- //console.log(marks)
677
749
 
678
750
  inlines = mergeInlinesAndMarks(inlines, marks)
679
- //console.log('fix inlines:')
680
- //console.log(inlines)
681
751
 
682
752
  setToken(state, inlines, opt)
683
753
 
684
- //console.log ('End process:: max:' + max + ', state.posMax: ' + state.posMax + ', opt.mditAttrs: ' + opt.mditAttrs)
685
-
686
754
  if (opt.mditAttrs && max !== state.posMax) {
687
755
  if (!attributesSrc) {
688
756
  state.pos = max
689
757
  return true
690
758
  }
691
- //console.log('start: ' + start + ', attributesSrc[0]::' + attributesSrc[0] + ', attributesSrc[1].length: ' + attributesSrc[1].length)
692
759
  if (attributesSrc[1].length > 1) {
693
760
  state.pos = max + attributesSrc[1].length
694
761
  } else {
@@ -697,7 +764,6 @@ const strongJa = (state, silent, opt) => {
697
764
  } else {
698
765
  state.pos = max
699
766
  }
700
- //console.log(state.tokens)
701
767
  return true
702
768
  }
703
769
 
@@ -706,6 +772,7 @@ const mditStrongJa = (md, option) => {
706
772
  dollarMath: true, //inline math $...$
707
773
  mditAttrs: true, //markdown-it-attrs
708
774
  mdBreaks: md.options.breaks,
775
+ disallowMixed: false, //Non-Japanese text handling
709
776
  }
710
777
  if (option) Object.assign(opt, option)
711
778