Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Tools / GardeningServer / scripts / base.js
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 var base = base || {};
27
28 (function(){
29
30 base.endsWith = function(string, suffix)
31 {
32     if (suffix.length > string.length)
33         return false;
34     var expectedIndex = string.length - suffix.length;
35     return string.lastIndexOf(suffix) == expectedIndex;
36 };
37
38 base.joinPath = function(parent, child)
39 {
40     if (parent.length == 0)
41         return child;
42     return parent + '/' + child;
43 };
44
45 base.dirName = function(path)
46 {
47     var directoryIndex = path.lastIndexOf('/');
48     if (directoryIndex == -1)
49         return path;
50     return path.substr(0, directoryIndex);
51 };
52
53 base.trimExtension = function(url)
54 {
55     var index = url.lastIndexOf('.');
56     if (index == -1)
57         return url;
58     return url.substr(0, index);
59 }
60
61 base.uniquifyArray = function(array)
62 {
63     var seen = {};
64     var result = [];
65     $.each(array, function(index, value) {
66         if (seen[value])
67             return;
68         seen[value] = true;
69         result.push(value);
70     });
71     return result;
72 };
73
74 base.flattenArray = function(arrayOfArrays)
75 {
76     if (!arrayOfArrays.length)
77         return [];
78     return arrayOfArrays.reduce(function(left, right) {
79         return left.concat(right);
80     });
81 };
82
83 base.filterDictionary = function(dictionary, predicate)
84 {
85     var result = {};
86
87     for (var key in dictionary) {
88         if (predicate(key))
89             result[key] = dictionary[key];
90     }
91
92     return result;
93 };
94
95 base.mapDictionary = function(dictionary, functor)
96 {
97     var result = {};
98
99     for (var key in dictionary) {
100         var value = functor(dictionary[key]);
101         if (typeof value !== 'undefined')
102             result[key] = value;
103     }
104
105     return result;
106 };
107
108 base.filterTree = function(tree, isLeaf, predicate)
109 {
110     var filteredTree = {};
111
112     function walkSubtree(subtree, directory)
113     {
114         for (var childName in subtree) {
115             var child = subtree[childName];
116             var childPath = base.joinPath(directory, childName);
117             if (isLeaf(child)) {
118                 if (predicate(child))
119                     filteredTree[childPath] = child;
120                 continue;
121             }
122             walkSubtree(child, childPath);
123         }
124     }
125
126     walkSubtree(tree, '');
127     return filteredTree;
128 };
129
130 base.forEachDirectory = function(pathList, callback)
131 {
132     var pathsByDirectory = {};
133     pathList.forEach(function(path) {
134         var directory = base.dirName(path);
135         pathsByDirectory[directory] = pathsByDirectory[directory] || [];
136         pathsByDirectory[directory].push(path);
137     });
138     Object.keys(pathsByDirectory).sort().forEach(function(directory) {
139         var paths = pathsByDirectory[directory];
140         callback(directory + ' (' + paths.length + ' tests)', paths);
141     });
142 };
143
144 base.parseJSONP = function(jsonp)
145 {
146     if (!jsonp)
147         return {};
148
149     if (!jsonp.match(/^[^{[]*\(/))
150         return JSON.parse(jsonp);
151
152     var startIndex = jsonp.indexOf('(') + 1;
153     var endIndex = jsonp.lastIndexOf(')');
154     if (startIndex == 0 || endIndex == -1)
155         return {};
156     return JSON.parse(jsonp.substr(startIndex, endIndex - startIndex));
157 };
158
159 // This is effectively a cache of possibly-resolved promises.
160 base.AsynchronousCache = function(fetch)
161 {
162     this._fetch = fetch;
163     this._promiseCache = {};
164 };
165
166 base.AsynchronousCache._sentinel = new Object();
167 base.AsynchronousCache.prototype.get = function(key)
168 {
169     if (!(key in this._promiseCache)) {
170         this._promiseCache[key] = base.AsynchronousCache._sentinel;
171         this._promiseCache[key] = this._fetch.call(null, key);
172     }
173     if (this._promiseCache[key] === base.AsynchronousCache._sentinel)
174         return Promise.reject(Error("Reentrant request for ", key));
175
176     return this._promiseCache[key];
177 };
178
179 base.AsynchronousCache.prototype.clear = function()
180 {
181     this._promiseCache = {};
182 };
183
184 /*
185     Maintains a dictionary of items, tracking their updates and removing items that haven't been updated.
186     An "update" is a call to the "update" method.
187     To remove stale items, call the "remove" method. It will remove all
188     items that have not been been updated since the last call of "remove".
189 */
190 base.UpdateTracker = function()
191 {
192     this._items = {};
193     this._updated = {};
194 }
195
196 base.UpdateTracker.prototype = {
197     /*
198         Update an {key}/{item} pair. You can make the dictionary act as a set and
199         skip the {item}, in which case the {key} is also the {item}.
200     */
201     update: function(key, object)
202     {
203         object = object || key;
204         this._items[key] = object;
205         this._updated[key] = 1;
206     },
207     exists: function(key)
208     {
209         return !!this.get(key);
210     },
211     get: function(key)
212     {
213         return this._items[key];
214     },
215     length: function()
216     {
217         return Object.keys(this._items).length;
218     },
219     /*
220         Callback parameters are:
221         - item
222         - key
223         - updated, which is true if the item was updated after last purge() call.
224     */
225     forEach: function(callback, thisObject)
226     {
227         if (!callback)
228             return;
229
230         Object.keys(this._items).sort().forEach(function(key) {
231             var item = this._items[key];
232             callback.call(thisObject || item, item, key, !!this._updated[key]);
233         }, this);
234     },
235     purge: function(removeCallback, thisObject) {
236         removeCallback = removeCallback || function() {};
237         this.forEach(function(item, key, updated) {
238             if (updated)
239                 return;
240             removeCallback.call(thisObject || item, item);
241             delete this._items[key];
242         }, this);
243         this._updated = {};
244     }
245 }
246
247 // Based on http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/resources/shared/js/cr/ui.js
248 base.extends = function(base, prototype)
249 {
250     var extended = function() {
251         var element = typeof base == 'string' ? document.createElement(base) : base.call(this);
252         extended.prototype.__proto__ = element.__proto__;
253         element.__proto__ = extended.prototype;
254         var singleton = element.init && element.init.apply(element, arguments);
255         if (singleton)
256             return singleton;
257         return element;
258     }
259
260     extended.prototype = prototype;
261     return extended;
262 }
263
264 base.getURLParameter = function(name)
265 {
266     var match = RegExp(name + '=' + '(.+?)(&|$)').exec(location.search);
267     if (!match)
268         return null;
269     return decodeURI(match[1])
270 }
271
272 base.underscoredBuilderName = function(builderName)
273 {
274     return builderName.replace(/[ .()]/g, '_');
275 }
276
277 })();