@@ -101,6 +101,10 @@ var i = 0,
101101 SPECIAL_SCRIPT = j ++ ,
102102 SPECIAL_STYLE = j ++ ;
103103
104+ function whitespace ( c ) {
105+ return c === " " || c === "\n" || c === "\t" || c === "\f" || c === "\r" ;
106+ }
107+
104108Tokenizer . prototype . _stateMarkdown = function ( c ) {
105109 if ( c === '`' ) {
106110 this . _state = TEXT ;
@@ -129,6 +133,152 @@ Tokenizer.prototype._stateText = function(c){
129133 }
130134} ;
131135
136+
137+ // Tags will be provided by plugins
138+ const specialTagNames = [
139+ 'abc' ,
140+ 'cab' ,
141+ 'script' ,
142+ 'style' ,
143+ ] ;
144+
145+ Tokenizer . prototype . isFirstCharacterSpecialTagCharacter = function ( c ) {
146+ this . _specialFunctions = specialTagNames
147+ . map ( ( str , index ) => ( {
148+ index,
149+ nextTestIndex : 0 ,
150+ } ) )
151+ . filter ( indexObj => c . toLowerCase ( ) === specialTagNames [ indexObj . index ] [ indexObj . nextTestIndex ] )
152+ . map ( indexObj => ( {
153+ index : indexObj . index ,
154+ nextTestIndex : indexObj . nextTestIndex + 1 ,
155+ hasFinishedMatching : specialTagNames [ indexObj . index ] [ indexObj . nextTestIndex + 1 ] === undefined ,
156+ } ) ) ;
157+
158+ return this . _specialFunctions . length > 0 ;
159+ } ;
160+
161+ Tokenizer . prototype . processSpecialFunctions = function ( c ) {
162+ let matchIndex ;
163+
164+ this . _specialFunctions = this . _specialFunctions
165+ . filter ( ( indexObj ) => {
166+ if ( indexObj . hasFinishedMatching ) {
167+ matchIndex = indexObj . index ;
168+
169+ return c === "/" || c === ">" || whitespace ( c ) ;
170+ }
171+
172+ return c . toLowerCase ( ) === specialTagNames [ indexObj . index ] [ indexObj . nextTestIndex ]
173+ } )
174+ . map ( indexObj => ( {
175+ index : indexObj . index ,
176+ nextTestIndex : indexObj . nextTestIndex + 1 ,
177+ hasFinishedMatching : specialTagNames [ indexObj . index ] [ indexObj . nextTestIndex + 1 ] === undefined ,
178+ } ) ) ;
179+
180+ return {
181+ matchIndex,
182+ hasMatching : this . _specialFunctions . length > 0 ,
183+ } ;
184+ } ;
185+
186+ Tokenizer . prototype . _stateBeforeTagName = function ( c ) {
187+ if ( c === "/" ) {
188+ this . _state = BEFORE_CLOSING_TAG_NAME ;
189+ } else if ( c === "<" ) {
190+ this . _cbs . ontext ( this . _getSection ( ) ) ;
191+ this . _sectionStart = this . _index ;
192+ } else if ( c === ">" || this . _special !== SPECIAL_NONE || whitespace ( c ) ) {
193+ this . _state = TEXT ;
194+ } else if ( c === "!" ) {
195+ this . _state = BEFORE_DECLARATION ;
196+ this . _sectionStart = this . _index + 1 ;
197+ } else if ( c === "?" ) {
198+ this . _state = IN_PROCESSING_INSTRUCTION ;
199+ this . _sectionStart = this . _index + 1 ;
200+ } else {
201+ this . _state = ! this . _xmlMode && this . isFirstCharacterSpecialTagCharacter ( c )
202+ ? BEFORE_SPECIAL
203+ : IN_TAG_NAME ;
204+ this . _sectionStart = this . _index ;
205+ }
206+ } ;
207+
208+
209+ Tokenizer . prototype . _stateBeforeSpecial = function ( c ) {
210+ const result = this . processSpecialFunctions ( c ) ;
211+ if ( ! result . matchIndex && result . hasMatching ) {
212+ this . _state = BEFORE_SPECIAL ;
213+ return ;
214+ }
215+
216+ if ( result . matchIndex ) {
217+ this . _special = result . matchIndex ;
218+ this . _nextSpecialClosingTagMatchIndex = 0 ;
219+ }
220+ this . _state = IN_TAG_NAME ;
221+ this . _index -- ; //consume the token again
222+ } ;
223+
224+ Tokenizer . prototype . processSpecialClosingTagCharacter = function ( c ) {
225+ let finishedMatching = false ;
226+ let matchNext = false ;
227+
228+ if ( specialTagNames [ this . _special ] [ this . _nextSpecialClosingTagMatchIndex ] === undefined ) {
229+ this . _nextSpecialClosingTagMatchIndex = 0 ;
230+ finishedMatching = c === ">" || whitespace ( c ) ;
231+ } else if ( specialTagNames [ this . _special ] [ this . _nextSpecialClosingTagMatchIndex ] === c . toLowerCase ( ) ) {
232+ this . _nextSpecialClosingTagMatchIndex += 1 ;
233+ matchNext = true ;
234+ } else {
235+ // reset
236+ this . _nextSpecialClosingTagMatchIndex = 0 ;
237+ }
238+
239+ return {
240+ finishedMatching,
241+ matchNext,
242+ } ;
243+ } ;
244+
245+ Tokenizer . prototype . _stateBeforeCloseingTagName = function ( c ) {
246+ if ( whitespace ( c ) ) ;
247+ else if ( c === ">" ) {
248+ this . _state = TEXT ;
249+ } else if ( this . _special !== SPECIAL_NONE ) {
250+ if ( this . processSpecialClosingTagCharacter ( c ) ) {
251+ this . _state = BEFORE_SPECIAL_END ;
252+ } else {
253+ this . _state = TEXT ;
254+ this . _index -- ;
255+ }
256+ } else {
257+ this . _state = IN_CLOSING_TAG_NAME ;
258+ this . _sectionStart = this . _index ;
259+ }
260+ } ;
261+
262+ Tokenizer . prototype . _stateBeforeSpecialEnd = function ( c ) {
263+ const result = this . processSpecialClosingTagCharacter ( c ) ;
264+ if ( result . matchNext ) {
265+ this . _state = BEFORE_SPECIAL_END ;
266+ return ;
267+ }
268+
269+ if ( result . finishedMatching ) {
270+ this . _sectionStart = this . _index - specialTagNames [ this . _special ] . length ;
271+ this . _special = SPECIAL_NONE ;
272+ this . _state = IN_CLOSING_TAG_NAME ;
273+ this . _index -- ; //reconsume the token
274+ return ;
275+ }
276+
277+ this . _index -- ;
278+ this . _state = TEXT ;
279+ } ;
280+
281+
132282Tokenizer . prototype . _parse = function ( ) {
133283 while ( this . _index < this . _buffer . length && this . _running ) {
134284 var c = this . _buffer . charAt ( this . _index ) ;
0 commit comments