in Nodejs/Product/Nodejs/Jade/Tokenizer/States/TagState.cs [9:183]
private void OnTag()
{
var ident = string.Empty;
var blockIndent = CalculateLineIndent();
// regular tag like
// html
// body
var range = ParseTagName();
if (range.Length > 0)
{
ident = this._cs.GetSubstringAt(range.Start, range.Length);
if (JadeTagKeywords.IsKeyword(ident))
{
// extends, javascripts:, stylesheets:
var length = this._cs.CurrentChar == ':' ? range.Length + 1 : range.Length;
AddToken(JadeTokenType.TagKeyword, range.Start, length);
if (this._cs.CurrentChar != ':' && StringComparer.Ordinal.Equals(ident, "mixin"))
{
SkipWhiteSpace();
if (!this._cs.IsAtNewLine())
{
OnTag();
}
}
else
{
SkipToEndOfLine();
}
return;
}
if (this._cs.CurrentChar == ':')
{
// Block expansion like
// li.first: a(href='#') foo
AddToken(JadeTokenType.TagName, range.Start, range.Length);
this._cs.MoveToNextChar();
SkipWhiteSpace();
if (!this._cs.IsAtNewLine())
{
OnTag();
}
return;
}
if (JadeCodeKeywords.IsKeyword(ident))
{
AddToken(JadeTokenType.CodeKeyword, range.Start, range.Length);
OnInlineCode();
return;
}
AddToken(JadeTokenType.TagName, range.Start, range.Length);
}
while (!this._cs.IsWhiteSpace() && !this._cs.IsEndOfStream())
{
if (this._cs.CurrentChar == '.' && char.IsWhiteSpace(this._cs.NextChar))
{
// If this is last ., then what follows is a text literal
if (StringComparer.OrdinalIgnoreCase.Equals(ident, "script"))
{
this._cs.MoveToNextChar();
OnScript(blockIndent);
}
else if (StringComparer.OrdinalIgnoreCase.Equals(ident, "style"))
{
this._cs.MoveToNextChar();
OnStyle(blockIndent);
}
else if (IsAllWhiteSpaceBeforeEndOfLine(this._cs.Position + 1))
{
SkipToEndOfBlock(blockIndent, text: true);
}
else
{
this._cs.MoveToNextChar();
}
return;
}
if (this._cs.CurrentChar == '(')
{
OnAttributes(')');
}
if (this._cs.CurrentChar == '#' || this._cs.CurrentChar == '.')
{
var isID = this._cs.CurrentChar == '#';
// container(a=b).bar or container(a=b)#bar
var selectorRange = GetNonWSSequence("(:=.#");
if (selectorRange.Length > 0)
{
AddToken(
isID ? JadeTokenType.IdLiteral : JadeTokenType.ClassLiteral,
selectorRange.Start,
selectorRange.Length
);
if (char.IsWhiteSpace(this._cs.CurrentChar) && this._cs.LookAhead(-1) == '.')
{
this._cs.Position--;
}
}
}
if (this._cs.CurrentChar != '.' && this._cs.CurrentChar != '#' && this._cs.CurrentChar != '(')
{
break;
}
}
if (this._cs.CurrentChar == ':')
{
// Block expansion like
// li.first: a(href='#') foo
this._cs.MoveToNextChar();
SkipWhiteSpace();
if (!this._cs.IsAtNewLine())
{
OnTag();
}
return;
}
// There may be ws between tag name and = sign. However, = must be on the same line.
var allWsToEol = IsAllWhiteSpaceBeforeEndOfLine(this._cs.Position);
if (!allWsToEol)
{
SkipWhiteSpace();
if (this._cs.CurrentChar == '=' || (this._cs.CurrentChar == '!' && this._cs.NextChar == '='))
{
// Something like 'foo ='
var length = this._cs.CurrentChar == '!' ? 2 : 1;
AddToken(JadeTokenType.Operator, this._cs.Position, length);
this._cs.Advance(length);
OnInlineCode();
}
else
{
OnText(strings: false, html: true, entities: true);
}
}
else
{
if (StringComparer.OrdinalIgnoreCase.Equals(ident, "script"))
{
OnScript(blockIndent);
}
else if (StringComparer.OrdinalIgnoreCase.Equals(ident, "style"))
{
OnStyle(blockIndent);
}
else
{
SkipToEndOfLine();
}
}
}