Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F1172012
javascript.js
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Sep 28, 10:03 PM
Size
16 KB
Mime Type
text/plain
Expires
Tue, Sep 30, 10:03 PM (1 d, 16 h)
Engine
blob
Format
Raw Data
Handle
759514
Attached To
rINP In-Portal
javascript.js
View Options
// TODO actually recognize syntax of TypeScript constructs
CodeMirror
.
defineMode
(
"javascript"
,
function
(
config
,
parserConfig
)
{
var
indentUnit
=
config
.
indentUnit
;
var
statementIndent
=
parserConfig
.
statementIndent
;
var
jsonMode
=
parserConfig
.
json
;
var
isTS
=
parserConfig
.
typescript
;
// Tokenizer
var
keywords
=
function
(){
function
kw
(
type
)
{
return
{
type
:
type
,
style
:
"keyword"
};}
var
A
=
kw
(
"keyword a"
),
B
=
kw
(
"keyword b"
),
C
=
kw
(
"keyword c"
);
var
operator
=
kw
(
"operator"
),
atom
=
{
type
:
"atom"
,
style
:
"atom"
};
var
jsKeywords
=
{
"if"
:
kw
(
"if"
),
"while"
:
A
,
"with"
:
A
,
"else"
:
B
,
"do"
:
B
,
"try"
:
B
,
"finally"
:
B
,
"return"
:
C
,
"break"
:
C
,
"continue"
:
C
,
"new"
:
C
,
"delete"
:
C
,
"throw"
:
C
,
"var"
:
kw
(
"var"
),
"const"
:
kw
(
"var"
),
"let"
:
kw
(
"var"
),
"function"
:
kw
(
"function"
),
"catch"
:
kw
(
"catch"
),
"for"
:
kw
(
"for"
),
"switch"
:
kw
(
"switch"
),
"case"
:
kw
(
"case"
),
"default"
:
kw
(
"default"
),
"in"
:
operator
,
"typeof"
:
operator
,
"instanceof"
:
operator
,
"true"
:
atom
,
"false"
:
atom
,
"null"
:
atom
,
"undefined"
:
atom
,
"NaN"
:
atom
,
"Infinity"
:
atom
,
"this"
:
kw
(
"this"
)
};
// Extend the 'normal' keywords with the TypeScript language extensions
if
(
isTS
)
{
var
type
=
{
type
:
"variable"
,
style
:
"variable-3"
};
var
tsKeywords
=
{
// object-like things
"interface"
:
kw
(
"interface"
),
"class"
:
kw
(
"class"
),
"extends"
:
kw
(
"extends"
),
"constructor"
:
kw
(
"constructor"
),
// scope modifiers
"public"
:
kw
(
"public"
),
"private"
:
kw
(
"private"
),
"protected"
:
kw
(
"protected"
),
"static"
:
kw
(
"static"
),
"super"
:
kw
(
"super"
),
// types
"string"
:
type
,
"number"
:
type
,
"bool"
:
type
,
"any"
:
type
};
for
(
var
attr
in
tsKeywords
)
{
jsKeywords
[
attr
]
=
tsKeywords
[
attr
];
}
}
return
jsKeywords
;
}();
var
isOperatorChar
=
/[+\-*&%=<>!?|~^]/
;
function
chain
(
stream
,
state
,
f
)
{
state
.
tokenize
=
f
;
return
f
(
stream
,
state
);
}
function
nextUntilUnescaped
(
stream
,
end
)
{
var
escaped
=
false
,
next
;
while
((
next
=
stream
.
next
())
!=
null
)
{
if
(
next
==
end
&&
!
escaped
)
return
false
;
escaped
=
!
escaped
&&
next
==
"\\"
;
}
return
escaped
;
}
// Used as scratch variables to communicate multiple values without
// consing up tons of objects.
var
type
,
content
;
function
ret
(
tp
,
style
,
cont
)
{
type
=
tp
;
content
=
cont
;
return
style
;
}
function
jsTokenBase
(
stream
,
state
)
{
var
ch
=
stream
.
next
();
if
(
ch
==
'"'
||
ch
==
"'"
)
return
chain
(
stream
,
state
,
jsTokenString
(
ch
));
else
if
(
/[\[\]{}\(\),;\:\.]/
.
test
(
ch
))
return
ret
(
ch
);
else
if
(
ch
==
"0"
&&
stream
.
eat
(
/x/i
))
{
stream
.
eatWhile
(
/[\da-f]/i
);
return
ret
(
"number"
,
"number"
);
}
else
if
(
/\d/
.
test
(
ch
)
||
ch
==
"-"
&&
stream
.
eat
(
/\d/
))
{
stream
.
match
(
/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/
);
return
ret
(
"number"
,
"number"
);
}
else
if
(
ch
==
"/"
)
{
if
(
stream
.
eat
(
"*"
))
{
return
chain
(
stream
,
state
,
jsTokenComment
);
}
else
if
(
stream
.
eat
(
"/"
))
{
stream
.
skipToEnd
();
return
ret
(
"comment"
,
"comment"
);
}
else
if
(
state
.
lastType
==
"operator"
||
state
.
lastType
==
"keyword c"
||
/^[\[{}\(,;:]$/
.
test
(
state
.
lastType
))
{
nextUntilUnescaped
(
stream
,
"/"
);
stream
.
eatWhile
(
/[gimy]/
);
// 'y' is "sticky" option in Mozilla
return
ret
(
"regexp"
,
"string-2"
);
}
else
{
stream
.
eatWhile
(
isOperatorChar
);
return
ret
(
"operator"
,
null
,
stream
.
current
());
}
}
else
if
(
ch
==
"#"
)
{
stream
.
skipToEnd
();
return
ret
(
"error"
,
"error"
);
}
else
if
(
isOperatorChar
.
test
(
ch
))
{
stream
.
eatWhile
(
isOperatorChar
);
return
ret
(
"operator"
,
null
,
stream
.
current
());
}
else
{
stream
.
eatWhile
(
/[\w\$_]/
);
var
word
=
stream
.
current
(),
known
=
keywords
.
propertyIsEnumerable
(
word
)
&&
keywords
[
word
];
return
(
known
&&
state
.
lastType
!=
"."
)
?
ret
(
known
.
type
,
known
.
style
,
word
)
:
ret
(
"variable"
,
"variable"
,
word
);
}
}
function
jsTokenString
(
quote
)
{
return
function
(
stream
,
state
)
{
if
(
!
nextUntilUnescaped
(
stream
,
quote
))
state
.
tokenize
=
jsTokenBase
;
return
ret
(
"string"
,
"string"
);
};
}
function
jsTokenComment
(
stream
,
state
)
{
var
maybeEnd
=
false
,
ch
;
while
(
ch
=
stream
.
next
())
{
if
(
ch
==
"/"
&&
maybeEnd
)
{
state
.
tokenize
=
jsTokenBase
;
break
;
}
maybeEnd
=
(
ch
==
"*"
);
}
return
ret
(
"comment"
,
"comment"
);
}
// Parser
var
atomicTypes
=
{
"atom"
:
true
,
"number"
:
true
,
"variable"
:
true
,
"string"
:
true
,
"regexp"
:
true
,
"this"
:
true
};
function
JSLexical
(
indented
,
column
,
type
,
align
,
prev
,
info
)
{
this
.
indented
=
indented
;
this
.
column
=
column
;
this
.
type
=
type
;
this
.
prev
=
prev
;
this
.
info
=
info
;
if
(
align
!=
null
)
this
.
align
=
align
;
}
function
inScope
(
state
,
varname
)
{
for
(
var
v
=
state
.
localVars
;
v
;
v
=
v
.
next
)
if
(
v
.
name
==
varname
)
return
true
;
}
function
parseJS
(
state
,
style
,
type
,
content
,
stream
)
{
var
cc
=
state
.
cc
;
// Communicate our context to the combinators.
// (Less wasteful than consing up a hundred closures on every call.)
cx
.
state
=
state
;
cx
.
stream
=
stream
;
cx
.
marked
=
null
,
cx
.
cc
=
cc
;
if
(
!
state
.
lexical
.
hasOwnProperty
(
"align"
))
state
.
lexical
.
align
=
true
;
while
(
true
)
{
var
combinator
=
cc
.
length
?
cc
.
pop
()
:
jsonMode
?
expression
:
statement
;
if
(
combinator
(
type
,
content
))
{
while
(
cc
.
length
&&
cc
[
cc
.
length
-
1
].
lex
)
cc
.
pop
()();
if
(
cx
.
marked
)
return
cx
.
marked
;
if
(
type
==
"variable"
&&
inScope
(
state
,
content
))
return
"variable-2"
;
return
style
;
}
}
}
// Combinator utils
var
cx
=
{
state
:
null
,
column
:
null
,
marked
:
null
,
cc
:
null
};
function
pass
()
{
for
(
var
i
=
arguments
.
length
-
1
;
i
>=
0
;
i
--
)
cx
.
cc
.
push
(
arguments
[
i
]);
}
function
cont
()
{
pass
.
apply
(
null
,
arguments
);
return
true
;
}
function
register
(
varname
)
{
function
inList
(
list
)
{
for
(
var
v
=
list
;
v
;
v
=
v
.
next
)
if
(
v
.
name
==
varname
)
return
true
;
return
false
;
}
var
state
=
cx
.
state
;
if
(
state
.
context
)
{
cx
.
marked
=
"def"
;
if
(
inList
(
state
.
localVars
))
return
;
state
.
localVars
=
{
name
:
varname
,
next
:
state
.
localVars
};
}
else
{
if
(
inList
(
state
.
globalVars
))
return
;
state
.
globalVars
=
{
name
:
varname
,
next
:
state
.
globalVars
};
}
}
// Combinators
var
defaultVars
=
{
name
:
"this"
,
next
:
{
name
:
"arguments"
}};
function
pushcontext
()
{
cx
.
state
.
context
=
{
prev
:
cx
.
state
.
context
,
vars
:
cx
.
state
.
localVars
};
cx
.
state
.
localVars
=
defaultVars
;
}
function
popcontext
()
{
cx
.
state
.
localVars
=
cx
.
state
.
context
.
vars
;
cx
.
state
.
context
=
cx
.
state
.
context
.
prev
;
}
function
pushlex
(
type
,
info
)
{
var
result
=
function
()
{
var
state
=
cx
.
state
,
indent
=
state
.
indented
;
if
(
state
.
lexical
.
type
==
"stat"
)
indent
=
state
.
lexical
.
indented
;
state
.
lexical
=
new
JSLexical
(
indent
,
cx
.
stream
.
column
(),
type
,
null
,
state
.
lexical
,
info
);
};
result
.
lex
=
true
;
return
result
;
}
function
poplex
()
{
var
state
=
cx
.
state
;
if
(
state
.
lexical
.
prev
)
{
if
(
state
.
lexical
.
type
==
")"
)
state
.
indented
=
state
.
lexical
.
indented
;
state
.
lexical
=
state
.
lexical
.
prev
;
}
}
poplex
.
lex
=
true
;
function
expect
(
wanted
)
{
return
function
(
type
)
{
if
(
type
==
wanted
)
return
cont
();
else
if
(
wanted
==
";"
)
return
pass
();
else
return
cont
(
arguments
.
callee
);
};
}
function
statement
(
type
)
{
if
(
type
==
"var"
)
return
cont
(
pushlex
(
"vardef"
),
vardef1
,
expect
(
";"
),
poplex
);
if
(
type
==
"keyword a"
)
return
cont
(
pushlex
(
"form"
),
expression
,
statement
,
poplex
);
if
(
type
==
"keyword b"
)
return
cont
(
pushlex
(
"form"
),
statement
,
poplex
);
if
(
type
==
"{"
)
return
cont
(
pushlex
(
"}"
),
block
,
poplex
);
if
(
type
==
";"
)
return
cont
();
if
(
type
==
"if"
)
return
cont
(
pushlex
(
"form"
),
expression
,
statement
,
poplex
,
maybeelse
(
cx
.
state
.
indented
));
if
(
type
==
"function"
)
return
cont
(
functiondef
);
if
(
type
==
"for"
)
return
cont
(
pushlex
(
"form"
),
expect
(
"("
),
pushlex
(
")"
),
forspec1
,
expect
(
")"
),
poplex
,
statement
,
poplex
);
if
(
type
==
"variable"
)
return
cont
(
pushlex
(
"stat"
),
maybelabel
);
if
(
type
==
"switch"
)
return
cont
(
pushlex
(
"form"
),
expression
,
pushlex
(
"}"
,
"switch"
),
expect
(
"{"
),
block
,
poplex
,
poplex
);
if
(
type
==
"case"
)
return
cont
(
expression
,
expect
(
":"
));
if
(
type
==
"default"
)
return
cont
(
expect
(
":"
));
if
(
type
==
"catch"
)
return
cont
(
pushlex
(
"form"
),
pushcontext
,
expect
(
"("
),
funarg
,
expect
(
")"
),
statement
,
poplex
,
popcontext
);
return
pass
(
pushlex
(
"stat"
),
expression
,
expect
(
";"
),
poplex
);
}
function
expression
(
type
)
{
return
expressionInner
(
type
,
false
);
}
function
expressionNoComma
(
type
)
{
return
expressionInner
(
type
,
true
);
}
function
expressionInner
(
type
,
noComma
)
{
var
maybeop
=
noComma
?
maybeoperatorNoComma
:
maybeoperatorComma
;
if
(
atomicTypes
.
hasOwnProperty
(
type
))
return
cont
(
maybeop
);
if
(
type
==
"function"
)
return
cont
(
functiondef
);
if
(
type
==
"keyword c"
)
return
cont
(
noComma
?
maybeexpressionNoComma
:
maybeexpression
);
if
(
type
==
"("
)
return
cont
(
pushlex
(
")"
),
maybeexpression
,
expect
(
")"
),
poplex
,
maybeop
);
if
(
type
==
"operator"
)
return
cont
(
noComma
?
expressionNoComma
:
expression
);
if
(
type
==
"["
)
return
cont
(
pushlex
(
"]"
),
commasep
(
expressionNoComma
,
"]"
),
poplex
,
maybeop
);
if
(
type
==
"{"
)
return
cont
(
pushlex
(
"}"
),
commasep
(
objprop
,
"}"
),
poplex
,
maybeop
);
return
cont
();
}
function
maybeexpression
(
type
)
{
if
(
type
.
match
(
/[;\}\)\],]/
))
return
pass
();
return
pass
(
expression
);
}
function
maybeexpressionNoComma
(
type
)
{
if
(
type
.
match
(
/[;\}\)\],]/
))
return
pass
();
return
pass
(
expressionNoComma
);
}
function
maybeoperatorComma
(
type
,
value
)
{
if
(
type
==
","
)
return
cont
(
expression
);
return
maybeoperatorNoComma
(
type
,
value
,
maybeoperatorComma
);
}
function
maybeoperatorNoComma
(
type
,
value
,
me
)
{
if
(
!
me
)
me
=
maybeoperatorNoComma
;
if
(
type
==
"operator"
)
{
if
(
/\+\+|--/
.
test
(
value
))
return
cont
(
me
);
if
(
value
==
"?"
)
return
cont
(
expression
,
expect
(
":"
),
expression
);
return
cont
(
expression
);
}
if
(
type
==
";"
)
return
;
if
(
type
==
"("
)
return
cont
(
pushlex
(
")"
,
"call"
),
commasep
(
expressionNoComma
,
")"
),
poplex
,
me
);
if
(
type
==
"."
)
return
cont
(
property
,
me
);
if
(
type
==
"["
)
return
cont
(
pushlex
(
"]"
),
expression
,
expect
(
"]"
),
poplex
,
me
);
}
function
maybelabel
(
type
)
{
if
(
type
==
":"
)
return
cont
(
poplex
,
statement
);
return
pass
(
maybeoperatorComma
,
expect
(
";"
),
poplex
);
}
function
property
(
type
)
{
if
(
type
==
"variable"
)
{
cx
.
marked
=
"property"
;
return
cont
();}
}
function
objprop
(
type
,
value
)
{
if
(
type
==
"variable"
)
{
cx
.
marked
=
"property"
;
if
(
value
==
"get"
||
value
==
"set"
)
return
cont
(
getterSetter
);
}
else
if
(
type
==
"number"
||
type
==
"string"
)
{
cx
.
marked
=
type
+
" property"
;
}
if
(
atomicTypes
.
hasOwnProperty
(
type
))
return
cont
(
expect
(
":"
),
expressionNoComma
);
}
function
getterSetter
(
type
)
{
if
(
type
==
":"
)
return
cont
(
expression
);
if
(
type
!=
"variable"
)
return
cont
(
expect
(
":"
),
expression
);
cx
.
marked
=
"property"
;
return
cont
(
functiondef
);
}
function
commasep
(
what
,
end
)
{
function
proceed
(
type
)
{
if
(
type
==
","
)
{
var
lex
=
cx
.
state
.
lexical
;
if
(
lex
.
info
==
"call"
)
lex
.
pos
=
(
lex
.
pos
||
0
)
+
1
;
return
cont
(
what
,
proceed
);
}
if
(
type
==
end
)
return
cont
();
return
cont
(
expect
(
end
));
}
return
function
(
type
)
{
if
(
type
==
end
)
return
cont
();
else
return
pass
(
what
,
proceed
);
};
}
function
block
(
type
)
{
if
(
type
==
"}"
)
return
cont
();
return
pass
(
statement
,
block
);
}
function
maybetype
(
type
)
{
if
(
type
==
":"
)
return
cont
(
typedef
);
return
pass
();
}
function
typedef
(
type
)
{
if
(
type
==
"variable"
){
cx
.
marked
=
"variable-3"
;
return
cont
();}
return
pass
();
}
function
vardef1
(
type
,
value
)
{
if
(
type
==
"variable"
)
{
register
(
value
);
return
isTS
?
cont
(
maybetype
,
vardef2
)
:
cont
(
vardef2
);
}
return
pass
();
}
function
vardef2
(
type
,
value
)
{
if
(
value
==
"="
)
return
cont
(
expressionNoComma
,
vardef2
);
if
(
type
==
","
)
return
cont
(
vardef1
);
}
function
maybeelse
(
indent
)
{
return
function
(
type
,
value
)
{
if
(
type
==
"keyword b"
&&
value
==
"else"
)
{
cx
.
state
.
lexical
=
new
JSLexical
(
indent
,
0
,
"form"
,
null
,
cx
.
state
.
lexical
);
return
cont
(
statement
,
poplex
);
}
return
pass
();
};
}
function
forspec1
(
type
)
{
if
(
type
==
"var"
)
return
cont
(
vardef1
,
expect
(
";"
),
forspec2
);
if
(
type
==
";"
)
return
cont
(
forspec2
);
if
(
type
==
"variable"
)
return
cont
(
formaybein
);
return
pass
(
expression
,
expect
(
";"
),
forspec2
);
}
function
formaybein
(
_type
,
value
)
{
if
(
value
==
"in"
)
return
cont
(
expression
);
return
cont
(
maybeoperatorComma
,
forspec2
);
}
function
forspec2
(
type
,
value
)
{
if
(
type
==
";"
)
return
cont
(
forspec3
);
if
(
value
==
"in"
)
return
cont
(
expression
);
return
pass
(
expression
,
expect
(
";"
),
forspec3
);
}
function
forspec3
(
type
)
{
if
(
type
!=
")"
)
cont
(
expression
);
}
function
functiondef
(
type
,
value
)
{
if
(
type
==
"variable"
)
{
register
(
value
);
return
cont
(
functiondef
);}
if
(
type
==
"("
)
return
cont
(
pushlex
(
")"
),
pushcontext
,
commasep
(
funarg
,
")"
),
poplex
,
statement
,
popcontext
);
}
function
funarg
(
type
,
value
)
{
if
(
type
==
"variable"
)
{
register
(
value
);
return
isTS
?
cont
(
maybetype
)
:
cont
();}
}
// Interface
return
{
startState
:
function
(
basecolumn
)
{
return
{
tokenize
:
jsTokenBase
,
lastType
:
null
,
cc
:
[],
lexical
:
new
JSLexical
((
basecolumn
||
0
)
-
indentUnit
,
0
,
"block"
,
false
),
localVars
:
parserConfig
.
localVars
,
globalVars
:
parserConfig
.
globalVars
,
context
:
parserConfig
.
localVars
&&
{
vars
:
parserConfig
.
localVars
},
indented
:
0
};
},
token
:
function
(
stream
,
state
)
{
if
(
stream
.
sol
())
{
if
(
!
state
.
lexical
.
hasOwnProperty
(
"align"
))
state
.
lexical
.
align
=
false
;
state
.
indented
=
stream
.
indentation
();
}
if
(
state
.
tokenize
!=
jsTokenComment
&&
stream
.
eatSpace
())
return
null
;
var
style
=
state
.
tokenize
(
stream
,
state
);
if
(
type
==
"comment"
)
return
style
;
state
.
lastType
=
type
==
"operator"
&&
(
content
==
"++"
||
content
==
"--"
)
?
"incdec"
:
type
;
return
parseJS
(
state
,
style
,
type
,
content
,
stream
);
},
indent
:
function
(
state
,
textAfter
)
{
if
(
state
.
tokenize
==
jsTokenComment
)
return
CodeMirror
.
Pass
;
if
(
state
.
tokenize
!=
jsTokenBase
)
return
0
;
var
firstChar
=
textAfter
&&
textAfter
.
charAt
(
0
),
lexical
=
state
.
lexical
;
if
(
lexical
.
type
==
"stat"
&&
firstChar
==
"}"
)
lexical
=
lexical
.
prev
;
if
(
statementIndent
&&
lexical
.
type
==
")"
&&
lexical
.
prev
.
type
==
"stat"
)
lexical
=
lexical
.
prev
;
var
type
=
lexical
.
type
,
closing
=
firstChar
==
type
;
if
(
type
==
"vardef"
)
return
lexical
.
indented
+
(
state
.
lastType
==
"operator"
||
state
.
lastType
==
","
?
4
:
0
);
else
if
(
type
==
"form"
&&
firstChar
==
"{"
)
return
lexical
.
indented
;
else
if
(
type
==
"form"
)
return
lexical
.
indented
+
indentUnit
;
else
if
(
type
==
"stat"
)
return
lexical
.
indented
+
(
state
.
lastType
==
"operator"
||
state
.
lastType
==
","
?
statementIndent
||
indentUnit
:
0
);
else
if
(
lexical
.
info
==
"switch"
&&
!
closing
&&
parserConfig
.
doubleIndentSwitch
!=
false
)
return
lexical
.
indented
+
(
/^(?:case|default)\b/
.
test
(
textAfter
)
?
indentUnit
:
2
*
indentUnit
);
else
if
(
lexical
.
align
)
return
lexical
.
column
+
(
closing
?
0
:
1
);
else
return
lexical
.
indented
+
(
closing
?
0
:
indentUnit
);
},
electricChars
:
":{}"
,
blockCommentStart
:
jsonMode
?
null
:
"/*"
,
blockCommentEnd
:
jsonMode
?
null
:
"*/"
,
lineComment
:
jsonMode
?
null
:
"//"
,
jsonMode
:
jsonMode
};
});
CodeMirror
.
defineMIME
(
"text/javascript"
,
"javascript"
);
CodeMirror
.
defineMIME
(
"text/ecmascript"
,
"javascript"
);
CodeMirror
.
defineMIME
(
"application/javascript"
,
"javascript"
);
CodeMirror
.
defineMIME
(
"application/ecmascript"
,
"javascript"
);
CodeMirror
.
defineMIME
(
"application/json"
,
{
name
:
"javascript"
,
json
:
true
});
CodeMirror
.
defineMIME
(
"application/x-json"
,
{
name
:
"javascript"
,
json
:
true
});
CodeMirror
.
defineMIME
(
"text/typescript"
,
{
name
:
"javascript"
,
typescript
:
true
});
CodeMirror
.
defineMIME
(
"application/typescript"
,
{
name
:
"javascript"
,
typescript
:
true
});
Event Timeline
Log In to Comment