Resources/Public/JavaScript/editormd/lib/codemirror/mode/rst/rst.js   F
last analyzed

Complexity

Total Complexity 85
Complexity/F 4.05

Size

Lines of Code 554
Function Count 21

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 85
eloc 406
c 0
b 0
f 0
dl 0
loc 554
rs 2
mnd 64
bc 64
fnc 21
bpm 3.0476
cpm 4.0476
noi 4

11 Functions

Rating   Name   Duplication   Size   Complexity  
A rst.js ➔ stage 0 3 1
A rst.js ➔ to_comment 0 3 1
A rst.js ➔ as_block 0 9 2
A rst.js ➔ to_mode 0 15 4
A rst.js ➔ context 0 3 1
A rst.js ➔ change 0 4 1
F rst.js ➔ format 0 6 25
F rst.js ➔ to_explicit 0 103 14
A rst.js ➔ phase 0 3 1
A rst.js ➔ to_verbatim 0 3 1
F rst.js ➔ to_normal 0 196 26

How to fix   Complexity   

Complexity

Complex classes like Resources/Public/JavaScript/editormd/lib/codemirror/mode/rst/rst.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
// CodeMirror, copyright (c) by Marijn Haverbeke and others
2
// Distributed under an MIT license: http://codemirror.net/LICENSE
3
4
(function(mod) {
5
  if (typeof exports == "object" && typeof module == "object") // CommonJS
6
    mod(require("../../lib/codemirror"), require("../python/python"), require("../stex/stex"), require("../../addon/mode/overlay"));
7
  else if (typeof define == "function" && define.amd) // AMD
0 ignored issues
show
Bug introduced by
The variable define seems to be never declared. If this is a global, consider adding a /** global: define */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
8
    define(["../../lib/codemirror", "../python/python", "../stex/stex", "../../addon/mode/overlay"], mod);
9
  else // Plain browser env
10
    mod(CodeMirror);
0 ignored issues
show
Bug introduced by
The variable CodeMirror seems to be never declared. If this is a global, consider adding a /** global: CodeMirror */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
11
})(function(CodeMirror) {
12
"use strict";
13
14
CodeMirror.defineMode('rst', function (config, options) {
15
16
  var rx_strong = /^\*\*[^\*\s](?:[^\*]*[^\*\s])?\*\*/;
17
  var rx_emphasis = /^\*[^\*\s](?:[^\*]*[^\*\s])?\*/;
18
  var rx_literal = /^``[^`\s](?:[^`]*[^`\s])``/;
19
20
  var rx_number = /^(?:[\d]+(?:[\.,]\d+)*)/;
21
  var rx_positive = /^(?:\s\+[\d]+(?:[\.,]\d+)*)/;
22
  var rx_negative = /^(?:\s\-[\d]+(?:[\.,]\d+)*)/;
23
24
  var rx_uri_protocol = "[Hh][Tt][Tt][Pp][Ss]?://";
25
  var rx_uri_domain = "(?:[\\d\\w.-]+)\\.(?:\\w{2,6})";
26
  var rx_uri_path = "(?:/[\\d\\w\\#\\%\\&\\-\\.\\,\\/\\:\\=\\?\\~]+)*";
27
  var rx_uri = new RegExp("^" + rx_uri_protocol + rx_uri_domain + rx_uri_path);
28
29
  var overlay = {
30
    token: function (stream) {
31
32
      if (stream.match(rx_strong) && stream.match (/\W+|$/, false))
33
        return 'strong';
34
      if (stream.match(rx_emphasis) && stream.match (/\W+|$/, false))
35
        return 'em';
36
      if (stream.match(rx_literal) && stream.match (/\W+|$/, false))
37
        return 'string-2';
38
      if (stream.match(rx_number))
39
        return 'number';
40
      if (stream.match(rx_positive))
41
        return 'positive';
42
      if (stream.match(rx_negative))
43
        return 'negative';
44
      if (stream.match(rx_uri))
45
        return 'link';
46
47
      while (stream.next() != null) {
0 ignored issues
show
Best Practice introduced by
Comparing stream.next() to null using the != operator is not safe. Consider using !== instead.
Loading history...
48
        if (stream.match(rx_strong, false)) break;
49
        if (stream.match(rx_emphasis, false)) break;
50
        if (stream.match(rx_literal, false)) break;
51
        if (stream.match(rx_number, false)) break;
52
        if (stream.match(rx_positive, false)) break;
53
        if (stream.match(rx_negative, false)) break;
54
        if (stream.match(rx_uri, false)) break;
55
      }
56
57
      return null;
58
    }
59
  };
60
61
  var mode = CodeMirror.getMode(
62
    config, options.backdrop || 'rst-base'
63
  );
64
65
  return CodeMirror.overlayMode(mode, overlay, true); // combine
66
}, 'python', 'stex');
67
68
///////////////////////////////////////////////////////////////////////////////
69
///////////////////////////////////////////////////////////////////////////////
70
71
CodeMirror.defineMode('rst-base', function (config) {
72
73
  ///////////////////////////////////////////////////////////////////////////
74
  ///////////////////////////////////////////////////////////////////////////
75
76
  function format(string) {
77
    var args = Array.prototype.slice.call(arguments, 1);
78
    return string.replace(/{(\d+)}/g, function (match, n) {
79
      return typeof args[n] != 'undefined' ? args[n] : match;
80
    });
81
  }
82
83
  ///////////////////////////////////////////////////////////////////////////
84
  ///////////////////////////////////////////////////////////////////////////
85
86
  var mode_python = CodeMirror.getMode(config, 'python');
87
  var mode_stex = CodeMirror.getMode(config, 'stex');
88
89
  ///////////////////////////////////////////////////////////////////////////
90
  ///////////////////////////////////////////////////////////////////////////
91
92
  var SEPA = "\\s+";
93
  var TAIL = "(?:\\s*|\\W|$)",
94
  rx_TAIL = new RegExp(format('^{0}', TAIL));
95
96
  var NAME =
97
    "(?:[^\\W\\d_](?:[\\w!\"#$%&'()\\*\\+,\\-\\.\/:;<=>\\?]*[^\\W_])?)",
98
  rx_NAME = new RegExp(format('^{0}', NAME));
99
  var NAME_WWS =
100
    "(?:[^\\W\\d_](?:[\\w\\s!\"#$%&'()\\*\\+,\\-\\.\/:;<=>\\?]*[^\\W_])?)";
101
  var REF_NAME = format('(?:{0}|`{1}`)', NAME, NAME_WWS);
102
103
  var TEXT1 = "(?:[^\\s\\|](?:[^\\|]*[^\\s\\|])?)";
104
  var TEXT2 = "(?:[^\\`]+)",
105
  rx_TEXT2 = new RegExp(format('^{0}', TEXT2));
106
107
  var rx_section = new RegExp(
108
    "^([!'#$%&\"()*+,-./:;<=>?@\\[\\\\\\]^_`{|}~])\\1{3,}\\s*$");
109
  var rx_explicit = new RegExp(
110
    format('^\\.\\.{0}', SEPA));
111
  var rx_link = new RegExp(
112
    format('^_{0}:{1}|^__:{1}', REF_NAME, TAIL));
113
  var rx_directive = new RegExp(
114
    format('^{0}::{1}', REF_NAME, TAIL));
115
  var rx_substitution = new RegExp(
116
    format('^\\|{0}\\|{1}{2}::{3}', TEXT1, SEPA, REF_NAME, TAIL));
117
  var rx_footnote = new RegExp(
118
    format('^\\[(?:\\d+|#{0}?|\\*)]{1}', REF_NAME, TAIL));
119
  var rx_citation = new RegExp(
120
    format('^\\[{0}\\]{1}', REF_NAME, TAIL));
121
122
  var rx_substitution_ref = new RegExp(
123
    format('^\\|{0}\\|', TEXT1));
124
  var rx_footnote_ref = new RegExp(
125
    format('^\\[(?:\\d+|#{0}?|\\*)]_', REF_NAME));
126
  var rx_citation_ref = new RegExp(
127
    format('^\\[{0}\\]_', REF_NAME));
128
  var rx_link_ref1 = new RegExp(
129
    format('^{0}__?', REF_NAME));
130
  var rx_link_ref2 = new RegExp(
131
    format('^`{0}`_', TEXT2));
132
133
  var rx_role_pre = new RegExp(
134
    format('^:{0}:`{1}`{2}', NAME, TEXT2, TAIL));
135
  var rx_role_suf = new RegExp(
136
    format('^`{1}`:{0}:{2}', NAME, TEXT2, TAIL));
137
  var rx_role = new RegExp(
138
    format('^:{0}:{1}', NAME, TAIL));
139
140
  var rx_directive_name = new RegExp(format('^{0}', REF_NAME));
141
  var rx_directive_tail = new RegExp(format('^::{0}', TAIL));
142
  var rx_substitution_text = new RegExp(format('^\\|{0}\\|', TEXT1));
143
  var rx_substitution_sepa = new RegExp(format('^{0}', SEPA));
144
  var rx_substitution_name = new RegExp(format('^{0}', REF_NAME));
145
  var rx_substitution_tail = new RegExp(format('^::{0}', TAIL));
146
  var rx_link_head = new RegExp("^_");
147
  var rx_link_name = new RegExp(format('^{0}|_', REF_NAME));
148
  var rx_link_tail = new RegExp(format('^:{0}', TAIL));
149
150
  var rx_verbatim = new RegExp('^::\\s*$');
151
  var rx_examples = new RegExp('^\\s+(?:>>>|In \\[\\d+\\]:)\\s');
152
153
  ///////////////////////////////////////////////////////////////////////////
154
  ///////////////////////////////////////////////////////////////////////////
155
156
  function to_normal(stream, state) {
157
    var token = null;
158
159
    if (stream.sol() && stream.match(rx_examples, false)) {
160
      change(state, to_mode, {
161
        mode: mode_python, local: CodeMirror.startState(mode_python)
162
      });
163
    } else if (stream.sol() && stream.match(rx_explicit)) {
164
      change(state, to_explicit);
165
      token = 'meta';
166
    } else if (stream.sol() && stream.match(rx_section)) {
167
      change(state, to_normal);
168
      token = 'header';
169
    } else if (phase(state) == rx_role_pre ||
170
               stream.match(rx_role_pre, false)) {
171
172
      switch (stage(state)) {
173
      case 0:
174
        change(state, to_normal, context(rx_role_pre, 1));
175
        stream.match(/^:/);
176
        token = 'meta';
177
        break;
178
      case 1:
179
        change(state, to_normal, context(rx_role_pre, 2));
180
        stream.match(rx_NAME);
181
        token = 'keyword';
182
183
        if (stream.current().match(/^(?:math|latex)/)) {
184
          state.tmp_stex = true;
185
        }
186
        break;
187
      case 2:
188
        change(state, to_normal, context(rx_role_pre, 3));
189
        stream.match(/^:`/);
190
        token = 'meta';
191
        break;
192
      case 3:
193
        if (state.tmp_stex) {
194
          state.tmp_stex = undefined; state.tmp = {
195
            mode: mode_stex, local: CodeMirror.startState(mode_stex)
196
          };
197
        }
198
199
        if (state.tmp) {
200
          if (stream.peek() == '`') {
201
            change(state, to_normal, context(rx_role_pre, 4));
202
            state.tmp = undefined;
203
            break;
204
          }
205
206
          token = state.tmp.mode.token(stream, state.tmp.local);
207
          break;
208
        }
209
210
        change(state, to_normal, context(rx_role_pre, 4));
211
        stream.match(rx_TEXT2);
212
        token = 'string';
213
        break;
214
      case 4:
215
        change(state, to_normal, context(rx_role_pre, 5));
216
        stream.match(/^`/);
217
        token = 'meta';
218
        break;
219
      case 5:
220
        change(state, to_normal, context(rx_role_pre, 6));
221
        stream.match(rx_TAIL);
222
        break;
223
      default:
224
        change(state, to_normal);
225
      }
226
    } else if (phase(state) == rx_role_suf ||
227
               stream.match(rx_role_suf, false)) {
228
229
      switch (stage(state)) {
230
      case 0:
231
        change(state, to_normal, context(rx_role_suf, 1));
232
        stream.match(/^`/);
233
        token = 'meta';
234
        break;
235
      case 1:
236
        change(state, to_normal, context(rx_role_suf, 2));
237
        stream.match(rx_TEXT2);
238
        token = 'string';
239
        break;
240
      case 2:
241
        change(state, to_normal, context(rx_role_suf, 3));
242
        stream.match(/^`:/);
243
        token = 'meta';
244
        break;
245
      case 3:
246
        change(state, to_normal, context(rx_role_suf, 4));
247
        stream.match(rx_NAME);
248
        token = 'keyword';
249
        break;
250
      case 4:
251
        change(state, to_normal, context(rx_role_suf, 5));
252
        stream.match(/^:/);
253
        token = 'meta';
254
        break;
255
      case 5:
256
        change(state, to_normal, context(rx_role_suf, 6));
257
        stream.match(rx_TAIL);
258
        break;
259
      default:
260
        change(state, to_normal);
261
      }
262
    } else if (phase(state) == rx_role || stream.match(rx_role, false)) {
263
264
      switch (stage(state)) {
265
      case 0:
266
        change(state, to_normal, context(rx_role, 1));
267
        stream.match(/^:/);
268
        token = 'meta';
269
        break;
270
      case 1:
271
        change(state, to_normal, context(rx_role, 2));
272
        stream.match(rx_NAME);
273
        token = 'keyword';
274
        break;
275
      case 2:
276
        change(state, to_normal, context(rx_role, 3));
277
        stream.match(/^:/);
278
        token = 'meta';
279
        break;
280
      case 3:
281
        change(state, to_normal, context(rx_role, 4));
282
        stream.match(rx_TAIL);
283
        break;
284
      default:
285
        change(state, to_normal);
286
      }
287
    } else if (phase(state) == rx_substitution_ref ||
288
               stream.match(rx_substitution_ref, false)) {
289
290
      switch (stage(state)) {
291
      case 0:
292
        change(state, to_normal, context(rx_substitution_ref, 1));
293
        stream.match(rx_substitution_text);
294
        token = 'variable-2';
295
        break;
296
      case 1:
297
        change(state, to_normal, context(rx_substitution_ref, 2));
298
        if (stream.match(/^_?_?/)) token = 'link';
299
        break;
300
      default:
301
        change(state, to_normal);
302
      }
303
    } else if (stream.match(rx_footnote_ref)) {
304
      change(state, to_normal);
305
      token = 'quote';
306
    } else if (stream.match(rx_citation_ref)) {
307
      change(state, to_normal);
308
      token = 'quote';
309
    } else if (stream.match(rx_link_ref1)) {
310
      change(state, to_normal);
311
      if (!stream.peek() || stream.peek().match(/^\W$/)) {
312
        token = 'link';
313
      }
314
    } else if (phase(state) == rx_link_ref2 ||
315
               stream.match(rx_link_ref2, false)) {
316
317
      switch (stage(state)) {
318
      case 0:
319
        if (!stream.peek() || stream.peek().match(/^\W$/)) {
320
          change(state, to_normal, context(rx_link_ref2, 1));
321
        } else {
322
          stream.match(rx_link_ref2);
323
        }
324
        break;
325
      case 1:
326
        change(state, to_normal, context(rx_link_ref2, 2));
327
        stream.match(/^`/);
328
        token = 'link';
329
        break;
330
      case 2:
331
        change(state, to_normal, context(rx_link_ref2, 3));
332
        stream.match(rx_TEXT2);
333
        break;
334
      case 3:
335
        change(state, to_normal, context(rx_link_ref2, 4));
336
        stream.match(/^`_/);
337
        token = 'link';
338
        break;
339
      default:
340
        change(state, to_normal);
341
      }
342
    } else if (stream.match(rx_verbatim)) {
343
      change(state, to_verbatim);
344
    }
345
346
    else {
347
      if (stream.next()) change(state, to_normal);
348
    }
349
350
    return token;
351
  }
352
353
  ///////////////////////////////////////////////////////////////////////////
354
  ///////////////////////////////////////////////////////////////////////////
355
356
  function to_explicit(stream, state) {
357
    var token = null;
358
359
    if (phase(state) == rx_substitution ||
360
        stream.match(rx_substitution, false)) {
361
362
      switch (stage(state)) {
363
      case 0:
364
        change(state, to_explicit, context(rx_substitution, 1));
365
        stream.match(rx_substitution_text);
366
        token = 'variable-2';
367
        break;
368
      case 1:
369
        change(state, to_explicit, context(rx_substitution, 2));
370
        stream.match(rx_substitution_sepa);
371
        break;
372
      case 2:
373
        change(state, to_explicit, context(rx_substitution, 3));
374
        stream.match(rx_substitution_name);
375
        token = 'keyword';
376
        break;
377
      case 3:
378
        change(state, to_explicit, context(rx_substitution, 4));
379
        stream.match(rx_substitution_tail);
380
        token = 'meta';
381
        break;
382
      default:
383
        change(state, to_normal);
384
      }
385
    } else if (phase(state) == rx_directive ||
386
               stream.match(rx_directive, false)) {
387
388
      switch (stage(state)) {
389
      case 0:
390
        change(state, to_explicit, context(rx_directive, 1));
391
        stream.match(rx_directive_name);
392
        token = 'keyword';
393
394
        if (stream.current().match(/^(?:math|latex)/))
395
          state.tmp_stex = true;
396
        else if (stream.current().match(/^python/))
397
          state.tmp_py = true;
398
        break;
399
      case 1:
400
        change(state, to_explicit, context(rx_directive, 2));
401
        stream.match(rx_directive_tail);
402
        token = 'meta';
403
404
        if (stream.match(/^latex\s*$/) || state.tmp_stex) {
405
          state.tmp_stex = undefined; change(state, to_mode, {
406
            mode: mode_stex, local: CodeMirror.startState(mode_stex)
407
          });
408
        }
409
        break;
410
      case 2:
411
        change(state, to_explicit, context(rx_directive, 3));
412
        if (stream.match(/^python\s*$/) || state.tmp_py) {
413
          state.tmp_py = undefined; change(state, to_mode, {
414
            mode: mode_python, local: CodeMirror.startState(mode_python)
415
          });
416
        }
417
        break;
418
      default:
419
        change(state, to_normal);
420
      }
421
    } else if (phase(state) == rx_link || stream.match(rx_link, false)) {
422
423
      switch (stage(state)) {
424
      case 0:
425
        change(state, to_explicit, context(rx_link, 1));
426
        stream.match(rx_link_head);
427
        stream.match(rx_link_name);
428
        token = 'link';
429
        break;
430
      case 1:
431
        change(state, to_explicit, context(rx_link, 2));
432
        stream.match(rx_link_tail);
433
        token = 'meta';
434
        break;
435
      default:
436
        change(state, to_normal);
437
      }
438
    } else if (stream.match(rx_footnote)) {
439
      change(state, to_normal);
440
      token = 'quote';
441
    } else if (stream.match(rx_citation)) {
442
      change(state, to_normal);
443
      token = 'quote';
444
    }
445
446
    else {
447
      stream.eatSpace();
448
      if (stream.eol()) {
449
        change(state, to_normal);
450
      } else {
451
        stream.skipToEnd();
452
        change(state, to_comment);
453
        token = 'comment';
454
      }
455
    }
456
457
    return token;
458
  }
459
460
  ///////////////////////////////////////////////////////////////////////////
461
  ///////////////////////////////////////////////////////////////////////////
462
463
  function to_comment(stream, state) {
464
    return as_block(stream, state, 'comment');
465
  }
466
467
  function to_verbatim(stream, state) {
468
    return as_block(stream, state, 'meta');
469
  }
470
471
  function as_block(stream, state, token) {
472
    if (stream.eol() || stream.eatSpace()) {
473
      stream.skipToEnd();
474
      return token;
475
    } else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
476
      change(state, to_normal);
477
      return null;
478
    }
479
  }
480
481
  ///////////////////////////////////////////////////////////////////////////
482
  ///////////////////////////////////////////////////////////////////////////
483
484
  function to_mode(stream, state) {
485
486
    if (state.ctx.mode && state.ctx.local) {
487
488
      if (stream.sol()) {
489
        if (!stream.eatSpace()) change(state, to_normal);
490
        return null;
491
      }
492
493
      return state.ctx.mode.token(stream, state.ctx.local);
494
    }
495
496
    change(state, to_normal);
497
    return null;
498
  }
499
500
  ///////////////////////////////////////////////////////////////////////////
501
  ///////////////////////////////////////////////////////////////////////////
502
503
  function context(phase, stage, mode, local) {
504
    return {phase: phase, stage: stage, mode: mode, local: local};
505
  }
506
507
  function change(state, tok, ctx) {
508
    state.tok = tok;
509
    state.ctx = ctx || {};
510
  }
511
512
  function stage(state) {
513
    return state.ctx.stage || 0;
514
  }
515
516
  function phase(state) {
517
    return state.ctx.phase;
518
  }
519
520
  ///////////////////////////////////////////////////////////////////////////
521
  ///////////////////////////////////////////////////////////////////////////
522
523
  return {
524
    startState: function () {
525
      return {tok: to_normal, ctx: context(undefined, 0)};
526
    },
527
528
    copyState: function (state) {
529
      var ctx = state.ctx, tmp = state.tmp;
530
      if (ctx.local)
531
        ctx = {mode: ctx.mode, local: CodeMirror.copyState(ctx.mode, ctx.local)};
532
      if (tmp)
533
        tmp = {mode: tmp.mode, local: CodeMirror.copyState(tmp.mode, tmp.local)};
534
      return {tok: state.tok, ctx: ctx, tmp: tmp};
535
    },
536
537
    innerMode: function (state) {
538
      return state.tmp      ? {state: state.tmp.local, mode: state.tmp.mode}
539
      : state.ctx.mode ? {state: state.ctx.local, mode: state.ctx.mode}
540
      : null;
541
    },
542
543
    token: function (stream, state) {
544
      return state.tok(stream, state);
545
    }
546
  };
547
}, 'python', 'stex');
548
549
///////////////////////////////////////////////////////////////////////////////
550
///////////////////////////////////////////////////////////////////////////////
551
552
CodeMirror.defineMIME('text/x-rst', 'rst');
553
554
///////////////////////////////////////////////////////////////////////////////
555
///////////////////////////////////////////////////////////////////////////////
556
557
});
558