mirror of
				https://github.com/fooflington/selfdefined.git
				synced 2025-10-31 14:18:32 +00:00 
			
		
		
		
	
		
			
	
	
		
			131 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			131 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|   | // Inline parser state
 | ||
|  | 
 | ||
|  | 'use strict'; | ||
|  | 
 | ||
|  | 
 | ||
|  | var Token          = require('../token'); | ||
|  | var isWhiteSpace   = require('../common/utils').isWhiteSpace; | ||
|  | var isPunctChar    = require('../common/utils').isPunctChar; | ||
|  | var isMdAsciiPunct = require('../common/utils').isMdAsciiPunct; | ||
|  | 
 | ||
|  | 
 | ||
|  | function StateInline(src, md, env, outTokens) { | ||
|  |   this.src = src; | ||
|  |   this.env = env; | ||
|  |   this.md = md; | ||
|  |   this.tokens = outTokens; | ||
|  | 
 | ||
|  |   this.pos = 0; | ||
|  |   this.posMax = this.src.length; | ||
|  |   this.level = 0; | ||
|  |   this.pending = ''; | ||
|  |   this.pendingLevel = 0; | ||
|  | 
 | ||
|  |   this.cache = {};        // Stores { start: end } pairs. Useful for backtrack
 | ||
|  |                           // optimization of pairs parse (emphasis, strikes).
 | ||
|  | 
 | ||
|  |   this.delimiters = [];   // Emphasis-like delimiters
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // Flush pending text
 | ||
|  | //
 | ||
|  | StateInline.prototype.pushPending = function () { | ||
|  |   var token = new Token('text', '', 0); | ||
|  |   token.content = this.pending; | ||
|  |   token.level = this.pendingLevel; | ||
|  |   this.tokens.push(token); | ||
|  |   this.pending = ''; | ||
|  |   return token; | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | // Push new token to "stream".
 | ||
|  | // If pending text exists - flush it as text token
 | ||
|  | //
 | ||
|  | StateInline.prototype.push = function (type, tag, nesting) { | ||
|  |   if (this.pending) { | ||
|  |     this.pushPending(); | ||
|  |   } | ||
|  | 
 | ||
|  |   var token = new Token(type, tag, nesting); | ||
|  | 
 | ||
|  |   if (nesting < 0) { this.level--; } | ||
|  |   token.level = this.level; | ||
|  |   if (nesting > 0) { this.level++; } | ||
|  | 
 | ||
|  |   this.pendingLevel = this.level; | ||
|  |   this.tokens.push(token); | ||
|  |   return token; | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | // Scan a sequence of emphasis-like markers, and determine whether
 | ||
|  | // it can start an emphasis sequence or end an emphasis sequence.
 | ||
|  | //
 | ||
|  | //  - start - position to scan from (it should point at a valid marker);
 | ||
|  | //  - canSplitWord - determine if these markers can be found inside a word
 | ||
|  | //
 | ||
|  | StateInline.prototype.scanDelims = function (start, canSplitWord) { | ||
|  |   var pos = start, lastChar, nextChar, count, can_open, can_close, | ||
|  |       isLastWhiteSpace, isLastPunctChar, | ||
|  |       isNextWhiteSpace, isNextPunctChar, | ||
|  |       left_flanking = true, | ||
|  |       right_flanking = true, | ||
|  |       max = this.posMax, | ||
|  |       marker = this.src.charCodeAt(start); | ||
|  | 
 | ||
|  |   // treat beginning of the line as a whitespace
 | ||
|  |   lastChar = start > 0 ? this.src.charCodeAt(start - 1) : 0x20; | ||
|  | 
 | ||
|  |   while (pos < max && this.src.charCodeAt(pos) === marker) { pos++; } | ||
|  | 
 | ||
|  |   count = pos - start; | ||
|  | 
 | ||
|  |   // treat end of the line as a whitespace
 | ||
|  |   nextChar = pos < max ? this.src.charCodeAt(pos) : 0x20; | ||
|  | 
 | ||
|  |   isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar)); | ||
|  |   isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar)); | ||
|  | 
 | ||
|  |   isLastWhiteSpace = isWhiteSpace(lastChar); | ||
|  |   isNextWhiteSpace = isWhiteSpace(nextChar); | ||
|  | 
 | ||
|  |   if (isNextWhiteSpace) { | ||
|  |     left_flanking = false; | ||
|  |   } else if (isNextPunctChar) { | ||
|  |     if (!(isLastWhiteSpace || isLastPunctChar)) { | ||
|  |       left_flanking = false; | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   if (isLastWhiteSpace) { | ||
|  |     right_flanking = false; | ||
|  |   } else if (isLastPunctChar) { | ||
|  |     if (!(isNextWhiteSpace || isNextPunctChar)) { | ||
|  |       right_flanking = false; | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   if (!canSplitWord) { | ||
|  |     can_open  = left_flanking  && (!right_flanking || isLastPunctChar); | ||
|  |     can_close = right_flanking && (!left_flanking  || isNextPunctChar); | ||
|  |   } else { | ||
|  |     can_open  = left_flanking; | ||
|  |     can_close = right_flanking; | ||
|  |   } | ||
|  | 
 | ||
|  |   return { | ||
|  |     can_open:  can_open, | ||
|  |     can_close: can_close, | ||
|  |     length:    count | ||
|  |   }; | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | // re-export Token class to use in block rules
 | ||
|  | StateInline.prototype.Token = Token; | ||
|  | 
 | ||
|  | 
 | ||
|  | module.exports = StateInline; |