<?xml version="1.0"?>
<syntax name="language-root.js">
	<zones>
		<!-- Standard JavaScript syntax -->
		<include collection="comments" />
		<include collection="functions" />
		<include collection="strings" />
		<include collection="regex" />
		<include collection="classes" />
		<include collection="switch-blocks" />
		<include collection="keywords" />
		<include collection="punctuation" />
		<include collection="variables" />
	</zones>

	<library>
		<!--Comments-->
		<collection name="comments">
			<!-- Inline documentation style comments -->
			<zone name="comment.block.documentation">
				<starts-with>
					<expression>/\*(?:(?!\*/)[*!](?:\*(?!/$)|/(?!$))*|\s*(?:[*#=~+-]{3,}(?!/)|!)|(?=.*?\b(?i:FIX ?ME|TODO)\b))</expression>
					<capture number="0" name="punctuation.definition.begin"/>
				</starts-with>
				<ends-with>
					<expression>\*/</expression>
					<capture number="0" name="punctuation.definition.end"/>
				</ends-with>
				<subzones>
					<zone>
						<expression>(?i)\b((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()&lt;>]+|\((?:[^\s()&lt;>]+|(?:\([^\s()&lt;>]+\)))*\))+(?:\((?:[^\s()&lt;>]+|(?:\([^\s()&lt;>]+\)))*\)|[^\s`!()\[\]{};:'".,&lt;>?«»“”‘’]))|(?&lt;=\s|^)(@[a-z]+\b|\bFIX ?ME\b|\bTODO\b)</expression>
						<capture number="1" name="markup.link"/>
						<capture number="2" name="keyword"/>
					</zone>
				</subzones>
			</zone>
			<zone name="comment.line.documentation">
				<expression>(//[!/*]?)(?:(?&lt;=//[!/*])|\s*(?:[*#=~+-]{3,}(?=[ \t]*[^\s*#=~+-])|!)|.*?\b(?i:FIX ?ME|TODO)\b).*$[\n\r]*</expression>
				<capture number="1" name="punctuation.definition.begin"/>
				<subzones>
					<zone name="keyword">
						<expression>\b(?i:FIX ?ME|TODO)\b</expression>
					</zone>
				</subzones>
			</zone>
			<include collection="comments.basic" />
		</collection>

		<!-- Standard comments -->
		<collection name="comments.basic">
			<zone name="comment.block">
				<starts-with>
					<expression>/\*</expression>
					<capture number="0" name="punctuation.definition.begin"/>
				</starts-with>
				<ends-with>
					<expression>\*/</expression>
					<capture number="0" name="punctuation.definition.end"/>
				</ends-with>
			</zone>
			<zone name="comment.line">
				<expression>(//).*$[\n\r]*</expression>
				<capture number="1" name="punctuation.definition.begin"/>
			</zone>
		</collection>

		<!--Strings-->
		<collection name="strings">
			<!--Property assignments with quoted names-->
			<zone>
				<expression>(?:((')((?:\\.|[^\\'])*)('))|((")((?:\\.|[^\\"])*)(")))\s*(:)</expression>
				<capture number="0" name="x-assignment"/>
				<capture number="1" name="string.quoted"/>
				<capture number="2" name="punctuation.definition.begin"/>
				<capture number="3" name="name">
					<subzones>
						<include collection="character-escapes"/>
					</subzones>
				</capture>
				<capture number="4" name="punctuation.definition.end"/>
				<!-- Double quoted strings -->
				<capture number="5" name="string.quoted"/>
				<capture number="6" name="punctuation.definition.begin"/>
				<capture number="7" name="name">
					<subzones>
						<include collection="character-escapes"/>
					</subzones>
				</capture>
				<capture number="8" name="punctuation.definition.end"/>
				<!-- Shared by both -->
				<capture number="9" name="operator.x-colon"/>
			</zone>
			<include collection="strings.basic" />
		</collection>

		<collection name="strings.basic">
			<!--Standard strings-->
			<zone name="string.quoted">
				<starts-with>
					<expression>('|")</expression>
					<capture number="0" name="punctuation.definition.begin"/>
				</starts-with>
				<ends-with>
					<expression>\1</expression>
					<capture number="0" name="punctuation.definition.end"/>
				</ends-with>
				<subzones>
					<include collection="character-escapes" />
				</subzones>
			</zone>
		</collection>

		<!--Character Escapes-->
		<collection name="character-escapes">
			<zone name="constant.character.escape">
				<expression>\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.)</expression>
			</zone>
		</collection>

		<!--Regex Literals-->
		<collection name="regex">
			<zone name="regex.literal">
				<starts-with>
					<expression>(?&lt;=[=(\[:;,!|&amp;]|^|return)\s*(/)(?![/*+{}?])</expression>
					<capture number="1" name="punctuation.definition.begin"/>
				</starts-with>
				<ends-with>
					<expression>(/)([igm]*)</expression>
					<capture number="1" name="punctuation.definition.end"/>
					<capture number="2" name="regex.flags"/>
				</ends-with>
				<subzones>
					<cut-off>(?&lt;!\\)/</cut-off>
					<include syntax="language-root.regex" />
				</subzones>
			</zone>
		</collection>

		<!--All Functions-->
		<collection name="functions">
			<!-- someObject.doSomething = function(...) ... -->
			<zone>
				<expression>((?:(var)\s+)?(?:([a-zA-Z_$][\w$.]*)|('(?:\\'|[^'])+'|"(?:\\"|[^"])+"))\s*(=|:)\s*(function))\s*(\()|\b((function)\s+([a-zA-Z_$][\w$]*)\s*)(\()|\b((function)\s*)(\()</expression>
				<capture number="1" name="function.definition.x-assignment"/>
				<capture number="2" name="keyword.storage.type"/>
				<capture number="3" name="name"/>
				<capture number="4" name="string.quoted">
					<!--Optional quoted version of properties-->
					<subzones>
						<zone>
							<expression>('|")((?:(\\(?:x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.))|.)*?)(\1)</expression>
							<capture number="1" name="punctuation.definition.begin"/>
							<capture number="2" name="name"/>
							<capture number="3" name="constant.character.escape"/>
							<capture number="4" name="punctuation.definition.end"/>
						</zone>
					</subzones>
				</capture>
				<capture number="5" name="operator" behavior="text-to-name" behavior-match="^=|(:)$" behavior-transform="(?1:x-colon:)"/>
				<capture number="6" name="keyword.storage.type"/>
				<capture number="7" name="punctuation.brace.round.open"/>
				<!-- function doSomething(...) ... -->
				<capture number="8" name="function.definition"/>
				<capture number="9" name="keyword.storage.type"/>
				<capture number="10" name="name"/>
				<capture number="11" name="punctuation.brace.round.open"/>
				<!-- function() { ... } -->
				<capture number="12" name="function.definition.anonymous"/>
				<capture number="13" name="keyword.storage.type"/>
				<capture number="14" name="punctuation.brace.round.open"/>
			</zone>
		</collection>

		<!--Classes-->
		<collection name="classes">
			<zone name="class.constructor">
				<expression>\b(new)\s+([a-zA-Z_$][\w$.]*)</expression>
				<capture number="1" name="keyword.operator.new"/>
				<capture number="2" name="variable.class"/>
			</zone>
		</collection>

		<!--Switch blocks-->
		<collection name="switch-blocks">
			<zone name="x-item-start.x-case">
				<starts-with>
					<expression>\b(?:case|default)\b</expression>
					<capture number="0" name="keyword.control"/>
				</starts-with>
				<ends-with>
					<expression>:|;</expression>
					<capture number="0" name="punctuation"/>
				</ends-with>
				<subzones>
					<include collection="comments" />
					<include collection="strings.basic" />
					<include collection="keywords" />
					<include collection="regex" />
					<include collection="punctuation" />
				</subzones>
			</zone>
		</collection>

		<!--Keywords and constants-->
		<collection name="keywords">
			<zone>
				<expression>\b(?:(case|catch|continue|default|finally|for|throw|void|delete|in|instanceof|typeof|with|new)|(else if)|(switch|break|return|else|try|do|while|if)|(abstract|boolean|byte|char|class|const|debugger|double|enum|export|extends|final|float|goto|implements|import|int|interface|long|native|package|private|protected|public|short|static|synchronized|throws|transient|volatile)|(super|this)|(Array|Boolean|Date|Function|Math|Number|Object|RegExp|String|console|document|history|location|screen|window|self|top|parent)|(undefined|NaN|true|false|null)|([0-9]+\.?[0-9]*(?:[eE]-?[0-9]+)?|0(?:x|X)[0-9a-fA-F]+|Infinity))\b</expression>
				<capture number="1" name="keyword.control"/>
				<capture number="2" name="keyword.control.x-else-if"/>
				<capture number="3" name="keyword.control" behavior="text-to-name" behavior-transform="x-$0" />
				<capture number="4" name="keyword.reserved"/>
				<capture number="5" name="keyword.variable.language"/>
				<capture number="6" name="support.variable.built-in"/>
				<capture number="7" name="constant.language"/>
				<capture number="8" name="constant.numeric"/>
			</zone>
		</collection>

		<collection name="keywords.all">
			<include collection="keywords" />
			<!--These have to be deferred for the normal language, so include them explicitly here-->
			<zone name="keyword.storage.type">
				<expression>\b(?:function|var)\b</expression>
			</zone>
		</collection>

		<!--Punctuation and operators-->
		<collection name="punctuation">
			<zone>
				<expression>((?:\+|-|\*|/|%|&amp;|\||\^|>{1,3}|&lt;{1,2})=|!={1,2}|={1,3}|\+{1,2}|-{1,2}|\*|/|%|&lt;{1,2}|>{1,3}|!{1,2}|&amp;{1,2}|\|{1,2}|\^|~)|(\()|(\)(?:;|,)?)|(\{)|(\}(?:;|,)?)|(\[)|(\](?:;|,)?)|(\.|:|\?)|(,)|(;)</expression>
				<capture number="1" name="operator"/>
				<capture number="2" name="punctuation.brace.round.open"/>
				<capture number="3" name="punctuation.brace.round.close" behavior="text-to-name" behavior-match="^.*?(?:(;)|(,))?$" behavior-transform="(?1:x-semicolon:)(?2:x-comma:)"/>
				<capture number="4" name="punctuation.brace.curly.open"/>
				<capture number="5" name="punctuation.brace.curly.close" behavior="text-to-name" behavior-match="^.*?(?:(;)|(,))?$" behavior-transform="(?1:x-semicolon:)(?2:x-comma:)"/>
				<capture number="6" name="punctuation.brace.square.open"/>
				<capture number="7" name="punctuation.brace.square.close" behavior="text-to-name" behavior-match="^.*?(?:(;)|(,))?$" behavior-transform="(?1:x-semicolon:)(?2:x-comma:)"/>
				<capture number="8" name="punctuation"/>
				<capture number="9" name="punctuation.x-comma"/>
				<capture number="10" name="punctuation.x-semicolon"/>
			</zone>
		</collection>

		<!--Variables-->
		<collection name="variables">
			<!--Variable assignment-->
			<!-- We define special zones for variable assignments to allow the itemizers to easily capture anonymous functions assigned to specific variables as a named function (since they are equivalent, and otherwise we end up with a lot of anonymous functions depending on coding style) -->
			<!-- The var keyword is included to allow the itemizers to be drag and dropped with predictable results -->
			<zone>
				<expression>((?:(var)\s+)?([a-zA-Z_$][\w$.]*)\s*(=|:))(?!=)|(\.?)(addEventListener|removeEventListener)\s*(\()|(\.?)([a-zA-Z_$][\w$]*)\s*(\()|\b(function|var)\b</expression>
				<capture number="1" name="x-assignment"/>
				<capture number="2" name="keyword.storage.type"/>
				<capture number="3" name="name"/>
				<capture number="4" name="operator" behavior="text-to-name" behavior-match="^=|(:)$" behavior-transform="(?1:x-colon:)"/>
				<!-- Special case to avoid [text] comparisons in CodeSenseProviders -->
				<capture number="5" name="punctuation"/>
				<capture number="6" name="function.eventListener"/>
				<capture number="7" name="punctuation.brace.round.open"/>
				<!--Function Invocation-->
				<capture number="8" name="punctuation"/>
				<capture number="9" name="function"/>
				<capture number="10" name="punctuation.brace.round.open"/>
				<!--Generic var/function keywords (needs to be last so that they don't mess up x-assignment zones)-->
				<capture number="11" name="keyword.storage.type"/>
			</zone>
		</collection>
	</library>
</syntax>
