]>
git.r.bdr.sh - rbdr/dotfiles/blob - atom/packages/pretty-json/node_modules/jsonminify/report/assets/scripts/vendor/codemirror/javascript.js
f00be91e86e80e53d46af6c7f6306a68fd804948
1 // TODO actually recognize syntax of TypeScript constructs
3 CodeMirror
.defineMode("javascript", function(config
, parserConfig
) {
4 var indentUnit
= config
.indentUnit
;
5 var jsonMode
= parserConfig
.json
;
6 var isTS
= parserConfig
.typescript
;
10 var keywords = function(){
11 function kw(type
) {return {type: type
, style: "keyword"};}
12 var A
= kw("keyword a"), B
= kw("keyword b"), C
= kw("keyword c");
13 var operator
= kw("operator"), atom
= {type: "atom", style: "atom"};
16 "if": A
, "while": A
, "with": A
, "else": B
, "do": B
, "try": B
, "finally": B
,
17 "return": C
, "break": C
, "continue": C
, "new": C
, "delete": C
, "throw": C
,
18 "var": kw("var"), "const": kw("var"), "let": kw("var"),
19 "function": kw("function"), "catch": kw("catch"),
20 "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
21 "in": operator
, "typeof": operator
, "instanceof": operator
,
22 "true": atom
, "false": atom
, "null": atom
, "undefined": atom
, "NaN": atom
, "Infinity": atom
25 // Extend the 'normal' keywords with the TypeScript language extensions
27 var type
= {type: "variable", style: "variable-3"};
30 "interface": kw("interface"),
32 "extends": kw("extends"),
33 "constructor": kw("constructor"),
36 "public": kw("public"),
37 "private": kw("private"),
38 "protected": kw("protected"),
39 "static": kw("static"),
44 "string": type
, "number": type
, "bool": type
, "any": type
47 for (var attr
in tsKeywords
) {
48 jsKeywords
[attr
] = tsKeywords
[attr
];
55 var isOperatorChar
= /[+\-*&%=<>!?|]/;
57 function chain(stream
, state
, f
) {
59 return f(stream
, state
);
62 function nextUntilUnescaped(stream
, end
) {
63 var escaped
= false, next
;
64 while ((next
= stream
.next()) != null) {
65 if (next
== end
&& !escaped
)
67 escaped
= !escaped
&& next
== "\\";
72 // Used as scratch variables to communicate multiple values without
73 // consing up tons of objects.
75 function ret(tp
, style
, cont
) {
76 type
= tp
; content
= cont
;
80 function jsTokenBase(stream
, state
) {
81 var ch
= stream
.next();
82 if (ch
== '"' || ch
== "'")
83 return chain(stream
, state
, jsTokenString(ch
));
84 else if (/[\[\]{}\(\),;\:\.]/.test(ch
))
86 else if (ch
== "0" && stream
.eat(/x
/i
)) {
87 stream
.eatWhile(/[\da-f]/i);
88 return ret("number", "number");
90 else if (/\d/.test(ch
) || ch
== "-" && stream
.eat(/\d/)) {
91 stream
.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
92 return ret("number", "number");
95 if (stream
.eat("*")) {
96 return chain(stream
, state
, jsTokenComment
);
98 else if (stream
.eat("/")) {
100 return ret("comment", "comment");
102 else if (state
.lastType
== "operator" || state
.lastType
== "keyword c" ||
103 /^[\[{}\(,;:]$/.test(state
.lastType
)) {
104 nextUntilUnescaped(stream
, "/");
105 stream
.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
106 return ret("regexp", "string-2");
109 stream
.eatWhile(isOperatorChar
);
110 return ret("operator", null, stream
.current());
113 else if (ch
== "#") {
115 return ret("error", "error");
117 else if (isOperatorChar
.test(ch
)) {
118 stream
.eatWhile(isOperatorChar
);
119 return ret("operator", null, stream
.current());
122 stream
.eatWhile(/[\w\$_]/);
123 var word
= stream
.current(), known
= keywords
.propertyIsEnumerable(word
) && keywords
[word
];
124 return (known
&& state
.lastType
!= ".") ? ret(known
.type
, known
.style
, word
) :
125 ret("variable", "variable", word
);
129 function jsTokenString(quote
) {
130 return function(stream
, state
) {
131 if (!nextUntilUnescaped(stream
, quote
))
132 state
.tokenize
= jsTokenBase
;
133 return ret("string", "string");
137 function jsTokenComment(stream
, state
) {
138 var maybeEnd
= false, ch
;
139 while (ch
= stream
.next()) {
140 if (ch
== "/" && maybeEnd
) {
141 state
.tokenize
= jsTokenBase
;
144 maybeEnd
= (ch
== "*");
146 return ret("comment", "comment");
151 var atomicTypes
= {"atom": true, "number": true, "variable": true, "string": true, "regexp": true};
153 function JSLexical(indented
, column
, type
, align
, prev
, info
) {
154 this.indented
= indented
;
155 this.column
= column
;
159 if (align
!= null) this.align
= align
;
162 function inScope(state
, varname
) {
163 for (var v
= state
.localVars
; v
; v
= v
.next
)
164 if (v
.name
== varname
) return true;
167 function parseJS(state
, style
, type
, content
, stream
) {
169 // Communicate our context to the combinators.
170 // (Less wasteful than consing up a hundred closures on every call.)
171 cx
.state
= state
; cx
.stream
= stream
; cx
.marked
= null, cx
.cc
= cc
;
173 if (!state
.lexical
.hasOwnProperty("align"))
174 state
.lexical
.align
= true;
177 var combinator
= cc
.length
? cc
.pop() : jsonMode
? expression : statement
;
178 if (combinator(type
, content
)) {
179 while(cc
.length
&& cc
[cc
.length
- 1].lex
)
181 if (cx
.marked
) return cx
.marked
;
182 if (type
== "variable" && inScope(state
, content
)) return "variable-2";
190 var cx
= {state: null, column: null, marked: null, cc: null};
192 for (var i
= arguments
.length
- 1; i
>= 0; i
--) cx
.cc
.push(arguments
[i
]);
195 pass
.apply(null, arguments
);
198 function register(varname
) {
199 var state
= cx
.state
;
202 for (var v
= state
.localVars
; v
; v
= v
.next
)
203 if (v
.name
== varname
) return;
204 state
.localVars
= {name: varname
, next: state
.localVars
};
210 var defaultVars
= {name: "this", next: {name: "arguments"}};
211 function pushcontext() {
212 cx
.state
.context
= {prev: cx
.state
.context
, vars: cx
.state
.localVars
};
213 cx
.state
.localVars
= defaultVars
;
215 function popcontext() {
216 cx
.state
.localVars
= cx
.state
.context
.vars
;
217 cx
.state
.context
= cx
.state
.context
.prev
;
219 function pushlex(type
, info
) {
220 var result = function() {
221 var state
= cx
.state
;
222 state
.lexical
= new JSLexical(state
.indented
, cx
.stream
.column(), type
, null, state
.lexical
, info
);
228 var state
= cx
.state
;
229 if (state
.lexical
.prev
) {
230 if (state
.lexical
.type
== ")")
231 state
.indented
= state
.lexical
.indented
;
232 state
.lexical
= state
.lexical
.prev
;
237 function expect(wanted
) {
238 return function expecting(type
) {
239 if (type
== wanted
) return cont();
240 else if (wanted
== ";") return pass();
241 else return cont(arguments
.callee
);
245 function statement(type
) {
246 if (type
== "var") return cont(pushlex("vardef"), vardef1
, expect(";"), poplex
);
247 if (type
== "keyword a") return cont(pushlex("form"), expression
, statement
, poplex
);
248 if (type
== "keyword b") return cont(pushlex("form"), statement
, poplex
);
249 if (type
== "{") return cont(pushlex("}"), block
, poplex
);
250 if (type
== ";") return cont();
251 if (type
== "function") return cont(functiondef
);
252 if (type
== "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1
, expect(")"),
253 poplex
, statement
, poplex
);
254 if (type
== "variable") return cont(pushlex("stat"), maybelabel
);
255 if (type
== "switch") return cont(pushlex("form"), expression
, pushlex("}", "switch"), expect("{"),
256 block
, poplex
, poplex
);
257 if (type
== "case") return cont(expression
, expect(":"));
258 if (type
== "default") return cont(expect(":"));
259 if (type
== "catch") return cont(pushlex("form"), pushcontext
, expect("("), funarg
, expect(")"),
260 statement
, poplex
, popcontext
);
261 return pass(pushlex("stat"), expression
, expect(";"), poplex
);
263 function expression(type
) {
264 if (atomicTypes
.hasOwnProperty(type
)) return cont(maybeoperator
);
265 if (type
== "function") return cont(functiondef
);
266 if (type
== "keyword c") return cont(maybeexpression
);
267 if (type
== "(") return cont(pushlex(")"), maybeexpression
, expect(")"), poplex
, maybeoperator
);
268 if (type
== "operator") return cont(expression
);
269 if (type
== "[") return cont(pushlex("]"), commasep(expression
, "]"), poplex
, maybeoperator
);
270 if (type
== "{") return cont(pushlex("}"), commasep(objprop
, "}"), poplex
, maybeoperator
);
273 function maybeexpression(type
) {
274 if (type
.match(/[;\}\)\],]/)) return pass();
275 return pass(expression
);
278 function maybeoperator(type
, value
) {
279 if (type
== "operator" && /\+\+|--/.test(value
)) return cont(maybeoperator
);
280 if (type
== "operator" && value
== "?") return cont(expression
, expect(":"), expression
);
281 if (type
== ";") return;
282 if (type
== "(") return cont(pushlex(")"), commasep(expression
, ")"), poplex
, maybeoperator
);
283 if (type
== ".") return cont(property
, maybeoperator
);
284 if (type
== "[") return cont(pushlex("]"), expression
, expect("]"), poplex
, maybeoperator
);
286 function maybelabel(type
) {
287 if (type
== ":") return cont(poplex
, statement
);
288 return pass(maybeoperator
, expect(";"), poplex
);
290 function property(type
) {
291 if (type
== "variable") {cx
.marked
= "property"; return cont();}
293 function objprop(type
) {
294 if (type
== "variable") cx
.marked
= "property";
295 if (atomicTypes
.hasOwnProperty(type
)) return cont(expect(":"), expression
);
297 function commasep(what
, end
) {
298 function proceed(type
) {
299 if (type
== ",") return cont(what
, proceed
);
300 if (type
== end
) return cont();
301 return cont(expect(end
));
303 return function commaSeparated(type
) {
304 if (type
== end
) return cont();
305 else return pass(what
, proceed
);
308 function block(type
) {
309 if (type
== "}") return cont();
310 return pass(statement
, block
);
312 function maybetype(type
) {
313 if (type
== ":") return cont(typedef
);
316 function typedef(type
) {
317 if (type
== "variable"){cx
.marked
= "variable-3"; return cont();}
320 function vardef1(type
, value
) {
321 if (type
== "variable") {
323 return isTS
? cont(maybetype
, vardef2
) : cont(vardef2
);
327 function vardef2(type
, value
) {
328 if (value
== "=") return cont(expression
, vardef2
);
329 if (type
== ",") return cont(vardef1
);
331 function forspec1(type
) {
332 if (type
== "var") return cont(vardef1
, expect(";"), forspec2
);
333 if (type
== ";") return cont(forspec2
);
334 if (type
== "variable") return cont(formaybein
);
335 return cont(forspec2
);
337 function formaybein(_type
, value
) {
338 if (value
== "in") return cont(expression
);
339 return cont(maybeoperator
, forspec2
);
341 function forspec2(type
, value
) {
342 if (type
== ";") return cont(forspec3
);
343 if (value
== "in") return cont(expression
);
344 return cont(expression
, expect(";"), forspec3
);
346 function forspec3(type
) {
347 if (type
!= ")") cont(expression
);
349 function functiondef(type
, value
) {
350 if (type
== "variable") {register(value
); return cont(functiondef
);}
351 if (type
== "(") return cont(pushlex(")"), pushcontext
, commasep(funarg
, ")"), poplex
, statement
, popcontext
);
353 function funarg(type
, value
) {
354 if (type
== "variable") {register(value
); return isTS
? cont(maybetype
) : cont();}
360 startState: function(basecolumn
) {
362 tokenize: jsTokenBase
,
365 lexical: new JSLexical((basecolumn
|| 0) - indentUnit
, 0, "block", false),
366 localVars: parserConfig
.localVars
,
367 context: parserConfig
.localVars
&& {vars: parserConfig
.localVars
},
372 token: function(stream
, state
) {
374 if (!state
.lexical
.hasOwnProperty("align"))
375 state
.lexical
.align
= false;
376 state
.indented
= stream
.indentation();
378 if (stream
.eatSpace()) return null;
379 var style
= state
.tokenize(stream
, state
);
380 if (type
== "comment") return style
;
381 state
.lastType
= type
;
382 return parseJS(state
, style
, type
, content
, stream
);
385 indent: function(state
, textAfter
) {
386 if (state
.tokenize
== jsTokenComment
) return CodeMirror
.Pass
;
387 if (state
.tokenize
!= jsTokenBase
) return 0;
388 var firstChar
= textAfter
&& textAfter
.charAt(0), lexical
= state
.lexical
;
389 if (lexical
.type
== "stat" && firstChar
== "}") lexical
= lexical
.prev
;
390 var type
= lexical
.type
, closing
= firstChar
== type
;
391 if (type
== "vardef") return lexical
.indented
+ (state
.lastType
== "operator" || state
.lastType
== "," ? 4 : 0);
392 else if (type
== "form" && firstChar
== "{") return lexical
.indented
;
393 else if (type
== "form") return lexical
.indented
+ indentUnit
;
394 else if (type
== "stat")
395 return lexical
.indented
+ (state
.lastType
== "operator" || state
.lastType
== "," ? indentUnit : 0);
396 else if (lexical
.info
== "switch" && !closing
)
397 return lexical
.indented
+ (/^(?:case|default)\b/.test(textAfter
) ? indentUnit : 2 * indentUnit
);
398 else if (lexical
.align
) return lexical
.column
+ (closing
? 0 : 1);
399 else return lexical
.indented
+ (closing
? 0 : indentUnit
);
402 electricChars: ":{}",
408 CodeMirror
.defineMIME("text/javascript", "javascript");
409 CodeMirror
.defineMIME("application/json", {name: "javascript", json: true});
410 CodeMirror
.defineMIME("text/typescript", { name: "javascript", typescript: true });
411 CodeMirror
.defineMIME("application/typescript", { name: "javascript", typescript: true });