ember-material-icons
Version:
Google Material icons for your ember-cli app
443 lines (379 loc) • 11.2 kB
JavaScript
import { preprocessInput, isAlpha, isSpace } from './utils';
function EventedTokenizer(delegate, entityParser) {
this.delegate = delegate;
this.entityParser = entityParser;
this.state = null;
this.input = null;
this.index = -1;
this.line = -1;
this.column = -1;
this.tagLine = -1;
this.tagColumn = -1;
this.reset();
}
EventedTokenizer.prototype = {
reset: function() {
this.state = 'beforeData';
this.input = '';
this.index = 0;
this.line = 1;
this.column = 0;
this.tagLine = -1;
this.tagColumn = -1;
this.delegate.reset();
},
tokenize: function(input) {
this.reset();
this.tokenizePart(input);
this.tokenizeEOF();
},
tokenizePart: function(input) {
this.input += preprocessInput(input);
while (this.index < this.input.length) {
this.states[this.state].call(this);
}
},
tokenizeEOF: function() {
this.flushData();
},
flushData: function() {
if (this.state === 'data') {
this.delegate.finishData();
this.state = 'beforeData';
}
},
peek: function() {
return this.input.charAt(this.index);
},
consume: function() {
var char = this.peek();
this.index++;
if (char === "\n") {
this.line++;
this.column = 0;
} else {
this.column++;
}
return char;
},
consumeCharRef: function() {
var endIndex = this.input.indexOf(';', this.index);
if (endIndex === -1) {
return;
}
var entity = this.input.slice(this.index, endIndex);
var chars = this.entityParser.parse(entity);
if (chars) {
var count = entity.length;
// consume the entity chars
while (count) {
this.consume();
count--;
}
// consume the `;`
this.consume();
return chars;
}
},
markTagStart: function() {
// these properties to be removed in next major bump
this.tagLine = this.line;
this.tagColumn = this.column;
if (this.delegate.tagOpen) {
this.delegate.tagOpen();
}
},
states: {
beforeData: function() {
var char = this.peek();
if (char === "<") {
this.state = 'tagOpen';
this.markTagStart();
this.consume();
} else {
this.state = 'data';
this.delegate.beginData();
}
},
data: function() {
var char = this.peek();
if (char === "<") {
this.delegate.finishData();
this.state = 'tagOpen';
this.markTagStart();
this.consume();
} else if (char === "&") {
this.consume();
this.delegate.appendToData(this.consumeCharRef() || "&");
} else {
this.consume();
this.delegate.appendToData(char);
}
},
tagOpen: function() {
var char = this.consume();
if (char === "!") {
this.state = 'markupDeclaration';
} else if (char === "/") {
this.state = 'endTagOpen';
} else if (isAlpha(char)) {
this.state = 'tagName';
this.delegate.beginStartTag();
this.delegate.appendToTagName(char.toLowerCase());
}
},
markupDeclaration: function() {
var char = this.consume();
if (char === "-" && this.input.charAt(this.index) === "-") {
this.consume();
this.state = 'commentStart';
this.delegate.beginComment();
}
},
commentStart: function() {
var char = this.consume();
if (char === "-") {
this.state = 'commentStartDash';
} else if (char === ">") {
this.delegate.finishComment();
this.state = 'beforeData';
} else {
this.delegate.appendToCommentData(char);
this.state = 'comment';
}
},
commentStartDash: function() {
var char = this.consume();
if (char === "-") {
this.state = 'commentEnd';
} else if (char === ">") {
this.delegate.finishComment();
this.state = 'beforeData';
} else {
this.delegate.appendToCommentData("-");
this.state = 'comment';
}
},
comment: function() {
var char = this.consume();
if (char === "-") {
this.state = 'commentEndDash';
} else {
this.delegate.appendToCommentData(char);
}
},
commentEndDash: function() {
var char = this.consume();
if (char === "-") {
this.state = 'commentEnd';
} else {
this.delegate.appendToCommentData("-" + char);
this.state = 'comment';
}
},
commentEnd: function() {
var char = this.consume();
if (char === ">") {
this.delegate.finishComment();
this.state = 'beforeData';
} else {
this.delegate.appendToCommentData("--" + char);
this.state = 'comment';
}
},
tagName: function() {
var char = this.consume();
if (isSpace(char)) {
this.state = 'beforeAttributeName';
} else if (char === "/") {
this.state = 'selfClosingStartTag';
} else if (char === ">") {
this.delegate.finishTag();
this.state = 'beforeData';
} else {
this.delegate.appendToTagName(char);
}
},
beforeAttributeName: function() {
var char = this.peek();
if (isSpace(char)) {
this.consume();
return;
} else if (char === "/") {
this.state = 'selfClosingStartTag';
this.consume();
} else if (char === ">") {
this.consume();
this.delegate.finishTag();
this.state = 'beforeData';
} else if (char === '=') {
this.delegate.reportSyntaxError("attribute name cannot start with equals sign");
this.state = 'attributeName';
this.delegate.beginAttribute();
this.consume();
this.delegate.appendToAttributeName(char);
} else {
this.state = 'attributeName';
this.delegate.beginAttribute();
}
},
attributeName: function() {
var char = this.peek();
if (isSpace(char)) {
this.state = 'afterAttributeName';
this.consume();
} else if (char === "/") {
this.delegate.beginAttributeValue(false);
this.delegate.finishAttributeValue();
this.consume();
this.state = 'selfClosingStartTag';
} else if (char === "=") {
this.state = 'beforeAttributeValue';
this.consume();
} else if (char === ">") {
this.delegate.beginAttributeValue(false);
this.delegate.finishAttributeValue();
this.consume();
this.delegate.finishTag();
this.state = 'beforeData';
} else if (char === '"' || char === "'" || char === '<') {
this.delegate.reportSyntaxError(char + " is not a valid character within attribute names");
this.consume();
this.delegate.appendToAttributeName(char);
} else {
this.consume();
this.delegate.appendToAttributeName(char);
}
},
afterAttributeName: function() {
var char = this.peek();
if (isSpace(char)) {
this.consume();
return;
} else if (char === "/") {
this.delegate.beginAttributeValue(false);
this.delegate.finishAttributeValue();
this.consume();
this.state = 'selfClosingStartTag';
} else if (char === "=") {
this.consume();
this.state = 'beforeAttributeValue';
} else if (char === ">") {
this.delegate.beginAttributeValue(false);
this.delegate.finishAttributeValue();
this.consume();
this.delegate.finishTag();
this.state = 'beforeData';
} else {
this.delegate.beginAttributeValue(false);
this.delegate.finishAttributeValue();
this.consume();
this.state = 'attributeName';
this.delegate.beginAttribute();
this.delegate.appendToAttributeName(char);
}
},
beforeAttributeValue: function() {
var char = this.peek();
if (isSpace(char)) {
this.consume();
} else if (char === '"') {
this.state = 'attributeValueDoubleQuoted';
this.delegate.beginAttributeValue(true);
this.consume();
} else if (char === "'") {
this.state = 'attributeValueSingleQuoted';
this.delegate.beginAttributeValue(true);
this.consume();
} else if (char === ">") {
this.delegate.beginAttributeValue(false);
this.delegate.finishAttributeValue();
this.consume();
this.delegate.finishTag();
this.state = 'beforeData';
} else {
this.state = 'attributeValueUnquoted';
this.delegate.beginAttributeValue(false);
this.consume();
this.delegate.appendToAttributeValue(char);
}
},
attributeValueDoubleQuoted: function() {
var char = this.consume();
if (char === '"') {
this.delegate.finishAttributeValue();
this.state = 'afterAttributeValueQuoted';
} else if (char === "&") {
this.delegate.appendToAttributeValue(this.consumeCharRef('"') || "&");
} else {
this.delegate.appendToAttributeValue(char);
}
},
attributeValueSingleQuoted: function() {
var char = this.consume();
if (char === "'") {
this.delegate.finishAttributeValue();
this.state = 'afterAttributeValueQuoted';
} else if (char === "&") {
this.delegate.appendToAttributeValue(this.consumeCharRef("'") || "&");
} else {
this.delegate.appendToAttributeValue(char);
}
},
attributeValueUnquoted: function() {
var char = this.peek();
if (isSpace(char)) {
this.delegate.finishAttributeValue();
this.consume();
this.state = 'beforeAttributeName';
} else if (char === "&") {
this.consume();
this.delegate.appendToAttributeValue(this.consumeCharRef(">") || "&");
} else if (char === ">") {
this.delegate.finishAttributeValue();
this.consume();
this.delegate.finishTag();
this.state = 'beforeData';
} else {
this.consume();
this.delegate.appendToAttributeValue(char);
}
},
afterAttributeValueQuoted: function() {
var char = this.peek();
if (isSpace(char)) {
this.consume();
this.state = 'beforeAttributeName';
} else if (char === "/") {
this.consume();
this.state = 'selfClosingStartTag';
} else if (char === ">") {
this.consume();
this.delegate.finishTag();
this.state = 'beforeData';
} else {
this.state = 'beforeAttributeName';
}
},
selfClosingStartTag: function() {
var char = this.peek();
if (char === ">") {
this.consume();
this.delegate.markTagAsSelfClosing();
this.delegate.finishTag();
this.state = 'beforeData';
} else {
this.state = 'beforeAttributeName';
}
},
endTagOpen: function() {
var char = this.consume();
if (isAlpha(char)) {
this.state = 'tagName';
this.delegate.beginEndTag();
this.delegate.appendToTagName(char.toLowerCase());
}
}
}
};
export default EventedTokenizer;