Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/string/internal.js
4501 views
1
/**
2
* @license
3
* Copyright The Closure Library Authors.
4
* SPDX-License-Identifier: Apache-2.0
5
*/
6
7
/**
8
* @fileoverview String functions called from Closure packages that couldn't
9
* depend on each other. Outside Closure, use goog.string function which
10
* delegate to these.
11
*/
12
13
14
goog.provide('goog.string.internal');
15
16
17
/**
18
* Fast prefix-checker.
19
* @param {string} str The string to check.
20
* @param {string} prefix A string to look for at the start of `str`.
21
* @return {boolean} True if `str` begins with `prefix`.
22
* @see goog.string.startsWith
23
*/
24
goog.string.internal.startsWith = function(str, prefix) {
25
'use strict';
26
return str.lastIndexOf(prefix, 0) == 0;
27
};
28
29
30
/**
31
* Fast suffix-checker.
32
* @param {string} str The string to check.
33
* @param {string} suffix A string to look for at the end of `str`.
34
* @return {boolean} True if `str` ends with `suffix`.
35
* @see goog.string.endsWith
36
*/
37
goog.string.internal.endsWith = function(str, suffix) {
38
'use strict';
39
const l = str.length - suffix.length;
40
return l >= 0 && str.indexOf(suffix, l) == l;
41
};
42
43
44
/**
45
* Case-insensitive prefix-checker.
46
* @param {string} str The string to check.
47
* @param {string} prefix A string to look for at the end of `str`.
48
* @return {boolean} True if `str` begins with `prefix` (ignoring
49
* case).
50
* @see goog.string.caseInsensitiveStartsWith
51
*/
52
goog.string.internal.caseInsensitiveStartsWith = function(str, prefix) {
53
'use strict';
54
return (
55
goog.string.internal.caseInsensitiveCompare(
56
prefix, str.slice(0, prefix.length)) == 0);
57
};
58
59
60
/**
61
* Case-insensitive suffix-checker.
62
* @param {string} str The string to check.
63
* @param {string} suffix A string to look for at the end of `str`.
64
* @return {boolean} True if `str` ends with `suffix` (ignoring
65
* case).
66
* @see goog.string.caseInsensitiveEndsWith
67
*/
68
goog.string.internal.caseInsensitiveEndsWith = function(str, suffix) {
69
'use strict';
70
return (
71
goog.string.internal.caseInsensitiveCompare(
72
suffix, str.slice(str.length - suffix.length)) == 0);
73
};
74
75
76
/**
77
* Case-insensitive equality checker.
78
* @param {string} str1 First string to check.
79
* @param {string} str2 Second string to check.
80
* @return {boolean} True if `str1` and `str2` are the same string,
81
* ignoring case.
82
* @see goog.string.caseInsensitiveEquals
83
*/
84
goog.string.internal.caseInsensitiveEquals = function(str1, str2) {
85
'use strict';
86
return str1.toLowerCase() == str2.toLowerCase();
87
};
88
89
90
/**
91
* Checks if a string is empty or contains only whitespaces.
92
* @param {string} str The string to check.
93
* @return {boolean} Whether `str` is empty or whitespace only.
94
* @see goog.string.isEmptyOrWhitespace
95
*/
96
goog.string.internal.isEmptyOrWhitespace = function(str) {
97
'use strict';
98
// testing length == 0 first is actually slower in all browsers (about the
99
// same in Opera).
100
// Since IE doesn't include non-breaking-space (0xa0) in their \s character
101
// class (as required by section 7.2 of the ECMAScript spec), we explicitly
102
// include it in the regexp to enforce consistent cross-browser behavior.
103
return /^[\s\xa0]*$/.test(str);
104
};
105
106
107
/**
108
* Trims white spaces to the left and right of a string.
109
* @param {string} str The string to trim.
110
* @return {string} A trimmed copy of `str`.
111
*/
112
goog.string.internal.trim =
113
(goog.TRUSTED_SITE && String.prototype.trim) ? function(str) {
114
'use strict';
115
return str.trim();
116
} : function(str) {
117
'use strict';
118
// Since IE doesn't include non-breaking-space (0xa0) in their \s
119
// character class (as required by section 7.2 of the ECMAScript spec),
120
// we explicitly include it in the regexp to enforce consistent
121
// cross-browser behavior.
122
// NOTE: We don't use String#replace because it might have side effects
123
// causing this function to not compile to 0 bytes.
124
return /^[\s\xa0]*([\s\S]*?)[\s\xa0]*$/.exec(str)[1];
125
};
126
127
128
/**
129
* A string comparator that ignores case.
130
* -1 = str1 less than str2
131
* 0 = str1 equals str2
132
* 1 = str1 greater than str2
133
*
134
* @param {string} str1 The string to compare.
135
* @param {string} str2 The string to compare `str1` to.
136
* @return {number} The comparator result, as described above.
137
* @see goog.string.caseInsensitiveCompare
138
*/
139
goog.string.internal.caseInsensitiveCompare = function(str1, str2) {
140
'use strict';
141
const test1 = String(str1).toLowerCase();
142
const test2 = String(str2).toLowerCase();
143
144
if (test1 < test2) {
145
return -1;
146
} else if (test1 == test2) {
147
return 0;
148
} else {
149
return 1;
150
}
151
};
152
153
154
/**
155
* Converts \n to <br>s or <br />s.
156
* @param {string} str The string in which to convert newlines.
157
* @param {boolean=} opt_xml Whether to use XML compatible tags.
158
* @return {string} A copy of `str` with converted newlines.
159
* @see goog.string.newLineToBr
160
*/
161
goog.string.internal.newLineToBr = function(str, opt_xml) {
162
'use strict';
163
return str.replace(/(\r\n|\r|\n)/g, opt_xml ? '<br />' : '<br>');
164
};
165
166
167
/**
168
* Escapes double quote '"' and single quote '\'' characters in addition to
169
* '&', '<', and '>' so that a string can be included in an HTML tag attribute
170
* value within double or single quotes.
171
* @param {string} str string to be escaped.
172
* @param {boolean=} opt_isLikelyToContainHtmlChars
173
* @return {string} An escaped copy of `str`.
174
* @see goog.string.htmlEscape
175
*/
176
goog.string.internal.htmlEscape = function(
177
str, opt_isLikelyToContainHtmlChars) {
178
'use strict';
179
if (opt_isLikelyToContainHtmlChars) {
180
str = str.replace(goog.string.internal.AMP_RE_, '&amp;')
181
.replace(goog.string.internal.LT_RE_, '&lt;')
182
.replace(goog.string.internal.GT_RE_, '&gt;')
183
.replace(goog.string.internal.QUOT_RE_, '&quot;')
184
.replace(goog.string.internal.SINGLE_QUOTE_RE_, '&#39;')
185
.replace(goog.string.internal.NULL_RE_, '&#0;');
186
return str;
187
188
} else {
189
// quick test helps in the case when there are no chars to replace, in
190
// worst case this makes barely a difference to the time taken
191
if (!goog.string.internal.ALL_RE_.test(str)) return str;
192
193
// str.indexOf is faster than regex.test in this case
194
if (str.indexOf('&') != -1) {
195
str = str.replace(goog.string.internal.AMP_RE_, '&amp;');
196
}
197
if (str.indexOf('<') != -1) {
198
str = str.replace(goog.string.internal.LT_RE_, '&lt;');
199
}
200
if (str.indexOf('>') != -1) {
201
str = str.replace(goog.string.internal.GT_RE_, '&gt;');
202
}
203
if (str.indexOf('"') != -1) {
204
str = str.replace(goog.string.internal.QUOT_RE_, '&quot;');
205
}
206
if (str.indexOf('\'') != -1) {
207
str = str.replace(goog.string.internal.SINGLE_QUOTE_RE_, '&#39;');
208
}
209
if (str.indexOf('\x00') != -1) {
210
str = str.replace(goog.string.internal.NULL_RE_, '&#0;');
211
}
212
return str;
213
}
214
};
215
216
217
/**
218
* Regular expression that matches an ampersand, for use in escaping.
219
* @const {!RegExp}
220
* @private
221
*/
222
goog.string.internal.AMP_RE_ = /&/g;
223
224
225
/**
226
* Regular expression that matches a less than sign, for use in escaping.
227
* @const {!RegExp}
228
* @private
229
*/
230
goog.string.internal.LT_RE_ = /</g;
231
232
233
/**
234
* Regular expression that matches a greater than sign, for use in escaping.
235
* @const {!RegExp}
236
* @private
237
*/
238
goog.string.internal.GT_RE_ = />/g;
239
240
241
/**
242
* Regular expression that matches a double quote, for use in escaping.
243
* @const {!RegExp}
244
* @private
245
*/
246
goog.string.internal.QUOT_RE_ = /"/g;
247
248
249
/**
250
* Regular expression that matches a single quote, for use in escaping.
251
* @const {!RegExp}
252
* @private
253
*/
254
goog.string.internal.SINGLE_QUOTE_RE_ = /'/g;
255
256
257
/**
258
* Regular expression that matches null character, for use in escaping.
259
* @const {!RegExp}
260
* @private
261
*/
262
goog.string.internal.NULL_RE_ = /\x00/g;
263
264
265
/**
266
* Regular expression that matches any character that needs to be escaped.
267
* @const {!RegExp}
268
* @private
269
*/
270
goog.string.internal.ALL_RE_ = /[\x00&<>"']/;
271
272
273
/**
274
* Do escaping of whitespace to preserve spatial formatting. We use character
275
* entity #160 to make it safer for xml.
276
* @param {string} str The string in which to escape whitespace.
277
* @param {boolean=} opt_xml Whether to use XML compatible tags.
278
* @return {string} An escaped copy of `str`.
279
* @see goog.string.whitespaceEscape
280
*/
281
goog.string.internal.whitespaceEscape = function(str, opt_xml) {
282
'use strict';
283
// This doesn't use goog.string.preserveSpaces for backwards compatibility.
284
return goog.string.internal.newLineToBr(
285
str.replace(/ /g, ' &#160;'), opt_xml);
286
};
287
288
289
/**
290
* Determines whether a string contains a substring.
291
* @param {string} str The string to search.
292
* @param {string} subString The substring to search for.
293
* @return {boolean} Whether `str` contains `subString`.
294
* @see goog.string.contains
295
*/
296
goog.string.internal.contains = function(str, subString) {
297
'use strict';
298
return str.indexOf(subString) != -1;
299
};
300
301
302
/**
303
* Determines whether a string contains a substring, ignoring case.
304
* @param {string} str The string to search.
305
* @param {string} subString The substring to search for.
306
* @return {boolean} Whether `str` contains `subString`.
307
* @see goog.string.caseInsensitiveContains
308
*/
309
goog.string.internal.caseInsensitiveContains = function(str, subString) {
310
'use strict';
311
return goog.string.internal.contains(
312
str.toLowerCase(), subString.toLowerCase());
313
};
314
315
316
/**
317
* Compares two version numbers.
318
*
319
* @param {string|number} version1 Version of first item.
320
* @param {string|number} version2 Version of second item.
321
*
322
* @return {number} 1 if `version1` is higher.
323
* 0 if arguments are equal.
324
* -1 if `version2` is higher.
325
* @see goog.string.compareVersions
326
*/
327
goog.string.internal.compareVersions = function(version1, version2) {
328
'use strict';
329
let order = 0;
330
// Trim leading and trailing whitespace and split the versions into
331
// subversions.
332
const v1Subs = goog.string.internal.trim(String(version1)).split('.');
333
const v2Subs = goog.string.internal.trim(String(version2)).split('.');
334
const subCount = Math.max(v1Subs.length, v2Subs.length);
335
336
// Iterate over the subversions, as long as they appear to be equivalent.
337
for (let subIdx = 0; order == 0 && subIdx < subCount; subIdx++) {
338
let v1Sub = v1Subs[subIdx] || '';
339
let v2Sub = v2Subs[subIdx] || '';
340
341
do {
342
// Split the subversions into pairs of numbers and qualifiers (like 'b').
343
// Two different RegExp objects are use to make it clear the code
344
// is side-effect free
345
const v1Comp = /(\d*)(\D*)(.*)/.exec(v1Sub) || ['', '', '', ''];
346
const v2Comp = /(\d*)(\D*)(.*)/.exec(v2Sub) || ['', '', '', ''];
347
// Break if there are no more matches.
348
if (v1Comp[0].length == 0 && v2Comp[0].length == 0) {
349
break;
350
}
351
352
// Parse the numeric part of the subversion. A missing number is
353
// equivalent to 0.
354
const v1CompNum = v1Comp[1].length == 0 ? 0 : parseInt(v1Comp[1], 10);
355
const v2CompNum = v2Comp[1].length == 0 ? 0 : parseInt(v2Comp[1], 10);
356
357
// Compare the subversion components. The number has the highest
358
// precedence. Next, if the numbers are equal, a subversion without any
359
// qualifier is always higher than a subversion with any qualifier. Next,
360
// the qualifiers are compared as strings.
361
order = goog.string.internal.compareElements_(v1CompNum, v2CompNum) ||
362
goog.string.internal.compareElements_(
363
v1Comp[2].length == 0, v2Comp[2].length == 0) ||
364
goog.string.internal.compareElements_(v1Comp[2], v2Comp[2]);
365
// Stop as soon as an inequality is discovered.
366
367
v1Sub = v1Comp[3];
368
v2Sub = v2Comp[3];
369
} while (order == 0);
370
}
371
372
return order;
373
};
374
375
376
/**
377
* Compares elements of a version number.
378
*
379
* @param {string|number|boolean} left An element from a version number.
380
* @param {string|number|boolean} right An element from a version number.
381
*
382
* @return {number} 1 if `left` is higher.
383
* 0 if arguments are equal.
384
* -1 if `right` is higher.
385
* @private
386
*/
387
goog.string.internal.compareElements_ = function(left, right) {
388
'use strict';
389
if (left < right) {
390
return -1;
391
} else if (left > right) {
392
return 1;
393
}
394
return 0;
395
};
396
397