Passed
Pull Request — develop (#92)
by Felipe
06:19
created

tests/selenium/selenium-lib/core/lib/cssQuery/src/cssQuery.js   F

Complexity

Total Complexity 94
Complexity/F 2.69

Size

Lines of Code 349
Function Count 35

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 0
nc 1
dl 0
loc 349
rs 3.12
c 0
b 0
f 0
wmc 94
mnd 6
bc 54
fnc 35
bpm 1.5428
cpm 2.6857
noi 14

34 Functions

Rating   Name   Duplication   Size   Complexity  
A cssQuery.addModule 0 4 2
A cssQuery.js ➔ firstElementChild 0 3 1
A Quote.test 0 3 1
A cssQuery.js ➔ selectors[:] 0 8 4
A cssQuery.js ➔ selectors[#] 0 5 3
A cssQuery.js ➔ _toStream 0 4 2
A cssQuery.js ➔ getText 0 3 1
A cssQuery.js ➔ select 0 12 3
A selectors[.] 0 8 3
A cssQuery.js ➔ getDocument 0 3 1
A cssQuery.toString 0 3 1
A cssQuery.js ➔ nextElementSibling 0 4 4
A cssQuery.js ➔ isXML 0 6 2
A Quote.remove 0 3 2
F cssQuery.js ➔ cssQuery 0 44 14
A cssQuery.js ➔ previousElementSibling 0 4 4
A cssQuery.js ➔ pseudoClasses[visited] 0 3 1
A Quote.add 0 3 2
A Array.push 0 6 2
A cssQuery.js ➔ compareTagName 0 6 4
A Quote.toString 0 1 1
A cssQuery.js ➔ childElements 0 9 2
A cssQuery.js ➔ regEscape 0 3 1
A cssQuery.valueOf 0 3 2
A cssQuery.js ➔ getTextContent 0 3 1
A cssQuery.js ➔ thisElement 0 3 4
A cssQuery.js ➔ parseSelector 0 7 1
B cssQuery.js ➔ _msie_selectById 0 14 7
A cssQuery.js ➔ compareNamespace 0 3 1
A cssQuery.js ➔ getElementsByTagName 0 3 3
B cssQuery.js ➔ selectors[ ] 0 13 5
A cssQuery.clearCache 0 6 2
A cssQuery.js ➔ pseudoClasses[link] 0 6 4
A cssQuery.js ➔ lastElementChild 0 3 1

How to fix   Complexity   

Complexity

Complex classes like .tests/selenium/selenium-lib/core/lib/cssQuery/src/cssQuery.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
/*
2
	cssQuery, version 2.0.2 (2005-08-19)
3
	Copyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)
4
	License: http://creativecommons.org/licenses/LGPL/2.1/
5
*/
6
7
// the following functions allow querying of the DOM using CSS selectors
8
var cssQuery = function() {
9
var version = "2.0.2";
10
11
// -----------------------------------------------------------------------
12
// main query function
13
// -----------------------------------------------------------------------
14
15
var $COMMA = /\s*,\s*/;
16
var cssQuery = function($selector, $$from) {
17
try {
18
	var $match = [];
19
	var $useCache = arguments.callee.caching && !$$from;
20
	var $base = ($$from) ? ($$from.constructor == Array) ? $$from : [$$from] : [document];
21
	// process comma separated selectors
22
	var $$selectors = parseSelector($selector).split($COMMA), i;
23
	for (i = 0; i < $$selectors.length; i++) {
24
		// convert the selector to a stream
25
		$selector = _toStream($$selectors[i]);
26
		// faster chop if it starts with id (MSIE only)
27
		if (isMSIE && $selector.slice(0, 3).join("") == " *#") {
28
			$selector = $selector.slice(2);
29
			$$from = _msie_selectById([], $base, $selector[1]);
30
		} else $$from = $base;
31
		// process the stream
32
		var j = 0, $token, $filter, $arguments, $cacheSelector = "";
33
		while (j < $selector.length) {
34
			$token = $selector[j++];
35
			$filter = $selector[j++];
36
			$cacheSelector += $token + $filter;
37
			// some pseudo-classes allow arguments to be passed
38
			//  e.g. nth-child(even)
39
			$arguments = "";
40
			if ($selector[j] == "(") {
41
				while ($selector[j++] != ")" && j < $selector.length) {
42
					$arguments += $selector[j];
43
				}
44
				$arguments = $arguments.slice(0, -1);
45
				$cacheSelector += "(" + $arguments + ")";
46
			}
47
			// process a token/filter pair use cached results if possible
48
			$$from = ($useCache && cache[$cacheSelector]) ?
49
				cache[$cacheSelector] : select($$from, $token, $filter, $arguments);
50
			if ($useCache) cache[$cacheSelector] = $$from;
51
		}
52
		$match = $match.concat($$from);
53
	}
54
	delete cssQuery.error;
55
	return $match;
56
} catch ($error) {
57
	cssQuery.error = $error;
58
	return [];
59
}};
60
61
// -----------------------------------------------------------------------
62
// public interface
63
// -----------------------------------------------------------------------
64
65
cssQuery.toString = function() {
66
	return "function cssQuery() {\n  [version " + version + "]\n}";
67
};
68
69
// caching
70
var cache = {};
71
cssQuery.caching = false;
72
cssQuery.clearCache = function($selector) {
73
	if ($selector) {
74
		$selector = _toStream($selector).join("");
75
		delete cache[$selector];
76
	} else cache = {};
77
};
78
79
// allow extensions
80
var modules = {};
81
var loaded = false;
82
cssQuery.addModule = function($name, $script) {
83
	if (loaded) eval("$script=" + String($script));
0 ignored issues
show
Security Performance introduced by
Calls to eval are slow and potentially dangerous, especially on untrusted code. Please consider whether there is another way to achieve your goal.
Loading history...
84
	modules[$name] = new $script();;
85
};
86
87
// hackery
88
cssQuery.valueOf = function($code) {
89
	return $code ? eval($code) : this;
0 ignored issues
show
Security Performance introduced by
Calls to eval are slow and potentially dangerous, especially on untrusted code. Please consider whether there is another way to achieve your goal.
Loading history...
90
};
91
92
// -----------------------------------------------------------------------
93
// declarations
94
// -----------------------------------------------------------------------
95
96
var selectors = {};
97
var pseudoClasses = {};
98
// a safari bug means that these have to be declared here
99
var AttributeSelector = {match: /\[([\w-]+(\|[\w-]+)?)\s*(\W?=)?\s*([^\]]*)\]/};
0 ignored issues
show
Unused Code introduced by
The variable AttributeSelector seems to be never used. Consider removing it.
Loading history...
100
var attributeSelectors = [];
0 ignored issues
show
Unused Code introduced by
The variable attributeSelectors seems to be never used. Consider removing it.
Loading history...
101
102
// -----------------------------------------------------------------------
103
// selectors
104
// -----------------------------------------------------------------------
105
106
// descendant selector
107
selectors[" "] = function($results, $from, $tagName, $namespace) {
108
	// loop through current selection
109
	var $element, i, j;
110
	for (i = 0; i < $from.length; i++) {
111
		// get descendants
112
		var $subset = getElementsByTagName($from[i], $tagName, $namespace);
113
		// loop through descendants and add to results selection
114
		for (j = 0; ($element = $subset[j]); j++) {
115
			if (thisElement($element) && compareNamespace($element, $namespace))
116
				$results.push($element);
117
		}
118
	}
119
};
120
121
// ID selector
122
selectors["#"] = function($results, $from, $id) {
123
	// loop through current selection and check ID
124
	var $element, j;
125
	for (j = 0; ($element = $from[j]); j++) if ($element.id == $id) $results.push($element);
126
};
127
128
// class selector
129
selectors["."] = function($results, $from, $className) {
130
	// create a RegExp version of the class
131
	$className = new RegExp("(^|\\s)" + $className + "(\\s|$)");
132
	// loop through current selection and check class
133
	var $element, i;
134
	for (i = 0; ($element = $from[i]); i++)
135
		if ($className.test($element.className)) $results.push($element);
136
};
137
138
// pseudo-class selector
139
selectors[":"] = function($results, $from, $pseudoClass, $arguments) {
140
	// retrieve the cssQuery pseudo-class function
141
	var $test = pseudoClasses[$pseudoClass], $element, i;
142
	// loop through current selection and apply pseudo-class filter
143
	if ($test) for (i = 0; ($element = $from[i]); i++)
144
		// if the cssQuery pseudo-class function returns "true" add the element
145
		if ($test($element, $arguments)) $results.push($element);
146
};
147
148
// -----------------------------------------------------------------------
149
// pseudo-classes
150
// -----------------------------------------------------------------------
151
152
pseudoClasses["link"] = function($element) {
153
	var $document = getDocument($element);
154
	if ($document.links) for (var i = 0; i < $document.links.length; i++) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if $document.links 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...
155
		if ($document.links[i] == $element) return true;
156
	}
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
157
};
158
159
pseudoClasses["visited"] = function($element) {
0 ignored issues
show
Unused Code introduced by
The parameter $element is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
160
	// can't do this without jiggery-pokery
161
};
162
163
// -----------------------------------------------------------------------
164
// DOM traversal
165
// -----------------------------------------------------------------------
166
167
// IE5/6 includes comments (LOL) in it's elements collections.
168
// so we have to check for this. the test is tagName != "!". LOL (again).
169
var thisElement = function($element) {
170
	return ($element && $element.nodeType == 1 && $element.tagName != "!") ? $element : null;
171
};
172
173
// return the previous element to the supplied element
174
//  previousSibling is not good enough as it might return a text or comment node
175
var previousElementSibling = function($element) {
176
	while ($element && ($element = $element.previousSibling) && !thisElement($element)) continue;
177
	return $element;
178
};
179
180
// return the next element to the supplied element
181
var nextElementSibling = function($element) {
182
	while ($element && ($element = $element.nextSibling) && !thisElement($element)) continue;
183
	return $element;
184
};
185
186
// return the first child ELEMENT of an element
187
//  NOT the first child node (though they may be the same thing)
188
var firstElementChild = function($element) {
189
	return thisElement($element.firstChild) || nextElementSibling($element.firstChild);
190
};
191
192
var lastElementChild = function($element) {
0 ignored issues
show
Unused Code introduced by
The variable lastElementChild seems to be never used. Consider removing it.
Loading history...
193
	return thisElement($element.lastChild) || previousElementSibling($element.lastChild);
194
};
195
196
// return child elements of an element (not child nodes)
197
var childElements = function($element) {
0 ignored issues
show
Unused Code introduced by
The variable childElements seems to be never used. Consider removing it.
Loading history...
198
	var $childElements = [];
199
	$element = firstElementChild($element);
200
	while ($element) {
201
		$childElements.push($element);
202
		$element = nextElementSibling($element);
203
	}
204
	return $childElements;
205
};
206
207
// -----------------------------------------------------------------------
208
// browser compatibility
209
// -----------------------------------------------------------------------
210
211
// all of the functions in this section can be overwritten. the default
212
//  configuration is for IE. The functions below reflect this. standard
213
//  methods are included in a separate module. It would probably be better
214
//  the other way round of course but this makes it easier to keep IE7 trim.
215
216
var isMSIE = true;
217
218
var isXML = function($element) {
219
	var $document = getDocument($element);
220
	return (typeof $document.mimeType == "unknown") ?
221
		/\.xml$/i.test($document.URL) :
222
		Boolean($document.mimeType == "XML Document");
223
};
224
225
// return the element's containing document
226
var getDocument = function($element) {
227
	return $element.ownerDocument || $element.document;
228
};
229
230
var getElementsByTagName = function($element, $tagName) {
231
	return ($tagName == "*" && $element.all) ? $element.all : $element.getElementsByTagName($tagName);
232
};
233
234
var compareTagName = function($element, $tagName, $namespace) {
0 ignored issues
show
Unused Code introduced by
The variable compareTagName seems to be never used. Consider removing it.
Loading history...
235
	if ($tagName == "*") return thisElement($element);
236
	if (!compareNamespace($element, $namespace)) return false;
237
	if (!isXML($element)) $tagName = $tagName.toUpperCase();
238
	return $element.tagName == $tagName;
239
};
240
241
var compareNamespace = function($element, $namespace) {
242
	return !$namespace || ($namespace == "*") || ($element.scopeName == $namespace);
243
};
244
245
var getTextContent = function($element) {
0 ignored issues
show
Unused Code introduced by
The variable getTextContent seems to be never used. Consider removing it.
Loading history...
246
	return $element.innerText;
247
};
248
249
function _msie_selectById($results, $from, id) {
250
	var $match, i, j;
251
	for (i = 0; i < $from.length; i++) {
252
		if ($match = $from[i].all.item(id)) {
253
			if ($match.id == id) $results.push($match);
254
			else if ($match.length != null) {
255
				for (j = 0; j < $match.length; j++) {
256
					if ($match[j].id == id) $results.push($match[j]);
257
				}
258
			}
259
		}
260
	}
261
	return $results;
262
};
263
264
// for IE5.0
265
if (![].push) Array.prototype.push = function() {
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type Array. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
266
	for (var i = 0; i < arguments.length; i++) {
267
		this[this.length] = arguments[i];
268
	}
269
	return this.length;
270
};
271
272
// -----------------------------------------------------------------------
273
// query support
274
// -----------------------------------------------------------------------
275
276
// select a set of matching elements.
277
// "from" is an array of elements.
278
// "token" is a character representing the type of filter
279
//  e.g. ">" means child selector
280
// "filter" represents the tag name, id or class name that is being selected
281
// the function returns an array of matching elements
282
var $NAMESPACE = /\|/;
283
function select($$from, $token, $filter, $arguments) {
284
	if ($NAMESPACE.test($filter)) {
285
		$filter = $filter.split($NAMESPACE);
286
		$arguments = $filter[0];
287
		$filter = $filter[1];
288
	}
289
	var $results = [];
290
	if (selectors[$token]) {
291
		selectors[$token]($results, $$from, $filter, $arguments);
292
	}
293
	return $results;
294
};
295
296
// -----------------------------------------------------------------------
297
// parsing
298
// -----------------------------------------------------------------------
299
300
// convert css selectors to a stream of tokens and filters
301
//  it's not a real stream. it's just an array of strings.
302
var $STANDARD_SELECT = /^[^\s>+~]/;
303
var $$STREAM = /[\s#.:>+~()@]|[^\s#.:>+~()@]+/g;
304
function _toStream($selector) {
305
	if ($STANDARD_SELECT.test($selector)) $selector = " " + $selector;
306
	return $selector.match($$STREAM) || [];
307
};
308
309
var $WHITESPACE = /\s*([\s>+~(),]|^|$)\s*/g;
310
var $IMPLIED_ALL = /([\s>+~,]|[^(]\+|^)([#.:@])/g;
311
var parseSelector = function($selector) {
312
	return $selector
313
	// trim whitespace
314
	.replace($WHITESPACE, "$1")
315
	// e.g. ".class1" --> "*.class1"
316
	.replace($IMPLIED_ALL, "$1*$2");
317
};
318
319
var Quote = {
320
	toString: function() {return "'"},
321
	match: /^('[^']*')|("[^"]*")$/,
322
	test: function($string) {
323
		return this.match.test($string);
324
	},
325
	add: function($string) {
326
		return this.test($string) ? $string : this + $string + this;
327
	},
328
	remove: function($string) {
329
		return this.test($string) ? $string.slice(1, -1) : $string;
330
	}
331
};
332
333
var getText = function($text) {
0 ignored issues
show
Unused Code introduced by
The variable getText seems to be never used. Consider removing it.
Loading history...
334
	return Quote.remove($text);
335
};
336
337
var $ESCAPE = /([\/()[\]?{}|*+-])/g;
338
function regEscape($string) {
0 ignored issues
show
introduced by
The function regEscape does not seem to be used and can be removed.
Loading history...
339
	return $string.replace($ESCAPE, "\\$1");
340
};
341
342
// -----------------------------------------------------------------------
343
// modules
344
// -----------------------------------------------------------------------
345
346
// -------- >>      insert modules here for packaging       << -------- \\
347
348
loaded = true;
349
350
// -----------------------------------------------------------------------
351
// return the query function
352
// -----------------------------------------------------------------------
353
354
return cssQuery;
355
356
}(); // cssQuery
357