src/backbone_modules/core.js   B
last analyzed

Complexity

Total Complexity 48
Complexity/F 2.4

Size

Lines of Code 239
Function Count 20

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 0
c 2
b 0
f 0
nc 896
dl 0
loc 239
rs 8.4864
wmc 48
mnd 2
bc 33
fnc 20
bpm 1.65
cpm 2.4
noi 3

9 Functions

Rating   Name   Duplication   Size   Complexity  
A Backbone.noConflict 0 4 1
B core.js ➔ addMethod 0 28 6
A core.js ➔ wrapError 0 9 1
B core.js ➔ cb 0 15 5
A core.js ➔ modelMatcher 0 6 1
A core.js ➔ addUnderscoreMethods 0 9 1
A core.js ➔ urlError 0 3 1
D Backbone.sync 0 75 16
A Backbone.ajax 0 3 1

How to fix   Complexity   

Complexity

Complex classes like src/backbone_modules/core.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
//     Backbone.js 1.3.3
2
3
//     (c) 2010-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
4
//     Backbone may be freely distributed under the MIT license.
5
//     For all details and documentation:
6
//     http://backbonejs.org
7
import $ from 'jquery';
0 ignored issues
show
introduced by
Definition for rule 'keyword-spacing' was not found
Loading history...
8
import _ from 'underscore';
9
10
// Establish the root object, `window` (`self`) in the browser, or `global` on the server.
11
// We use `self` instead of `window` for `WebWorker` support.
12
var root = (typeof self === 'object' && self.self === self && self) ||
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable self is declared in the current environment, consider using typeof self === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
13
  (typeof global === 'object' && global.global === global && global);
