Skip to content

Commit 3f1e5dc

Browse files
committed
Proof of concept
1 parent 0dde42d commit 3f1e5dc

File tree

1 file changed

+150
-0
lines changed

1 file changed

+150
-0
lines changed

src/lib/markbind/src/patches/htmlparser2.js

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
104108
Tokenizer.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+
132282
Tokenizer.prototype._parse = function(){
133283
while(this._index < this._buffer.length && this._running){
134284
var c = this._buffer.charAt(this._index);

0 commit comments

Comments
 (0)