haml.js ➔ html   F
last analyzed

Complexity

Conditions 14

Size

Total Lines 54
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 35
c 0
b 0
f 0
dl 0
loc 54
rs 3.6
cc 14

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like haml.js ➔ html 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("../htmlmixed/htmlmixed"), require("../ruby/ruby"));
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", "../htmlmixed/htmlmixed", "../ruby/ruby"], 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
  // full haml mode. This handled embeded ruby and html fragments too
15
  CodeMirror.defineMode("haml", function(config) {
16
    var htmlMode = CodeMirror.getMode(config, {name: "htmlmixed"});
17
    var rubyMode = CodeMirror.getMode(config, "ruby");
18
19
    function rubyInQuote(endQuote) {
20
      return function(stream, state) {
21
        var ch = stream.peek();
22
        if (ch == endQuote && state.rubyState.tokenize.length == 1) {
0 ignored issues
show
Best Practice introduced by
Comparing state.rubyState.tokenize.length to 1 using the == operator is not safe. Consider using === instead.
Loading history...
23
          // step out of ruby context as it seems to complete processing all the braces
24
          stream.next();
25
          state.tokenize = html;
26
          return "closeAttributeTag";
27
        } 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...
28
          return ruby(stream, state);
29
        }
30
      };
31
    }
32
33
    function ruby(stream, state) {
34
      if (stream.match("-#")) {
35
        stream.skipToEnd();
36
        return "comment";
37
      }
38
      return rubyMode.token(stream, state.rubyState);
39
    }
40
41
    function html(stream, state) {
42
      var ch = stream.peek();
43
44
      // handle haml declarations. All declarations that cant be handled here
45
      // will be passed to html mode
46
      if (state.previousToken.style == "comment" ) {
47
        if (state.indented > state.previousToken.indented) {
48
          stream.skipToEnd();
49
          return "commentLine";
50
        }
51
      }
52
53
      if (state.startOfLine) {
54
        if (ch == "!" && stream.match("!!")) {
55
          stream.skipToEnd();
56
          return "tag";
57
        } else if (stream.match(/^%[\w:#\.]+=/)) {
58
          state.tokenize = ruby;
59
          return "hamlTag";
60
        } else if (stream.match(/^%[\w:]+/)) {
61
          return "hamlTag";
62
        } else if (ch == "/" ) {
63
          stream.skipToEnd();
64
          return "comment";
65
        }
66
      }
67
68
      if (state.startOfLine || state.previousToken.style == "hamlTag") {
69
        if ( ch == "#" || ch == ".") {
70
          stream.match(/[\w-#\.]*/);
71
          return "hamlAttribute";
72
        }
73
      }
74
75
      // donot handle --> as valid ruby, make it HTML close comment instead
76
      if (state.startOfLine && !stream.match("-->", false) && (ch == "=" || ch == "-" )) {
77
        state.tokenize = ruby;
78
        return state.tokenize(stream, state);
79
      }
80
81
      if (state.previousToken.style == "hamlTag" ||
82
          state.previousToken.style == "closeAttributeTag" ||
83
          state.previousToken.style == "hamlAttribute") {
84
        if (ch == "(") {
85
          state.tokenize = rubyInQuote(")");
86
          return state.tokenize(stream, state);
87
        } else if (ch == "{") {
88
          state.tokenize = rubyInQuote("}");
89
          return state.tokenize(stream, state);
90
        }
91
      }
92
93
      return htmlMode.token(stream, state.htmlState);
94
    }
95
96
    return {
97
      // default to html mode
98
      startState: function() {
99
        var htmlState = htmlMode.startState();
100
        var rubyState = rubyMode.startState();
101
        return {
102
          htmlState: htmlState,
103
          rubyState: rubyState,
104
          indented: 0,
105
          previousToken: { style: null, indented: 0},
106
          tokenize: html
107
        };
108
      },
109
110
      copyState: function(state) {
111
        return {
112
          htmlState : CodeMirror.copyState(htmlMode, state.htmlState),
113
          rubyState: CodeMirror.copyState(rubyMode, state.rubyState),
114
          indented: state.indented,
115
          previousToken: state.previousToken,
116
          tokenize: state.tokenize
117
        };
118
      },
119
120
      token: function(stream, state) {
121
        if (stream.sol()) {
122
          state.indented = stream.indentation();
123
          state.startOfLine = true;
124
        }
125
        if (stream.eatSpace()) return null;
126
        var style = state.tokenize(stream, state);
127
        state.startOfLine = false;
128
        // dont record comment line as we only want to measure comment line with
129
        // the opening comment block
130
        if (style && style != "commentLine") {
131
          state.previousToken = { style: style, indented: state.indented };
132
        }
133
        // if current state is ruby and the previous token is not `,` reset the
134
        // tokenize to html
135
        if (stream.eol() && state.tokenize == ruby) {
136
          stream.backUp(1);
137
          var ch = stream.peek();
138
          stream.next();
139
          if (ch && ch != ",") {
140
            state.tokenize = html;
141
          }
142
        }
143
        // reprocess some of the specific style tag when finish setting previousToken
144
        if (style == "hamlTag") {
145
          style = "tag";
146
        } else if (style == "commentLine") {
147
          style = "comment";
148
        } else if (style == "hamlAttribute") {
149
          style = "attribute";
150
        } else if (style == "closeAttributeTag") {
151
          style = null;
152
        }
153
        return style;
154
      }
155
    };
156
  }, "htmlmixed", "ruby");
157
158
  CodeMirror.defineMIME("text/x-haml", "haml");
159
});
160