14
15
// Initial Setup
16
// -------------
17
var previousBackbone = root.Backbone;
18
19
// Create a local reference to a common array method we'll want to use later.
20
var slice = Array.prototype.slice;
21
22
// Current version of the library. Keep in sync with `package.json`.
23
var Backbone = {
24
  VERSION: '1.3.3-es6'
25
};
26
27
// For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
28
// the `$` variable.
29
Backbone.$ = $;
30
31
// Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
32
// to its previous owner. Returns a reference to this Backbone object.
33
Backbone.noConflict = function () {
34
  root.Backbone = previousBackbone;
35
  return this;
36
};
37
var modelMatcher = function (attrs) {
38
  var matcher = _.matches(attrs);
39
  return function (model) {
40
    return matcher(model.attributes);
41
  };
42
};
43
44
// Throw an error when a URL is needed, and none is supplied.
45
var urlError = function () {
46
  throw new Error('A "url" property or function must be specified');
47
};
48
49
// Wrap an optional error callback with a fallback error event.
50
var wrapError = function (model, options) {
51
  var error = options.error;
52
  options.error = function (resp) {
53
    if (error) {
54
      error.call(options.context, model, resp, options);
55
    }
56
    model.trigger('error', model, resp, options);
57
  };
58
};
59
60
// Support `collection.sortBy('attr')` and `collection.findWhere({id: 1})`.
61
var cb = function (iteratee, instance) {
62
  if (_.isFunction(iteratee)) {
63
    return iteratee;
64
  }
65
  if (_.isObject(iteratee) && !instance._isModel(iteratee)) {
66
    return modelMatcher(
67
      iteratee);
68
  }
69
  if (_.isString(iteratee)) {
70
    return function (model) {
71
      return model.get(iteratee);
72
    };
73
  }
74
  return iteratee;
75
};
76
// Proxy Backbone class methods to Underscore functions, wrapping the model's
77
// `attributes` object or collection's `models` array behind the scenes.
78
//
79
// collection.filter(function(model) { return model.get('age') > 10 });
80
// collection.each(this.addView);
81
//
82
// `Function#apply` can be slow so we use the method's arg count, if we know it.
83
var addMethod = function (length, method, attribute) {
84
  switch (length) {
85
  case 1:
86
    return function () {
87
      return _[method](this[attribute]);
88
    };
89
  case 2:
90
    return function (value) {
91
      return _[method](this[attribute], value);
92
    };
93
  case 3:
94
    return function (iteratee, context) {
95
      return _[method](this[attribute], cb(iteratee, this),
96
        context);
97
    };
98
  case 4:
99
    return function (iteratee, defaultVal, context) {
100
      return _[method](this[attribute], cb(iteratee, this),
101
        defaultVal, context);
102
    };
103
  default:
104
    return function () {
105
      var args = slice.call(arguments);
106
      args.unshift(this[attribute]);
107
      return _[method].apply(_, args);
108
    };
109
  }
110
};
111
var addUnderscoreMethods = function (Class, methods, attribute) {
112
  _.each(methods, function (length, method) {
113
    if (_[method]) {
114
      Class.prototype[method] = addMethod(
115
        length,
116
        method, attribute);
117
    }
118
  });
119
};
120
121
// Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option
122
// will fake `"PATCH"`, `"PUT"` and `"DELETE"` requests via the `_method` parameter and
123
// set a `X-Http-Method-Override` header.
124
Backbone.emulateHTTP = false;
125
126
// Turn on `emulateJSON` to support legacy servers that can't deal with direct
127
// `application/json` requests ... this will encode the body as
128
// `application/x-www-form-urlencoded` instead and will send the model in a
129
// form param named `model`.
130
Backbone.emulateJSON = false;
131
132
// Map from CRUD to HTTP for our default `Backbone.sync` implementation.
133
var methodMap = {
134
  'create': 'POST',
135
  'update': 'PUT',
136
  'patch': 'PATCH',
137
  'delete': 'DELETE',
138
  'read': 'GET'
139
};
140
// Backbone.sync
141
// -------------
142
143
// Override this function to change the manner in which Backbone persists
144
// models to the server. You will be passed the type of request, and the
145
// model in question. By default, makes a RESTful Ajax request
146
// to the model's `url()`. Some possible customizations could be:
147
//
148
// * Use `setTimeout` to batch rapid-fire updates into a single request.
149
// * Send up the models as XML instead of JSON.
150
// * Persist models via WebSockets instead of Ajax.
151
//
152
// Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests
153
// as `POST`, with a `_method` parameter containing the true HTTP method,
154
// as well as all requests with the body as `application/x-www-form-urlencoded`
155
// instead of `application/json` with the model in a param named `model`.
156
// Useful when interfacing with server-side languages like **PHP** that make
157
// it difficult to read the body of `PUT` requests.
158
Backbone.sync = function (method, model, options) {
159
  var type = methodMap[method];
160
161
  // Default options, unless specified.
162
  _.defaults(options || (options = {}), {
163
    emulateHTTP: Backbone.emulateHTTP,
164
    emulateJSON: Backbone.emulateJSON
165
  });
166
167
  // Default JSON-request options.
168
  var params = {
169
    type: type,
170
    dataType: 'json'
171
  };
172
173
  // Ensure that we have a URL.
174
  if (!options.url) {
175
    params.url = _.result(model, 'url') || urlError();
176
  }
177
178
  // Ensure that we have the appropriate request data.
179
  if (options.data == null && model && (method === 'create' || method ===
180
      'update' || method === 'patch')) {
181
    params.contentType = 'application/json';
182
    params.data = JSON.stringify(options.attrs || model.toJSON(
183
      options));
184
  }
185
186
  // For older servers, emulate JSON by encoding the request into an HTML-form.
187
  if (options.emulateJSON) {
188
    params.contentType = 'application/x-www-form-urlencoded';
189
    params.data = params.data ? {
190
      model: params.data
191
    } : {};
192
  }
193
194
  // For older servers, emulate HTTP by mimicking the HTTP method with `_method`
195
  // And an `X-HTTP-Method-Override` header.
196
  if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' ||
197
      type ===
198
      'PATCH')) {
199
    params.type = 'POST';
200
    if (options.emulateJSON) {
201
      params.data._method = type;
202
    }
203
    var beforeSend = options.beforeSend;
204
    options.beforeSend = function (xhr) {
205
      xhr.setRequestHeader('X-HTTP-Method-Override', type);
206
      if (beforeSend) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if beforeSend is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
207
        return beforeSend.apply(this, arguments);
208
      }
209
    };
210
  }
211
212
  // Don't process data on a non-GET request.
213
  if (params.type !== 'GET' && !options.emulateJSON) {
214
    params.processData = false;
215
  }
216
217
  // Pass along `textStatus` and `errorThrown` from jQuery.
218
  var error = options.error;
219
  options.error = function (xhr, textStatus, errorThrown) {
220
    options.textStatus = textStatus;
221
    options.errorThrown = errorThrown;
222
    if (error) {
223
      error.call(options.context, xhr, textStatus,
224
        errorThrown);
225
    }
226
  };
227
228
  // Make the request, allowing the user to override any Ajax options.
229
  var xhr = options.xhr = Backbone.ajax(_.extend(params, options));
230
  model.trigger('request', model, xhr, options);
231
  return xhr;
232
};
233
234
// Set the default implementation of `Backbone.ajax` to proxy through to `$`.
235
// Override this if you'd like to use a different library.
236
Backbone.ajax = function () {
237
  return Backbone.$.ajax.apply(Backbone.$, arguments);
238
};
239
240
export {
241
  urlError,
242
  wrapError,
243
  addUnderscoreMethods,
244
  Backbone
245
};
246