blogelator 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,102 @@
1
+ CodeMirror.defineMode("gfm", function(config, modeConfig) {
2
+ var codeDepth = 0;
3
+ function blankLine(state) {
4
+ state.code = false;
5
+ return null;
6
+ }
7
+ var gfmOverlay = {
8
+ startState: function() {
9
+ return {
10
+ code: false,
11
+ codeBlock: false,
12
+ ateSpace: false
13
+ };
14
+ },
15
+ copyState: function(s) {
16
+ return {
17
+ code: s.code,
18
+ codeBlock: s.codeBlock,
19
+ ateSpace: s.ateSpace
20
+ };
21
+ },
22
+ token: function(stream, state) {
23
+ // Hack to prevent formatting override inside code blocks (block and inline)
24
+ if (state.codeBlock) {
25
+ if (stream.match(/^```/)) {
26
+ state.codeBlock = false;
27
+ return null;
28
+ }
29
+ stream.skipToEnd();
30
+ return null;
31
+ }
32
+ if (stream.sol()) {
33
+ state.code = false;
34
+ }
35
+ if (stream.sol() && stream.match(/^```/)) {
36
+ stream.skipToEnd();
37
+ state.codeBlock = true;
38
+ return null;
39
+ }
40
+ // If this block is changed, it may need to be updated in Markdown mode
41
+ if (stream.peek() === '`') {
42
+ stream.next();
43
+ var before = stream.pos;
44
+ stream.eatWhile('`');
45
+ var difference = 1 + stream.pos - before;
46
+ if (!state.code) {
47
+ codeDepth = difference;
48
+ state.code = true;
49
+ } else {
50
+ if (difference === codeDepth) { // Must be exact
51
+ state.code = false;
52
+ }
53
+ }
54
+ return null;
55
+ } else if (state.code) {
56
+ stream.next();
57
+ return null;
58
+ }
59
+ // Check if space. If so, links can be formatted later on
60
+ if (stream.eatSpace()) {
61
+ state.ateSpace = true;
62
+ return null;
63
+ }
64
+ if (stream.sol() || state.ateSpace) {
65
+ state.ateSpace = false;
66
+ if(stream.match(/^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+@)?(?:[a-f0-9]{7,40}\b)/)) {
67
+ // User/Project@SHA
68
+ // User@SHA
69
+ // SHA
70
+ return "link";
71
+ } else if (stream.match(/^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+)?#[0-9]+\b/)) {
72
+ // User/Project#Num
73
+ // User#Num
74
+ // #Num
75
+ return "link";
76
+ }
77
+ }
78
+ if (stream.match(/^((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]|\([^\s()<>]*\))+(?:\([^\s()<>]*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/i) &&
79
+ stream.string.slice(stream.start - 2, stream.start) != "](") {
80
+ // URLs
81
+ // Taken from http://daringfireball.net/2010/07/improved_regex_for_matching_urls
82
+ // And then (issue #1160) simplified to make it not crash the Chrome Regexp engine
83
+ return "link";
84
+ }
85
+ stream.next();
86
+ return null;
87
+ },
88
+ blankLine: blankLine
89
+ };
90
+
91
+ var markdownConfig = {
92
+ underscoresBreakWords: false,
93
+ taskLists: true,
94
+ fencedCodeBlocks: true
95
+ };
96
+ for (var attr in modeConfig) {
97
+ markdownConfig[attr] = modeConfig[attr];
98
+ }
99
+ markdownConfig.name = "markdown";
100
+ CodeMirror.defineMIME("gfmBase", markdownConfig);
101
+ return CodeMirror.overlayMode(CodeMirror.getMode(config, "gfmBase"), gfmOverlay);
102
+ }, "markdown");
@@ -0,0 +1,105 @@
1
+ CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
2
+ var htmlMode = CodeMirror.getMode(config, {name: "xml",
3
+ htmlMode: true,
4
+ multilineTagIndentFactor: parserConfig.multilineTagIndentFactor,
5
+ multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag});
6
+ var cssMode = CodeMirror.getMode(config, "css");
7
+
8
+ var scriptTypes = [], scriptTypesConf = parserConfig && parserConfig.scriptTypes;
9
+ scriptTypes.push({matches: /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i,
10
+ mode: CodeMirror.getMode(config, "javascript")});
11
+ if (scriptTypesConf) for (var i = 0; i < scriptTypesConf.length; ++i) {
12
+ var conf = scriptTypesConf[i];
13
+ scriptTypes.push({matches: conf.matches, mode: conf.mode && CodeMirror.getMode(config, conf.mode)});
14
+ }
15
+ scriptTypes.push({matches: /./,
16
+ mode: CodeMirror.getMode(config, "text/plain")});
17
+
18
+ function html(stream, state) {
19
+ var tagName = state.htmlState.tagName;
20
+ var style = htmlMode.token(stream, state.htmlState);
21
+ if (tagName == "script" && /\btag\b/.test(style) && stream.current() == ">") {
22
+ // Script block: mode to change to depends on type attribute
23
+ var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i);
24
+ scriptType = scriptType ? scriptType[1] : "";
25
+ if (scriptType && /[\"\']/.test(scriptType.charAt(0))) scriptType = scriptType.slice(1, scriptType.length - 1);
26
+ for (var i = 0; i < scriptTypes.length; ++i) {
27
+ var tp = scriptTypes[i];
28
+ if (typeof tp.matches == "string" ? scriptType == tp.matches : tp.matches.test(scriptType)) {
29
+ if (tp.mode) {
30
+ state.token = script;
31
+ state.localMode = tp.mode;
32
+ state.localState = tp.mode.startState && tp.mode.startState(htmlMode.indent(state.htmlState, ""));
33
+ }
34
+ break;
35
+ }
36
+ }
37
+ } else if (tagName == "style" && /\btag\b/.test(style) && stream.current() == ">") {
38
+ state.token = css;
39
+ state.localMode = cssMode;
40
+ state.localState = cssMode.startState(htmlMode.indent(state.htmlState, ""));
41
+ }
42
+ return style;
43
+ }
44
+ function maybeBackup(stream, pat, style) {
45
+ var cur = stream.current();
46
+ var close = cur.search(pat), m;
47
+ if (close > -1) stream.backUp(cur.length - close);
48
+ else if (m = cur.match(/<\/?$/)) {
49
+ stream.backUp(cur.length);
50
+ if (!stream.match(pat, false)) stream.match(cur);
51
+ }
52
+ return style;
53
+ }
54
+ function script(stream, state) {
55
+ if (stream.match(/^<\/\s*script\s*>/i, false)) {
56
+ state.token = html;
57
+ state.localState = state.localMode = null;
58
+ return html(stream, state);
59
+ }
60
+ return maybeBackup(stream, /<\/\s*script\s*>/,
61
+ state.localMode.token(stream, state.localState));
62
+ }
63
+ function css(stream, state) {
64
+ if (stream.match(/^<\/\s*style\s*>/i, false)) {
65
+ state.token = html;
66
+ state.localState = state.localMode = null;
67
+ return html(stream, state);
68
+ }
69
+ return maybeBackup(stream, /<\/\s*style\s*>/,
70
+ cssMode.token(stream, state.localState));
71
+ }
72
+
73
+ return {
74
+ startState: function() {
75
+ var state = htmlMode.startState();
76
+ return {token: html, localMode: null, localState: null, htmlState: state};
77
+ },
78
+
79
+ copyState: function(state) {
80
+ if (state.localState)
81
+ var local = CodeMirror.copyState(state.localMode, state.localState);
82
+ return {token: state.token, localMode: state.localMode, localState: local,
83
+ htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
84
+ },
85
+
86
+ token: function(stream, state) {
87
+ return state.token(stream, state);
88
+ },
89
+
90
+ indent: function(state, textAfter) {
91
+ if (!state.localMode || /^\s*<\//.test(textAfter))
92
+ return htmlMode.indent(state.htmlState, textAfter);
93
+ else if (state.localMode.indent)
94
+ return state.localMode.indent(state.localState, textAfter);
95
+ else
96
+ return CodeMirror.Pass;
97
+ },
98
+
99
+ innerMode: function(state) {
100
+ return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
101
+ }
102
+ };
103
+ }, "xml", "javascript", "css");
104
+
105
+ CodeMirror.defineMIME("text/html", "htmlmixed");
@@ -0,0 +1,638 @@
1
+ // TODO actually recognize syntax of TypeScript constructs
2
+
3
+ CodeMirror.defineMode("javascript", function(config, parserConfig) {
4
+ var indentUnit = config.indentUnit;
5
+ var statementIndent = parserConfig.statementIndent;
6
+ var jsonldMode = parserConfig.jsonld;
7
+ var jsonMode = parserConfig.json || jsonldMode;
8
+ var isTS = parserConfig.typescript;
9
+
10
+ // Tokenizer
11
+
12
+ var keywords = function(){
13
+ function kw(type) {return {type: type, style: "keyword"};}
14
+ var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
15
+ var operator = kw("operator"), atom = {type: "atom", style: "atom"};
16
+
17
+ var jsKeywords = {
18
+ "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
19
+ "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "debugger": C,
20
+ "var": kw("var"), "const": kw("var"), "let": kw("var"),
21
+ "function": kw("function"), "catch": kw("catch"),
22
+ "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
23
+ "in": operator, "typeof": operator, "instanceof": operator,
24
+ "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
25
+ "this": kw("this"), "module": kw("module"), "class": kw("class"), "super": kw("atom"),
26
+ "yield": C, "export": kw("export"), "import": kw("import"), "extends": C
27
+ };
28
+
29
+ // Extend the 'normal' keywords with the TypeScript language extensions
30
+ if (isTS) {
31
+ var type = {type: "variable", style: "variable-3"};
32
+ var tsKeywords = {
33
+ // object-like things
34
+ "interface": kw("interface"),
35
+ "extends": kw("extends"),
36
+ "constructor": kw("constructor"),
37
+
38
+ // scope modifiers
39
+ "public": kw("public"),
40
+ "private": kw("private"),
41
+ "protected": kw("protected"),
42
+ "static": kw("static"),
43
+
44
+ // types
45
+ "string": type, "number": type, "bool": type, "any": type
46
+ };
47
+
48
+ for (var attr in tsKeywords) {
49
+ jsKeywords[attr] = tsKeywords[attr];
50
+ }
51
+ }
52
+
53
+ return jsKeywords;
54
+ }();
55
+
56
+ var isOperatorChar = /[+\-*&%=<>!?|~^]/;
57
+ var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
58
+
59
+ function readRegexp(stream) {
60
+ var escaped = false, next, inSet = false;
61
+ while ((next = stream.next()) != null) {
62
+ if (!escaped) {
63
+ if (next == "/" && !inSet) return;
64
+ if (next == "[") inSet = true;
65
+ else if (inSet && next == "]") inSet = false;
66
+ }
67
+ escaped = !escaped && next == "\\";
68
+ }
69
+ }
70
+
71
+ // Used as scratch variables to communicate multiple values without
72
+ // consing up tons of objects.
73
+ var type, content;
74
+ function ret(tp, style, cont) {
75
+ type = tp; content = cont;
76
+ return style;
77
+ }
78
+ function tokenBase(stream, state) {
79
+ var ch = stream.next();
80
+ if (ch == '"' || ch == "'") {
81
+ state.tokenize = tokenString(ch);
82
+ return state.tokenize(stream, state);
83
+ } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
84
+ return ret("number", "number");
85
+ } else if (ch == "." && stream.match("..")) {
86
+ return ret("spread", "meta");
87
+ } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
88
+ return ret(ch);
89
+ } else if (ch == "=" && stream.eat(">")) {
90
+ return ret("=>", "operator");
91
+ } else if (ch == "0" && stream.eat(/x/i)) {
92
+ stream.eatWhile(/[\da-f]/i);
93
+ return ret("number", "number");
94
+ } else if (/\d/.test(ch)) {
95
+ stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
96
+ return ret("number", "number");
97
+ } else if (ch == "/") {
98
+ if (stream.eat("*")) {
99
+ state.tokenize = tokenComment;
100
+ return tokenComment(stream, state);
101
+ } else if (stream.eat("/")) {
102
+ stream.skipToEnd();
103
+ return ret("comment", "comment");
104
+ } else if (state.lastType == "operator" || state.lastType == "keyword c" ||
105
+ state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) {
106
+ readRegexp(stream);
107
+ stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
108
+ return ret("regexp", "string-2");
109
+ } else {
110
+ stream.eatWhile(isOperatorChar);
111
+ return ret("operator", "operator", stream.current());
112
+ }
113
+ } else if (ch == "`") {
114
+ state.tokenize = tokenQuasi;
115
+ return tokenQuasi(stream, state);
116
+ } else if (ch == "#") {
117
+ stream.skipToEnd();
118
+ return ret("error", "error");
119
+ } else if (isOperatorChar.test(ch)) {
120
+ stream.eatWhile(isOperatorChar);
121
+ return ret("operator", "operator", stream.current());
122
+ } else {
123
+ stream.eatWhile(/[\w\$_]/);
124
+ var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
125
+ return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
126
+ ret("variable", "variable", word);
127
+ }
128
+ }
129
+
130
+ function tokenString(quote) {
131
+ return function(stream, state) {
132
+ var escaped = false, next;
133
+ if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
134
+ state.tokenize = tokenBase;
135
+ return ret("jsonld-keyword", "meta");
136
+ }
137
+ while ((next = stream.next()) != null) {
138
+ if (next == quote && !escaped) break;
139
+ escaped = !escaped && next == "\\";
140
+ }
141
+ if (!escaped) state.tokenize = tokenBase;
142
+ return ret("string", "string");
143
+ };
144
+ }
145
+
146
+ function tokenComment(stream, state) {
147
+ var maybeEnd = false, ch;
148
+ while (ch = stream.next()) {
149
+ if (ch == "/" && maybeEnd) {
150
+ state.tokenize = tokenBase;
151
+ break;
152
+ }
153
+ maybeEnd = (ch == "*");
154
+ }
155
+ return ret("comment", "comment");
156
+ }
157
+
158
+ function tokenQuasi(stream, state) {
159
+ var escaped = false, next;
160
+ while ((next = stream.next()) != null) {
161
+ if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
162
+ state.tokenize = tokenBase;
163
+ break;
164
+ }
165
+ escaped = !escaped && next == "\\";
166
+ }
167
+ return ret("quasi", "string-2", stream.current());
168
+ }
169
+
170
+ var brackets = "([{}])";
171
+ // This is a crude lookahead trick to try and notice that we're
172
+ // parsing the argument patterns for a fat-arrow function before we
173
+ // actually hit the arrow token. It only works if the arrow is on
174
+ // the same line as the arguments and there's no strange noise
175
+ // (comments) in between. Fallback is to only notice when we hit the
176
+ // arrow, and not declare the arguments as locals for the arrow
177
+ // body.
178
+ function findFatArrow(stream, state) {
179
+ if (state.fatArrowAt) state.fatArrowAt = null;
180
+ var arrow = stream.string.indexOf("=>", stream.start);
181
+ if (arrow < 0) return;
182
+
183
+ var depth = 0, sawSomething = false;
184
+ for (var pos = arrow - 1; pos >= 0; --pos) {
185
+ var ch = stream.string.charAt(pos);
186
+ var bracket = brackets.indexOf(ch);
187
+ if (bracket >= 0 && bracket < 3) {
188
+ if (!depth) { ++pos; break; }
189
+ if (--depth == 0) break;
190
+ } else if (bracket >= 3 && bracket < 6) {
191
+ ++depth;
192
+ } else if (/[$\w]/.test(ch)) {
193
+ sawSomething = true;
194
+ } else if (sawSomething && !depth) {
195
+ ++pos;
196
+ break;
197
+ }
198
+ }
199
+ if (sawSomething && !depth) state.fatArrowAt = pos;
200
+ }
201
+
202
+ // Parser
203
+
204
+ var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};
205
+
206
+ function JSLexical(indented, column, type, align, prev, info) {
207
+ this.indented = indented;
208
+ this.column = column;
209
+ this.type = type;
210
+ this.prev = prev;
211
+ this.info = info;
212
+ if (align != null) this.align = align;
213
+ }
214
+
215
+ function inScope(state, varname) {
216
+ for (var v = state.localVars; v; v = v.next)
217
+ if (v.name == varname) return true;
218
+ for (var cx = state.context; cx; cx = cx.prev) {
219
+ for (var v = cx.vars; v; v = v.next)
220
+ if (v.name == varname) return true;
221
+ }
222
+ }
223
+
224
+ function parseJS(state, style, type, content, stream) {
225
+ var cc = state.cc;
226
+ // Communicate our context to the combinators.
227
+ // (Less wasteful than consing up a hundred closures on every call.)
228
+ cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
229
+
230
+ if (!state.lexical.hasOwnProperty("align"))
231
+ state.lexical.align = true;
232
+
233
+ while(true) {
234
+ var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
235
+ if (combinator(type, content)) {
236
+ while(cc.length && cc[cc.length - 1].lex)
237
+ cc.pop()();
238
+ if (cx.marked) return cx.marked;
239
+ if (type == "variable" && inScope(state, content)) return "variable-2";
240
+ return style;
241
+ }
242
+ }
243
+ }
244
+
245
+ // Combinator utils
246
+
247
+ var cx = {state: null, column: null, marked: null, cc: null};
248
+ function pass() {
249
+ for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
250
+ }
251
+ function cont() {
252
+ pass.apply(null, arguments);
253
+ return true;
254
+ }
255
+ function register(varname) {
256
+ function inList(list) {
257
+ for (var v = list; v; v = v.next)
258
+ if (v.name == varname) return true;
259
+ return false;
260
+ }
261
+ var state = cx.state;
262
+ if (state.context) {
263
+ cx.marked = "def";
264
+ if (inList(state.localVars)) return;
265
+ state.localVars = {name: varname, next: state.localVars};
266
+ } else {
267
+ if (inList(state.globalVars)) return;
268
+ if (parserConfig.globalVars)
269
+ state.globalVars = {name: varname, next: state.globalVars};
270
+ }
271
+ }
272
+
273
+ // Combinators
274
+
275
+ var defaultVars = {name: "this", next: {name: "arguments"}};
276
+ function pushcontext() {
277
+ cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
278
+ cx.state.localVars = defaultVars;
279
+ }
280
+ function popcontext() {
281
+ cx.state.localVars = cx.state.context.vars;
282
+ cx.state.context = cx.state.context.prev;
283
+ }
284
+ function pushlex(type, info) {
285
+ var result = function() {
286
+ var state = cx.state, indent = state.indented;
287
+ if (state.lexical.type == "stat") indent = state.lexical.indented;
288
+ state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
289
+ };
290
+ result.lex = true;
291
+ return result;
292
+ }
293
+ function poplex() {
294
+ var state = cx.state;
295
+ if (state.lexical.prev) {
296
+ if (state.lexical.type == ")")
297
+ state.indented = state.lexical.indented;
298
+ state.lexical = state.lexical.prev;
299
+ }
300
+ }
301
+ poplex.lex = true;
302
+
303
+ function expect(wanted) {
304
+ return function(type) {
305
+ if (type == wanted) return cont();
306
+ else if (wanted == ";") return pass();
307
+ else return cont(arguments.callee);
308
+ };
309
+ }
310
+
311
+ function statement(type, value) {
312
+ if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
313
+ if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
314
+ if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
315
+ if (type == "{") return cont(pushlex("}"), block, poplex);
316
+ if (type == ";") return cont();
317
+ if (type == "if") return cont(pushlex("form"), expression, statement, poplex, maybeelse);
318
+ if (type == "function") return cont(functiondef);
319
+ if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
320
+ if (type == "variable") return cont(pushlex("stat"), maybelabel);
321
+ if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
322
+ block, poplex, poplex);
323
+ if (type == "case") return cont(expression, expect(":"));
324
+ if (type == "default") return cont(expect(":"));
325
+ if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
326
+ statement, poplex, popcontext);
327
+ if (type == "module") return cont(pushlex("form"), pushcontext, afterModule, popcontext, poplex);
328
+ if (type == "class") return cont(pushlex("form"), className, objlit, poplex);
329
+ if (type == "export") return cont(pushlex("form"), afterExport, poplex);
330
+ if (type == "import") return cont(pushlex("form"), afterImport, poplex);
331
+ return pass(pushlex("stat"), expression, expect(";"), poplex);
332
+ }
333
+ function expression(type) {
334
+ return expressionInner(type, false);
335
+ }
336
+ function expressionNoComma(type) {
337
+ return expressionInner(type, true);
338
+ }
339
+ function expressionInner(type, noComma) {
340
+ if (cx.state.fatArrowAt == cx.stream.start) {
341
+ var body = noComma ? arrowBodyNoComma : arrowBody;
342
+ if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
343
+ else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
344
+ }
345
+
346
+ var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
347
+ if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
348
+ if (type == "function") return cont(functiondef);
349
+ if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
350
+ if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop);
351
+ if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
352
+ if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
353
+ if (type == "{") return contCommasep(objprop, "}", null, maybeop);
354
+ return cont();
355
+ }
356
+ function maybeexpression(type) {
357
+ if (type.match(/[;\}\)\],]/)) return pass();
358
+ return pass(expression);
359
+ }
360
+ function maybeexpressionNoComma(type) {
361
+ if (type.match(/[;\}\)\],]/)) return pass();
362
+ return pass(expressionNoComma);
363
+ }
364
+
365
+ function maybeoperatorComma(type, value) {
366
+ if (type == ",") return cont(expression);
367
+ return maybeoperatorNoComma(type, value, false);
368
+ }
369
+ function maybeoperatorNoComma(type, value, noComma) {
370
+ var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
371
+ var expr = noComma == false ? expression : expressionNoComma;
372
+ if (value == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
373
+ if (type == "operator") {
374
+ if (/\+\+|--/.test(value)) return cont(me);
375
+ if (value == "?") return cont(expression, expect(":"), expr);
376
+ return cont(expr);
377
+ }
378
+ if (type == "quasi") { cx.cc.push(me); return quasi(value); }
379
+ if (type == ";") return;
380
+ if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
381
+ if (type == ".") return cont(property, me);
382
+ if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
383
+ }
384
+ function quasi(value) {
385
+ if (value.slice(value.length - 2) != "${") return cont();
386
+ return cont(expression, continueQuasi);
387
+ }
388
+ function continueQuasi(type) {
389
+ if (type == "}") {
390
+ cx.marked = "string-2";
391
+ cx.state.tokenize = tokenQuasi;
392
+ return cont();
393
+ }
394
+ }
395
+ function arrowBody(type) {
396
+ findFatArrow(cx.stream, cx.state);
397
+ if (type == "{") return pass(statement);
398
+ return pass(expression);
399
+ }
400
+ function arrowBodyNoComma(type) {
401
+ findFatArrow(cx.stream, cx.state);
402
+ if (type == "{") return pass(statement);
403
+ return pass(expressionNoComma);
404
+ }
405
+ function maybelabel(type) {
406
+ if (type == ":") return cont(poplex, statement);
407
+ return pass(maybeoperatorComma, expect(";"), poplex);
408
+ }
409
+ function property(type) {
410
+ if (type == "variable") {cx.marked = "property"; return cont();}
411
+ }
412
+ function objprop(type, value) {
413
+ if (type == "variable") {
414
+ cx.marked = "property";
415
+ if (value == "get" || value == "set") return cont(getterSetter);
416
+ } else if (type == "number" || type == "string") {
417
+ cx.marked = jsonldMode ? "property" : (type + " property");
418
+ } else if (type == "[") {
419
+ return cont(expression, expect("]"), afterprop);
420
+ }
421
+ if (atomicTypes.hasOwnProperty(type)) return cont(afterprop);
422
+ }
423
+ function getterSetter(type) {
424
+ if (type != "variable") return pass(afterprop);
425
+ cx.marked = "property";
426
+ return cont(functiondef);
427
+ }
428
+ function afterprop(type) {
429
+ if (type == ":") return cont(expressionNoComma);
430
+ if (type == "(") return pass(functiondef);
431
+ }
432
+ function commasep(what, end) {
433
+ function proceed(type) {
434
+ if (type == ",") {
435
+ var lex = cx.state.lexical;
436
+ if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
437
+ return cont(what, proceed);
438
+ }
439
+ if (type == end) return cont();
440
+ return cont(expect(end));
441
+ }
442
+ return function(type) {
443
+ if (type == end) return cont();
444
+ return pass(what, proceed);
445
+ };
446
+ }
447
+ function contCommasep(what, end, info) {
448
+ for (var i = 3; i < arguments.length; i++)
449
+ cx.cc.push(arguments[i]);
450
+ return cont(pushlex(end, info), commasep(what, end), poplex);
451
+ }
452
+ function block(type) {
453
+ if (type == "}") return cont();
454
+ return pass(statement, block);
455
+ }
456
+ function maybetype(type) {
457
+ if (isTS && type == ":") return cont(typedef);
458
+ }
459
+ function typedef(type) {
460
+ if (type == "variable"){cx.marked = "variable-3"; return cont();}
461
+ }
462
+ function vardef() {
463
+ return pass(pattern, maybetype, maybeAssign, vardefCont);
464
+ }
465
+ function pattern(type, value) {
466
+ if (type == "variable") { register(value); return cont(); }
467
+ if (type == "[") return contCommasep(pattern, "]");
468
+ if (type == "{") return contCommasep(proppattern, "}");
469
+ }
470
+ function proppattern(type, value) {
471
+ if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
472
+ register(value);
473
+ return cont(maybeAssign);
474
+ }
475
+ if (type == "variable") cx.marked = "property";
476
+ return cont(expect(":"), pattern, maybeAssign);
477
+ }
478
+ function maybeAssign(_type, value) {
479
+ if (value == "=") return cont(expressionNoComma);
480
+ }
481
+ function vardefCont(type) {
482
+ if (type == ",") return cont(vardef);
483
+ }
484
+ function maybeelse(type, value) {
485
+ if (type == "keyword b" && value == "else") return cont(pushlex("form"), statement, poplex);
486
+ }
487
+ function forspec(type) {
488
+ if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
489
+ }
490
+ function forspec1(type) {
491
+ if (type == "var") return cont(vardef, expect(";"), forspec2);
492
+ if (type == ";") return cont(forspec2);
493
+ if (type == "variable") return cont(formaybeinof);
494
+ return pass(expression, expect(";"), forspec2);
495
+ }
496
+ function formaybeinof(_type, value) {
497
+ if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
498
+ return cont(maybeoperatorComma, forspec2);
499
+ }
500
+ function forspec2(type, value) {
501
+ if (type == ";") return cont(forspec3);
502
+ if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
503
+ return pass(expression, expect(";"), forspec3);
504
+ }
505
+ function forspec3(type) {
506
+ if (type != ")") cont(expression);
507
+ }
508
+ function functiondef(type, value) {
509
+ if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
510
+ if (type == "variable") {register(value); return cont(functiondef);}
511
+ if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, statement, popcontext);
512
+ }
513
+ function funarg(type) {
514
+ if (type == "spread") return cont(funarg);
515
+ return pass(pattern, maybetype);
516
+ }
517
+ function className(type, value) {
518
+ if (type == "variable") {register(value); return cont(classNameAfter);}
519
+ }
520
+ function classNameAfter(_type, value) {
521
+ if (value == "extends") return cont(expression);
522
+ }
523
+ function objlit(type) {
524
+ if (type == "{") return contCommasep(objprop, "}");
525
+ }
526
+ function afterModule(type, value) {
527
+ if (type == "string") return cont(statement);
528
+ if (type == "variable") { register(value); return cont(maybeFrom); }
529
+ }
530
+ function afterExport(_type, value) {
531
+ if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
532
+ if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
533
+ return pass(statement);
534
+ }
535
+ function afterImport(type) {
536
+ if (type == "string") return cont();
537
+ return pass(importSpec, maybeFrom);
538
+ }
539
+ function importSpec(type, value) {
540
+ if (type == "{") return contCommasep(importSpec, "}");
541
+ if (type == "variable") register(value);
542
+ return cont();
543
+ }
544
+ function maybeFrom(_type, value) {
545
+ if (value == "from") { cx.marked = "keyword"; return cont(expression); }
546
+ }
547
+ function arrayLiteral(type) {
548
+ if (type == "]") return cont();
549
+ return pass(expressionNoComma, maybeArrayComprehension);
550
+ }
551
+ function maybeArrayComprehension(type) {
552
+ if (type == "for") return pass(comprehension, expect("]"));
553
+ if (type == ",") return cont(commasep(expressionNoComma, "]"));
554
+ return pass(commasep(expressionNoComma, "]"));
555
+ }
556
+ function comprehension(type) {
557
+ if (type == "for") return cont(forspec, comprehension);
558
+ if (type == "if") return cont(expression, comprehension);
559
+ }
560
+
561
+ // Interface
562
+
563
+ return {
564
+ startState: function(basecolumn) {
565
+ var state = {
566
+ tokenize: tokenBase,
567
+ lastType: "sof",
568
+ cc: [],
569
+ lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
570
+ localVars: parserConfig.localVars,
571
+ context: parserConfig.localVars && {vars: parserConfig.localVars},
572
+ indented: 0
573
+ };
574
+ if (parserConfig.globalVars) state.globalVars = parserConfig.globalVars;
575
+ return state;
576
+ },
577
+
578
+ token: function(stream, state) {
579
+ if (stream.sol()) {
580
+ if (!state.lexical.hasOwnProperty("align"))
581
+ state.lexical.align = false;
582
+ state.indented = stream.indentation();
583
+ findFatArrow(stream, state);
584
+ }
585
+ if (state.tokenize != tokenComment && stream.eatSpace()) return null;
586
+ var style = state.tokenize(stream, state);
587
+ if (type == "comment") return style;
588
+ state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
589
+ return parseJS(state, style, type, content, stream);
590
+ },
591
+
592
+ indent: function(state, textAfter) {
593
+ if (state.tokenize == tokenComment) return CodeMirror.Pass;
594
+ if (state.tokenize != tokenBase) return 0;
595
+ var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
596
+ // Kludge to prevent 'maybelse' from blocking lexical scope pops
597
+ for (var i = state.cc.length - 1; i >= 0; --i) {
598
+ var c = state.cc[i];
599
+ if (c == poplex) lexical = lexical.prev;
600
+ else if (c != maybeelse) break;
601
+ }
602
+ if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
603
+ if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
604
+ lexical = lexical.prev;
605
+ var type = lexical.type, closing = firstChar == type;
606
+
607
+ if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
608
+ else if (type == "form" && firstChar == "{") return lexical.indented;
609
+ else if (type == "form") return lexical.indented + indentUnit;
610
+ else if (type == "stat")
611
+ return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? statementIndent || indentUnit : 0);
612
+ else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
613
+ return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
614
+ else if (lexical.align) return lexical.column + (closing ? 0 : 1);
615
+ else return lexical.indented + (closing ? 0 : indentUnit);
616
+ },
617
+
618
+ electricChars: ":{}",
619
+ blockCommentStart: jsonMode ? null : "/*",
620
+ blockCommentEnd: jsonMode ? null : "*/",
621
+ lineComment: jsonMode ? null : "//",
622
+ fold: "brace",
623
+
624
+ helperType: jsonMode ? "json" : "javascript",
625
+ jsonldMode: jsonldMode,
626
+ jsonMode: jsonMode
627
+ };
628
+ });
629
+
630
+ CodeMirror.defineMIME("text/javascript", "javascript");
631
+ CodeMirror.defineMIME("text/ecmascript", "javascript");
632
+ CodeMirror.defineMIME("application/javascript", "javascript");
633
+ CodeMirror.defineMIME("application/ecmascript", "javascript");
634
+ CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
635
+ CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
636
+ CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
637
+ CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
638
+ CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });