cs142/project2/node_modules/jshint/dist/jshint.js

31232 lines
1.2 MiB
JavaScript
Raw Permalink Normal View History

2020-08-01 22:26:11 +00:00
/*! 2.11.0 */
var JSHINT;
if (typeof window === 'undefined') window = {};
(function () {
var require;
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var identifierStartTable = [];
for (var i = 0; i < 128; i++) {
identifierStartTable[i] =
i === 36 || // $
i >= 65 && i <= 90 || // A-Z
i === 95 || // _
i >= 97 && i <= 122; // a-z
}
var identifierPartTable = [];
for (var i = 0; i < 128; i++) {
identifierPartTable[i] =
identifierStartTable[i] || // $, _, A-Z, a-z
i >= 48 && i <= 57; // 0-9
}
module.exports = {
asciiIdentifierStartTable: identifierStartTable,
asciiIdentifierPartTable: identifierPartTable
};
},{}],2:[function(require,module,exports){
module.exports = /^(?:[\$A-Z_a-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0525\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0621-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971\u0972\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D3D\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC\u0EDD\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8B\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10D0-\u10FA\u10FC\u1100-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u2094\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2D00-\u2D25\u2D30-\u2D65\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31B7\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCB\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA65F\uA662-\uA66E\uA67F-\uA697\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B\uA78C\uA7FB-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA2D\uFA30-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC])(?:[\$0-9A-Z_a-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-
},{}],3:[function(require,module,exports){
var str = '183,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,903,1155,1156,1157,1158,1159,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,1450,1451,1452,1453,1454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,1469,1471,1473,1474,1476,1477,1479,1552,1553,1554,1555,1556,1557,1558,1559,1560,1561,1562,1611,1612,1613,1614,1615,1616,1617,1618,1619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629,1630,1631,1632,1633,1634,1635,1636,1637,1638,1639,1640,1641,1648,1750,1751,1752,1753,1754,1755,1756,1759,1760,1761,1762,1763,1764,1767,1768,1770,1771,1772,1773,1776,1777,1778,1779,1780,1781,1782,1783,1784,1785,1809,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,1855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1958,1959,1960,1961,1962,1963,1964,1965,1966,1967,1968,1984,1985,1986,1987,1988,1989,1990,1991,1992,1993,2027,2028,2029,2030,2031,2032,2033,2034,2035,2045,2070,2071,2072,2073,2075,2076,2077,2078,2079,2080,2081,2082,2083,2085,2086,2087,2089,2090,2091,2092,2093,2137,2138,2139,2259,2260,2261,2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2275,2276,2277,2278,2279,2280,2281,2282,2283,2284,2285,2286,2287,2288,2289,2290,2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302,2303,2304,2305,2306,2307,2362,2363,2364,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,2380,2381,2382,2383,2385,2386,2387,2388,2389,2390,2391,2402,2403,2406,2407,2408,2409,2410,2411,2412,2413,2414,2415,2433,2434,2435,2492,2494,2495,2496,2497,2498,2499,2500,2503,2504,2507,2508,2509,2519,2530,2531,2534,2535,2536,2537,2538,2539,2540,2541,2542,2543,2558,2561,2562,2563,2620,2622,2623,2624,2625,2626,2631,2632,2635,2636,2637,2641,2662,2663,2664,2665,2666,2667,2668,2669,2670,2671,2672,2673,2677,2689,2690,2691,2748,2750,2751,2752,2753,2754,2755,2756,2757,2759,2760,2761,2763,2764,2765,2786,2787,2790,2791,2792,2793,2794,2795,2796,2797,2798,2799,2810,2811,2812,2813,2814,2815,2817,2818,2819,2876,2878,2879,2880,2881,2882,2883,2884,2887,2888,2891,2892,2893,2902,2903,2914,2915,2918,2919,2920,2921,2922,2923,2924,2925,2926,2927,2946,3006,3007,3008,3009,3010,3014,3015,3016,3018,3019,3020,3021,3031,3046,3047,3048,3049,3050,3051,3052,3053,3054,3055,3072,3073,3074,3075,3076,3134,3135,3136,3137,3138,3139,3140,3142,3143,3144,3146,3147,3148,3149,3157,3158,3170,3171,3174,3175,3176,3177,3178,3179,3180,3181,3182,3183,3201,3202,3203,3260,3262,3263,3264,3265,3266,3267,3268,3270,3271,3272,3274,3275,3276,3277,3285,3286,3298,3299,3302,3303,3304,3305,3306,3307,3308,3309,3310,3311,3328,3329,3330,3331,3387,3388,3390,3391,3392,3393,3394,3395,3396,3398,3399,3400,3402,3403,3404,3405,3415,3426,3427,3430,3431,3432,3433,3434,3435,3436,3437,3438,3439,3458,3459,3530,3535,3536,3537,3538,3539,3540,3542,3544,3545,3546,3547,3548,3549,3550,3551,3558,3559,3560,3561,3562,3563,3564,3565,3566,3567,3570,3571,3633,3636,3637,3638,3639,3640,3641,3642,3655,3656,3657,3658,3659,3660,3661,3662,3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,3761,3764,3765,3766,3767,3768,3769,3771,3772,3784,3785,3786,3787,3788,3789,3792,3793,3794,3795,3796,3797,3798,3799,3800,3801,3864,3865,3872,3873,3874,3875,3876,3877,3878,3879,3880,3881,3893,3895,3897,3902,3903,3953,3954,3955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,3972,3974,3975,3981,3982,3983,3984,3985,3986,3987,3988,3989,3990,3991,3993,3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4038,4139,4140,4141,4142,4143,4144,4145,4146,4147,4148,4149,4150,415
var arr = str.split(',').map(function(code) {
return parseInt(code, 10);
});
module.exports = arr;
},{}],4:[function(require,module,exports){
var str = '170,181,186,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,710,711,712,713,714,715,716,717,718,719,720,721,736,737,738,739,740,748,750,880,881,882,883,884,886,887,890,891,892,893,895,902,904,905,906,908,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,975,976,977,978,979,980,981,982,983,984,985,986,987,988,989,990,991,992,993,994,995,996,997,998,999,1000,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,1015,1016,1017,1018,1019,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,1104,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126,1127,1128,1129,1130,1131,1132,1133,1134,1135,1136,1137,1138,1139,1140,1141,1142,1143,1144,1145,1146,1147,1148,1149,1150,1151,1152,1153,1162,1163,1164,1165,1166,1167,1168,1169,1170,1171,1172,1173,1174,1175,1176,1177,1178,1179,1180,1181,1182,1183,1184,1185,1186,1187,1188,1189,1190,1191,1192,1193,1194,1195,1196,1197,1198,1199,1200,1201,1202,1203,1204,1205,1206,1207,1208,1209,1210,1211,1212,1213,1214,1215,1216,1217,1218,1219,1220,1221,1222,1223,1224,1225,1226,1227,1228,1229,1230,1231,1232,1233,1234,1235,1236,1237,1238,1239,1240,1241,1242,1243,1244,1245,1246,1247,1248,1249,1250,1251,1252,1253,1254,1255,1256,1257,1258,1259,1260,1261,1262,1263,1264,1265,1266,1267,1268,1269,1270,1271,1272,1273,1274,1275,1276,1277,1278,1279,1280,1281,1282,1283,1284,1285,1286,1287,1288,1289,1290,1291,1292,1293,1294,1295,1296,1297,1298,1299,1300,1301,1302,1303,1304,1305,1306,1307,1308,1309,1310,1311,1312,1313
var arr = str.split(',').map(function(code) {
return parseInt(code, 10);
});
module.exports = arr;
},{}],5:[function(require,module,exports){
// http://wiki.commonjs.org/wiki/Unit_Testing/1.0
//
// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
//
// Originally from narwhal.js (http://narwhaljs.org)
// Copyright (c) 2009 Thomas Robinson <280north.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the 'Software'), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// when used in node, this will actually load the util module we depend on
// versus loading the builtin util module as happens otherwise
// this is a bug in node module loading as far as I am concerned
var util = require('util/');
var pSlice = Array.prototype.slice;
var hasOwn = Object.prototype.hasOwnProperty;
// 1. The assert module provides functions that throw
// AssertionError's when particular conditions are not met. The
// assert module must conform to the following interface.
var assert = module.exports = ok;
// 2. The AssertionError is defined in assert.
// new assert.AssertionError({ message: message,
// actual: actual,
// expected: expected })
assert.AssertionError = function AssertionError(options) {
this.name = 'AssertionError';
this.actual = options.actual;
this.expected = options.expected;
this.operator = options.operator;
if (options.message) {
this.message = options.message;
this.generatedMessage = false;
} else {
this.message = getMessage(this);
this.generatedMessage = true;
}
var stackStartFunction = options.stackStartFunction || fail;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, stackStartFunction);
}
else {
// non v8 browsers so we can have a stacktrace
var err = new Error();
if (err.stack) {
var out = err.stack;
// try to strip useless frames
var fn_name = stackStartFunction.name;
var idx = out.indexOf('\n' + fn_name);
if (idx >= 0) {
// once we have located the function frame
// we need to strip out everything before it (and its line)
var next_line = out.indexOf('\n', idx + 1);
out = out.substring(next_line + 1);
}
this.stack = out;
}
}
};
// assert.AssertionError instanceof Error
util.inherits(assert.AssertionError, Error);
function replacer(key, value) {
if (util.isUndefined(value)) {
return '' + value;
}
if (util.isNumber(value) && !isFinite(value)) {
return value.toString();
}
if (util.isFunction(value) || util.isRegExp(value)) {
return value.toString();
}
return value;
}
function truncate(s, n) {
if (util.isString(s)) {
return s.length < n ? s : s.slice(0, n);
} else {
return s;
}
}
function getMessage(self) {
return truncate(JSON.stringify(self.actual, replacer), 128) + ' ' +
self.operator + ' ' +
truncate(JSON.stringify(self.expected, replacer), 128);
}
// At present only the three keys mentioned above are used and
// understood by the spec. Implementations or sub modules can pass
// other keys to the AssertionError's constructor - they will be
// ignored.
// 3. All of the following functions must throw an AssertionError
// when a corresponding condition is not met, with a message that
// may be undefined if not provided. All assertion methods provide
// both the actual and expected values to the assertion error for
// display purposes.
function fail(actual, expected, message, operator, stackStartFunction) {
throw new assert.AssertionError({
message: message,
actual: actual,
expected: expected,
operator: operator,
stackStartFunction: stackStartFunction
});
}
// EXTENSION! allows for well behaved errors defined elsewhere.
assert.fail = fail;
// 4. Pure assertion tests whether a value is truthy, as determined
// by !!guard.
// assert.ok(guard, message_opt);
// This statement is equivalent to assert.equal(true, !!guard,
// message_opt);. To test strictly for the value true, use
// assert.strictEqual(true, guard, message_opt);.
function ok(value, message) {
if (!value) fail(value, true, message, '==', assert.ok);
}
assert.ok = ok;
// 5. The equality assertion tests shallow, coercive equality with
// ==.
// assert.equal(actual, expected, message_opt);
assert.equal = function equal(actual, expected, message) {
if (actual != expected) fail(actual, expected, message, '==', assert.equal);
};
// 6. The non-equality assertion tests for whether two objects are not equal
// with != assert.notEqual(actual, expected, message_opt);
assert.notEqual = function notEqual(actual, expected, message) {
if (actual == expected) {
fail(actual, expected, message, '!=', assert.notEqual);
}
};
// 7. The equivalence assertion tests a deep equality relation.
// assert.deepEqual(actual, expected, message_opt);
assert.deepEqual = function deepEqual(actual, expected, message) {
if (!_deepEqual(actual, expected)) {
fail(actual, expected, message, 'deepEqual', assert.deepEqual);
}
};
function _deepEqual(actual, expected) {
// 7.1. All identical values are equivalent, as determined by ===.
if (actual === expected) {
return true;
} else if (util.isBuffer(actual) && util.isBuffer(expected)) {
if (actual.length != expected.length) return false;
for (var i = 0; i < actual.length; i++) {
if (actual[i] !== expected[i]) return false;
}
return true;
// 7.2. If the expected value is a Date object, the actual value is
// equivalent if it is also a Date object that refers to the same time.
} else if (util.isDate(actual) && util.isDate(expected)) {
return actual.getTime() === expected.getTime();
// 7.3 If the expected value is a RegExp object, the actual value is
// equivalent if it is also a RegExp object with the same source and
// properties (`global`, `multiline`, `lastIndex`, `ignoreCase`).
} else if (util.isRegExp(actual) && util.isRegExp(expected)) {
return actual.source === expected.source &&
actual.global === expected.global &&
actual.multiline === expected.multiline &&
actual.lastIndex === expected.lastIndex &&
actual.ignoreCase === expected.ignoreCase;
// 7.4. Other pairs that do not both pass typeof value == 'object',
// equivalence is determined by ==.
} else if (!util.isObject(actual) && !util.isObject(expected)) {
return actual == expected;
// 7.5 For all other Object pairs, including Array objects, equivalence is
// determined by having the same number of owned properties (as verified
// with Object.prototype.hasOwnProperty.call), the same set of keys
// (although not necessarily the same order), equivalent values for every
// corresponding key, and an identical 'prototype' property. Note: this
// accounts for both named and indexed properties on Arrays.
} else {
return objEquiv(actual, expected);
}
}
function isArguments(object) {
return Object.prototype.toString.call(object) == '[object Arguments]';
}
function objEquiv(a, b) {
if (util.isNullOrUndefined(a) || util.isNullOrUndefined(b))
return false;
// an identical 'prototype' property.
if (a.prototype !== b.prototype) return false;
// if one is a primitive, the other must be same
if (util.isPrimitive(a) || util.isPrimitive(b)) {
return a === b;
}
var aIsArgs = isArguments(a),
bIsArgs = isArguments(b);
if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs))
return false;
if (aIsArgs) {
a = pSlice.call(a);
b = pSlice.call(b);
return _deepEqual(a, b);
}
var ka = objectKeys(a),
kb = objectKeys(b),
key, i;
// having the same number of owned properties (keys incorporates
// hasOwnProperty)
if (ka.length != kb.length)
return false;
//the same set of keys (although not necessarily the same order),
ka.sort();
kb.sort();
//~~~cheap key test
for (i = ka.length - 1; i >= 0; i--) {
if (ka[i] != kb[i])
return false;
}
//equivalent values for every corresponding key, and
//~~~possibly expensive deep test
for (i = ka.length - 1; i >= 0; i--) {
key = ka[i];
if (!_deepEqual(a[key], b[key])) return false;
}
return true;
}
// 8. The non-equivalence assertion tests for any deep inequality.
// assert.notDeepEqual(actual, expected, message_opt);
assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
if (_deepEqual(actual, expected)) {
fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);
}
};
// 9. The strict equality assertion tests strict equality, as determined by ===.
// assert.strictEqual(actual, expected, message_opt);
assert.strictEqual = function strictEqual(actual, expected, message) {
if (actual !== expected) {
fail(actual, expected, message, '===', assert.strictEqual);
}
};
// 10. The strict non-equality assertion tests for strict inequality, as
// determined by !==. assert.notStrictEqual(actual, expected, message_opt);
assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
if (actual === expected) {
fail(actual, expected, message, '!==', assert.notStrictEqual);
}
};
function expectedException(actual, expected) {
if (!actual || !expected) {
return false;
}
if (Object.prototype.toString.call(expected) == '[object RegExp]') {
return expected.test(actual);
} else if (actual instanceof expected) {
return true;
} else if (expected.call({}, actual) === true) {
return true;
}
return false;
}
function _throws(shouldThrow, block, expected, message) {
var actual;
if (util.isString(expected)) {
message = expected;
expected = null;
}
try {
block();
} catch (e) {
actual = e;
}
message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
(message ? ' ' + message : '.');
if (shouldThrow && !actual) {
fail(actual, expected, 'Missing expected exception' + message);
}
if (!shouldThrow && expectedException(actual, expected)) {
fail(actual, expected, 'Got unwanted exception' + message);
}
if ((shouldThrow && actual && expected &&
!expectedException(actual, expected)) || (!shouldThrow && actual)) {
throw actual;
}
}
// 11. Expected to throw an error:
// assert.throws(block, Error_opt, message_opt);
assert.throws = function(block, /*optional*/error, /*optional*/message) {
_throws.apply(this, [true].concat(pSlice.call(arguments)));
};
// EXTENSION! This is annoying to write outside this module.
assert.doesNotThrow = function(block, /*optional*/message) {
_throws.apply(this, [false].concat(pSlice.call(arguments)));
};
assert.ifError = function(err) { if (err) {throw err;}};
var objectKeys = Object.keys || function (obj) {
var keys = [];
for (var key in obj) {
if (hasOwn.call(obj, key)) keys.push(key);
}
return keys;
};
},{"util/":8}],6:[function(require,module,exports){
if (typeof Object.create === 'function') {
// implementation from standard node.js 'util' module
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
};
} else {
// old school shim for old browsers
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor
var TempCtor = function () {}
TempCtor.prototype = superCtor.prototype
ctor.prototype = new TempCtor()
ctor.prototype.constructor = ctor
}
}
},{}],7:[function(require,module,exports){
module.exports = function isBuffer(arg) {
return arg && typeof arg === 'object'
&& typeof arg.copy === 'function'
&& typeof arg.fill === 'function'
&& typeof arg.readUInt8 === 'function';
}
},{}],8:[function(require,module,exports){
(function (process,global){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var formatRegExp = /%[sdj%]/g;
exports.format = function(f) {
if (!isString(f)) {
var objects = [];
for (var i = 0; i < arguments.length; i++) {
objects.push(inspect(arguments[i]));
}
return objects.join(' ');
}
var i = 1;
var args = arguments;
var len = args.length;
var str = String(f).replace(formatRegExp, function(x) {
if (x === '%%') return '%';
if (i >= len) return x;
switch (x) {
case '%s': return String(args[i++]);
case '%d': return Number(args[i++]);
case '%j':
try {
return JSON.stringify(args[i++]);
} catch (_) {
return '[Circular]';
}
default:
return x;
}
});
for (var x = args[i]; i < len; x = args[++i]) {
if (isNull(x) || !isObject(x)) {
str += ' ' + x;
} else {
str += ' ' + inspect(x);
}
}
return str;
};
// Mark that a method should not be used.
// Returns a modified function which warns once by default.
// If --no-deprecation is set, then it is a no-op.
exports.deprecate = function(fn, msg) {
// Allow for deprecating things in the process of starting up.
if (isUndefined(global.process)) {
return function() {
return exports.deprecate(fn, msg).apply(this, arguments);
};
}
if (process.noDeprecation === true) {
return fn;
}
var warned = false;
function deprecated() {
if (!warned) {
if (process.throwDeprecation) {
throw new Error(msg);
} else if (process.traceDeprecation) {
console.trace(msg);
} else {
console.error(msg);
}
warned = true;
}
return fn.apply(this, arguments);
}
return deprecated;
};
var debugs = {};
var debugEnviron;
exports.debuglog = function(set) {
if (isUndefined(debugEnviron))
debugEnviron = process.env.NODE_DEBUG || '';
set = set.toUpperCase();
if (!debugs[set]) {
if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
var pid = process.pid;
debugs[set] = function() {
var msg = exports.format.apply(exports, arguments);
console.error('%s %d: %s', set, pid, msg);
};
} else {
debugs[set] = function() {};
}
}
return debugs[set];
};
/**
* Echos the value of a value. Trys to print the value out
* in the best way possible given the different types.
*
* @param {Object} obj The object to print out.
* @param {Object} opts Optional options object that alters the output.
*/
/* legacy: obj, showHidden, depth, colors*/
function inspect(obj, opts) {
// default options
var ctx = {
seen: [],
stylize: stylizeNoColor
};
// legacy...
if (arguments.length >= 3) ctx.depth = arguments[2];
if (arguments.length >= 4) ctx.colors = arguments[3];
if (isBoolean(opts)) {
// legacy...
ctx.showHidden = opts;
} else if (opts) {
// got an "options" object
exports._extend(ctx, opts);
}
// set default options
if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
if (isUndefined(ctx.depth)) ctx.depth = 2;
if (isUndefined(ctx.colors)) ctx.colors = false;
if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
if (ctx.colors) ctx.stylize = stylizeWithColor;
return formatValue(ctx, obj, ctx.depth);
}
exports.inspect = inspect;
// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
inspect.colors = {
'bold' : [1, 22],
'italic' : [3, 23],
'underline' : [4, 24],
'inverse' : [7, 27],
'white' : [37, 39],
'grey' : [90, 39],
'black' : [30, 39],
'blue' : [34, 39],
'cyan' : [36, 39],
'green' : [32, 39],
'magenta' : [35, 39],
'red' : [31, 39],
'yellow' : [33, 39]
};
// Don't use 'blue' not visible on cmd.exe
inspect.styles = {
'special': 'cyan',
'number': 'yellow',
'boolean': 'yellow',
'undefined': 'grey',
'null': 'bold',
'string': 'green',
'date': 'magenta',
// "name": intentionally not styling
'regexp': 'red'
};
function stylizeWithColor(str, styleType) {
var style = inspect.styles[styleType];
if (style) {
return '\u001b[' + inspect.colors[style][0] + 'm' + str +
'\u001b[' + inspect.colors[style][1] + 'm';
} else {
return str;
}
}
function stylizeNoColor(str, styleType) {
return str;
}
function arrayToHash(array) {
var hash = {};
array.forEach(function(val, idx) {
hash[val] = true;
});
return hash;
}
function formatValue(ctx, value, recurseTimes) {
// Provide a hook for user-specified inspect functions.
// Check that value is an object with an inspect function on it
if (ctx.customInspect &&
value &&
isFunction(value.inspect) &&
// Filter out the util module, it's inspect function is special
value.inspect !== exports.inspect &&
// Also filter out any prototype objects using the circular check.
!(value.constructor && value.constructor.prototype === value)) {
var ret = value.inspect(recurseTimes, ctx);
if (!isString(ret)) {
ret = formatValue(ctx, ret, recurseTimes);
}
return ret;
}
// Primitive types cannot have properties
var primitive = formatPrimitive(ctx, value);
if (primitive) {
return primitive;
}
// Look up the keys of the object.
var keys = Object.keys(value);
var visibleKeys = arrayToHash(keys);
if (ctx.showHidden) {
keys = Object.getOwnPropertyNames(value);
}
// IE doesn't make error fields non-enumerable
// http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
if (isError(value)
&& (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
return formatError(value);
}
// Some type of object without properties can be shortcutted.
if (keys.length === 0) {
if (isFunction(value)) {
var name = value.name ? ': ' + value.name : '';
return ctx.stylize('[Function' + name + ']', 'special');
}
if (isRegExp(value)) {
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
}
if (isDate(value)) {
return ctx.stylize(Date.prototype.toString.call(value), 'date');
}
if (isError(value)) {
return formatError(value);
}
}
var base = '', array = false, braces = ['{', '}'];
// Make Array say that they are Array
if (isArray(value)) {
array = true;
braces = ['[', ']'];
}
// Make functions say that they are functions
if (isFunction(value)) {
var n = value.name ? ': ' + value.name : '';
base = ' [Function' + n + ']';
}
// Make RegExps say that they are RegExps
if (isRegExp(value)) {
base = ' ' + RegExp.prototype.toString.call(value);
}
// Make dates with properties first say the date
if (isDate(value)) {
base = ' ' + Date.prototype.toUTCString.call(value);
}
// Make error with message first say the error
if (isError(value)) {
base = ' ' + formatError(value);
}
if (keys.length === 0 && (!array || value.length == 0)) {
return braces[0] + base + braces[1];
}
if (recurseTimes < 0) {
if (isRegExp(value)) {
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
} else {
return ctx.stylize('[Object]', 'special');
}
}
ctx.seen.push(value);
var output;
if (array) {
output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
} else {
output = keys.map(function(key) {
return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
});
}
ctx.seen.pop();
return reduceToSingleString(output, base, braces);
}
function formatPrimitive(ctx, value) {
if (isUndefined(value))
return ctx.stylize('undefined', 'undefined');
if (isString(value)) {
var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
.replace(/'/g, "\\'")
.replace(/\\"/g, '"') + '\'';
return ctx.stylize(simple, 'string');
}
if (isNumber(value))
return ctx.stylize('' + value, 'number');
if (isBoolean(value))
return ctx.stylize('' + value, 'boolean');
// For some reason typeof null is "object", so special case here.
if (isNull(value))
return ctx.stylize('null', 'null');
}
function formatError(value) {
return '[' + Error.prototype.toString.call(value) + ']';
}
function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
var output = [];
for (var i = 0, l = value.length; i < l; ++i) {
if (hasOwnProperty(value, String(i))) {
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
String(i), true));
} else {
output.push('');
}
}
keys.forEach(function(key) {
if (!key.match(/^\d+$/)) {
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
key, true));
}
});
return output;
}
function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
var name, str, desc;
desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
if (desc.get) {
if (desc.set) {
str = ctx.stylize('[Getter/Setter]', 'special');
} else {
str = ctx.stylize('[Getter]', 'special');
}
} else {
if (desc.set) {
str = ctx.stylize('[Setter]', 'special');
}
}
if (!hasOwnProperty(visibleKeys, key)) {
name = '[' + key + ']';
}
if (!str) {
if (ctx.seen.indexOf(desc.value) < 0) {
if (isNull(recurseTimes)) {
str = formatValue(ctx, desc.value, null);
} else {
str = formatValue(ctx, desc.value, recurseTimes - 1);
}
if (str.indexOf('\n') > -1) {
if (array) {
str = str.split('\n').map(function(line) {
return ' ' + line;
}).join('\n').substr(2);
} else {
str = '\n' + str.split('\n').map(function(line) {
return ' ' + line;
}).join('\n');
}
}
} else {
str = ctx.stylize('[Circular]', 'special');
}
}
if (isUndefined(name)) {
if (array && key.match(/^\d+$/)) {
return str;
}
name = JSON.stringify('' + key);
if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
name = name.substr(1, name.length - 2);
name = ctx.stylize(name, 'name');
} else {
name = name.replace(/'/g, "\\'")
.replace(/\\"/g, '"')
.replace(/(^"|"$)/g, "'");
name = ctx.stylize(name, 'string');
}
}
return name + ': ' + str;
}
function reduceToSingleString(output, base, braces) {
var numLinesEst = 0;
var length = output.reduce(function(prev, cur) {
numLinesEst++;
if (cur.indexOf('\n') >= 0) numLinesEst++;
return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
}, 0);
if (length > 60) {
return braces[0] +
(base === '' ? '' : base + '\n ') +
' ' +
output.join(',\n ') +
' ' +
braces[1];
}
return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
}
// NOTE: These type checking functions intentionally don't use `instanceof`
// because it is fragile and can be easily faked with `Object.create()`.
function isArray(ar) {
return Array.isArray(ar);
}
exports.isArray = isArray;
function isBoolean(arg) {
return typeof arg === 'boolean';
}
exports.isBoolean = isBoolean;
function isNull(arg) {
return arg === null;
}
exports.isNull = isNull;
function isNullOrUndefined(arg) {
return arg == null;
}
exports.isNullOrUndefined = isNullOrUndefined;
function isNumber(arg) {
return typeof arg === 'number';
}
exports.isNumber = isNumber;
function isString(arg) {
return typeof arg === 'string';
}
exports.isString = isString;
function isSymbol(arg) {
return typeof arg === 'symbol';
}
exports.isSymbol = isSymbol;
function isUndefined(arg) {
return arg === void 0;
}
exports.isUndefined = isUndefined;
function isRegExp(re) {
return isObject(re) && objectToString(re) === '[object RegExp]';
}
exports.isRegExp = isRegExp;
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
exports.isObject = isObject;
function isDate(d) {
return isObject(d) && objectToString(d) === '[object Date]';
}
exports.isDate = isDate;
function isError(e) {
return isObject(e) &&
(objectToString(e) === '[object Error]' || e instanceof Error);
}
exports.isError = isError;
function isFunction(arg) {
return typeof arg === 'function';
}
exports.isFunction = isFunction;
function isPrimitive(arg) {
return arg === null ||
typeof arg === 'boolean' ||
typeof arg === 'number' ||
typeof arg === 'string' ||
typeof arg === 'symbol' || // ES6 symbol
typeof arg === 'undefined';
}
exports.isPrimitive = isPrimitive;
exports.isBuffer = require('./support/isBuffer');
function objectToString(o) {
return Object.prototype.toString.call(o);
}
function pad(n) {
return n < 10 ? '0' + n.toString(10) : n.toString(10);
}
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
'Oct', 'Nov', 'Dec'];
// 26 Feb 16:19:34
function timestamp() {
var d = new Date();
var time = [pad(d.getHours()),
pad(d.getMinutes()),
pad(d.getSeconds())].join(':');
return [d.getDate(), months[d.getMonth()], time].join(' ');
}
// log is just a thin wrapper to console.log that prepends a timestamp
exports.log = function() {
console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
};
/**
* Inherit the prototype methods from one constructor into another.
*
* The Function.prototype.inherits from lang.js rewritten as a standalone
* function (not on Function.prototype). NOTE: If this file is to be loaded
* during bootstrapping this function needs to be rewritten using some native
* functions as prototype setup using normal JavaScript does not work as
* expected during bootstrapping (see mirror.js in r114903).
*
* @param {function} ctor Constructor function which needs to inherit the
* prototype.
* @param {function} superCtor Constructor function to inherit prototype from.
*/
exports.inherits = require('inherits');
exports._extend = function(origin, add) {
// Don't do anything if add isn't an object
if (!add || !isObject(add)) return origin;
var keys = Object.keys(add);
var i = keys.length;
while (i--) {
origin[keys[i]] = add[keys[i]];
}
return origin;
};
function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./support/isBuffer":7,"_process":11,"inherits":6}],9:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
function EventEmitter() {
this._events = this._events || {};
this._maxListeners = this._maxListeners || undefined;
}
module.exports = EventEmitter;
// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;
EventEmitter.prototype._events = undefined;
EventEmitter.prototype._maxListeners = undefined;
// By default EventEmitters will print a warning if more than 10 listeners are
// added to it. This is a useful default which helps finding memory leaks.
EventEmitter.defaultMaxListeners = 10;
// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
EventEmitter.prototype.setMaxListeners = function(n) {
if (!isNumber(n) || n < 0 || isNaN(n))
throw TypeError('n must be a positive number');
this._maxListeners = n;
return this;
};
EventEmitter.prototype.emit = function(type) {
var er, handler, len, args, i, listeners;
if (!this._events)
this._events = {};
// If there is no 'error' event listener then throw.
if (type === 'error') {
if (!this._events.error ||
(isObject(this._events.error) && !this._events.error.length)) {
er = arguments[1];
if (er instanceof Error) {
throw er; // Unhandled 'error' event
}
throw TypeError('Uncaught, unspecified "error" event.');
}
}
handler = this._events[type];
if (isUndefined(handler))
return false;
if (isFunction(handler)) {
switch (arguments.length) {
// fast cases
case 1:
handler.call(this);
break;
case 2:
handler.call(this, arguments[1]);
break;
case 3:
handler.call(this, arguments[1], arguments[2]);
break;
// slower
default:
len = arguments.length;
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
handler.apply(this, args);
}
} else if (isObject(handler)) {
len = arguments.length;
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
listeners = handler.slice();
len = listeners.length;
for (i = 0; i < len; i++)
listeners[i].apply(this, args);
}
return true;
};
EventEmitter.prototype.addListener = function(type, listener) {
var m;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events)
this._events = {};
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
if (this._events.newListener)
this.emit('newListener', type,
isFunction(listener.listener) ?
listener.listener : listener);
if (!this._events[type])
// Optimize the case of one listener. Don't need the extra array object.
this._events[type] = listener;
else if (isObject(this._events[type]))
// If we've already got an array, just append.
this._events[type].push(listener);
else
// Adding the second element, need to change to array.
this._events[type] = [this._events[type], listener];
// Check for listener leak
if (isObject(this._events[type]) && !this._events[type].warned) {
var m;
if (!isUndefined(this._maxListeners)) {
m = this._maxListeners;
} else {
m = EventEmitter.defaultMaxListeners;
}
if (m && m > 0 && this._events[type].length > m) {
this._events[type].warned = true;
console.error('(node) warning: possible EventEmitter memory ' +
'leak detected. %d listeners added. ' +
'Use emitter.setMaxListeners() to increase limit.',
this._events[type].length);
if (typeof console.trace === 'function') {
// not supported in IE 10
console.trace();
}
}
}
return this;
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.once = function(type, listener) {
if (!isFunction(listener))
throw TypeError('listener must be a function');
var fired = false;
function g() {
this.removeListener(type, g);
if (!fired) {
fired = true;
listener.apply(this, arguments);
}
}
g.listener = listener;
this.on(type, g);
return this;
};
// emits a 'removeListener' event iff the listener was removed
EventEmitter.prototype.removeListener = function(type, listener) {
var list, position, length, i;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events || !this._events[type])
return this;
list = this._events[type];
length = list.length;
position = -1;
if (list === listener ||
(isFunction(list.listener) && list.listener === listener)) {
delete this._events[type];
if (this._events.removeListener)
this.emit('removeListener', type, listener);
} else if (isObject(list)) {
for (i = length; i-- > 0;) {
if (list[i] === listener ||
(list[i].listener && list[i].listener === listener)) {
position = i;
break;
}
}
if (position < 0)
return this;
if (list.length === 1) {
list.length = 0;
delete this._events[type];
} else {
list.splice(position, 1);
}
if (this._events.removeListener)
this.emit('removeListener', type, listener);
}
return this;
};
EventEmitter.prototype.removeAllListeners = function(type) {
var key, listeners;
if (!this._events)
return this;
// not listening for removeListener, no need to emit
if (!this._events.removeListener) {
if (arguments.length === 0)
this._events = {};
else if (this._events[type])
delete this._events[type];
return this;
}
// emit removeListener for all listeners on all events
if (arguments.length === 0) {
for (key in this._events) {
if (key === 'removeListener') continue;
this.removeAllListeners(key);
}
this.removeAllListeners('removeListener');
this._events = {};
return this;
}
listeners = this._events[type];
if (isFunction(listeners)) {
this.removeListener(type, listeners);
} else {
// LIFO order
while (listeners.length)
this.removeListener(type, listeners[listeners.length - 1]);
}
delete this._events[type];
return this;
};
EventEmitter.prototype.listeners = function(type) {
var ret;
if (!this._events || !this._events[type])
ret = [];
else if (isFunction(this._events[type]))
ret = [this._events[type]];
else
ret = this._events[type].slice();
return ret;
};
EventEmitter.listenerCount = function(emitter, type) {
var ret;
if (!emitter._events || !emitter._events[type])
ret = 0;
else if (isFunction(emitter._events[type]))
ret = 1;
else
ret = emitter._events[type].length;
return ret;
};
function isFunction(arg) {
return typeof arg === 'function';
}
function isNumber(arg) {
return typeof arg === 'number';
}
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
function isUndefined(arg) {
return arg === void 0;
}
},{}],10:[function(require,module,exports){
arguments[4][6][0].apply(exports,arguments)
},{"dup":6}],11:[function(require,module,exports){
// shim for using process in browser
var process = module.exports = {};
var queue = [];
var draining = false;
function drainQueue() {
if (draining) {
return;
}
draining = true;
var currentQueue;
var len = queue.length;
while(len) {
currentQueue = queue;
queue = [];
var i = -1;
while (++i < len) {
currentQueue[i]();
}
len = queue.length;
}
draining = false;
}
process.nextTick = function (fun) {
queue.push(fun);
if (!draining) {
setTimeout(drainQueue, 0);
}
};
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
process.version = ''; // empty string to avoid regexp issues
process.versions = {};
function noop() {}
process.on = noop;
process.addListener = noop;
process.once = noop;
process.off = noop;
process.removeListener = noop;
process.removeAllListeners = noop;
process.emit = noop;
process.binding = function (name) {
throw new Error('process.binding is not supported');
};
// TODO(shtylman)
process.cwd = function () { return '/' };
process.chdir = function (dir) {
throw new Error('process.chdir is not supported');
};
process.umask = function() { return 0; };
},{}],12:[function(require,module,exports){
arguments[4][7][0].apply(exports,arguments)
},{"dup":7}],13:[function(require,module,exports){
arguments[4][8][0].apply(exports,arguments)
},{"./support/isBuffer":12,"_process":11,"dup":8,"inherits":10}],14:[function(require,module,exports){
(function (global){
/*global window, global*/
var util = require("util")
var assert = require("assert")
var now = require("date-now")
var slice = Array.prototype.slice
var console
var times = {}
if (typeof global !== "undefined" && global.console) {
console = global.console
} else if (typeof window !== "undefined" && window.console) {
console = window.console
} else {
console = {}
}
var functions = [
[log, "log"],
[info, "info"],
[warn, "warn"],
[error, "error"],
[time, "time"],
[timeEnd, "timeEnd"],
[trace, "trace"],
[dir, "dir"],
[consoleAssert, "assert"]
]
for (var i = 0; i < functions.length; i++) {
var tuple = functions[i]
var f = tuple[0]
var name = tuple[1]
if (!console[name]) {
console[name] = f
}
}
module.exports = console
function log() {}
function info() {
console.log.apply(console, arguments)
}
function warn() {
console.log.apply(console, arguments)
}
function error() {
console.warn.apply(console, arguments)
}
function time(label) {
times[label] = now()
}
function timeEnd(label) {
var time = times[label]
if (!time) {
throw new Error("No such label: " + label)
}
var duration = now() - time
console.log(label + ": " + duration + "ms")
}
function trace() {
var err = new Error()
err.name = "Trace"
err.message = util.format.apply(null, arguments)
console.error(err.stack)
}
function dir(object) {
console.log(util.inspect(object) + "\n")
}
function consoleAssert(expression) {
if (!expression) {
var arr = slice.call(arguments, 1)
assert.ok(false, util.format.apply(null, arr))
}
}
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"assert":5,"date-now":15,"util":13}],15:[function(require,module,exports){
module.exports = now
function now() {
return new Date().getTime()
}
},{}],16:[function(require,module,exports){
(function (global){
/**
* @license
* Lodash <https://lodash.com/>
* Copyright JS Foundation and other contributors <https://js.foundation/>
* Released under MIT license <https://lodash.com/license>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
*/
;(function() {
/** Used as a safe reference for `undefined` in pre-ES5 environments. */
var undefined;
/** Used as the semantic version number. */
var VERSION = '4.17.11';
/** Used as the size to enable large array optimizations. */
var LARGE_ARRAY_SIZE = 200;
/** Error message constants. */
var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.',
FUNC_ERROR_TEXT = 'Expected a function';
/** Used to stand-in for `undefined` hash values. */
var HASH_UNDEFINED = '__lodash_hash_undefined__';
/** Used as the maximum memoize cache size. */
var MAX_MEMOIZE_SIZE = 500;
/** Used as the internal argument placeholder. */
var PLACEHOLDER = '__lodash_placeholder__';
/** Used to compose bitmasks for cloning. */
var CLONE_DEEP_FLAG = 1,
CLONE_FLAT_FLAG = 2,
CLONE_SYMBOLS_FLAG = 4;
/** Used to compose bitmasks for value comparisons. */
var COMPARE_PARTIAL_FLAG = 1,
COMPARE_UNORDERED_FLAG = 2;
/** Used to compose bitmasks for function metadata. */
var WRAP_BIND_FLAG = 1,
WRAP_BIND_KEY_FLAG = 2,
WRAP_CURRY_BOUND_FLAG = 4,
WRAP_CURRY_FLAG = 8,
WRAP_CURRY_RIGHT_FLAG = 16,
WRAP_PARTIAL_FLAG = 32,
WRAP_PARTIAL_RIGHT_FLAG = 64,
WRAP_ARY_FLAG = 128,
WRAP_REARG_FLAG = 256,
WRAP_FLIP_FLAG = 512;
/** Used as default options for `_.truncate`. */
var DEFAULT_TRUNC_LENGTH = 30,
DEFAULT_TRUNC_OMISSION = '...';
/** Used to detect hot functions by number of calls within a span of milliseconds. */
var HOT_COUNT = 800,
HOT_SPAN = 16;
/** Used to indicate the type of lazy iteratees. */
var LAZY_FILTER_FLAG = 1,
LAZY_MAP_FLAG = 2,
LAZY_WHILE_FLAG = 3;
/** Used as references for various `Number` constants. */
var INFINITY = 1 / 0,
MAX_SAFE_INTEGER = 9007199254740991,
MAX_INTEGER = 1.7976931348623157e+308,
NAN = 0 / 0;
/** Used as references for the maximum length and index of an array. */
var MAX_ARRAY_LENGTH = 4294967295,
MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
/** Used to associate wrap methods with their bit flags. */
var wrapFlags = [
['ary', WRAP_ARY_FLAG],
['bind', WRAP_BIND_FLAG],
['bindKey', WRAP_BIND_KEY_FLAG],
['curry', WRAP_CURRY_FLAG],
['curryRight', WRAP_CURRY_RIGHT_FLAG],
['flip', WRAP_FLIP_FLAG],
['partial', WRAP_PARTIAL_FLAG],
['partialRight', WRAP_PARTIAL_RIGHT_FLAG],
['rearg', WRAP_REARG_FLAG]
];
/** `Object#toString` result references. */
var argsTag = '[object Arguments]',
arrayTag = '[object Array]',
asyncTag = '[object AsyncFunction]',
boolTag = '[object Boolean]',
dateTag = '[object Date]',
domExcTag = '[object DOMException]',
errorTag = '[object Error]',
funcTag = '[object Function]',
genTag = '[object GeneratorFunction]',
mapTag = '[object Map]',
numberTag = '[object Number]',
nullTag = '[object Null]',
objectTag = '[object Object]',
promiseTag = '[object Promise]',
proxyTag = '[object Proxy]',
regexpTag = '[object RegExp]',
setTag = '[object Set]',
stringTag = '[object String]',
symbolTag = '[object Symbol]',
undefinedTag = '[object Undefined]',
weakMapTag = '[object WeakMap]',
weakSetTag = '[object WeakSet]';
var arrayBufferTag = '[object ArrayBuffer]',
dataViewTag = '[object DataView]',
float32Tag = '[object Float32Array]',
float64Tag = '[object Float64Array]',
int8Tag = '[object Int8Array]',
int16Tag = '[object Int16Array]',
int32Tag = '[object Int32Array]',
uint8Tag = '[object Uint8Array]',
uint8ClampedTag = '[object Uint8ClampedArray]',
uint16Tag = '[object Uint16Array]',
uint32Tag = '[object Uint32Array]';
/** Used to match empty string literals in compiled template source. */
var reEmptyStringLeading = /\b__p \+= '';/g,
reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
/** Used to match HTML entities and HTML characters. */
var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g,
reUnescapedHtml = /[&<>"']/g,
reHasEscapedHtml = RegExp(reEscapedHtml.source),
reHasUnescapedHtml = RegExp(reUnescapedHtml.source);
/** Used to match template delimiters. */
var reEscape = /<%-([\s\S]+?)%>/g,
reEvaluate = /<%([\s\S]+?)%>/g,
reInterpolate = /<%=([\s\S]+?)%>/g;
/** Used to match property names within property paths. */
var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
reIsPlainProp = /^\w*$/,
rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
/**
* Used to match `RegExp`
* [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
*/
var reRegExpChar = /[\\^$.*+?()[\]{}|]/g,
reHasRegExpChar = RegExp(reRegExpChar.source);
/** Used to match leading and trailing whitespace. */
var reTrim = /^\s+|\s+$/g,
reTrimStart = /^\s+/,
reTrimEnd = /\s+$/;
/** Used to match wrap detail comments. */
var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,
reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/,
reSplitDetails = /,? & /;
/** Used to match words composed of alphanumeric characters. */
var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
/** Used to match backslashes in property paths. */
var reEscapeChar = /\\(\\)?/g;
/**
* Used to match
* [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components).
*/
var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
/** Used to match `RegExp` flags from their coerced string values. */
var reFlags = /\w*$/;
/** Used to detect bad signed hexadecimal string values. */
var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
/** Used to detect binary string values. */
var reIsBinary = /^0b[01]+$/i;
/** Used to detect host constructors (Safari). */
var reIsHostCtor = /^\[object .+?Constructor\]$/;
/** Used to detect octal string values. */
var reIsOctal = /^0o[0-7]+$/i;
/** Used to detect unsigned integer values. */
var reIsUint = /^(?:0|[1-9]\d*)$/;
/** Used to match Latin Unicode letters (excluding mathematical operators). */
var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;
/** Used to ensure capturing order of template delimiters. */
var reNoMatch = /($^)/;
/** Used to match unescaped characters in compiled string literals. */
var reUnescapedString = /['\n\r\u2028\u2029\\]/g;
/** Used to compose unicode character classes. */
var rsAstralRange = '\\ud800-\\udfff',
rsComboMarksRange = '\\u0300-\\u036f',
reComboHalfMarksRange = '\\ufe20-\\ufe2f',
rsComboSymbolsRange = '\\u20d0-\\u20ff',
rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,
rsDingbatRange = '\\u2700-\\u27bf',
rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff',
rsMathOpRange = '\\xac\\xb1\\xd7\\xf7',
rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf',
rsPunctuationRange = '\\u2000-\\u206f',
rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000',
rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde',
rsVarRange = '\\ufe0e\\ufe0f',
rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange;
/** Used to compose unicode capture groups. */
var rsApos = "['\u2019]",
rsAstral = '[' + rsAstralRange + ']',
rsBreak = '[' + rsBreakRange + ']',
rsCombo = '[' + rsComboRange + ']',
rsDigits = '\\d+',
rsDingbat = '[' + rsDingbatRange + ']',
rsLower = '[' + rsLowerRange + ']',
rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']',
rsFitz = '\\ud83c[\\udffb-\\udfff]',
rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',
rsNonAstral = '[^' + rsAstralRange + ']',
rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}',
rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]',
rsUpper = '[' + rsUpperRange + ']',
rsZWJ = '\\u200d';
/** Used to compose unicode regexes. */
var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')',
rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')',
rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?',
rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?',
reOptMod = rsModifier + '?',
rsOptVar = '[' + rsVarRange + ']?',
rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',
rsOrdLower = '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])',
rsOrdUpper = '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])',
rsSeq = rsOptVar + reOptMod + rsOptJoin,
rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq,
rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';
/** Used to match apostrophes. */
var reApos = RegExp(rsApos, 'g');
/**
* Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
* [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
*/
var reComboMark = RegExp(rsCombo, 'g');
/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');
/** Used to match complex or compound words. */
var reUnicodeWord = RegExp([
rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')',
rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')',
rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower,
rsUpper + '+' + rsOptContrUpper,
rsOrdUpper,
rsOrdLower,
rsDigits,
rsEmoji
].join('|'), 'g');
/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */
var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');
/** Used to detect strings that need a more robust regexp to match words. */
var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;
/** Used to assign default `context` object properties. */
var contextProps = [
'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array',
'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object',
'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array',
'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap',
'_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout'
];
/** Used to make template sourceURLs easier to identify. */
var templateCounter = -1;
/** Used to identify `toStringTag` values of typed arrays. */
var typedArrayTags = {};
typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
typedArrayTags[uint32Tag] = true;
typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
typedArrayTags[dataViewTag] = typedArrayTags[dateTag] =
typedArrayTags[errorTag] = typedArrayTags[funcTag] =
typedArrayTags[mapTag] = typedArrayTags[numberTag] =
typedArrayTags[objectTag] = typedArrayTags[regexpTag] =
typedArrayTags[setTag] = typedArrayTags[stringTag] =
typedArrayTags[weakMapTag] = false;
/** Used to identify `toStringTag` values supported by `_.clone`. */
var cloneableTags = {};
cloneableTags[argsTag] = cloneableTags[arrayTag] =
cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =
cloneableTags[boolTag] = cloneableTags[dateTag] =
cloneableTags[float32Tag] = cloneableTags[float64Tag] =
cloneableTags[int8Tag] = cloneableTags[int16Tag] =
cloneableTags[int32Tag] = cloneableTags[mapTag] =
cloneableTags[numberTag] = cloneableTags[objectTag] =
cloneableTags[regexpTag] = cloneableTags[setTag] =
cloneableTags[stringTag] = cloneableTags[symbolTag] =
cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
cloneableTags[errorTag] = cloneableTags[funcTag] =
cloneableTags[weakMapTag] = false;
/** Used to map Latin Unicode letters to basic Latin letters. */
var deburredLetters = {
// Latin-1 Supplement block.
'\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
'\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
'\xc7': 'C', '\xe7': 'c',
'\xd0': 'D', '\xf0': 'd',
'\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
'\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
'\xcc': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
'\xec': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i',
'\xd1': 'N', '\xf1': 'n',
'\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
'\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
'\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
'\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
'\xdd': 'Y', '\xfd': 'y', '\xff': 'y',
'\xc6': 'Ae', '\xe6': 'ae',
'\xde': 'Th', '\xfe': 'th',
'\xdf': 'ss',
// Latin Extended-A block.
'\u0100': 'A', '\u0102': 'A', '\u0104': 'A',
'\u0101': 'a', '\u0103': 'a', '\u0105': 'a',
'\u0106': 'C', '\u0108': 'C', '\u010a': 'C', '\u010c': 'C',
'\u0107': 'c', '\u0109': 'c', '\u010b': 'c', '\u010d': 'c',
'\u010e': 'D', '\u0110': 'D', '\u010f': 'd', '\u0111': 'd',
'\u0112': 'E', '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E',
'\u0113': 'e', '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e',
'\u011c': 'G', '\u011e': 'G', '\u0120': 'G', '\u0122': 'G',
'\u011d': 'g', '\u011f': 'g', '\u0121': 'g', '\u0123': 'g',
'\u0124': 'H', '\u0126': 'H', '\u0125': 'h', '\u0127': 'h',
'\u0128': 'I', '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I',
'\u0129': 'i', '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i',
'\u0134': 'J', '\u0135': 'j',
'\u0136': 'K', '\u0137': 'k', '\u0138': 'k',
'\u0139': 'L', '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L',
'\u013a': 'l', '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l',
'\u0143': 'N', '\u0145': 'N', '\u0147': 'N', '\u014a': 'N',
'\u0144': 'n', '\u0146': 'n', '\u0148': 'n', '\u014b': 'n',
'\u014c': 'O', '\u014e': 'O', '\u0150': 'O',
'\u014d': 'o', '\u014f': 'o', '\u0151': 'o',
'\u0154': 'R', '\u0156': 'R', '\u0158': 'R',
'\u0155': 'r', '\u0157': 'r', '\u0159': 'r',
'\u015a': 'S', '\u015c': 'S', '\u015e': 'S', '\u0160': 'S',
'\u015b': 's', '\u015d': 's', '\u015f': 's', '\u0161': 's',
'\u0162': 'T', '\u0164': 'T', '\u0166': 'T',
'\u0163': 't', '\u0165': 't', '\u0167': 't',
'\u0168': 'U', '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U',
'\u0169': 'u', '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u',
'\u0174': 'W', '\u0175': 'w',
'\u0176': 'Y', '\u0177': 'y', '\u0178': 'Y',
'\u0179': 'Z', '\u017b': 'Z', '\u017d': 'Z',
'\u017a': 'z', '\u017c': 'z', '\u017e': 'z',
'\u0132': 'IJ', '\u0133': 'ij',
'\u0152': 'Oe', '\u0153': 'oe',
'\u0149': "'n", '\u017f': 's'
};
/** Used to map characters to HTML entities. */
var htmlEscapes = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;'
};
/** Used to map HTML entities to characters. */
var htmlUnescapes = {
'&amp;': '&',
'&lt;': '<',
'&gt;': '>',
'&quot;': '"',
'&#39;': "'"
};
/** Used to escape characters for inclusion in compiled string literals. */
var stringEscapes = {
'\\': '\\',
"'": "'",
'\n': 'n',
'\r': 'r',
'\u2028': 'u2028',
'\u2029': 'u2029'
};
/** Built-in method references without a dependency on `root`. */
var freeParseFloat = parseFloat,
freeParseInt = parseInt;
/** Detect free variable `global` from Node.js. */
var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
/** Detect free variable `self`. */
var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
/** Used as a reference to the global object. */
var root = freeGlobal || freeSelf || Function('return this')();
/** Detect free variable `exports`. */
var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;
/** Detect free variable `module`. */
var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;
/** Detect the popular CommonJS extension `module.exports`. */
var moduleExports = freeModule && freeModule.exports === freeExports;
/** Detect free variable `process` from Node.js. */
var freeProcess = moduleExports && freeGlobal.process;
/** Used to access faster Node.js helpers. */
var nodeUtil = (function() {
try {
// Use `util.types` for Node.js 10+.
var types = freeModule && freeModule.require && freeModule.require('util').types;
if (types) {
return types;
}
// Legacy `process.binding('util')` for Node.js < 10.
return freeProcess && freeProcess.binding && freeProcess.binding('util');
} catch (e) {}
}());
/* Node.js helper references. */
var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer,
nodeIsDate = nodeUtil && nodeUtil.isDate,
nodeIsMap = nodeUtil && nodeUtil.isMap,
nodeIsRegExp = nodeUtil && nodeUtil.isRegExp,
nodeIsSet = nodeUtil && nodeUtil.isSet,
nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;
/*--------------------------------------------------------------------------*/
/**
* A faster alternative to `Function#apply`, this function invokes `func`
* with the `this` binding of `thisArg` and the arguments of `args`.
*
* @private
* @param {Function} func The function to invoke.
* @param {*} thisArg The `this` binding of `func`.
* @param {Array} args The arguments to invoke `func` with.
* @returns {*} Returns the result of `func`.
*/
function apply(func, thisArg, args) {
switch (args.length) {
case 0: return func.call(thisArg);
case 1: return func.call(thisArg, args[0]);
case 2: return func.call(thisArg, args[0], args[1]);
case 3: return func.call(thisArg, args[0], args[1], args[2]);
}
return func.apply(thisArg, args);
}
/**
* A specialized version of `baseAggregator` for arrays.
*
* @private
* @param {Array} [array] The array to iterate over.
* @param {Function} setter The function to set `accumulator` values.
* @param {Function} iteratee The iteratee to transform keys.
* @param {Object} accumulator The initial aggregated object.
* @returns {Function} Returns `accumulator`.
*/
function arrayAggregator(array, setter, iteratee, accumulator) {
var index = -1,
length = array == null ? 0 : array.length;
while (++index < length) {
var value = array[index];
setter(accumulator, value, iteratee(value), array);
}
return accumulator;
}
/**
* A specialized version of `_.forEach` for arrays without support for
* iteratee shorthands.
*
* @private
* @param {Array} [array] The array to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @returns {Array} Returns `array`.
*/
function arrayEach(array, iteratee) {
var index = -1,
length = array == null ? 0 : array.length;
while (++index < length) {
if (iteratee(array[index], index, array) === false) {
break;
}
}
return array;
}
/**
* A specialized version of `_.forEachRight` for arrays without support for
* iteratee shorthands.
*
* @private
* @param {Array} [array] The array to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @returns {Array} Returns `array`.
*/
function arrayEachRight(array, iteratee) {
var length = array == null ? 0 : array.length;
while (length--) {
if (iteratee(array[length], length, array) === false) {
break;
}
}
return array;
}
/**
* A specialized version of `_.every` for arrays without support for
* iteratee shorthands.
*
* @private
* @param {Array} [array] The array to iterate over.
* @param {Function} predicate The function invoked per iteration.
* @returns {boolean} Returns `true` if all elements pass the predicate check,
* else `false`.
*/
function arrayEvery(array, predicate) {
var index = -1,
length = array == null ? 0 : array.length;
while (++index < length) {
if (!predicate(array[index], index, array)) {
return false;
}
}
return true;
}
/**
* A specialized version of `_.filter` for arrays without support for
* iteratee shorthands.
*
* @private
* @param {Array} [array] The array to iterate over.
* @param {Function} predicate The function invoked per iteration.
* @returns {Array} Returns the new filtered array.
*/
function arrayFilter(array, predicate) {
var index = -1,
length = array == null ? 0 : array.length,
resIndex = 0,
result = [];
while (++index < length) {
var value = array[index];
if (predicate(value, index, array)) {
result[resIndex++] = value;
}
}
return result;
}
/**
* A specialized version of `_.includes` for arrays without support for
* specifying an index to search from.
*
* @private
* @param {Array} [array] The array to inspect.
* @param {*} target The value to search for.
* @returns {boolean} Returns `true` if `target` is found, else `false`.
*/
function arrayIncludes(array, value) {
var length = array == null ? 0 : array.length;
return !!length && baseIndexOf(array, value, 0) > -1;
}
/**
* This function is like `arrayIncludes` except that it accepts a comparator.
*
* @private
* @param {Array} [array] The array to inspect.
* @param {*} target The value to search for.
* @param {Function} comparator The comparator invoked per element.
* @returns {boolean} Returns `true` if `target` is found, else `false`.
*/
function arrayIncludesWith(array, value, comparator) {
var index = -1,
length = array == null ? 0 : array.length;
while (++index < length) {
if (comparator(value, array[index])) {
return true;
}
}
return false;
}
/**
* A specialized version of `_.map` for arrays without support for iteratee
* shorthands.
*
* @private
* @param {Array} [array] The array to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @returns {Array} Returns the new mapped array.
*/
function arrayMap(array, iteratee) {
var index = -1,
length = array == null ? 0 : array.length,
result = Array(length);
while (++index < length) {
result[index] = iteratee(array[index], index, array);
}
return result;
}
/**
* Appends the elements of `values` to `array`.
*
* @private
* @param {Array} array The array to modify.
* @param {Array} values The values to append.
* @returns {Array} Returns `array`.
*/
function arrayPush(array, values) {
var index = -1,
length = values.length,
offset = array.length;
while (++index < length) {
array[offset + index] = values[index];
}
return array;
}
/**
* A specialized version of `_.reduce` for arrays without support for
* iteratee shorthands.
*
* @private
* @param {Array} [array] The array to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @param {*} [accumulator] The initial value.
* @param {boolean} [initAccum] Specify using the first element of `array` as
* the initial value.
* @returns {*} Returns the accumulated value.
*/
function arrayReduce(array, iteratee, accumulator, initAccum) {
var index = -1,
length = array == null ? 0 : array.length;
if (initAccum && length) {
accumulator = array[++index];
}
while (++index < length) {
accumulator = iteratee(accumulator, array[index], index, array);
}
return accumulator;
}
/**
* A specialized version of `_.reduceRight` for arrays without support for
* iteratee shorthands.
*
* @private
* @param {Array} [array] The array to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @param {*} [accumulator] The initial value.
* @param {boolean} [initAccum] Specify using the last element of `array` as
* the initial value.
* @returns {*} Returns the accumulated value.
*/
function arrayReduceRight(array, iteratee, accumulator, initAccum) {
var length = array == null ? 0 : array.length;
if (initAccum && length) {
accumulator = array[--length];
}
while (length--) {
accumulator = iteratee(accumulator, array[length], length, array);
}
return accumulator;
}
/**
* A specialized version of `_.some` for arrays without support for iteratee
* shorthands.
*
* @private
* @param {Array} [array] The array to iterate over.
* @param {Function} predicate The function invoked per iteration.
* @returns {boolean} Returns `true` if any element passes the predicate check,
* else `false`.
*/
function arraySome(array, predicate) {
var index = -1,
length = array == null ? 0 : array.length;
while (++index < length) {
if (predicate(array[index], index, array)) {
return true;
}
}
return false;
}
/**
* Gets the size of an ASCII `string`.
*
* @private
* @param {string} string The string inspect.
* @returns {number} Returns the string size.
*/
var asciiSize = baseProperty('length');
/**
* Converts an ASCII `string` to an array.
*
* @private
* @param {string} string The string to convert.
* @returns {Array} Returns the converted array.
*/
function asciiToArray(string) {
return string.split('');
}
/**
* Splits an ASCII `string` into an array of its words.
*
* @private
* @param {string} The string to inspect.
* @returns {Array} Returns the words of `string`.
*/
function asciiWords(string) {
return string.match(reAsciiWord) || [];
}
/**
* The base implementation of methods like `_.findKey` and `_.findLastKey`,
* without support for iteratee shorthands, which iterates over `collection`
* using `eachFunc`.
*
* @private
* @param {Array|Object} collection The collection to inspect.
* @param {Function} predicate The function invoked per iteration.
* @param {Function} eachFunc The function to iterate over `collection`.
* @returns {*} Returns the found element or its key, else `undefined`.
*/
function baseFindKey(collection, predicate, eachFunc) {
var result;
eachFunc(collection, function(value, key, collection) {
if (predicate(value, key, collection)) {
result = key;
return false;
}
});
return result;
}
/**
* The base implementation of `_.findIndex` and `_.findLastIndex` without
* support for iteratee shorthands.
*
* @private
* @param {Array} array The array to inspect.
* @param {Function} predicate The function invoked per iteration.
* @param {number} fromIndex The index to search from.
* @param {boolean} [fromRight] Specify iterating from right to left.
* @returns {number} Returns the index of the matched value, else `-1`.
*/
function baseFindIndex(array, predicate, fromIndex, fromRight) {
var length = array.length,
index = fromIndex + (fromRight ? 1 : -1);
while ((fromRight ? index-- : ++index < length)) {
if (predicate(array[index], index, array)) {
return index;
}
}
return -1;
}
/**
* The base implementation of `_.indexOf` without `fromIndex` bounds checks.
*
* @private
* @param {Array} array The array to inspect.
* @param {*} value The value to search for.
* @param {number} fromIndex The index to search from.
* @returns {number} Returns the index of the matched value, else `-1`.
*/
function baseIndexOf(array, value, fromIndex) {
return value === value
? strictIndexOf(array, value, fromIndex)
: baseFindIndex(array, baseIsNaN, fromIndex);
}
/**
* This function is like `baseIndexOf` except that it accepts a comparator.
*
* @private
* @param {Array} array The array to inspect.
* @param {*} value The value to search for.
* @param {number} fromIndex The index to search from.
* @param {Function} comparator The comparator invoked per element.
* @returns {number} Returns the index of the matched value, else `-1`.
*/
function baseIndexOfWith(array, value, fromIndex, comparator) {
var index = fromIndex - 1,
length = array.length;
while (++index < length) {
if (comparator(array[index], value)) {
return index;
}
}
return -1;
}
/**
* The base implementation of `_.isNaN` without support for number objects.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
*/
function baseIsNaN(value) {
return value !== value;
}
/**
* The base implementation of `_.mean` and `_.meanBy` without support for
* iteratee shorthands.
*
* @private
* @param {Array} array The array to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @returns {number} Returns the mean.
*/
function baseMean(array, iteratee) {
var length = array == null ? 0 : array.length;
return length ? (baseSum(array, iteratee) / length) : NAN;
}
/**
* The base implementation of `_.property` without support for deep paths.
*
* @private
* @param {string} key The key of the property to get.
* @returns {Function} Returns the new accessor function.
*/
function baseProperty(key) {
return function(object) {
return object == null ? undefined : object[key];
};
}
/**
* The base implementation of `_.propertyOf` without support for deep paths.
*
* @private
* @param {Object} object The object to query.
* @returns {Function} Returns the new accessor function.
*/
function basePropertyOf(object) {
return function(key) {
return object == null ? undefined : object[key];
};
}
/**
* The base implementation of `_.reduce` and `_.reduceRight`, without support
* for iteratee shorthands, which iterates over `collection` using `eachFunc`.
*
* @private
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @param {*} accumulator The initial value.
* @param {boolean} initAccum Specify using the first or last element of
* `collection` as the initial value.
* @param {Function} eachFunc The function to iterate over `collection`.
* @returns {*} Returns the accumulated value.
*/
function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) {
eachFunc(collection, function(value, index, collection) {
accumulator = initAccum
? (initAccum = false, value)
: iteratee(accumulator, value, index, collection);
});
return accumulator;
}
/**
* The base implementation of `_.sortBy` which uses `comparer` to define the
* sort order of `array` and replaces criteria objects with their corresponding
* values.
*
* @private
* @param {Array} array The array to sort.
* @param {Function} comparer The function to define sort order.
* @returns {Array} Returns `array`.
*/
function baseSortBy(array, comparer) {
var length = array.length;
array.sort(comparer);
while (length--) {
array[length] = array[length].value;
}
return array;
}
/**
* The base implementation of `_.sum` and `_.sumBy` without support for
* iteratee shorthands.
*
* @private
* @param {Array} array The array to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @returns {number} Returns the sum.
*/
function baseSum(array, iteratee) {
var result,
index = -1,
length = array.length;
while (++index < length) {
var current = iteratee(array[index]);
if (current !== undefined) {
result = result === undefined ? current : (result + current);
}
}
return result;
}
/**
* The base implementation of `_.times` without support for iteratee shorthands
* or max array length checks.
*
* @private
* @param {number} n The number of times to invoke `iteratee`.
* @param {Function} iteratee The function invoked per iteration.
* @returns {Array} Returns the array of results.
*/
function baseTimes(n, iteratee) {
var index = -1,
result = Array(n);
while (++index < n) {
result[index] = iteratee(index);
}
return result;
}
/**
* The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array
* of key-value pairs for `object` corresponding to the property names of `props`.
*
* @private
* @param {Object} object The object to query.
* @param {Array} props The property names to get values for.
* @returns {Object} Returns the key-value pairs.
*/
function baseToPairs(object, props) {
return arrayMap(props, function(key) {
return [key, object[key]];
});
}
/**
* The base implementation of `_.unary` without support for storing metadata.
*
* @private
* @param {Function} func The function to cap arguments for.
* @returns {Function} Returns the new capped function.
*/
function baseUnary(func) {
return function(value) {
return func(value);
};
}
/**
* The base implementation of `_.values` and `_.valuesIn` which creates an
* array of `object` property values corresponding to the property names
* of `props`.
*
* @private
* @param {Object} object The object to query.
* @param {Array} props The property names to get values for.
* @returns {Object} Returns the array of property values.
*/
function baseValues(object, props) {
return arrayMap(props, function(key) {
return object[key];
});
}
/**
* Checks if a `cache` value for `key` exists.
*
* @private
* @param {Object} cache The cache to query.
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
function cacheHas(cache, key) {
return cache.has(key);
}
/**
* Used by `_.trim` and `_.trimStart` to get the index of the first string symbol
* that is not found in the character symbols.
*
* @private
* @param {Array} strSymbols The string symbols to inspect.
* @param {Array} chrSymbols The character symbols to find.
* @returns {number} Returns the index of the first unmatched string symbol.
*/
function charsStartIndex(strSymbols, chrSymbols) {
var index = -1,
length = strSymbols.length;
while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
return index;
}
/**
* Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol
* that is not found in the character symbols.
*
* @private
* @param {Array} strSymbols The string symbols to inspect.
* @param {Array} chrSymbols The character symbols to find.
* @returns {number} Returns the index of the last unmatched string symbol.
*/
function charsEndIndex(strSymbols, chrSymbols) {
var index = strSymbols.length;
while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
return index;
}
/**
* Gets the number of `placeholder` occurrences in `array`.
*
* @private
* @param {Array} array The array to inspect.
* @param {*} placeholder The placeholder to search for.
* @returns {number} Returns the placeholder count.
*/
function countHolders(array, placeholder) {
var length = array.length,
result = 0;
while (length--) {
if (array[length] === placeholder) {
++result;
}
}
return result;
}
/**
* Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A
* letters to basic Latin letters.
*
* @private
* @param {string} letter The matched letter to deburr.
* @returns {string} Returns the deburred letter.
*/
var deburrLetter = basePropertyOf(deburredLetters);
/**
* Used by `_.escape` to convert characters to HTML entities.
*
* @private
* @param {string} chr The matched character to escape.
* @returns {string} Returns the escaped character.
*/
var escapeHtmlChar = basePropertyOf(htmlEscapes);
/**
* Used by `_.template` to escape characters for inclusion in compiled string literals.
*
* @private
* @param {string} chr The matched character to escape.
* @returns {string} Returns the escaped character.
*/
function escapeStringChar(chr) {
return '\\' + stringEscapes[chr];
}
/**
* Gets the value at `key` of `object`.
*
* @private
* @param {Object} [object] The object to query.
* @param {string} key The key of the property to get.
* @returns {*} Returns the property value.
*/
function getValue(object, key) {
return object == null ? undefined : object[key];
}
/**
* Checks if `string` contains Unicode symbols.
*
* @private
* @param {string} string The string to inspect.
* @returns {boolean} Returns `true` if a symbol is found, else `false`.
*/
function hasUnicode(string) {
return reHasUnicode.test(string);
}
/**
* Checks if `string` contains a word composed of Unicode symbols.
*
* @private
* @param {string} string The string to inspect.
* @returns {boolean} Returns `true` if a word is found, else `false`.
*/
function hasUnicodeWord(string) {
return reHasUnicodeWord.test(string);
}
/**
* Converts `iterator` to an array.
*
* @private
* @param {Object} iterator The iterator to convert.
* @returns {Array} Returns the converted array.
*/
function iteratorToArray(iterator) {
var data,
result = [];
while (!(data = iterator.next()).done) {
result.push(data.value);
}
return result;
}
/**
* Converts `map` to its key-value pairs.
*
* @private
* @param {Object} map The map to convert.
* @returns {Array} Returns the key-value pairs.
*/
function mapToArray(map) {
var index = -1,
result = Array(map.size);
map.forEach(function(value, key) {
result[++index] = [key, value];
});
return result;
}
/**
* Creates a unary function that invokes `func` with its argument transformed.
*
* @private
* @param {Function} func The function to wrap.
* @param {Function} transform The argument transform.
* @returns {Function} Returns the new function.
*/
function overArg(func, transform) {
return function(arg) {
return func(transform(arg));
};
}
/**
* Replaces all `placeholder` elements in `array` with an internal placeholder
* and returns an array of their indexes.
*
* @private
* @param {Array} array The array to modify.
* @param {*} placeholder The placeholder to replace.
* @returns {Array} Returns the new array of placeholder indexes.
*/
function replaceHolders(array, placeholder) {
var index = -1,
length = array.length,
resIndex = 0,
result = [];
while (++index < length) {
var value = array[index];
if (value === placeholder || value === PLACEHOLDER) {
array[index] = PLACEHOLDER;
result[resIndex++] = index;
}
}
return result;
}
/**
* Converts `set` to an array of its values.
*
* @private
* @param {Object} set The set to convert.
* @returns {Array} Returns the values.
*/
function setToArray(set) {
var index = -1,
result = Array(set.size);
set.forEach(function(value) {
result[++index] = value;
});
return result;
}
/**
* Converts `set` to its value-value pairs.
*
* @private
* @param {Object} set The set to convert.
* @returns {Array} Returns the value-value pairs.
*/
function setToPairs(set) {
var index = -1,
result = Array(set.size);
set.forEach(function(value) {
result[++index] = [value, value];
});
return result;
}
/**
* A specialized version of `_.indexOf` which performs strict equality
* comparisons of values, i.e. `===`.
*
* @private
* @param {Array} array The array to inspect.
* @param {*} value The value to search for.
* @param {number} fromIndex The index to search from.
* @returns {number} Returns the index of the matched value, else `-1`.
*/
function strictIndexOf(array, value, fromIndex) {
var index = fromIndex - 1,
length = array.length;
while (++index < length) {
if (array[index] === value) {
return index;
}
}
return -1;
}
/**
* A specialized version of `_.lastIndexOf` which performs strict equality
* comparisons of values, i.e. `===`.
*
* @private
* @param {Array} array The array to inspect.
* @param {*} value The value to search for.
* @param {number} fromIndex The index to search from.
* @returns {number} Returns the index of the matched value, else `-1`.
*/
function strictLastIndexOf(array, value, fromIndex) {
var index = fromIndex + 1;
while (index--) {
if (array[index] === value) {
return index;
}
}
return index;
}
/**
* Gets the number of symbols in `string`.
*
* @private
* @param {string} string The string to inspect.
* @returns {number} Returns the string size.
*/
function stringSize(string) {
return hasUnicode(string)
? unicodeSize(string)
: asciiSize(string);
}
/**
* Converts `string` to an array.
*
* @private
* @param {string} string The string to convert.
* @returns {Array} Returns the converted array.
*/
function stringToArray(string) {
return hasUnicode(string)
? unicodeToArray(string)
: asciiToArray(string);
}
/**
* Used by `_.unescape` to convert HTML entities to characters.
*
* @private
* @param {string} chr The matched character to unescape.
* @returns {string} Returns the unescaped character.
*/
var unescapeHtmlChar = basePropertyOf(htmlUnescapes);
/**
* Gets the size of a Unicode `string`.
*
* @private
* @param {string} string The string inspect.
* @returns {number} Returns the string size.
*/
function unicodeSize(string) {
var result = reUnicode.lastIndex = 0;
while (reUnicode.test(string)) {
++result;
}
return result;
}
/**
* Converts a Unicode `string` to an array.
*
* @private
* @param {string} string The string to convert.
* @returns {Array} Returns the converted array.
*/
function unicodeToArray(string) {
return string.match(reUnicode) || [];
}
/**
* Splits a Unicode `string` into an array of its words.
*
* @private
* @param {string} The string to inspect.
* @returns {Array} Returns the words of `string`.
*/
function unicodeWords(string) {
return string.match(reUnicodeWord) || [];
}
/*--------------------------------------------------------------------------*/
/**
* Create a new pristine `lodash` function using the `context` object.
*
* @static
* @memberOf _
* @since 1.1.0
* @category Util
* @param {Object} [context=root] The context object.
* @returns {Function} Returns a new `lodash` function.
* @example
*
* _.mixin({ 'foo': _.constant('foo') });
*
* var lodash = _.runInContext();
* lodash.mixin({ 'bar': lodash.constant('bar') });
*
* _.isFunction(_.foo);
* // => true
* _.isFunction(_.bar);
* // => false
*
* lodash.isFunction(lodash.foo);
* // => false
* lodash.isFunction(lodash.bar);
* // => true
*
* // Create a suped-up `defer` in Node.js.
* var defer = _.runInContext({ 'setTimeout': setImmediate }).defer;
*/
var runInContext = (function runInContext(context) {
context = context == null ? root : _.defaults(root.Object(), context, _.pick(root, contextProps));
/** Built-in constructor references. */
var Array = context.Array,
Date = context.Date,
Error = context.Error,
Function = context.Function,
Math = context.Math,
Object = context.Object,
RegExp = context.RegExp,
String = context.String,
TypeError = context.TypeError;
/** Used for built-in method references. */
var arrayProto = Array.prototype,
funcProto = Function.prototype,
objectProto = Object.prototype;
/** Used to detect overreaching core-js shims. */
var coreJsData = context['__core-js_shared__'];
/** Used to resolve the decompiled source of functions. */
var funcToString = funcProto.toString;
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;
/** Used to generate unique IDs. */
var idCounter = 0;
/** Used to detect methods masquerading as native. */
var maskSrcKey = (function() {
var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
return uid ? ('Symbol(src)_1.' + uid) : '';
}());
/**
* Used to resolve the
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
* of values.
*/
var nativeObjectToString = objectProto.toString;
/** Used to infer the `Object` constructor. */
var objectCtorString = funcToString.call(Object);
/** Used to restore the original `_` reference in `_.noConflict`. */
var oldDash = root._;
/** Used to detect if a method is native. */
var reIsNative = RegExp('^' +
funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
.replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
);
/** Built-in value references. */
var Buffer = moduleExports ? context.Buffer : undefined,
Symbol = context.Symbol,
Uint8Array = context.Uint8Array,
allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined,
getPrototype = overArg(Object.getPrototypeOf, Object),
objectCreate = Object.create,
propertyIsEnumerable = objectProto.propertyIsEnumerable,
splice = arrayProto.splice,
spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined,
symIterator = Symbol ? Symbol.iterator : undefined,
symToStringTag = Symbol ? Symbol.toStringTag : undefined;
var defineProperty = (function() {
try {
var func = getNative(Object, 'defineProperty');
func({}, '', {});
return func;
} catch (e) {}
}());
/** Mocked built-ins. */
var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout,
ctxNow = Date && Date.now !== root.Date.now && Date.now,
ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout;
/* Built-in method references for those with the same name as other `lodash` methods. */
var nativeCeil = Math.ceil,
nativeFloor = Math.floor,
nativeGetSymbols = Object.getOwnPropertySymbols,
nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined,
nativeIsFinite = context.isFinite,
nativeJoin = arrayProto.join,
nativeKeys = overArg(Object.keys, Object),
nativeMax = Math.max,
nativeMin = Math.min,
nativeNow = Date.now,
nativeParseInt = context.parseInt,
nativeRandom = Math.random,
nativeReverse = arrayProto.reverse;
/* Built-in method references that are verified to be native. */
var DataView = getNative(context, 'DataView'),
Map = getNative(context, 'Map'),
Promise = getNative(context, 'Promise'),
Set = getNative(context, 'Set'),
WeakMap = getNative(context, 'WeakMap'),
nativeCreate = getNative(Object, 'create');
/** Used to store function metadata. */
var metaMap = WeakMap && new WeakMap;
/** Used to lookup unminified function names. */
var realNames = {};
/** Used to detect maps, sets, and weakmaps. */
var dataViewCtorString = toSource(DataView),
mapCtorString = toSource(Map),
promiseCtorString = toSource(Promise),
setCtorString = toSource(Set),
weakMapCtorString = toSource(WeakMap);
/** Used to convert symbols to primitives and strings. */
var symbolProto = Symbol ? Symbol.prototype : undefined,
symbolValueOf = symbolProto ? symbolProto.valueOf : undefined,
symbolToString = symbolProto ? symbolProto.toString : undefined;
/*------------------------------------------------------------------------*/
/**
* Creates a `lodash` object which wraps `value` to enable implicit method
* chain sequences. Methods that operate on and return arrays, collections,
* and functions can be chained together. Methods that retrieve a single value
* or may return a primitive value will automatically end the chain sequence
* and return the unwrapped value. Otherwise, the value must be unwrapped
* with `_#value`.
*
* Explicit chain sequences, which must be unwrapped with `_#value`, may be
* enabled using `_.chain`.
*
* The execution of chained methods is lazy, that is, it's deferred until
* `_#value` is implicitly or explicitly called.
*
* Lazy evaluation allows several methods to support shortcut fusion.
* Shortcut fusion is an optimization to merge iteratee calls; this avoids
* the creation of intermediate arrays and can greatly reduce the number of
* iteratee executions. Sections of a chain sequence qualify for shortcut
* fusion if the section is applied to an array and iteratees accept only
* one argument. The heuristic for whether a section qualifies for shortcut
* fusion is subject to change.
*
* Chaining is supported in custom builds as long as the `_#value` method is
* directly or indirectly included in the build.
*
* In addition to lodash methods, wrappers have `Array` and `String` methods.
*
* The wrapper `Array` methods are:
* `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift`
*
* The wrapper `String` methods are:
* `replace` and `split`
*
* The wrapper methods that support shortcut fusion are:
* `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`,
* `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`,
* `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray`
*
* The chainable wrapper methods are:
* `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`,
* `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`,
* `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`,
* `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`,
* `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`,
* `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`,
* `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`,
* `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`,
* `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`,
* `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`,
* `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`,
* `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`,
* `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`,
* `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`,
* `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`,
* `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`,
* `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`,
* `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`,
* `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`,
* `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`,
* `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`,
* `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`,
* `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`,
* `zipObject`, `zipObjectDeep`, and `zipWith`
*
* The wrapper methods that are **not** chainable by default are:
* `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`,
* `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`,
* `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`,
* `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`,
* `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`,
* `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`,
* `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`,
* `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`,
* `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`,
* `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`,
* `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`,
* `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`,
* `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`,
* `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`,
* `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`,
* `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`,
* `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`,
* `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`,
* `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`,
* `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`,
* `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`,
* `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`,
* `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`,
* `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`,
* `upperFirst`, `value`, and `words`
*
* @name _
* @constructor
* @category Seq
* @param {*} value The value to wrap in a `lodash` instance.
* @returns {Object} Returns the new `lodash` wrapper instance.
* @example
*
* function square(n) {
* return n * n;
* }
*
* var wrapped = _([1, 2, 3]);
*
* // Returns an unwrapped value.
* wrapped.reduce(_.add);
* // => 6
*
* // Returns a wrapped value.
* var squares = wrapped.map(square);
*
* _.isArray(squares);
* // => false
*
* _.isArray(squares.value());
* // => true
*/
function lodash(value) {
if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) {
if (value instanceof LodashWrapper) {
return value;
}
if (hasOwnProperty.call(value, '__wrapped__')) {
return wrapperClone(value);
}
}
return new LodashWrapper(value);
}
/**
* The base implementation of `_.create` without support for assigning
* properties to the created object.
*
* @private
* @param {Object} proto The object to inherit from.
* @returns {Object} Returns the new object.
*/
var baseCreate = (function() {
function object() {}
return function(proto) {
if (!isObject(proto)) {
return {};
}
if (objectCreate) {
return objectCreate(proto);
}
object.prototype = proto;
var result = new object;
object.prototype = undefined;
return result;
};
}());
/**
* The function whose prototype chain sequence wrappers inherit from.
*
* @private
*/
function baseLodash() {
// No operation performed.
}
/**
* The base constructor for creating `lodash` wrapper objects.
*
* @private
* @param {*} value The value to wrap.
* @param {boolean} [chainAll] Enable explicit method chain sequences.
*/
function LodashWrapper(value, chainAll) {
this.__wrapped__ = value;
this.__actions__ = [];
this.__chain__ = !!chainAll;
this.__index__ = 0;
this.__values__ = undefined;
}
/**
* By default, the template delimiters used by lodash are like those in
* embedded Ruby (ERB) as well as ES2015 template strings. Change the
* following template settings to use alternative delimiters.
*
* @static
* @memberOf _
* @type {Object}
*/
lodash.templateSettings = {
/**
* Used to detect `data` property values to be HTML-escaped.
*
* @memberOf _.templateSettings
* @type {RegExp}
*/
'escape': reEscape,
/**
* Used to detect code to be evaluated.
*
* @memberOf _.templateSettings
* @type {RegExp}
*/
'evaluate': reEvaluate,
/**
* Used to detect `data` property values to inject.
*
* @memberOf _.templateSettings
* @type {RegExp}
*/
'interpolate': reInterpolate,
/**
* Used to reference the data object in the template text.
*
* @memberOf _.templateSettings
* @type {string}
*/
'variable': '',
/**
* Used to import variables into the compiled template.
*
* @memberOf _.templateSettings
* @type {Object}
*/
'imports': {
/**
* A reference to the `lodash` function.
*
* @memberOf _.templateSettings.imports
* @type {Function}
*/
'_': lodash
}
};
// Ensure wrappers are instances of `baseLodash`.
lodash.prototype = baseLodash.prototype;
lodash.prototype.constructor = lodash;
LodashWrapper.prototype = baseCreate(baseLodash.prototype);
LodashWrapper.prototype.constructor = LodashWrapper;
/*------------------------------------------------------------------------*/
/**
* Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
*
* @private
* @constructor
* @param {*} value The value to wrap.
*/
function LazyWrapper(value) {
this.__wrapped__ = value;
this.__actions__ = [];
this.__dir__ = 1;
this.__filtered__ = false;
this.__iteratees__ = [];
this.__takeCount__ = MAX_ARRAY_LENGTH;
this.__views__ = [];
}
/**
* Creates a clone of the lazy wrapper object.
*
* @private
* @name clone
* @memberOf LazyWrapper
* @returns {Object} Returns the cloned `LazyWrapper` object.
*/
function lazyClone() {
var result = new LazyWrapper(this.__wrapped__);
result.__actions__ = copyArray(this.__actions__);
result.__dir__ = this.__dir__;
result.__filtered__ = this.__filtered__;
result.__iteratees__ = copyArray(this.__iteratees__);
result.__takeCount__ = this.__takeCount__;
result.__views__ = copyArray(this.__views__);
return result;
}
/**
* Reverses the direction of lazy iteration.
*
* @private
* @name reverse
* @memberOf LazyWrapper
* @returns {Object} Returns the new reversed `LazyWrapper` object.
*/
function lazyReverse() {
if (this.__filtered__) {
var result = new LazyWrapper(this);
result.__dir__ = -1;
result.__filtered__ = true;
} else {
result = this.clone();
result.__dir__ *= -1;
}
return result;
}
/**
* Extracts the unwrapped value from its lazy wrapper.
*
* @private
* @name value
* @memberOf LazyWrapper
* @returns {*} Returns the unwrapped value.
*/
function lazyValue() {
var array = this.__wrapped__.value(),
dir = this.__dir__,
isArr = isArray(array),
isRight = dir < 0,
arrLength = isArr ? array.length : 0,
view = getView(0, arrLength, this.__views__),
start = view.start,
end = view.end,
length = end - start,
index = isRight ? end : (start - 1),
iteratees = this.__iteratees__,
iterLength = iteratees.length,
resIndex = 0,
takeCount = nativeMin(length, this.__takeCount__);
if (!isArr || (!isRight && arrLength == length && takeCount == length)) {
return baseWrapperValue(array, this.__actions__);
}
var result = [];
outer:
while (length-- && resIndex < takeCount) {
index += dir;
var iterIndex = -1,
value = array[index];
while (++iterIndex < iterLength) {
var data = iteratees[iterIndex],
iteratee = data.iteratee,
type = data.type,
computed = iteratee(value);
if (type == LAZY_MAP_FLAG) {
value = computed;
} else if (!computed) {
if (type == LAZY_FILTER_FLAG) {
continue outer;
} else {
break outer;
}
}
}
result[resIndex++] = value;
}
return result;
}
// Ensure `LazyWrapper` is an instance of `baseLodash`.
LazyWrapper.prototype = baseCreate(baseLodash.prototype);
LazyWrapper.prototype.constructor = LazyWrapper;
/*------------------------------------------------------------------------*/
/**
* Creates a hash object.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function Hash(entries) {
var index = -1,
length = entries == null ? 0 : entries.length;
this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
}
/**
* Removes all key-value entries from the hash.
*
* @private
* @name clear
* @memberOf Hash
*/
function hashClear() {
this.__data__ = nativeCreate ? nativeCreate(null) : {};
this.size = 0;
}
/**
* Removes `key` and its value from the hash.
*
* @private
* @name delete
* @memberOf Hash
* @param {Object} hash The hash to modify.
* @param {string} key The key of the value to remove.
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
function hashDelete(key) {
var result = this.has(key) && delete this.__data__[key];
this.size -= result ? 1 : 0;
return result;
}
/**
* Gets the hash value for `key`.
*
* @private
* @name get
* @memberOf Hash
* @param {string} key The key of the value to get.
* @returns {*} Returns the entry value.
*/
function hashGet(key) {
var data = this.__data__;
if (nativeCreate) {
var result = data[key];
return result === HASH_UNDEFINED ? undefined : result;
}
return hasOwnProperty.call(data, key) ? data[key] : undefined;
}
/**
* Checks if a hash value for `key` exists.
*
* @private
* @name has
* @memberOf Hash
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
function hashHas(key) {
var data = this.__data__;
return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);
}
/**
* Sets the hash `key` to `value`.
*
* @private
* @name set
* @memberOf Hash
* @param {string} key The key of the value to set.
* @param {*} value The value to set.
* @returns {Object} Returns the hash instance.
*/
function hashSet(key, value) {
var data = this.__data__;
this.size += this.has(key) ? 0 : 1;
data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
return this;
}
// Add methods to `Hash`.
Hash.prototype.clear = hashClear;
Hash.prototype['delete'] = hashDelete;
Hash.prototype.get = hashGet;
Hash.prototype.has = hashHas;
Hash.prototype.set = hashSet;
/*------------------------------------------------------------------------*/
/**
* Creates an list cache object.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function ListCache(entries) {
var index = -1,
length = entries == null ? 0 : entries.length;
this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
}
/**
* Removes all key-value entries from the list cache.
*
* @private
* @name clear
* @memberOf ListCache
*/
function listCacheClear() {
this.__data__ = [];
this.size = 0;
}
/**
* Removes `key` and its value from the list cache.
*
* @private
* @name delete
* @memberOf ListCache
* @param {string} key The key of the value to remove.
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
function listCacheDelete(key) {
var data = this.__data__,
index = assocIndexOf(data, key);
if (index < 0) {
return false;
}
var lastIndex = data.length - 1;
if (index == lastIndex) {
data.pop();
} else {
splice.call(data, index, 1);
}
--this.size;
return true;
}
/**
* Gets the list cache value for `key`.
*
* @private
* @name get
* @memberOf ListCache
* @param {string} key The key of the value to get.
* @returns {*} Returns the entry value.
*/
function listCacheGet(key) {
var data = this.__data__,
index = assocIndexOf(data, key);
return index < 0 ? undefined : data[index][1];
}
/**
* Checks if a list cache value for `key` exists.
*
* @private
* @name has
* @memberOf ListCache
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
function listCacheHas(key) {
return assocIndexOf(this.__data__, key) > -1;
}
/**
* Sets the list cache `key` to `value`.
*
* @private
* @name set
* @memberOf ListCache
* @param {string} key The key of the value to set.
* @param {*} value The value to set.
* @returns {Object} Returns the list cache instance.
*/
function listCacheSet(key, value) {
var data = this.__data__,
index = assocIndexOf(data, key);
if (index < 0) {
++this.size;
data.push([key, value]);
} else {
data[index][1] = value;
}
return this;
}
// Add methods to `ListCache`.
ListCache.prototype.clear = listCacheClear;
ListCache.prototype['delete'] = listCacheDelete;
ListCache.prototype.get = listCacheGet;
ListCache.prototype.has = listCacheHas;
ListCache.prototype.set = listCacheSet;
/*------------------------------------------------------------------------*/
/**
* Creates a map cache object to store key-value pairs.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function MapCache(entries) {
var index = -1,
length = entries == null ? 0 : entries.length;
this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
}
/**
* Removes all key-value entries from the map.
*
* @private
* @name clear
* @memberOf MapCache
*/
function mapCacheClear() {
this.size = 0;
this.__data__ = {
'hash': new Hash,
'map': new (Map || ListCache),
'string': new Hash
};
}
/**
* Removes `key` and its value from the map.
*
* @private
* @name delete
* @memberOf MapCache
* @param {string} key The key of the value to remove.
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
function mapCacheDelete(key) {
var result = getMapData(this, key)['delete'](key);
this.size -= result ? 1 : 0;
return result;
}
/**
* Gets the map value for `key`.
*
* @private
* @name get
* @memberOf MapCache
* @param {string} key The key of the value to get.
* @returns {*} Returns the entry value.
*/
function mapCacheGet(key) {
return getMapData(this, key).get(key);
}
/**
* Checks if a map value for `key` exists.
*
* @private
* @name has
* @memberOf MapCache
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
function mapCacheHas(key) {
return getMapData(this, key).has(key);
}
/**
* Sets the map `key` to `value`.
*
* @private
* @name set
* @memberOf MapCache
* @param {string} key The key of the value to set.
* @param {*} value The value to set.
* @returns {Object} Returns the map cache instance.
*/
function mapCacheSet(key, value) {
var data = getMapData(this, key),
size = data.size;
data.set(key, value);
this.size += data.size == size ? 0 : 1;
return this;
}
// Add methods to `MapCache`.
MapCache.prototype.clear = mapCacheClear;
MapCache.prototype['delete'] = mapCacheDelete;
MapCache.prototype.get = mapCacheGet;
MapCache.prototype.has = mapCacheHas;
MapCache.prototype.set = mapCacheSet;
/*------------------------------------------------------------------------*/
/**
*
* Creates an array cache object to store unique values.
*
* @private
* @constructor
* @param {Array} [values] The values to cache.
*/
function SetCache(values) {
var index = -1,
length = values == null ? 0 : values.length;
this.__data__ = new MapCache;
while (++index < length) {
this.add(values[index]);
}
}
/**
* Adds `value` to the array cache.
*
* @private
* @name add
* @memberOf SetCache
* @alias push
* @param {*} value The value to cache.
* @returns {Object} Returns the cache instance.
*/
function setCacheAdd(value) {
this.__data__.set(value, HASH_UNDEFINED);
return this;
}
/**
* Checks if `value` is in the array cache.
*
* @private
* @name has
* @memberOf SetCache
* @param {*} value The value to search for.
* @returns {number} Returns `true` if `value` is found, else `false`.
*/
function setCacheHas(value) {
return this.__data__.has(value);
}
// Add methods to `SetCache`.
SetCache.prototype.add = SetCache.prototype.push = setCacheAdd;
SetCache.prototype.has = setCacheHas;
/*------------------------------------------------------------------------*/
/**
* Creates a stack cache object to store key-value pairs.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function Stack(entries) {
var data = this.__data__ = new ListCache(entries);
this.size = data.size;
}
/**
* Removes all key-value entries from the stack.
*
* @private
* @name clear
* @memberOf Stack
*/
function stackClear() {
this.__data__ = new ListCache;
this.size = 0;
}
/**
* Removes `key` and its value from the stack.
*
* @private
* @name delete
* @memberOf Stack
* @param {string} key The key of the value to remove.
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
function stackDelete(key) {
var data = this.__data__,
result = data['delete'](key);
this.size = data.size;
return result;
}
/**
* Gets the stack value for `key`.
*
* @private
* @name get
* @memberOf Stack
* @param {string} key The key of the value to get.
* @returns {*} Returns the entry value.
*/
function stackGet(key) {
return this.__data__.get(key);
}
/**
* Checks if a stack value for `key` exists.
*
* @private
* @name has
* @memberOf Stack
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
function stackHas(key) {
return this.__data__.has(key);
}
/**
* Sets the stack `key` to `value`.
*
* @private
* @name set
* @memberOf Stack
* @param {string} key The key of the value to set.
* @param {*} value The value to set.
* @returns {Object} Returns the stack cache instance.
*/
function stackSet(key, value) {
var data = this.__data__;
if (data instanceof ListCache) {
var pairs = data.__data__;
if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {
pairs.push([key, value]);
this.size = ++data.size;
return this;
}
data = this.__data__ = new MapCache(pairs);
}
data.set(key, value);
this.size = data.size;
return this;
}
// Add methods to `Stack`.
Stack.prototype.clear = stackClear;
Stack.prototype['delete'] = stackDelete;
Stack.prototype.get = stackGet;
Stack.prototype.has = stackHas;
Stack.prototype.set = stackSet;
/*------------------------------------------------------------------------*/
/**
* Creates an array of the enumerable property names of the array-like `value`.
*
* @private
* @param {*} value The value to query.
* @param {boolean} inherited Specify returning inherited property names.
* @returns {Array} Returns the array of property names.
*/
function arrayLikeKeys(value, inherited) {
var isArr = isArray(value),
isArg = !isArr && isArguments(value),
isBuff = !isArr && !isArg && isBuffer(value),
isType = !isArr && !isArg && !isBuff && isTypedArray(value),
skipIndexes = isArr || isArg || isBuff || isType,
result = skipIndexes ? baseTimes(value.length, String) : [],
length = result.length;
for (var key in value) {
if ((inherited || hasOwnProperty.call(value, key)) &&
!(skipIndexes && (
// Safari 9 has enumerable `arguments.length` in strict mode.
key == 'length' ||
// Node.js 0.10 has enumerable non-index properties on buffers.
(isBuff && (key == 'offset' || key == 'parent')) ||
// PhantomJS 2 has enumerable non-index properties on typed arrays.
(isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||
// Skip index properties.
isIndex(key, length)
))) {
result.push(key);
}
}
return result;
}
/**
* A specialized version of `_.sample` for arrays.
*
* @private
* @param {Array} array The array to sample.
* @returns {*} Returns the random element.
*/
function arraySample(array) {
var length = array.length;
return length ? array[baseRandom(0, length - 1)] : undefined;
}
/**
* A specialized version of `_.sampleSize` for arrays.
*
* @private
* @param {Array} array The array to sample.
* @param {number} n The number of elements to sample.
* @returns {Array} Returns the random elements.
*/
function arraySampleSize(array, n) {
return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length));
}
/**
* A specialized version of `_.shuffle` for arrays.
*
* @private
* @param {Array} array The array to shuffle.
* @returns {Array} Returns the new shuffled array.
*/
function arrayShuffle(array) {
return shuffleSelf(copyArray(array));
}
/**
* This function is like `assignValue` except that it doesn't assign
* `undefined` values.
*
* @private
* @param {Object} object The object to modify.
* @param {string} key The key of the property to assign.
* @param {*} value The value to assign.
*/
function assignMergeValue(object, key, value) {
if ((value !== undefined && !eq(object[key], value)) ||
(value === undefined && !(key in object))) {
baseAssignValue(object, key, value);
}
}
/**
* Assigns `value` to `key` of `object` if the existing value is not equivalent
* using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
* for equality comparisons.
*
* @private
* @param {Object} object The object to modify.
* @param {string} key The key of the property to assign.
* @param {*} value The value to assign.
*/
function assignValue(object, key, value) {
var objValue = object[key];
if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
(value === undefined && !(key in object))) {
baseAssignValue(object, key, value);
}
}
/**
* Gets the index at which the `key` is found in `array` of key-value pairs.
*
* @private
* @param {Array} array The array to inspect.
* @param {*} key The key to search for.
* @returns {number} Returns the index of the matched value, else `-1`.
*/
function assocIndexOf(array, key) {
var length = array.length;
while (length--) {
if (eq(array[length][0], key)) {
return length;
}
}
return -1;
}
/**
* Aggregates elements of `collection` on `accumulator` with keys transformed
* by `iteratee` and values set by `setter`.
*
* @private
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} setter The function to set `accumulator` values.
* @param {Function} iteratee The iteratee to transform keys.
* @param {Object} accumulator The initial aggregated object.
* @returns {Function} Returns `accumulator`.
*/
function baseAggregator(collection, setter, iteratee, accumulator) {
baseEach(collection, function(value, key, collection) {
setter(accumulator, value, iteratee(value), collection);
});
return accumulator;
}
/**
* The base implementation of `_.assign` without support for multiple sources
* or `customizer` functions.
*
* @private
* @param {Object} object The destination object.
* @param {Object} source The source object.
* @returns {Object} Returns `object`.
*/
function baseAssign(object, source) {
return object && copyObject(source, keys(source), object);
}
/**
* The base implementation of `_.assignIn` without support for multiple sources
* or `customizer` functions.
*
* @private
* @param {Object} object The destination object.
* @param {Object} source The source object.
* @returns {Object} Returns `object`.
*/
function baseAssignIn(object, source) {
return object && copyObject(source, keysIn(source), object);
}
/**
* The base implementation of `assignValue` and `assignMergeValue` without
* value checks.
*
* @private
* @param {Object} object The object to modify.
* @param {string} key The key of the property to assign.
* @param {*} value The value to assign.
*/
function baseAssignValue(object, key, value) {
if (key == '__proto__' && defineProperty) {
defineProperty(object, key, {
'configurable': true,
'enumerable': true,
'value': value,
'writable': true
});
} else {
object[key] = value;
}
}
/**
* The base implementation of `_.at` without support for individual paths.
*
* @private
* @param {Object} object The object to iterate over.
* @param {string[]} paths The property paths to pick.
* @returns {Array} Returns the picked elements.
*/
function baseAt(object, paths) {
var index = -1,
length = paths.length,
result = Array(length),
skip = object == null;
while (++index < length) {
result[index] = skip ? undefined : get(object, paths[index]);
}
return result;
}
/**
* The base implementation of `_.clamp` which doesn't coerce arguments.
*
* @private
* @param {number} number The number to clamp.
* @param {number} [lower] The lower bound.
* @param {number} upper The upper bound.
* @returns {number} Returns the clamped number.
*/
function baseClamp(number, lower, upper) {
if (number === number) {
if (upper !== undefined) {
number = number <= upper ? number : upper;
}
if (lower !== undefined) {
number = number >= lower ? number : lower;
}
}
return number;
}
/**
* The base implementation of `_.clone` and `_.cloneDeep` which tracks
* traversed objects.
*
* @private
* @param {*} value The value to clone.
* @param {boolean} bitmask The bitmask flags.
* 1 - Deep clone
* 2 - Flatten inherited properties
* 4 - Clone symbols
* @param {Function} [customizer] The function to customize cloning.
* @param {string} [key] The key of `value`.
* @param {Object} [object] The parent object of `value`.
* @param {Object} [stack] Tracks traversed objects and their clone counterparts.
* @returns {*} Returns the cloned value.
*/
function baseClone(value, bitmask, customizer, key, object, stack) {
var result,
isDeep = bitmask & CLONE_DEEP_FLAG,
isFlat = bitmask & CLONE_FLAT_FLAG,
isFull = bitmask & CLONE_SYMBOLS_FLAG;
if (customizer) {
result = object ? customizer(value, key, object, stack) : customizer(value);
}
if (result !== undefined) {
return result;
}
if (!isObject(value)) {
return value;
}
var isArr = isArray(value);
if (isArr) {
result = initCloneArray(value);
if (!isDeep) {
return copyArray(value, result);
}
} else {
var tag = getTag(value),
isFunc = tag == funcTag || tag == genTag;
if (isBuffer(value)) {
return cloneBuffer(value, isDeep);
}
if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
result = (isFlat || isFunc) ? {} : initCloneObject(value);
if (!isDeep) {
return isFlat
? copySymbolsIn(value, baseAssignIn(result, value))
: copySymbols(value, baseAssign(result, value));
}
} else {
if (!cloneableTags[tag]) {
return object ? value : {};
}
result = initCloneByTag(value, tag, isDeep);
}
}
// Check for circular references and return its corresponding clone.
stack || (stack = new Stack);
var stacked = stack.get(value);
if (stacked) {
return stacked;
}
stack.set(value, result);
if (isSet(value)) {
value.forEach(function(subValue) {
result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack));
});
return result;
}
if (isMap(value)) {
value.forEach(function(subValue, key) {
result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack));
});
return result;
}
var keysFunc = isFull
? (isFlat ? getAllKeysIn : getAllKeys)
: (isFlat ? keysIn : keys);
var props = isArr ? undefined : keysFunc(value);
arrayEach(props || value, function(subValue, key) {
if (props) {
key = subValue;
subValue = value[key];
}
// Recursively populate clone (susceptible to call stack limits).
assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));
});
return result;
}
/**
* The base implementation of `_.conforms` which doesn't clone `source`.
*
* @private
* @param {Object} source The object of property predicates to conform to.
* @returns {Function} Returns the new spec function.
*/
function baseConforms(source) {
var props = keys(source);
return function(object) {
return baseConformsTo(object, source, props);
};
}
/**
* The base implementation of `_.conformsTo` which accepts `props` to check.
*
* @private
* @param {Object} object The object to inspect.
* @param {Object} source The object of property predicates to conform to.
* @returns {boolean} Returns `true` if `object` conforms, else `false`.
*/
function baseConformsTo(object, source, props) {
var length = props.length;
if (object == null) {
return !length;
}
object = Object(object);
while (length--) {
var key = props[length],
predicate = source[key],
value = object[key];
if ((value === undefined && !(key in object)) || !predicate(value)) {
return false;
}
}
return true;
}
/**
* The base implementation of `_.delay` and `_.defer` which accepts `args`
* to provide to `func`.
*
* @private
* @param {Function} func The function to delay.
* @param {number} wait The number of milliseconds to delay invocation.
* @param {Array} args The arguments to provide to `func`.
* @returns {number|Object} Returns the timer id or timeout object.
*/
function baseDelay(func, wait, args) {
if (typeof func != 'function') {
throw new TypeError(FUNC_ERROR_TEXT);
}
return setTimeout(function() { func.apply(undefined, args); }, wait);
}
/**
* The base implementation of methods like `_.difference` without support
* for excluding multiple arrays or iteratee shorthands.
*
* @private
* @param {Array} array The array to inspect.
* @param {Array} values The values to exclude.
* @param {Function} [iteratee] The iteratee invoked per element.
* @param {Function} [comparator] The comparator invoked per element.
* @returns {Array} Returns the new array of filtered values.
*/
function baseDifference(array, values, iteratee, comparator) {
var index = -1,
includes = arrayIncludes,
isCommon = true,
length = array.length,
result = [],
valuesLength = values.length;
if (!length) {
return result;
}
if (iteratee) {
values = arrayMap(values, baseUnary(iteratee));
}
if (comparator) {
includes = arrayIncludesWith;
isCommon = false;
}
else if (values.length >= LARGE_ARRAY_SIZE) {
includes = cacheHas;
isCommon = false;
values = new SetCache(values);
}
outer:
while (++index < length) {
var value = array[index],
computed = iteratee == null ? value : iteratee(value);
value = (comparator || value !== 0) ? value : 0;
if (isCommon && computed === computed) {
var valuesIndex = valuesLength;
while (valuesIndex--) {
if (values[valuesIndex] === computed) {
continue outer;
}
}
result.push(value);
}
else if (!includes(values, computed, comparator)) {
result.push(value);
}
}
return result;
}
/**
* The base implementation of `_.forEach` without support for iteratee shorthands.
*
* @private
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @returns {Array|Object} Returns `collection`.
*/
var baseEach = createBaseEach(baseForOwn);
/**
* The base implementation of `_.forEachRight` without support for iteratee shorthands.
*
* @private
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @returns {Array|Object} Returns `collection`.
*/
var baseEachRight = createBaseEach(baseForOwnRight, true);
/**
* The base implementation of `_.every` without support for iteratee shorthands.
*
* @private
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} predicate The function invoked per iteration.
* @returns {boolean} Returns `true` if all elements pass the predicate check,
* else `false`
*/
function baseEvery(collection, predicate) {
var result = true;
baseEach(collection, function(value, index, collection) {
result = !!predicate(value, index, collection);
return result;
});
return result;
}
/**
* The base implementation of methods like `_.max` and `_.min` which accepts a
* `comparator` to determine the extremum value.
*
* @private
* @param {Array} array The array to iterate over.
* @param {Function} iteratee The iteratee invoked per iteration.
* @param {Function} comparator The comparator used to compare values.
* @returns {*} Returns the extremum value.
*/
function baseExtremum(array, iteratee, comparator) {
var index = -1,
length = array.length;
while (++index < length) {
var value = array[index],
current = iteratee(value);
if (current != null && (computed === undefined
? (current === current && !isSymbol(current))
: comparator(current, computed)
)) {
var computed = current,
result = value;
}
}
return result;
}
/**
* The base implementation of `_.fill` without an iteratee call guard.
*
* @private
* @param {Array} array The array to fill.
* @param {*} value The value to fill `array` with.
* @param {number} [start=0] The start position.
* @param {number} [end=array.length] The end position.
* @returns {Array} Returns `array`.
*/
function baseFill(array, value, start, end) {
var length = array.length;
start = toInteger(start);
if (start < 0) {
start = -start > length ? 0 : (length + start);
}
end = (end === undefined || end > length) ? length : toInteger(end);
if (end < 0) {
end += length;
}
end = start > end ? 0 : toLength(end);
while (start < end) {
array[start++] = value;
}
return array;
}
/**
* The base implementation of `_.filter` without support for iteratee shorthands.
*
* @private
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} predicate The function invoked per iteration.
* @returns {Array} Returns the new filtered array.
*/
function baseFilter(collection, predicate) {
var result = [];
baseEach(collection, function(value, index, collection) {
if (predicate(value, index, collection)) {
result.push(value);
}
});
return result;
}
/**
* The base implementation of `_.flatten` with support for restricting flattening.
*
* @private
* @param {Array} array The array to flatten.
* @param {number} depth The maximum recursion depth.
* @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
* @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
* @param {Array} [result=[]] The initial result value.
* @returns {Array} Returns the new flattened array.
*/
function baseFlatten(array, depth, predicate, isStrict, result) {
var index = -1,
length = array.length;
predicate || (predicate = isFlattenable);
result || (result = []);
while (++index < length) {
var value = array[index];
if (depth > 0 && predicate(value)) {
if (depth > 1) {
// Recursively flatten arrays (susceptible to call stack limits).
baseFlatten(value, depth - 1, predicate, isStrict, result);
} else {
arrayPush(result, value);
}
} else if (!isStrict) {
result[result.length] = value;
}
}
return result;
}
/**
* The base implementation of `baseForOwn` which iterates over `object`
* properties returned by `keysFunc` and invokes `iteratee` for each property.
* Iteratee functions may exit iteration early by explicitly returning `false`.
*
* @private
* @param {Object} object The object to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @param {Function} keysFunc The function to get the keys of `object`.
* @returns {Object} Returns `object`.
*/
var baseFor = createBaseFor();
/**
* This function is like `baseFor` except that it iterates over properties
* in the opposite order.
*
* @private
* @param {Object} object The object to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @param {Function} keysFunc The function to get the keys of `object`.
* @returns {Object} Returns `object`.
*/
var baseForRight = createBaseFor(true);
/**
* The base implementation of `_.forOwn` without support for iteratee shorthands.
*
* @private
* @param {Object} object The object to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @returns {Object} Returns `object`.
*/
function baseForOwn(object, iteratee) {
return object && baseFor(object, iteratee, keys);
}
/**
* The base implementation of `_.forOwnRight` without support for iteratee shorthands.
*
* @private
* @param {Object} object The object to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @returns {Object} Returns `object`.
*/
function baseForOwnRight(object, iteratee) {
return object && baseForRight(object, iteratee, keys);
}
/**
* The base implementation of `_.functions` which creates an array of
* `object` function property names filtered from `props`.
*
* @private
* @param {Object} object The object to inspect.
* @param {Array} props The property names to filter.
* @returns {Array} Returns the function names.
*/
function baseFunctions(object, props) {
return arrayFilter(props, function(key) {
return isFunction(object[key]);
});
}
/**
* The base implementation of `_.get` without support for default values.
*
* @private
* @param {Object} object The object to query.
* @param {Array|string} path The path of the property to get.
* @returns {*} Returns the resolved value.
*/
function baseGet(object, path) {
path = castPath(path, object);
var index = 0,
length = path.length;
while (object != null && index < length) {
object = object[toKey(path[index++])];
}
return (index && index == length) ? object : undefined;
}
/**
* The base implementation of `getAllKeys` and `getAllKeysIn` which uses
* `keysFunc` and `symbolsFunc` to get the enumerable property names and
* symbols of `object`.
*
* @private
* @param {Object} object The object to query.
* @param {Function} keysFunc The function to get the keys of `object`.
* @param {Function} symbolsFunc The function to get the symbols of `object`.
* @returns {Array} Returns the array of property names and symbols.
*/
function baseGetAllKeys(object, keysFunc, symbolsFunc) {
var result = keysFunc(object);
return isArray(object) ? result : arrayPush(result, symbolsFunc(object));
}
/**
* The base implementation of `getTag` without fallbacks for buggy environments.
*
* @private
* @param {*} value The value to query.
* @returns {string} Returns the `toStringTag`.
*/
function baseGetTag(value) {
if (value == null) {
return value === undefined ? undefinedTag : nullTag;
}
return (symToStringTag && symToStringTag in Object(value))
? getRawTag(value)
: objectToString(value);
}
/**
* The base implementation of `_.gt` which doesn't coerce arguments.
*
* @private
* @param {*} value The value to compare.
* @param {*} other The other value to compare.
* @returns {boolean} Returns `true` if `value` is greater than `other`,
* else `false`.
*/
function baseGt(value, other) {
return value > other;
}
/**
* The base implementation of `_.has` without support for deep paths.
*
* @private
* @param {Object} [object] The object to query.
* @param {Array|string} key The key to check.
* @returns {boolean} Returns `true` if `key` exists, else `false`.
*/
function baseHas(object, key) {
return object != null && hasOwnProperty.call(object, key);
}
/**
* The base implementation of `_.hasIn` without support for deep paths.
*
* @private
* @param {Object} [object] The object to query.
* @param {Array|string} key The key to check.
* @returns {boolean} Returns `true` if `key` exists, else `false`.
*/
function baseHasIn(object, key) {
return object != null && key in Object(object);
}
/**
* The base implementation of `_.inRange` which doesn't coerce arguments.
*
* @private
* @param {number} number The number to check.
* @param {number} start The start of the range.
* @param {number} end The end of the range.
* @returns {boolean} Returns `true` if `number` is in the range, else `false`.
*/
function baseInRange(number, start, end) {
return number >= nativeMin(start, end) && number < nativeMax(start, end);
}
/**
* The base implementation of methods like `_.intersection`, without support
* for iteratee shorthands, that accepts an array of arrays to inspect.
*
* @private
* @param {Array} arrays The arrays to inspect.
* @param {Function} [iteratee] The iteratee invoked per element.
* @param {Function} [comparator] The comparator invoked per element.
* @returns {Array} Returns the new array of shared values.
*/
function baseIntersection(arrays, iteratee, comparator) {
var includes = comparator ? arrayIncludesWith : arrayIncludes,
length = arrays[0].length,
othLength = arrays.length,
othIndex = othLength,
caches = Array(othLength),
maxLength = Infinity,
result = [];
while (othIndex--) {
var array = arrays[othIndex];
if (othIndex && iteratee) {
array = arrayMap(array, baseUnary(iteratee));
}
maxLength = nativeMin(array.length, maxLength);
caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))
? new SetCache(othIndex && array)
: undefined;
}
array = arrays[0];
var index = -1,
seen = caches[0];
outer:
while (++index < length && result.length < maxLength) {
var value = array[index],
computed = iteratee ? iteratee(value) : value;
value = (comparator || value !== 0) ? value : 0;
if (!(seen
? cacheHas(seen, computed)
: includes(result, computed, comparator)
)) {
othIndex = othLength;
while (--othIndex) {
var cache = caches[othIndex];
if (!(cache
? cacheHas(cache, computed)
: includes(arrays[othIndex], computed, comparator))
) {
continue outer;
}
}
if (seen) {
seen.push(computed);
}
result.push(value);
}
}
return result;
}
/**
* The base implementation of `_.invert` and `_.invertBy` which inverts
* `object` with values transformed by `iteratee` and set by `setter`.
*
* @private
* @param {Object} object The object to iterate over.
* @param {Function} setter The function to set `accumulator` values.
* @param {Function} iteratee The iteratee to transform values.
* @param {Object} accumulator The initial inverted object.
* @returns {Function} Returns `accumulator`.
*/
function baseInverter(object, setter, iteratee, accumulator) {
baseForOwn(object, function(value, key, object) {
setter(accumulator, iteratee(value), key, object);
});
return accumulator;
}
/**
* The base implementation of `_.invoke` without support for individual
* method arguments.
*
* @private
* @param {Object} object The object to query.
* @param {Array|string} path The path of the method to invoke.
* @param {Array} args The arguments to invoke the method with.
* @returns {*} Returns the result of the invoked method.
*/
function baseInvoke(object, path, args) {
path = castPath(path, object);
object = parent(object, path);
var func = object == null ? object : object[toKey(last(path))];
return func == null ? undefined : apply(func, object, args);
}
/**
* The base implementation of `_.isArguments`.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an `arguments` object,
*/
function baseIsArguments(value) {
return isObjectLike(value) && baseGetTag(value) == argsTag;
}
/**
* The base implementation of `_.isArrayBuffer` without Node.js optimizations.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
*/
function baseIsArrayBuffer(value) {
return isObjectLike(value) && baseGetTag(value) == arrayBufferTag;
}
/**
* The base implementation of `_.isDate` without Node.js optimizations.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a date object, else `false`.
*/
function baseIsDate(value) {
return isObjectLike(value) && baseGetTag(value) == dateTag;
}
/**
* The base implementation of `_.isEqual` which supports partial comparisons
* and tracks traversed objects.
*
* @private
* @param {*} value The value to compare.
* @param {*} other The other value to compare.
* @param {boolean} bitmask The bitmask flags.
* 1 - Unordered comparison
* 2 - Partial comparison
* @param {Function} [customizer] The function to customize comparisons.
* @param {Object} [stack] Tracks traversed `value` and `other` objects.
* @returns {boolean} Returns `true` if the values are equivalent, else `false`.
*/
function baseIsEqual(value, other, bitmask, customizer, stack) {
if (value === other) {
return true;
}
if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) {
return value !== value && other !== other;
}
return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);
}
/**
* A specialized version of `baseIsEqual` for arrays and objects which performs
* deep comparisons and tracks traversed objects enabling objects with circular
* references to be compared.
*
* @private
* @param {Object} object The object to compare.
* @param {Object} other The other object to compare.
* @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
* @param {Function} customizer The function to customize comparisons.
* @param {Function} equalFunc The function to determine equivalents of values.
* @param {Object} [stack] Tracks traversed `object` and `other` objects.
* @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
*/
function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {
var objIsArr = isArray(object),
othIsArr = isArray(other),
objTag = objIsArr ? arrayTag : getTag(object),
othTag = othIsArr ? arrayTag : getTag(other);
objTag = objTag == argsTag ? objectTag : objTag;
othTag = othTag == argsTag ? objectTag : othTag;
var objIsObj = objTag == objectTag,
othIsObj = othTag == objectTag,
isSameTag = objTag == othTag;
if (isSameTag && isBuffer(object)) {
if (!isBuffer(other)) {
return false;
}
objIsArr = true;
objIsObj = false;
}
if (isSameTag && !objIsObj) {
stack || (stack = new Stack);
return (objIsArr || isTypedArray(object))
? equalArrays(object, other, bitmask, customizer, equalFunc, stack)
: equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);
}
if (!(bitmask & COMPARE_PARTIAL_FLAG)) {
var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
if (objIsWrapped || othIsWrapped) {
var objUnwrapped = objIsWrapped ? object.value() : object,
othUnwrapped = othIsWrapped ? other.value() : other;
stack || (stack = new Stack);
return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);
}
}
if (!isSameTag) {
return false;
}
stack || (stack = new Stack);
return equalObjects(object, other, bitmask, customizer, equalFunc, stack);
}
/**
* The base implementation of `_.isMap` without Node.js optimizations.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a map, else `false`.
*/
function baseIsMap(value) {
return isObjectLike(value) && getTag(value) == mapTag;
}
/**
* The base implementation of `_.isMatch` without support for iteratee shorthands.
*
* @private
* @param {Object} object The object to inspect.
* @param {Object} source The object of property values to match.
* @param {Array} matchData The property names, values, and compare flags to match.
* @param {Function} [customizer] The function to customize comparisons.
* @returns {boolean} Returns `true` if `object` is a match, else `false`.
*/
function baseIsMatch(object, source, matchData, customizer) {
var index = matchData.length,
length = index,
noCustomizer = !customizer;
if (object == null) {
return !length;
}
object = Object(object);
while (index--) {
var data = matchData[index];
if ((noCustomizer && data[2])
? data[1] !== object[data[0]]
: !(data[0] in object)
) {
return false;
}
}
while (++index < length) {
data = matchData[index];
var key = data[0],
objValue = object[key],
srcValue = data[1];
if (noCustomizer && data[2]) {
if (objValue === undefined && !(key in object)) {
return false;
}
} else {
var stack = new Stack;
if (customizer) {
var result = customizer(objValue, srcValue, key, object, source, stack);
}
if (!(result === undefined
? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack)
: result
)) {
return false;
}
}
}
return true;
}
/**
* The base implementation of `_.isNative` without bad shim checks.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a native function,
* else `false`.
*/
function baseIsNative(value) {
if (!isObject(value) || isMasked(value)) {
return false;
}
var pattern = isFunction(value) ? reIsNative : reIsHostCtor;
return pattern.test(toSource(value));
}
/**
* The base implementation of `_.isRegExp` without Node.js optimizations.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
*/
function baseIsRegExp(value) {
return isObjectLike(value) && baseGetTag(value) == regexpTag;
}
/**
* The base implementation of `_.isSet` without Node.js optimizations.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a set, else `false`.
*/
function baseIsSet(value) {
return isObjectLike(value) && getTag(value) == setTag;
}
/**
* The base implementation of `_.isTypedArray` without Node.js optimizations.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
*/
function baseIsTypedArray(value) {
return isObjectLike(value) &&
isLength(value.length) && !!typedArrayTags[baseGetTag(value)];
}
/**
* The base implementation of `_.iteratee`.
*
* @private
* @param {*} [value=_.identity] The value to convert to an iteratee.
* @returns {Function} Returns the iteratee.
*/
function baseIteratee(value) {
// Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9.
// See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.
if (typeof value == 'function') {
return value;
}
if (value == null) {
return identity;
}
if (typeof value == 'object') {
return isArray(value)
? baseMatchesProperty(value[0], value[1])
: baseMatches(value);
}
return property(value);
}
/**
* The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
*
* @private
* @param {Object} object The object to query.
* @returns {Array} Returns the array of property names.
*/
function baseKeys(object) {
if (!isPrototype(object)) {
return nativeKeys(object);
}
var result = [];
for (var key in Object(object)) {
if (hasOwnProperty.call(object, key) && key != 'constructor') {
result.push(key);
}
}
return result;
}
/**
* The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.
*
* @private
* @param {Object} object The object to query.
* @returns {Array} Returns the array of property names.
*/
function baseKeysIn(object) {
if (!isObject(object)) {
return nativeKeysIn(object);
}
var isProto = isPrototype(object),
result = [];
for (var key in object) {
if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
result.push(key);
}
}
return result;
}
/**
* The base implementation of `_.lt` which doesn't coerce arguments.
*
* @private
* @param {*} value The value to compare.
* @param {*} other The other value to compare.
* @returns {boolean} Returns `true` if `value` is less than `other`,
* else `false`.
*/
function baseLt(value, other) {
return value < other;
}
/**
* The base implementation of `_.map` without support for iteratee shorthands.
*
* @private
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @returns {Array} Returns the new mapped array.
*/
function baseMap(collection, iteratee) {
var index = -1,
result = isArrayLike(collection) ? Array(collection.length) : [];
baseEach(collection, function(value, key, collection) {
result[++index] = iteratee(value, key, collection);
});
return result;
}
/**
* The base implementation of `_.matches` which doesn't clone `source`.
*
* @private
* @param {Object} source The object of property values to match.
* @returns {Function} Returns the new spec function.
*/
function baseMatches(source) {
var matchData = getMatchData(source);
if (matchData.length == 1 && matchData[0][2]) {
return matchesStrictComparable(matchData[0][0], matchData[0][1]);
}
return function(object) {
return object === source || baseIsMatch(object, source, matchData);
};
}
/**
* The base implementation of `_.matchesProperty` which doesn't clone `srcValue`.
*
* @private
* @param {string} path The path of the property to get.
* @param {*} srcValue The value to match.
* @returns {Function} Returns the new spec function.
*/
function baseMatchesProperty(path, srcValue) {
if (isKey(path) && isStrictComparable(srcValue)) {
return matchesStrictComparable(toKey(path), srcValue);
}
return function(object) {
var objValue = get(object, path);
return (objValue === undefined && objValue === srcValue)
? hasIn(object, path)
: baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);
};
}
/**
* The base implementation of `_.merge` without support for multiple sources.
*
* @private
* @param {Object} object The destination object.
* @param {Object} source The source object.
* @param {number} srcIndex The index of `source`.
* @param {Function} [customizer] The function to customize merged values.
* @param {Object} [stack] Tracks traversed source values and their merged
* counterparts.
*/
function baseMerge(object, source, srcIndex, customizer, stack) {
if (object === source) {
return;
}
baseFor(source, function(srcValue, key) {
if (isObject(srcValue)) {
stack || (stack = new Stack);
baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
}
else {
var newValue = customizer
? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack)
: undefined;
if (newValue === undefined) {
newValue = srcValue;
}
assignMergeValue(object, key, newValue);
}
}, keysIn);
}
/**
* A specialized version of `baseMerge` for arrays and objects which performs
* deep merges and tracks traversed objects enabling objects with circular
* references to be merged.
*
* @private
* @param {Object} object The destination object.
* @param {Object} source The source object.
* @param {string} key The key of the value to merge.
* @param {number} srcIndex The index of `source`.
* @param {Function} mergeFunc The function to merge values.
* @param {Function} [customizer] The function to customize assigned values.
* @param {Object} [stack] Tracks traversed source values and their merged
* counterparts.
*/
function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {
var objValue = safeGet(object, key),
srcValue = safeGet(source, key),
stacked = stack.get(srcValue);
if (stacked) {
assignMergeValue(object, key, stacked);
return;
}
var newValue = customizer
? customizer(objValue, srcValue, (key + ''), object, source, stack)
: undefined;
var isCommon = newValue === undefined;
if (isCommon) {
var isArr = isArray(srcValue),
isBuff = !isArr && isBuffer(srcValue),
isTyped = !isArr && !isBuff && isTypedArray(srcValue);
newValue = srcValue;
if (isArr || isBuff || isTyped) {
if (isArray(objValue)) {
newValue = objValue;
}
else if (isArrayLikeObject(objValue)) {
newValue = copyArray(objValue);
}
else if (isBuff) {
isCommon = false;
newValue = cloneBuffer(srcValue, true);
}
else if (isTyped) {
isCommon = false;
newValue = cloneTypedArray(srcValue, true);
}
else {
newValue = [];
}
}
else if (isPlainObject(srcValue) || isArguments(srcValue)) {
newValue = objValue;
if (isArguments(objValue)) {
newValue = toPlainObject(objValue);
}
else if (!isObject(objValue) || isFunction(objValue)) {
newValue = initCloneObject(srcValue);
}
}
else {
isCommon = false;
}
}
if (isCommon) {
// Recursively merge objects and arrays (susceptible to call stack limits).
stack.set(srcValue, newValue);
mergeFunc(newValue, srcValue, srcIndex, customizer, stack);
stack['delete'](srcValue);
}
assignMergeValue(object, key, newValue);
}
/**
* The base implementation of `_.nth` which doesn't coerce arguments.
*
* @private
* @param {Array} array The array to query.
* @param {number} n The index of the element to return.
* @returns {*} Returns the nth element of `array`.
*/
function baseNth(array, n) {
var length = array.length;
if (!length) {
return;
}
n += n < 0 ? length : 0;
return isIndex(n, length) ? array[n] : undefined;
}
/**
* The base implementation of `_.orderBy` without param guards.
*
* @private
* @param {Array|Object} collection The collection to iterate over.
* @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by.
* @param {string[]} orders The sort orders of `iteratees`.
* @returns {Array} Returns the new sorted array.
*/
function baseOrderBy(collection, iteratees, orders) {
var index = -1;
iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(getIteratee()));
var result = baseMap(collection, function(value, key, collection) {
var criteria = arrayMap(iteratees, function(iteratee) {
return iteratee(value);
});
return { 'criteria': criteria, 'index': ++index, 'value': value };
});
return baseSortBy(result, function(object, other) {
return compareMultiple(object, other, orders);
});
}
/**
* The base implementation of `_.pick` without support for individual
* property identifiers.
*
* @private
* @param {Object} object The source object.
* @param {string[]} paths The property paths to pick.
* @returns {Object} Returns the new object.
*/
function basePick(object, paths) {
return basePickBy(object, paths, function(value, path) {
return hasIn(object, path);
});
}
/**
* The base implementation of `_.pickBy` without support for iteratee shorthands.
*
* @private
* @param {Object} object The source object.
* @param {string[]} paths The property paths to pick.
* @param {Function} predicate The function invoked per property.
* @returns {Object} Returns the new object.
*/
function basePickBy(object, paths, predicate) {
var index = -1,
length = paths.length,
result = {};
while (++index < length) {
var path = paths[index],
value = baseGet(object, path);
if (predicate(value, path)) {
baseSet(result, castPath(path, object), value);
}
}
return result;
}
/**
* A specialized version of `baseProperty` which supports deep paths.
*
* @private
* @param {Array|string} path The path of the property to get.
* @returns {Function} Returns the new accessor function.
*/
function basePropertyDeep(path) {
return function(object) {
return baseGet(object, path);
};
}
/**
* The base implementation of `_.pullAllBy` without support for iteratee
* shorthands.
*
* @private
* @param {Array} array The array to modify.
* @param {Array} values The values to remove.
* @param {Function} [iteratee] The iteratee invoked per element.
* @param {Function} [comparator] The comparator invoked per element.
* @returns {Array} Returns `array`.
*/
function basePullAll(array, values, iteratee, comparator) {
var indexOf = comparator ? baseIndexOfWith : baseIndexOf,
index = -1,
length = values.length,
seen = array;
if (array === values) {
values = copyArray(values);
}
if (iteratee) {
seen = arrayMap(array, baseUnary(iteratee));
}
while (++index < length) {
var fromIndex = 0,
value = values[index],
computed = iteratee ? iteratee(value) : value;
while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) {
if (seen !== array) {
splice.call(seen, fromIndex, 1);
}
splice.call(array, fromIndex, 1);
}
}
return array;
}
/**
* The base implementation of `_.pullAt` without support for individual
* indexes or capturing the removed elements.
*
* @private
* @param {Array} array The array to modify.
* @param {number[]} indexes The indexes of elements to remove.
* @returns {Array} Returns `array`.
*/
function basePullAt(array, indexes) {
var length = array ? indexes.length : 0,
lastIndex = length - 1;
while (length--) {
var index = indexes[length];
if (length == lastIndex || index !== previous) {
var previous = index;
if (isIndex(index)) {
splice.call(array, index, 1);
} else {
baseUnset(array, index);
}
}
}
return array;
}
/**
* The base implementation of `_.random` without support for returning
* floating-point numbers.
*
* @private
* @param {number} lower The lower bound.
* @param {number} upper The upper bound.
* @returns {number} Returns the random number.
*/
function baseRandom(lower, upper) {
return lower + nativeFloor(nativeRandom() * (upper - lower + 1));
}
/**
* The base implementation of `_.range` and `_.rangeRight` which doesn't
* coerce arguments.
*
* @private
* @param {number} start The start of the range.
* @param {number} end The end of the range.
* @param {number} step The value to increment or decrement by.
* @param {boolean} [fromRight] Specify iterating from right to left.
* @returns {Array} Returns the range of numbers.
*/
function baseRange(start, end, step, fromRight) {
var index = -1,
length = nativeMax(nativeCeil((end - start) / (step || 1)), 0),
result = Array(length);
while (length--) {
result[fromRight ? length : ++index] = start;
start += step;
}
return result;
}
/**
* The base implementation of `_.repeat` which doesn't coerce arguments.
*
* @private
* @param {string} string The string to repeat.
* @param {number} n The number of times to repeat the string.
* @returns {string} Returns the repeated string.
*/
function baseRepeat(string, n) {
var result = '';
if (!string || n < 1 || n > MAX_SAFE_INTEGER) {
return result;
}
// Leverage the exponentiation by squaring algorithm for a faster repeat.
// See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details.
do {
if (n % 2) {
result += string;
}
n = nativeFloor(n / 2);
if (n) {
string += string;
}
} while (n);
return result;
}
/**
* The base implementation of `_.rest` which doesn't validate or coerce arguments.
*
* @private
* @param {Function} func The function to apply a rest parameter to.
* @param {number} [start=func.length-1] The start position of the rest parameter.
* @returns {Function} Returns the new function.
*/
function baseRest(func, start) {
return setToString(overRest(func, start, identity), func + '');
}
/**
* The base implementation of `_.sample`.
*
* @private
* @param {Array|Object} collection The collection to sample.
* @returns {*} Returns the random element.
*/
function baseSample(collection) {
return arraySample(values(collection));
}
/**
* The base implementation of `_.sampleSize` without param guards.
*
* @private
* @param {Array|Object} collection The collection to sample.
* @param {number} n The number of elements to sample.
* @returns {Array} Returns the random elements.
*/
function baseSampleSize(collection, n) {
var array = values(collection);
return shuffleSelf(array, baseClamp(n, 0, array.length));
}
/**
* The base implementation of `_.set`.
*
* @private
* @param {Object} object The object to modify.
* @param {Array|string} path The path of the property to set.
* @param {*} value The value to set.
* @param {Function} [customizer] The function to customize path creation.
* @returns {Object} Returns `object`.
*/
function baseSet(object, path, value, customizer) {
if (!isObject(object)) {
return object;
}
path = castPath(path, object);
var index = -1,
length = path.length,
lastIndex = length - 1,
nested = object;
while (nested != null && ++index < length) {
var key = toKey(path[index]),
newValue = value;
if (index != lastIndex) {
var objValue = nested[key];
newValue = customizer ? customizer(objValue, key, nested) : undefined;
if (newValue === undefined) {
newValue = isObject(objValue)
? objValue
: (isIndex(path[index + 1]) ? [] : {});
}
}
assignValue(nested, key, newValue);
nested = nested[key];
}
return object;
}
/**
* The base implementation of `setData` without support for hot loop shorting.
*
* @private
* @param {Function} func The function to associate metadata with.
* @param {*} data The metadata.
* @returns {Function} Returns `func`.
*/
var baseSetData = !metaMap ? identity : function(func, data) {
metaMap.set(func, data);
return func;
};
/**
* The base implementation of `setToString` without support for hot loop shorting.
*
* @private
* @param {Function} func The function to modify.
* @param {Function} string The `toString` result.
* @returns {Function} Returns `func`.
*/
var baseSetToString = !defineProperty ? identity : function(func, string) {
return defineProperty(func, 'toString', {
'configurable': true,
'enumerable': false,
'value': constant(string),
'writable': true
});
};
/**
* The base implementation of `_.shuffle`.
*
* @private
* @param {Array|Object} collection The collection to shuffle.
* @returns {Array} Returns the new shuffled array.
*/
function baseShuffle(collection) {
return shuffleSelf(values(collection));
}
/**
* The base implementation of `_.slice` without an iteratee call guard.
*
* @private
* @param {Array} array The array to slice.
* @param {number} [start=0] The start position.
* @param {number} [end=array.length] The end position.
* @returns {Array} Returns the slice of `array`.
*/
function baseSlice(array, start, end) {
var index = -1,
length = array.length;
if (start < 0) {
start = -start > length ? 0 : (length + start);
}
end = end > length ? length : end;
if (end < 0) {
end += length;
}
length = start > end ? 0 : ((end - start) >>> 0);
start >>>= 0;
var result = Array(length);
while (++index < length) {
result[index] = array[index + start];
}
return result;
}
/**
* The base implementation of `_.some` without support for iteratee shorthands.
*
* @private
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} predicate The function invoked per iteration.
* @returns {boolean} Returns `true` if any element passes the predicate check,
* else `false`.
*/
function baseSome(collection, predicate) {
var result;
baseEach(collection, function(value, index, collection) {
result = predicate(value, index, collection);
return !result;
});
return !!result;
}
/**
* The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which
* performs a binary search of `array` to determine the index at which `value`
* should be inserted into `array` in order to maintain its sort order.
*
* @private
* @param {Array} array The sorted array to inspect.
* @param {*} value The value to evaluate.
* @param {boolean} [retHighest] Specify returning the highest qualified index.
* @returns {number} Returns the index at which `value` should be inserted
* into `array`.
*/
function baseSortedIndex(array, value, retHighest) {
var low = 0,
high = array == null ? low : array.length;
if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
while (low < high) {
var mid = (low + high) >>> 1,
computed = array[mid];
if (computed !== null && !isSymbol(computed) &&
(retHighest ? (computed <= value) : (computed < value))) {
low = mid + 1;
} else {
high = mid;
}
}
return high;
}
return baseSortedIndexBy(array, value, identity, retHighest);
}
/**
* The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy`
* which invokes `iteratee` for `value` and each element of `array` to compute
* their sort ranking. The iteratee is invoked with one argument; (value).
*
* @private
* @param {Array} array The sorted array to inspect.
* @param {*} value The value to evaluate.
* @param {Function} iteratee The iteratee invoked per element.
* @param {boolean} [retHighest] Specify returning the highest qualified index.
* @returns {number} Returns the index at which `value` should be inserted
* into `array`.
*/
function baseSortedIndexBy(array, value, iteratee, retHighest) {
value = iteratee(value);
var low = 0,
high = array == null ? 0 : array.length,
valIsNaN = value !== value,
valIsNull = value === null,
valIsSymbol = isSymbol(value),
valIsUndefined = value === undefined;
while (low < high) {
var mid = nativeFloor((low + high) / 2),
computed = iteratee(array[mid]),
othIsDefined = computed !== undefined,
othIsNull = computed === null,
othIsReflexive = computed === computed,
othIsSymbol = isSymbol(computed);
if (valIsNaN) {
var setLow = retHighest || othIsReflexive;
} else if (valIsUndefined) {
setLow = othIsReflexive && (retHighest || othIsDefined);
} else if (valIsNull) {
setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull);
} else if (valIsSymbol) {
setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol);
} else if (othIsNull || othIsSymbol) {
setLow = false;
} else {
setLow = retHighest ? (computed <= value) : (computed < value);
}
if (setLow) {
low = mid + 1;
} else {
high = mid;
}
}
return nativeMin(high, MAX_ARRAY_INDEX);
}
/**
* The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without
* support for iteratee shorthands.
*
* @private
* @param {Array} array The array to inspect.
* @param {Function} [iteratee] The iteratee invoked per element.
* @returns {Array} Returns the new duplicate free array.
*/
function baseSortedUniq(array, iteratee) {
var index = -1,
length = array.length,
resIndex = 0,
result = [];
while (++index < length) {
var value = array[index],
computed = iteratee ? iteratee(value) : value;
if (!index || !eq(computed, seen)) {
var seen = computed;
result[resIndex++] = value === 0 ? 0 : value;
}
}
return result;
}
/**
* The base implementation of `_.toNumber` which doesn't ensure correct
* conversions of binary, hexadecimal, or octal string values.
*
* @private
* @param {*} value The value to process.
* @returns {number} Returns the number.
*/
function baseToNumber(value) {
if (typeof value == 'number') {
return value;
}
if (isSymbol(value)) {
return NAN;
}
return +value;
}
/**
* The base implementation of `_.toString` which doesn't convert nullish
* values to empty strings.
*
* @private
* @param {*} value The value to process.
* @returns {string} Returns the string.
*/
function baseToString(value) {
// Exit early for strings to avoid a performance hit in some environments.
if (typeof value == 'string') {
return value;
}
if (isArray(value)) {
// Recursively convert values (susceptible to call stack limits).
return arrayMap(value, baseToString) + '';
}
if (isSymbol(value)) {
return symbolToString ? symbolToString.call(value) : '';
}
var result = (value + '');
return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
}
/**
* The base implementation of `_.uniqBy` without support for iteratee shorthands.
*
* @private
* @param {Array} array The array to inspect.
* @param {Function} [iteratee] The iteratee invoked per element.
* @param {Function} [comparator] The comparator invoked per element.
* @returns {Array} Returns the new duplicate free array.
*/
function baseUniq(array, iteratee, comparator) {
var index = -1,
includes = arrayIncludes,
length = array.length,
isCommon = true,
result = [],
seen = result;
if (comparator) {
isCommon = false;
includes = arrayIncludesWith;
}
else if (length >= LARGE_ARRAY_SIZE) {
var set = iteratee ? null : createSet(array);
if (set) {
return setToArray(set);
}
isCommon = false;
includes = cacheHas;
seen = new SetCache;
}
else {
seen = iteratee ? [] : result;
}
outer:
while (++index < length) {
var value = array[index],
computed = iteratee ? iteratee(value) : value;
value = (comparator || value !== 0) ? value : 0;
if (isCommon && computed === computed) {
var seenIndex = seen.length;
while (seenIndex--) {
if (seen[seenIndex] === computed) {
continue outer;
}
}
if (iteratee) {
seen.push(computed);
}
result.push(value);
}
else if (!includes(seen, computed, comparator)) {
if (seen !== result) {
seen.push(computed);
}
result.push(value);
}
}
return result;
}
/**
* The base implementation of `_.unset`.
*
* @private
* @param {Object} object The object to modify.
* @param {Array|string} path The property path to unset.
* @returns {boolean} Returns `true` if the property is deleted, else `false`.
*/
function baseUnset(object, path) {
path = castPath(path, object);
object = parent(object, path);
return object == null || delete object[toKey(last(path))];
}
/**
* The base implementation of `_.update`.
*
* @private
* @param {Object} object The object to modify.
* @param {Array|string} path The path of the property to update.
* @param {Function} updater The function to produce the updated value.
* @param {Function} [customizer] The function to customize path creation.
* @returns {Object} Returns `object`.
*/
function baseUpdate(object, path, updater, customizer) {
return baseSet(object, path, updater(baseGet(object, path)), customizer);
}
/**
* The base implementation of methods like `_.dropWhile` and `_.takeWhile`
* without support for iteratee shorthands.
*
* @private
* @param {Array} array The array to query.
* @param {Function} predicate The function invoked per iteration.
* @param {boolean} [isDrop] Specify dropping elements instead of taking them.
* @param {boolean} [fromRight] Specify iterating from right to left.
* @returns {Array} Returns the slice of `array`.
*/
function baseWhile(array, predicate, isDrop, fromRight) {
var length = array.length,
index = fromRight ? length : -1;
while ((fromRight ? index-- : ++index < length) &&
predicate(array[index], index, array)) {}
return isDrop
? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length))
: baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index));
}
/**
* The base implementation of `wrapperValue` which returns the result of
* performing a sequence of actions on the unwrapped `value`, where each
* successive action is supplied the return value of the previous.
*
* @private
* @param {*} value The unwrapped value.
* @param {Array} actions Actions to perform to resolve the unwrapped value.
* @returns {*} Returns the resolved value.
*/
function baseWrapperValue(value, actions) {
var result = value;
if (result instanceof LazyWrapper) {
result = result.value();
}
return arrayReduce(actions, function(result, action) {
return action.func.apply(action.thisArg, arrayPush([result], action.args));
}, result);
}
/**
* The base implementation of methods like `_.xor`, without support for
* iteratee shorthands, that accepts an array of arrays to inspect.
*
* @private
* @param {Array} arrays The arrays to inspect.
* @param {Function} [iteratee] The iteratee invoked per element.
* @param {Function} [comparator] The comparator invoked per element.
* @returns {Array} Returns the new array of values.
*/
function baseXor(arrays, iteratee, comparator) {
var length = arrays.length;
if (length < 2) {
return length ? baseUniq(arrays[0]) : [];
}
var index = -1,
result = Array(length);
while (++index < length) {
var array = arrays[index],
othIndex = -1;
while (++othIndex < length) {
if (othIndex != index) {
result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator);
}
}
}
return baseUniq(baseFlatten(result, 1), iteratee, comparator);
}
/**
* This base implementation of `_.zipObject` which assigns values using `assignFunc`.
*
* @private
* @param {Array} props The property identifiers.
* @param {Array} values The property values.
* @param {Function} assignFunc The function to assign values.
* @returns {Object} Returns the new object.
*/
function baseZipObject(props, values, assignFunc) {
var index = -1,
length = props.length,
valsLength = values.length,
result = {};
while (++index < length) {
var value = index < valsLength ? values[index] : undefined;
assignFunc(result, props[index], value);
}
return result;
}
/**
* Casts `value` to an empty array if it's not an array like object.
*
* @private
* @param {*} value The value to inspect.
* @returns {Array|Object} Returns the cast array-like object.
*/
function castArrayLikeObject(value) {
return isArrayLikeObject(value) ? value : [];
}
/**
* Casts `value` to `identity` if it's not a function.
*
* @private
* @param {*} value The value to inspect.
* @returns {Function} Returns cast function.
*/
function castFunction(value) {
return typeof value == 'function' ? value : identity;
}
/**
* Casts `value` to a path array if it's not one.
*
* @private
* @param {*} value The value to inspect.
* @param {Object} [object] The object to query keys on.
* @returns {Array} Returns the cast property path array.
*/
function castPath(value, object) {
if (isArray(value)) {
return value;
}
return isKey(value, object) ? [value] : stringToPath(toString(value));
}
/**
* A `baseRest` alias which can be replaced with `identity` by module
* replacement plugins.
*
* @private
* @type {Function}
* @param {Function} func The function to apply a rest parameter to.
* @returns {Function} Returns the new function.
*/
var castRest = baseRest;
/**
* Casts `array` to a slice if it's needed.
*
* @private
* @param {Array} array The array to inspect.
* @param {number} start The start position.
* @param {number} [end=array.length] The end position.
* @returns {Array} Returns the cast slice.
*/
function castSlice(array, start, end) {
var length = array.length;
end = end === undefined ? length : end;
return (!start && end >= length) ? array : baseSlice(array, start, end);
}
/**
* A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout).
*
* @private
* @param {number|Object} id The timer id or timeout object of the timer to clear.
*/
var clearTimeout = ctxClearTimeout || function(id) {
return root.clearTimeout(id);
};
/**
* Creates a clone of `buffer`.
*
* @private
* @param {Buffer} buffer The buffer to clone.
* @param {boolean} [isDeep] Specify a deep clone.
* @returns {Buffer} Returns the cloned buffer.
*/
function cloneBuffer(buffer, isDeep) {
if (isDeep) {
return buffer.slice();
}
var length = buffer.length,
result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length);
buffer.copy(result);
return result;
}
/**
* Creates a clone of `arrayBuffer`.
*
* @private
* @param {ArrayBuffer} arrayBuffer The array buffer to clone.
* @returns {ArrayBuffer} Returns the cloned array buffer.
*/
function cloneArrayBuffer(arrayBuffer) {
var result = new arrayBuffer.constructor(arrayBuffer.byteLength);
new Uint8Array(result).set(new Uint8Array(arrayBuffer));
return result;
}
/**
* Creates a clone of `dataView`.
*
* @private
* @param {Object} dataView The data view to clone.
* @param {boolean} [isDeep] Specify a deep clone.
* @returns {Object} Returns the cloned data view.
*/
function cloneDataView(dataView, isDeep) {
var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;
return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);
}
/**
* Creates a clone of `regexp`.
*
* @private
* @param {Object} regexp The regexp to clone.
* @returns {Object} Returns the cloned regexp.
*/
function cloneRegExp(regexp) {
var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));
result.lastIndex = regexp.lastIndex;
return result;
}
/**
* Creates a clone of the `symbol` object.
*
* @private
* @param {Object} symbol The symbol object to clone.
* @returns {Object} Returns the cloned symbol object.
*/
function cloneSymbol(symbol) {
return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};
}
/**
* Creates a clone of `typedArray`.
*
* @private
* @param {Object} typedArray The typed array to clone.
* @param {boolean} [isDeep] Specify a deep clone.
* @returns {Object} Returns the cloned typed array.
*/
function cloneTypedArray(typedArray, isDeep) {
var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;
return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
}
/**
* Compares values to sort them in ascending order.
*
* @private
* @param {*} value The value to compare.
* @param {*} other The other value to compare.
* @returns {number} Returns the sort order indicator for `value`.
*/
function compareAscending(value, other) {
if (value !== other) {
var valIsDefined = value !== undefined,
valIsNull = value === null,
valIsReflexive = value === value,
valIsSymbol = isSymbol(value);
var othIsDefined = other !== undefined,
othIsNull = other === null,
othIsReflexive = other === other,
othIsSymbol = isSymbol(other);
if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) ||
(valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) ||
(valIsNull && othIsDefined && othIsReflexive) ||
(!valIsDefined && othIsReflexive) ||
!valIsReflexive) {
return 1;
}
if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) ||
(othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) ||
(othIsNull && valIsDefined && valIsReflexive) ||
(!othIsDefined && valIsReflexive) ||
!othIsReflexive) {
return -1;
}
}
return 0;
}
/**
* Used by `_.orderBy` to compare multiple properties of a value to another
* and stable sort them.
*
* If `orders` is unspecified, all values are sorted in ascending order. Otherwise,
* specify an order of "desc" for descending or "asc" for ascending sort order
* of corresponding values.
*
* @private
* @param {Object} object The object to compare.
* @param {Object} other The other object to compare.
* @param {boolean[]|string[]} orders The order to sort by for each property.
* @returns {number} Returns the sort order indicator for `object`.
*/
function compareMultiple(object, other, orders) {
var index = -1,
objCriteria = object.criteria,
othCriteria = other.criteria,
length = objCriteria.length,
ordersLength = orders.length;
while (++index < length) {
var result = compareAscending(objCriteria[index], othCriteria[index]);
if (result) {
if (index >= ordersLength) {
return result;
}
var order = orders[index];
return result * (order == 'desc' ? -1 : 1);
}
}
// Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
// that causes it, under certain circumstances, to provide the same value for
// `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247
// for more details.
//
// This also ensures a stable sort in V8 and other engines.
// See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details.
return object.index - other.index;
}
/**
* Creates an array that is the composition of partially applied arguments,
* placeholders, and provided arguments into a single array of arguments.
*
* @private
* @param {Array} args The provided arguments.
* @param {Array} partials The arguments to prepend to those provided.
* @param {Array} holders The `partials` placeholder indexes.
* @params {boolean} [isCurried] Specify composing for a curried function.
* @returns {Array} Returns the new array of composed arguments.
*/
function composeArgs(args, partials, holders, isCurried) {
var argsIndex = -1,
argsLength = args.length,
holdersLength = holders.length,
leftIndex = -1,
leftLength = partials.length,
rangeLength = nativeMax(argsLength - holdersLength, 0),
result = Array(leftLength + rangeLength),
isUncurried = !isCurried;
while (++leftIndex < leftLength) {
result[leftIndex] = partials[leftIndex];
}
while (++argsIndex < holdersLength) {
if (isUncurried || argsIndex < argsLength) {
result[holders[argsIndex]] = args[argsIndex];
}
}
while (rangeLength--) {
result[leftIndex++] = args[argsIndex++];
}
return result;
}
/**
* This function is like `composeArgs` except that the arguments composition
* is tailored for `_.partialRight`.
*
* @private
* @param {Array} args The provided arguments.
* @param {Array} partials The arguments to append to those provided.
* @param {Array} holders The `partials` placeholder indexes.
* @params {boolean} [isCurried] Specify composing for a curried function.
* @returns {Array} Returns the new array of composed arguments.
*/
function composeArgsRight(args, partials, holders, isCurried) {
var argsIndex = -1,
argsLength = args.length,
holdersIndex = -1,
holdersLength = holders.length,
rightIndex = -1,
rightLength = partials.length,
rangeLength = nativeMax(argsLength - holdersLength, 0),
result = Array(rangeLength + rightLength),
isUncurried = !isCurried;
while (++argsIndex < rangeLength) {
result[argsIndex] = args[argsIndex];
}
var offset = argsIndex;
while (++rightIndex < rightLength) {
result[offset + rightIndex] = partials[rightIndex];
}
while (++holdersIndex < holdersLength) {
if (isUncurried || argsIndex < argsLength) {
result[offset + holders[holdersIndex]] = args[argsIndex++];
}
}
return result;
}
/**
* Copies the values of `source` to `array`.
*
* @private
* @param {Array} source The array to copy values from.
* @param {Array} [array=[]] The array to copy values to.
* @returns {Array} Returns `array`.
*/
function copyArray(source, array) {
var index = -1,
length = source.length;
array || (array = Array(length));
while (++index < length) {
array[index] = source[index];
}
return array;
}
/**
* Copies properties of `source` to `object`.
*
* @private
* @param {Object} source The object to copy properties from.
* @param {Array} props The property identifiers to copy.
* @param {Object} [object={}] The object to copy properties to.
* @param {Function} [customizer] The function to customize copied values.
* @returns {Object} Returns `object`.
*/
function copyObject(source, props, object, customizer) {
var isNew = !object;
object || (object = {});
var index = -1,
length = props.length;
while (++index < length) {
var key = props[index];
var newValue = customizer
? customizer(object[key], source[key], key, object, source)
: undefined;
if (newValue === undefined) {
newValue = source[key];
}
if (isNew) {
baseAssignValue(object, key, newValue);
} else {
assignValue(object, key, newValue);
}
}
return object;
}
/**
* Copies own symbols of `source` to `object`.
*
* @private
* @param {Object} source The object to copy symbols from.
* @param {Object} [object={}] The object to copy symbols to.
* @returns {Object} Returns `object`.
*/
function copySymbols(source, object) {
return copyObject(source, getSymbols(source), object);
}
/**
* Copies own and inherited symbols of `source` to `object`.
*
* @private
* @param {Object} source The object to copy symbols from.
* @param {Object} [object={}] The object to copy symbols to.
* @returns {Object} Returns `object`.
*/
function copySymbolsIn(source, object) {
return copyObject(source, getSymbolsIn(source), object);
}
/**
* Creates a function like `_.groupBy`.
*
* @private
* @param {Function} setter The function to set accumulator values.
* @param {Function} [initializer] The accumulator object initializer.
* @returns {Function} Returns the new aggregator function.
*/
function createAggregator(setter, initializer) {
return function(collection, iteratee) {
var func = isArray(collection) ? arrayAggregator : baseAggregator,
accumulator = initializer ? initializer() : {};
return func(collection, setter, getIteratee(iteratee, 2), accumulator);
};
}
/**
* Creates a function like `_.assign`.
*
* @private
* @param {Function} assigner The function to assign values.
* @returns {Function} Returns the new assigner function.
*/
function createAssigner(assigner) {
return baseRest(function(object, sources) {
var index = -1,
length = sources.length,
customizer = length > 1 ? sources[length - 1] : undefined,
guard = length > 2 ? sources[2] : undefined;
customizer = (assigner.length > 3 && typeof customizer == 'function')
? (length--, customizer)
: undefined;
if (guard && isIterateeCall(sources[0], sources[1], guard)) {
customizer = length < 3 ? undefined : customizer;
length = 1;
}
object = Object(object);
while (++index < length) {
var source = sources[index];
if (source) {
assigner(object, source, index, customizer);
}
}
return object;
});
}
/**
* Creates a `baseEach` or `baseEachRight` function.
*
* @private
* @param {Function} eachFunc The function to iterate over a collection.
* @param {boolean} [fromRight] Specify iterating from right to left.
* @returns {Function} Returns the new base function.
*/
function createBaseEach(eachFunc, fromRight) {
return function(collection, iteratee) {
if (collection == null) {
return collection;
}
if (!isArrayLike(collection)) {
return eachFunc(collection, iteratee);
}
var length = collection.length,
index = fromRight ? length : -1,
iterable = Object(collection);
while ((fromRight ? index-- : ++index < length)) {
if (iteratee(iterable[index], index, iterable) === false) {
break;
}
}
return collection;
};
}
/**
* Creates a base function for methods like `_.forIn` and `_.forOwn`.
*
* @private
* @param {boolean} [fromRight] Specify iterating from right to left.
* @returns {Function} Returns the new base function.
*/
function createBaseFor(fromRight) {
return function(object, iteratee, keysFunc) {
var index = -1,
iterable = Object(object),
props = keysFunc(object),
length = props.length;
while (length--) {
var key = props[fromRight ? length : ++index];
if (iteratee(iterable[key], key, iterable) === false) {
break;
}
}
return object;
};
}
/**
* Creates a function that wraps `func` to invoke it with the optional `this`
* binding of `thisArg`.
*
* @private
* @param {Function} func The function to wrap.
* @param {number} bitmask The bitmask flags. See `createWrap` for more details.
* @param {*} [thisArg] The `this` binding of `func`.
* @returns {Function} Returns the new wrapped function.
*/
function createBind(func, bitmask, thisArg) {
var isBind = bitmask & WRAP_BIND_FLAG,
Ctor = createCtor(func);
function wrapper() {
var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
return fn.apply(isBind ? thisArg : this, arguments);
}
return wrapper;
}
/**
* Creates a function like `_.lowerFirst`.
*
* @private
* @param {string} methodName The name of the `String` case method to use.
* @returns {Function} Returns the new case function.
*/
function createCaseFirst(methodName) {
return function(string) {
string = toString(string);
var strSymbols = hasUnicode(string)
? stringToArray(string)
: undefined;
var chr = strSymbols
? strSymbols[0]
: string.charAt(0);
var trailing = strSymbols
? castSlice(strSymbols, 1).join('')
: string.slice(1);
return chr[methodName]() + trailing;
};
}
/**
* Creates a function like `_.camelCase`.
*
* @private
* @param {Function} callback The function to combine each word.
* @returns {Function} Returns the new compounder function.
*/
function createCompounder(callback) {
return function(string) {
return arrayReduce(words(deburr(string).replace(reApos, '')), callback, '');
};
}
/**
* Creates a function that produces an instance of `Ctor` regardless of
* whether it was invoked as part of a `new` expression or by `call` or `apply`.
*
* @private
* @param {Function} Ctor The constructor to wrap.
* @returns {Function} Returns the new wrapped function.
*/
function createCtor(Ctor) {
return function() {
// Use a `switch` statement to work with class constructors. See
// http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
// for more details.
var args = arguments;
switch (args.length) {
case 0: return new Ctor;
case 1: return new Ctor(args[0]);
case 2: return new Ctor(args[0], args[1]);
case 3: return new Ctor(args[0], args[1], args[2]);
case 4: return new Ctor(args[0], args[1], args[2], args[3]);
case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]);
case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]);
case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
}
var thisBinding = baseCreate(Ctor.prototype),
result = Ctor.apply(thisBinding, args);
// Mimic the constructor's `return` behavior.
// See https://es5.github.io/#x13.2.2 for more details.
return isObject(result) ? result : thisBinding;
};
}
/**
* Creates a function that wraps `func` to enable currying.
*
* @private
* @param {Function} func The function to wrap.
* @param {number} bitmask The bitmask flags. See `createWrap` for more details.
* @param {number} arity The arity of `func`.
* @returns {Function} Returns the new wrapped function.
*/
function createCurry(func, bitmask, arity) {
var Ctor = createCtor(func);
function wrapper() {
var length = arguments.length,
args = Array(length),
index = length,
placeholder = getHolder(wrapper);
while (index--) {
args[index] = arguments[index];
}
var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder)
? []
: replaceHolders(args, placeholder);
length -= holders.length;
if (length < arity) {
return createRecurry(
func, bitmask, createHybrid, wrapper.placeholder, undefined,
args, holders, undefined, undefined, arity - length);
}
var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
return apply(fn, this, args);
}
return wrapper;
}
/**
* Creates a `_.find` or `_.findLast` function.
*
* @private
* @param {Function} findIndexFunc The function to find the collection index.
* @returns {Function} Returns the new find function.
*/
function createFind(findIndexFunc) {
return function(collection, predicate, fromIndex) {
var iterable = Object(collection);
if (!isArrayLike(collection)) {
var iteratee = getIteratee(predicate, 3);
collection = keys(collection);
predicate = function(key) { return iteratee(iterable[key], key, iterable); };
}
var index = findIndexFunc(collection, predicate, fromIndex);
return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined;
};
}
/**
* Creates a `_.flow` or `_.flowRight` function.
*
* @private
* @param {boolean} [fromRight] Specify iterating from right to left.
* @returns {Function} Returns the new flow function.
*/
function createFlow(fromRight) {
return flatRest(function(funcs) {
var length = funcs.length,
index = length,
prereq = LodashWrapper.prototype.thru;
if (fromRight) {
funcs.reverse();
}
while (index--) {
var func = funcs[index];
if (typeof func != 'function') {
throw new TypeError(FUNC_ERROR_TEXT);
}
if (prereq && !wrapper && getFuncName(func) == 'wrapper') {
var wrapper = new LodashWrapper([], true);
}
}
index = wrapper ? index : length;
while (++index < length) {
func = funcs[index];
var funcName = getFuncName(func),
data = funcName == 'wrapper' ? getData(func) : undefined;
if (data && isLaziable(data[0]) &&
data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) &&
!data[4].length && data[9] == 1
) {
wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]);
} else {
wrapper = (func.length == 1 && isLaziable(func))
? wrapper[funcName]()
: wrapper.thru(func);
}
}
return function() {
var args = arguments,
value = args[0];
if (wrapper && args.length == 1 && isArray(value)) {
return wrapper.plant(value).value();
}
var index = 0,
result = length ? funcs[index].apply(this, args) : value;
while (++index < length) {
result = funcs[index].call(this, result);
}
return result;
};
});
}
/**
* Creates a function that wraps `func` to invoke it with optional `this`
* binding of `thisArg`, partial application, and currying.
*
* @private
* @param {Function|string} func The function or method name to wrap.
* @param {number} bitmask The bitmask flags. See `createWrap` for more details.
* @param {*} [thisArg] The `this` binding of `func`.
* @param {Array} [partials] The arguments to prepend to those provided to
* the new function.
* @param {Array} [holders] The `partials` placeholder indexes.
* @param {Array} [partialsRight] The arguments to append to those provided
* to the new function.
* @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
* @param {Array} [argPos] The argument positions of the new function.
* @param {number} [ary] The arity cap of `func`.
* @param {number} [arity] The arity of `func`.
* @returns {Function} Returns the new wrapped function.
*/
function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
var isAry = bitmask & WRAP_ARY_FLAG,
isBind = bitmask & WRAP_BIND_FLAG,
isBindKey = bitmask & WRAP_BIND_KEY_FLAG,
isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG),
isFlip = bitmask & WRAP_FLIP_FLAG,
Ctor = isBindKey ? undefined : createCtor(func);
function wrapper() {
var length = arguments.length,
args = Array(length),
index = length;
while (index--) {
args[index] = arguments[index];
}
if (isCurried) {
var placeholder = getHolder(wrapper),
holdersCount = countHolders(args, placeholder);
}
if (partials) {
args = composeArgs(args, partials, holders, isCurried);
}
if (partialsRight) {
args = composeArgsRight(args, partialsRight, holdersRight, isCurried);
}
length -= holdersCount;
if (isCurried && length < arity) {
var newHolders = replaceHolders(args, placeholder);
return createRecurry(
func, bitmask, createHybrid, wrapper.placeholder, thisArg,
args, newHolders, argPos, ary, arity - length
);
}
var thisBinding = isBind ? thisArg : this,
fn = isBindKey ? thisBinding[func] : func;
length = args.length;
if (argPos) {
args = reorder(args, argPos);
} else if (isFlip && length > 1) {
args.reverse();
}
if (isAry && ary < length) {
args.length = ary;
}
if (this && this !== root && this instanceof wrapper) {
fn = Ctor || createCtor(fn);
}
return fn.apply(thisBinding, args);
}
return wrapper;
}
/**
* Creates a function like `_.invertBy`.
*
* @private
* @param {Function} setter The function to set accumulator values.
* @param {Function} toIteratee The function to resolve iteratees.
* @returns {Function} Returns the new inverter function.
*/
function createInverter(setter, toIteratee) {
return function(object, iteratee) {
return baseInverter(object, setter, toIteratee(iteratee), {});
};
}
/**
* Creates a function that performs a mathematical operation on two values.
*
* @private
* @param {Function} operator The function to perform the operation.
* @param {number} [defaultValue] The value used for `undefined` arguments.
* @returns {Function} Returns the new mathematical operation function.
*/
function createMathOperation(operator, defaultValue) {
return function(value, other) {
var result;
if (value === undefined && other === undefined) {
return defaultValue;
}
if (value !== undefined) {
result = value;
}
if (other !== undefined) {
if (result === undefined) {
return other;
}
if (typeof value == 'string' || typeof other == 'string') {
value = baseToString(value);
other = baseToString(other);
} else {
value = baseToNumber(value);
other = baseToNumber(other);
}
result = operator(value, other);
}
return result;
};
}
/**
* Creates a function like `_.over`.
*
* @private
* @param {Function} arrayFunc The function to iterate over iteratees.
* @returns {Function} Returns the new over function.
*/
function createOver(arrayFunc) {
return flatRest(function(iteratees) {
iteratees = arrayMap(iteratees, baseUnary(getIteratee()));
return baseRest(function(args) {
var thisArg = this;
return arrayFunc(iteratees, function(iteratee) {
return apply(iteratee, thisArg, args);
});
});
});
}
/**
* Creates the padding for `string` based on `length`. The `chars` string
* is truncated if the number of characters exceeds `length`.
*
* @private
* @param {number} length The padding length.
* @param {string} [chars=' '] The string used as padding.
* @returns {string} Returns the padding for `string`.
*/
function createPadding(length, chars) {
chars = chars === undefined ? ' ' : baseToString(chars);
var charsLength = chars.length;
if (charsLength < 2) {
return charsLength ? baseRepeat(chars, length) : chars;
}
var result = baseRepeat(chars, nativeCeil(length / stringSize(chars)));
return hasUnicode(chars)
? castSlice(stringToArray(result), 0, length).join('')
: result.slice(0, length);
}
/**
* Creates a function that wraps `func` to invoke it with the `this` binding
* of `thisArg` and `partials` prepended to the arguments it receives.
*
* @private
* @param {Function} func The function to wrap.
* @param {number} bitmask The bitmask flags. See `createWrap` for more details.
* @param {*} thisArg The `this` binding of `func`.
* @param {Array} partials The arguments to prepend to those provided to
* the new function.
* @returns {Function} Returns the new wrapped function.
*/
function createPartial(func, bitmask, thisArg, partials) {
var isBind = bitmask & WRAP_BIND_FLAG,
Ctor = createCtor(func);
function wrapper() {
var argsIndex = -1,
argsLength = arguments.length,
leftIndex = -1,
leftLength = partials.length,
args = Array(leftLength + argsLength),
fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
while (++leftIndex < leftLength) {
args[leftIndex] = partials[leftIndex];
}
while (argsLength--) {
args[leftIndex++] = arguments[++argsIndex];
}
return apply(fn, isBind ? thisArg : this, args);
}
return wrapper;
}
/**
* Creates a `_.range` or `_.rangeRight` function.
*
* @private
* @param {boolean} [fromRight] Specify iterating from right to left.
* @returns {Function} Returns the new range function.
*/
function createRange(fromRight) {
return function(start, end, step) {
if (step && typeof step != 'number' && isIterateeCall(start, end, step)) {
end = step = undefined;
}
// Ensure the sign of `-0` is preserved.
start = toFinite(start);
if (end === undefined) {
end = start;
start = 0;
} else {
end = toFinite(end);
}
step = step === undefined ? (start < end ? 1 : -1) : toFinite(step);
return baseRange(start, end, step, fromRight);
};
}
/**
* Creates a function that performs a relational operation on two values.
*
* @private
* @param {Function} operator The function to perform the operation.
* @returns {Function} Returns the new relational operation function.
*/
function createRelationalOperation(operator) {
return function(value, other) {
if (!(typeof value == 'string' && typeof other == 'string')) {
value = toNumber(value);
other = toNumber(other);
}
return operator(value, other);
};
}
/**
* Creates a function that wraps `func` to continue currying.
*
* @private
* @param {Function} func The function to wrap.
* @param {number} bitmask The bitmask flags. See `createWrap` for more details.
* @param {Function} wrapFunc The function to create the `func` wrapper.
* @param {*} placeholder The placeholder value.
* @param {*} [thisArg] The `this` binding of `func`.
* @param {Array} [partials] The arguments to prepend to those provided to
* the new function.
* @param {Array} [holders] The `partials` placeholder indexes.
* @param {Array} [argPos] The argument positions of the new function.
* @param {number} [ary] The arity cap of `func`.
* @param {number} [arity] The arity of `func`.
* @returns {Function} Returns the new wrapped function.
*/
function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) {
var isCurry = bitmask & WRAP_CURRY_FLAG,
newHolders = isCurry ? holders : undefined,
newHoldersRight = isCurry ? undefined : holders,
newPartials = isCurry ? partials : undefined,
newPartialsRight = isCurry ? undefined : partials;
bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG);
bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG);
if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) {
bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG);
}
var newData = [
func, bitmask, thisArg, newPartials, newHolders, newPartialsRight,
newHoldersRight, argPos, ary, arity
];
var result = wrapFunc.apply(undefined, newData);
if (isLaziable(func)) {
setData(result, newData);
}
result.placeholder = placeholder;
return setWrapToString(result, func, bitmask);
}
/**
* Creates a function like `_.round`.
*
* @private
* @param {string} methodName The name of the `Math` method to use when rounding.
* @returns {Function} Returns the new round function.
*/
function createRound(methodName) {
var func = Math[methodName];
return function(number, precision) {
number = toNumber(number);
precision = precision == null ? 0 : nativeMin(toInteger(precision), 292);
if (precision) {
// Shift with exponential notation to avoid floating-point issues.
// See [MDN](https://mdn.io/round#Examples) for more details.
var pair = (toString(number) + 'e').split('e'),
value = func(pair[0] + 'e' + (+pair[1] + precision));
pair = (toString(value) + 'e').split('e');
return +(pair[0] + 'e' + (+pair[1] - precision));
}
return func(number);
};
}
/**
* Creates a set object of `values`.
*
* @private
* @param {Array} values The values to add to the set.
* @returns {Object} Returns the new set.
*/
var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) {
return new Set(values);
};
/**
* Creates a `_.toPairs` or `_.toPairsIn` function.
*
* @private
* @param {Function} keysFunc The function to get the keys of a given object.
* @returns {Function} Returns the new pairs function.
*/
function createToPairs(keysFunc) {
return function(object) {
var tag = getTag(object);
if (tag == mapTag) {
return mapToArray(object);
}
if (tag == setTag) {
return setToPairs(object);
}
return baseToPairs(object, keysFunc(object));
};
}
/**
* Creates a function that either curries or invokes `func` with optional
* `this` binding and partially applied arguments.
*
* @private
* @param {Function|string} func The function or method name to wrap.
* @param {number} bitmask The bitmask flags.
* 1 - `_.bind`
* 2 - `_.bindKey`
* 4 - `_.curry` or `_.curryRight` of a bound function
* 8 - `_.curry`
* 16 - `_.curryRight`
* 32 - `_.partial`
* 64 - `_.partialRight`
* 128 - `_.rearg`
* 256 - `_.ary`
* 512 - `_.flip`
* @param {*} [thisArg] The `this` binding of `func`.
* @param {Array} [partials] The arguments to be partially applied.
* @param {Array} [holders] The `partials` placeholder indexes.
* @param {Array} [argPos] The argument positions of the new function.
* @param {number} [ary] The arity cap of `func`.
* @param {number} [arity] The arity of `func`.
* @returns {Function} Returns the new wrapped function.
*/
function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
var isBindKey = bitmask & WRAP_BIND_KEY_FLAG;
if (!isBindKey && typeof func != 'function') {
throw new TypeError(FUNC_ERROR_TEXT);
}
var length = partials ? partials.length : 0;
if (!length) {
bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG);
partials = holders = undefined;
}
ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0);
arity = arity === undefined ? arity : toInteger(arity);
length -= holders ? holders.length : 0;
if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) {
var partialsRight = partials,
holdersRight = holders;
partials = holders = undefined;
}
var data = isBindKey ? undefined : getData(func);
var newData = [
func, bitmask, thisArg, partials, holders, partialsRight, holdersRight,
argPos, ary, arity
];
if (data) {
mergeData(newData, data);
}
func = newData[0];
bitmask = newData[1];
thisArg = newData[2];
partials = newData[3];
holders = newData[4];
arity = newData[9] = newData[9] === undefined
? (isBindKey ? 0 : func.length)
: nativeMax(newData[9] - length, 0);
if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) {
bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG);
}
if (!bitmask || bitmask == WRAP_BIND_FLAG) {
var result = createBind(func, bitmask, thisArg);
} else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) {
result = createCurry(func, bitmask, arity);
} else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) {
result = createPartial(func, bitmask, thisArg, partials);
} else {
result = createHybrid.apply(undefined, newData);
}
var setter = data ? baseSetData : setData;
return setWrapToString(setter(result, newData), func, bitmask);
}
/**
* Used by `_.defaults` to customize its `_.assignIn` use to assign properties
* of source objects to the destination object for all destination properties
* that resolve to `undefined`.
*
* @private
* @param {*} objValue The destination value.
* @param {*} srcValue The source value.
* @param {string} key The key of the property to assign.
* @param {Object} object The parent object of `objValue`.
* @returns {*} Returns the value to assign.
*/
function customDefaultsAssignIn(objValue, srcValue, key, object) {
if (objValue === undefined ||
(eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) {
return srcValue;
}
return objValue;
}
/**
* Used by `_.defaultsDeep` to customize its `_.merge` use to merge source
* objects into destination objects that are passed thru.
*
* @private
* @param {*} objValue The destination value.
* @param {*} srcValue The source value.
* @param {string} key The key of the property to merge.
* @param {Object} object The parent object of `objValue`.
* @param {Object} source The parent object of `srcValue`.
* @param {Object} [stack] Tracks traversed source values and their merged
* counterparts.
* @returns {*} Returns the value to assign.
*/
function customDefaultsMerge(objValue, srcValue, key, object, source, stack) {
if (isObject(objValue) && isObject(srcValue)) {
// Recursively merge objects and arrays (susceptible to call stack limits).
stack.set(srcValue, objValue);
baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack);
stack['delete'](srcValue);
}
return objValue;
}
/**
* Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain
* objects.
*
* @private
* @param {*} value The value to inspect.
* @param {string} key The key of the property to inspect.
* @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`.
*/
function customOmitClone(value) {
return isPlainObject(value) ? undefined : value;
}
/**
* A specialized version of `baseIsEqualDeep` for arrays with support for
* partial deep comparisons.
*
* @private
* @param {Array} array The array to compare.
* @param {Array} other The other array to compare.
* @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
* @param {Function} customizer The function to customize comparisons.
* @param {Function} equalFunc The function to determine equivalents of values.
* @param {Object} stack Tracks traversed `array` and `other` objects.
* @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
*/
function equalArrays(array, other, bitmask, customizer, equalFunc, stack) {
var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
arrLength = array.length,
othLength = other.length;
if (arrLength != othLength && !(isPartial && othLength > arrLength)) {
return false;
}
// Assume cyclic values are equal.
var stacked = stack.get(array);
if (stacked && stack.get(other)) {
return stacked == other;
}
var index = -1,
result = true,
seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined;
stack.set(array, other);
stack.set(other, array);
// Ignore non-index properties.
while (++index < arrLength) {
var arrValue = array[index],
othValue = other[index];
if (customizer) {
var compared = isPartial
? customizer(othValue, arrValue, index, other, array, stack)
: customizer(arrValue, othValue, index, array, other, stack);
}
if (compared !== undefined) {
if (compared) {
continue;
}
result = false;
break;
}
// Recursively compare arrays (susceptible to call stack limits).
if (seen) {
if (!arraySome(other, function(othValue, othIndex) {
if (!cacheHas(seen, othIndex) &&
(arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) {
return seen.push(othIndex);
}
})) {
result = false;
break;
}
} else if (!(
arrValue === othValue ||
equalFunc(arrValue, othValue, bitmask, customizer, stack)
)) {
result = false;
break;
}
}
stack['delete'](array);
stack['delete'](other);
return result;
}
/**
* A specialized version of `baseIsEqualDeep` for comparing objects of
* the same `toStringTag`.
*
* **Note:** This function only supports comparing values with tags of
* `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
*
* @private
* @param {Object} object The object to compare.
* @param {Object} other The other object to compare.
* @param {string} tag The `toStringTag` of the objects to compare.
* @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
* @param {Function} customizer The function to customize comparisons.
* @param {Function} equalFunc The function to determine equivalents of values.
* @param {Object} stack Tracks traversed `object` and `other` objects.
* @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
*/
function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {
switch (tag) {
case dataViewTag:
if ((object.byteLength != other.byteLength) ||
(object.byteOffset != other.byteOffset)) {
return false;
}
object = object.buffer;
other = other.buffer;
case arrayBufferTag:
if ((object.byteLength != other.byteLength) ||
!equalFunc(new Uint8Array(object), new Uint8Array(other))) {
return false;
}
return true;
case boolTag:
case dateTag:
case numberTag:
// Coerce booleans to `1` or `0` and dates to milliseconds.
// Invalid dates are coerced to `NaN`.
return eq(+object, +other);
case errorTag:
return object.name == other.name && object.message == other.message;
case regexpTag:
case stringTag:
// Coerce regexes to strings and treat strings, primitives and objects,
// as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring
// for more details.
return object == (other + '');
case mapTag:
var convert = mapToArray;
case setTag:
var isPartial = bitmask & COMPARE_PARTIAL_FLAG;
convert || (convert = setToArray);
if (object.size != other.size && !isPartial) {
return false;
}
// Assume cyclic values are equal.
var stacked = stack.get(object);
if (stacked) {
return stacked == other;
}
bitmask |= COMPARE_UNORDERED_FLAG;
// Recursively compare objects (susceptible to call stack limits).
stack.set(object, other);
var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack);
stack['delete'](object);
return result;
case symbolTag:
if (symbolValueOf) {
return symbolValueOf.call(object) == symbolValueOf.call(other);
}
}
return false;
}
/**
* A specialized version of `baseIsEqualDeep` for objects with support for
* partial deep comparisons.
*
* @private
* @param {Object} object The object to compare.
* @param {Object} other The other object to compare.
* @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
* @param {Function} customizer The function to customize comparisons.
* @param {Function} equalFunc The function to determine equivalents of values.
* @param {Object} stack Tracks traversed `object` and `other` objects.
* @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
*/
function equalObjects(object, other, bitmask, customizer, equalFunc, stack) {
var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
objProps = getAllKeys(object),
objLength = objProps.length,
othProps = getAllKeys(other),
othLength = othProps.length;
if (objLength != othLength && !isPartial) {
return false;
}
var index = objLength;
while (index--) {
var key = objProps[index];
if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) {
return false;
}
}
// Assume cyclic values are equal.
var stacked = stack.get(object);
if (stacked && stack.get(other)) {
return stacked == other;
}
var result = true;
stack.set(object, other);
stack.set(other, object);
var skipCtor = isPartial;
while (++index < objLength) {
key = objProps[index];
var objValue = object[key],
othValue = other[key];
if (customizer) {
var compared = isPartial
? customizer(othValue, objValue, key, other, object, stack)
: customizer(objValue, othValue, key, object, other, stack);
}
// Recursively compare objects (susceptible to call stack limits).
if (!(compared === undefined
? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack))
: compared
)) {
result = false;
break;
}
skipCtor || (skipCtor = key == 'constructor');
}
if (result && !skipCtor) {
var objCtor = object.constructor,
othCtor = other.constructor;
// Non `Object` object instances with different constructors are not equal.
if (objCtor != othCtor &&
('constructor' in object && 'constructor' in other) &&
!(typeof objCtor == 'function' && objCtor instanceof objCtor &&
typeof othCtor == 'function' && othCtor instanceof othCtor)) {
result = false;
}
}
stack['delete'](object);
stack['delete'](other);
return result;
}
/**
* A specialized version of `baseRest` which flattens the rest array.
*
* @private
* @param {Function} func The function to apply a rest parameter to.
* @returns {Function} Returns the new function.
*/
function flatRest(func) {
return setToString(overRest(func, undefined, flatten), func + '');
}
/**
* Creates an array of own enumerable property names and symbols of `object`.
*
* @private
* @param {Object} object The object to query.
* @returns {Array} Returns the array of property names and symbols.
*/
function getAllKeys(object) {
return baseGetAllKeys(object, keys, getSymbols);
}
/**
* Creates an array of own and inherited enumerable property names and
* symbols of `object`.
*
* @private
* @param {Object} object The object to query.
* @returns {Array} Returns the array of property names and symbols.
*/
function getAllKeysIn(object) {
return baseGetAllKeys(object, keysIn, getSymbolsIn);
}
/**
* Gets metadata for `func`.
*
* @private
* @param {Function} func The function to query.
* @returns {*} Returns the metadata for `func`.
*/
var getData = !metaMap ? noop : function(func) {
return metaMap.get(func);
};
/**
* Gets the name of `func`.
*
* @private
* @param {Function} func The function to query.
* @returns {string} Returns the function name.
*/
function getFuncName(func) {
var result = (func.name + ''),
array = realNames[result],
length = hasOwnProperty.call(realNames, result) ? array.length : 0;
while (length--) {
var data = array[length],
otherFunc = data.func;
if (otherFunc == null || otherFunc == func) {
return data.name;
}
}
return result;
}
/**
* Gets the argument placeholder value for `func`.
*
* @private
* @param {Function} func The function to inspect.
* @returns {*} Returns the placeholder value.
*/
function getHolder(func) {
var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func;
return object.placeholder;
}
/**
* Gets the appropriate "iteratee" function. If `_.iteratee` is customized,
* this function returns the custom method, otherwise it returns `baseIteratee`.
* If arguments are provided, the chosen function is invoked with them and
* its result is returned.
*
* @private
* @param {*} [value] The value to convert to an iteratee.
* @param {number} [arity] The arity of the created iteratee.
* @returns {Function} Returns the chosen function or its result.
*/
function getIteratee() {
var result = lodash.iteratee || iteratee;
result = result === iteratee ? baseIteratee : result;
return arguments.length ? result(arguments[0], arguments[1]) : result;
}
/**
* Gets the data for `map`.
*
* @private
* @param {Object} map The map to query.
* @param {string} key The reference key.
* @returns {*} Returns the map data.
*/
function getMapData(map, key) {
var data = map.__data__;
return isKeyable(key)
? data[typeof key == 'string' ? 'string' : 'hash']
: data.map;
}
/**
* Gets the property names, values, and compare flags of `object`.
*
* @private
* @param {Object} object The object to query.
* @returns {Array} Returns the match data of `object`.
*/
function getMatchData(object) {
var result = keys(object),
length = result.length;
while (length--) {
var key = result[length],
value = object[key];
result[length] = [key, value, isStrictComparable(value)];
}
return result;
}
/**
* Gets the native function at `key` of `object`.
*
* @private
* @param {Object} object The object to query.
* @param {string} key The key of the method to get.
* @returns {*} Returns the function if it's native, else `undefined`.
*/
function getNative(object, key) {
var value = getValue(object, key);
return baseIsNative(value) ? value : undefined;
}
/**
* A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
*
* @private
* @param {*} value The value to query.
* @returns {string} Returns the raw `toStringTag`.
*/
function getRawTag(value) {
var isOwn = hasOwnProperty.call(value, symToStringTag),
tag = value[symToStringTag];
try {
value[symToStringTag] = undefined;
var unmasked = true;
} catch (e) {}
var result = nativeObjectToString.call(value);
if (unmasked) {
if (isOwn) {
value[symToStringTag] = tag;
} else {
delete value[symToStringTag];
}
}
return result;
}
/**
* Creates an array of the own enumerable symbols of `object`.
*
* @private
* @param {Object} object The object to query.
* @returns {Array} Returns the array of symbols.
*/
var getSymbols = !nativeGetSymbols ? stubArray : function(object) {
if (object == null) {
return [];
}
object = Object(object);
return arrayFilter(nativeGetSymbols(object), function(symbol) {
return propertyIsEnumerable.call(object, symbol);
});
};
/**
* Creates an array of the own and inherited enumerable symbols of `object`.
*
* @private
* @param {Object} object The object to query.
* @returns {Array} Returns the array of symbols.
*/
var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) {
var result = [];
while (object) {
arrayPush(result, getSymbols(object));
object = getPrototype(object);
}
return result;
};
/**
* Gets the `toStringTag` of `value`.
*
* @private
* @param {*} value The value to query.
* @returns {string} Returns the `toStringTag`.
*/
var getTag = baseGetTag;
// Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.
if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||
(Map && getTag(new Map) != mapTag) ||
(Promise && getTag(Promise.resolve()) != promiseTag) ||
(Set && getTag(new Set) != setTag) ||
(WeakMap && getTag(new WeakMap) != weakMapTag)) {
getTag = function(value) {
var result = baseGetTag(value),
Ctor = result == objectTag ? value.constructor : undefined,
ctorString = Ctor ? toSource(Ctor) : '';
if (ctorString) {
switch (ctorString) {
case dataViewCtorString: return dataViewTag;
case mapCtorString: return mapTag;
case promiseCtorString: return promiseTag;
case setCtorString: return setTag;
case weakMapCtorString: return weakMapTag;
}
}
return result;
};
}
/**
* Gets the view, applying any `transforms` to the `start` and `end` positions.
*
* @private
* @param {number} start The start of the view.
* @param {number} end The end of the view.
* @param {Array} transforms The transformations to apply to the view.
* @returns {Object} Returns an object containing the `start` and `end`
* positions of the view.
*/
function getView(start, end, transforms) {
var index = -1,
length = transforms.length;
while (++index < length) {
var data = transforms[index],
size = data.size;
switch (data.type) {
case 'drop': start += size; break;
case 'dropRight': end -= size; break;
case 'take': end = nativeMin(end, start + size); break;
case 'takeRight': start = nativeMax(start, end - size); break;
}
}
return { 'start': start, 'end': end };
}
/**
* Extracts wrapper details from the `source` body comment.
*
* @private
* @param {string} source The source to inspect.
* @returns {Array} Returns the wrapper details.
*/
function getWrapDetails(source) {
var match = source.match(reWrapDetails);
return match ? match[1].split(reSplitDetails) : [];
}
/**
* Checks if `path` exists on `object`.
*
* @private
* @param {Object} object The object to query.
* @param {Array|string} path The path to check.
* @param {Function} hasFunc The function to check properties.
* @returns {boolean} Returns `true` if `path` exists, else `false`.
*/
function hasPath(object, path, hasFunc) {
path = castPath(path, object);
var index = -1,
length = path.length,
result = false;
while (++index < length) {
var key = toKey(path[index]);
if (!(result = object != null && hasFunc(object, key))) {
break;
}
object = object[key];
}
if (result || ++index != length) {
return result;
}
length = object == null ? 0 : object.length;
return !!length && isLength(length) && isIndex(key, length) &&
(isArray(object) || isArguments(object));
}
/**
* Initializes an array clone.
*
* @private
* @param {Array} array The array to clone.
* @returns {Array} Returns the initialized clone.
*/
function initCloneArray(array) {
var length = array.length,
result = new array.constructor(length);
// Add properties assigned by `RegExp#exec`.
if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
result.index = array.index;
result.input = array.input;
}
return result;
}
/**
* Initializes an object clone.
*
* @private
* @param {Object} object The object to clone.
* @returns {Object} Returns the initialized clone.
*/
function initCloneObject(object) {
return (typeof object.constructor == 'function' && !isPrototype(object))
? baseCreate(getPrototype(object))
: {};
}
/**
* Initializes an object clone based on its `toStringTag`.
*
* **Note:** This function only supports cloning values with tags of
* `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`.
*
* @private
* @param {Object} object The object to clone.
* @param {string} tag The `toStringTag` of the object to clone.
* @param {boolean} [isDeep] Specify a deep clone.
* @returns {Object} Returns the initialized clone.
*/
function initCloneByTag(object, tag, isDeep) {
var Ctor = object.constructor;
switch (tag) {
case arrayBufferTag:
return cloneArrayBuffer(object);
case boolTag:
case dateTag:
return new Ctor(+object);
case dataViewTag:
return cloneDataView(object, isDeep);
case float32Tag: case float64Tag:
case int8Tag: case int16Tag: case int32Tag:
case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
return cloneTypedArray(object, isDeep);
case mapTag:
return new Ctor;
case numberTag:
case stringTag:
return new Ctor(object);
case regexpTag:
return cloneRegExp(object);
case setTag:
return new Ctor;
case symbolTag:
return cloneSymbol(object);
}
}
/**
* Inserts wrapper `details` in a comment at the top of the `source` body.
*
* @private
* @param {string} source The source to modify.
* @returns {Array} details The details to insert.
* @returns {string} Returns the modified source.
*/
function insertWrapDetails(source, details) {
var length = details.length;
if (!length) {
return source;
}
var lastIndex = length - 1;
details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex];
details = details.join(length > 2 ? ', ' : ' ');
return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n');
}
/**
* Checks if `value` is a flattenable `arguments` object or array.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
*/
function isFlattenable(value) {
return isArray(value) || isArguments(value) ||
!!(spreadableSymbol && value && value[spreadableSymbol]);
}
/**
* Checks if `value` is a valid array-like index.
*
* @private
* @param {*} value The value to check.
* @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
* @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
*/
function isIndex(value, length) {
var type = typeof value;
length = length == null ? MAX_SAFE_INTEGER : length;
return !!length &&
(type == 'number' ||
(type != 'symbol' && reIsUint.test(value))) &&
(value > -1 && value % 1 == 0 && value < length);
}
/**
* Checks if the given arguments are from an iteratee call.
*
* @private
* @param {*} value The potential iteratee value argument.
* @param {*} index The potential iteratee index or key argument.
* @param {*} object The potential iteratee object argument.
* @returns {boolean} Returns `true` if the arguments are from an iteratee call,
* else `false`.
*/
function isIterateeCall(value, index, object) {
if (!isObject(object)) {
return false;
}
var type = typeof index;
if (type == 'number'
? (isArrayLike(object) && isIndex(index, object.length))
: (type == 'string' && index in object)
) {
return eq(object[index], value);
}
return false;
}
/**
* Checks if `value` is a property name and not a property path.
*
* @private
* @param {*} value The value to check.
* @param {Object} [object] The object to query keys on.
* @returns {boolean} Returns `true` if `value` is a property name, else `false`.
*/
function isKey(value, object) {
if (isArray(value)) {
return false;
}
var type = typeof value;
if (type == 'number' || type == 'symbol' || type == 'boolean' ||
value == null || isSymbol(value)) {
return true;
}
return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
(object != null && value in Object(object));
}
/**
* Checks if `value` is suitable for use as unique object key.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is suitable, else `false`.
*/
function isKeyable(value) {
var type = typeof value;
return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
? (value !== '__proto__')
: (value === null);
}
/**
* Checks if `func` has a lazy counterpart.
*
* @private
* @param {Function} func The function to check.
* @returns {boolean} Returns `true` if `func` has a lazy counterpart,
* else `false`.
*/
function isLaziable(func) {
var funcName = getFuncName(func),
other = lodash[funcName];
if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) {
return false;
}
if (func === other) {
return true;
}
var data = getData(other);
return !!data && func === data[0];
}
/**
* Checks if `func` has its source masked.
*
* @private
* @param {Function} func The function to check.
* @returns {boolean} Returns `true` if `func` is masked, else `false`.
*/
function isMasked(func) {
return !!maskSrcKey && (maskSrcKey in func);
}
/**
* Checks if `func` is capable of being masked.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `func` is maskable, else `false`.
*/
var isMaskable = coreJsData ? isFunction : stubFalse;
/**
* Checks if `value` is likely a prototype object.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
*/
function isPrototype(value) {
var Ctor = value && value.constructor,
proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;
return value === proto;
}
/**
* Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` if suitable for strict
* equality comparisons, else `false`.
*/
function isStrictComparable(value) {
return value === value && !isObject(value);
}
/**
* A specialized version of `matchesProperty` for source values suitable
* for strict equality comparisons, i.e. `===`.
*
* @private
* @param {string} key The key of the property to get.
* @param {*} srcValue The value to match.
* @returns {Function} Returns the new spec function.
*/
function matchesStrictComparable(key, srcValue) {
return function(object) {
if (object == null) {
return false;
}
return object[key] === srcValue &&
(srcValue !== undefined || (key in Object(object)));
};
}
/**
* A specialized version of `_.memoize` which clears the memoized function's
* cache when it exceeds `MAX_MEMOIZE_SIZE`.
*
* @private
* @param {Function} func The function to have its output memoized.
* @returns {Function} Returns the new memoized function.
*/
function memoizeCapped(func) {
var result = memoize(func, function(key) {
if (cache.size === MAX_MEMOIZE_SIZE) {
cache.clear();
}
return key;
});
var cache = result.cache;
return result;
}
/**
* Merges the function metadata of `source` into `data`.
*
* Merging metadata reduces the number of wrappers used to invoke a function.
* This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
* may be applied regardless of execution order. Methods like `_.ary` and
* `_.rearg` modify function arguments, making the order in which they are
* executed important, preventing the merging of metadata. However, we make
* an exception for a safe combined case where curried functions have `_.ary`
* and or `_.rearg` applied.
*
* @private
* @param {Array} data The destination metadata.
* @param {Array} source The source metadata.
* @returns {Array} Returns `data`.
*/
function mergeData(data, source) {
var bitmask = data[1],
srcBitmask = source[1],
newBitmask = bitmask | srcBitmask,
isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG);
var isCombo =
((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_CURRY_FLAG)) ||
((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_REARG_FLAG) && (data[7].length <= source[8])) ||
((srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == WRAP_CURRY_FLAG));
// Exit early if metadata can't be merged.
if (!(isCommon || isCombo)) {
return data;
}
// Use source `thisArg` if available.
if (srcBitmask & WRAP_BIND_FLAG) {
data[2] = source[2];
// Set when currying a bound function.
newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG;
}
// Compose partial arguments.
var value = source[3];
if (value) {
var partials = data[3];
data[3] = partials ? composeArgs(partials, value, source[4]) : value;
data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4];
}
// Compose partial right arguments.
value = source[5];
if (value) {
partials = data[5];
data[5] = partials ? composeArgsRight(partials, value, source[6]) : value;
data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6];
}
// Use source `argPos` if available.
value = source[7];
if (value) {
data[7] = value;
}
// Use source `ary` if it's smaller.
if (srcBitmask & WRAP_ARY_FLAG) {
data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
}
// Use source `arity` if one is not provided.
if (data[9] == null) {
data[9] = source[9];
}
// Use source `func` and merge bitmasks.
data[0] = source[0];
data[1] = newBitmask;
return data;
}
/**
* This function is like
* [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
* except that it includes inherited enumerable properties.
*
* @private
* @param {Object} object The object to query.
* @returns {Array} Returns the array of property names.
*/
function nativeKeysIn(object) {
var result = [];
if (object != null) {
for (var key in Object(object)) {
result.push(key);
}
}
return result;
}
/**
* Converts `value` to a string using `Object.prototype.toString`.
*
* @private
* @param {*} value The value to convert.
* @returns {string} Returns the converted string.
*/
function objectToString(value) {
return nativeObjectToString.call(value);
}
/**
* A specialized version of `baseRest` which transforms the rest array.
*
* @private
* @param {Function} func The function to apply a rest parameter to.
* @param {number} [start=func.length-1] The start position of the rest parameter.
* @param {Function} transform The rest array transform.
* @returns {Function} Returns the new function.
*/
function overRest(func, start, transform) {
start = nativeMax(start === undefined ? (func.length - 1) : start, 0);
return function() {
var args = arguments,
index = -1,
length = nativeMax(args.length - start, 0),
array = Array(length);
while (++index < length) {
array[index] = args[start + index];
}
index = -1;
var otherArgs = Array(start + 1);
while (++index < start) {
otherArgs[index] = args[index];
}
otherArgs[start] = transform(array);
return apply(func, this, otherArgs);
};
}
/**
* Gets the parent value at `path` of `object`.
*
* @private
* @param {Object} object The object to query.
* @param {Array} path The path to get the parent value of.
* @returns {*} Returns the parent value.
*/
function parent(object, path) {
return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1));
}
/**
* Reorder `array` according to the specified indexes where the element at
* the first index is assigned as the first element, the element at
* the second index is assigned as the second element, and so on.
*
* @private
* @param {Array} array The array to reorder.
* @param {Array} indexes The arranged array indexes.
* @returns {Array} Returns `array`.
*/
function reorder(array, indexes) {
var arrLength = array.length,
length = nativeMin(indexes.length, arrLength),
oldArray = copyArray(array);
while (length--) {
var index = indexes[length];
array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
}
return array;
}
/**
* Gets the value at `key`, unless `key` is "__proto__".
*
* @private
* @param {Object} object The object to query.
* @param {string} key The key of the property to get.
* @returns {*} Returns the property value.
*/
function safeGet(object, key) {
if (key == '__proto__') {
return;
}
return object[key];
}
/**
* Sets metadata for `func`.
*
* **Note:** If this function becomes hot, i.e. is invoked a lot in a short
* period of time, it will trip its breaker and transition to an identity
* function to avoid garbage collection pauses in V8. See
* [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070)
* for more details.
*
* @private
* @param {Function} func The function to associate metadata with.
* @param {*} data The metadata.
* @returns {Function} Returns `func`.
*/
var setData = shortOut(baseSetData);
/**
* A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout).
*
* @private
* @param {Function} func The function to delay.
* @param {number} wait The number of milliseconds to delay invocation.
* @returns {number|Object} Returns the timer id or timeout object.
*/
var setTimeout = ctxSetTimeout || function(func, wait) {
return root.setTimeout(func, wait);
};
/**
* Sets the `toString` method of `func` to return `string`.
*
* @private
* @param {Function} func The function to modify.
* @param {Function} string The `toString` result.
* @returns {Function} Returns `func`.
*/
var setToString = shortOut(baseSetToString);
/**
* Sets the `toString` method of `wrapper` to mimic the source of `reference`
* with wrapper details in a comment at the top of the source body.
*
* @private
* @param {Function} wrapper The function to modify.
* @param {Function} reference The reference function.
* @param {number} bitmask The bitmask flags. See `createWrap` for more details.
* @returns {Function} Returns `wrapper`.
*/
function setWrapToString(wrapper, reference, bitmask) {
var source = (reference + '');
return setToString(wrapper, insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask)));
}
/**
* Creates a function that'll short out and invoke `identity` instead
* of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`
* milliseconds.
*
* @private
* @param {Function} func The function to restrict.
* @returns {Function} Returns the new shortable function.
*/
function shortOut(func) {
var count = 0,
lastCalled = 0;
return function() {
var stamp = nativeNow(),
remaining = HOT_SPAN - (stamp - lastCalled);
lastCalled = stamp;
if (remaining > 0) {
if (++count >= HOT_COUNT) {
return arguments[0];
}
} else {
count = 0;
}
return func.apply(undefined, arguments);
};
}
/**
* A specialized version of `_.shuffle` which mutates and sets the size of `array`.
*
* @private
* @param {Array} array The array to shuffle.
* @param {number} [size=array.length] The size of `array`.
* @returns {Array} Returns `array`.
*/
function shuffleSelf(array, size) {
var index = -1,
length = array.length,
lastIndex = length - 1;
size = size === undefined ? length : size;
while (++index < size) {
var rand = baseRandom(index, lastIndex),
value = array[rand];
array[rand] = array[index];
array[index] = value;
}
array.length = size;
return array;
}
/**
* Converts `string` to a property path array.
*
* @private
* @param {string} string The string to convert.
* @returns {Array} Returns the property path array.
*/
var stringToPath = memoizeCapped(function(string) {
var result = [];
if (string.charCodeAt(0) === 46 /* . */) {
result.push('');
}
string.replace(rePropName, function(match, number, quote, subString) {
result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match));
});
return result;
});
/**
* Converts `value` to a string key if it's not a string or symbol.
*
* @private
* @param {*} value The value to inspect.
* @returns {string|symbol} Returns the key.
*/
function toKey(value) {
if (typeof value == 'string' || isSymbol(value)) {
return value;
}
var result = (value + '');
return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
}
/**
* Converts `func` to its source code.
*
* @private
* @param {Function} func The function to convert.
* @returns {string} Returns the source code.
*/
function toSource(func) {
if (func != null) {
try {
return funcToString.call(func);
} catch (e) {}
try {
return (func + '');
} catch (e) {}
}
return '';
}
/**
* Updates wrapper `details` based on `bitmask` flags.
*
* @private
* @returns {Array} details The details to modify.
* @param {number} bitmask The bitmask flags. See `createWrap` for more details.
* @returns {Array} Returns `details`.
*/
function updateWrapDetails(details, bitmask) {
arrayEach(wrapFlags, function(pair) {
var value = '_.' + pair[0];
if ((bitmask & pair[1]) && !arrayIncludes(details, value)) {
details.push(value);
}
});
return details.sort();
}
/**
* Creates a clone of `wrapper`.
*
* @private
* @param {Object} wrapper The wrapper to clone.
* @returns {Object} Returns the cloned wrapper.
*/
function wrapperClone(wrapper) {
if (wrapper instanceof LazyWrapper) {
return wrapper.clone();
}
var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__);
result.__actions__ = copyArray(wrapper.__actions__);
result.__index__ = wrapper.__index__;
result.__values__ = wrapper.__values__;
return result;
}
/*------------------------------------------------------------------------*/
/**
* Creates an array of elements split into groups the length of `size`.
* If `array` can't be split evenly, the final chunk will be the remaining
* elements.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Array
* @param {Array} array The array to process.
* @param {number} [size=1] The length of each chunk
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
* @returns {Array} Returns the new array of chunks.
* @example
*
* _.chunk(['a', 'b', 'c', 'd'], 2);
* // => [['a', 'b'], ['c', 'd']]
*
* _.chunk(['a', 'b', 'c', 'd'], 3);
* // => [['a', 'b', 'c'], ['d']]
*/
function chunk(array, size, guard) {
if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) {
size = 1;
} else {
size = nativeMax(toInteger(size), 0);
}
var length = array == null ? 0 : array.length;
if (!length || size < 1) {
return [];
}
var index = 0,
resIndex = 0,
result = Array(nativeCeil(length / size));
while (index < length) {
result[resIndex++] = baseSlice(array, index, (index += size));
}
return result;
}
/**
* Creates an array with all falsey values removed. The values `false`, `null`,
* `0`, `""`, `undefined`, and `NaN` are falsey.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Array
* @param {Array} array The array to compact.
* @returns {Array} Returns the new array of filtered values.
* @example
*
* _.compact([0, 1, false, 2, '', 3]);
* // => [1, 2, 3]
*/
function compact(array) {
var index = -1,
length = array == null ? 0 : array.length,
resIndex = 0,
result = [];
while (++index < length) {
var value = array[index];
if (value) {
result[resIndex++] = value;
}
}
return result;
}
/**
* Creates a new array concatenating `array` with any additional arrays
* and/or values.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {Array} array The array to concatenate.
* @param {...*} [values] The values to concatenate.
* @returns {Array} Returns the new concatenated array.
* @example
*
* var array = [1];
* var other = _.concat(array, 2, [3], [[4]]);
*
* console.log(other);
* // => [1, 2, 3, [4]]
*
* console.log(array);
* // => [1]
*/
function concat() {
var length = arguments.length;
if (!length) {
return [];
}
var args = Array(length - 1),
array = arguments[0],
index = length;
while (index--) {
args[index - 1] = arguments[index];
}
return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1));
}
/**
* Creates an array of `array` values not included in the other given arrays
* using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
* for equality comparisons. The order and references of result values are
* determined by the first array.
*
* **Note:** Unlike `_.pullAll`, this method returns a new array.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Array
* @param {Array} array The array to inspect.
* @param {...Array} [values] The values to exclude.
* @returns {Array} Returns the new array of filtered values.
* @see _.without, _.xor
* @example
*
* _.difference([2, 1], [2, 3]);
* // => [1]
*/
var difference = baseRest(function(array, values) {
return isArrayLikeObject(array)
? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))
: [];
});
/**
* This method is like `_.difference` except that it accepts `iteratee` which
* is invoked for each element of `array` and `values` to generate the criterion
* by which they're compared. The order and references of result values are
* determined by the first array. The iteratee is invoked with one argument:
* (value).
*
* **Note:** Unlike `_.pullAllBy`, this method returns a new array.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {Array} array The array to inspect.
* @param {...Array} [values] The values to exclude.
* @param {Function} [iteratee=_.identity] The iteratee invoked per element.
* @returns {Array} Returns the new array of filtered values.
* @example
*
* _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor);
* // => [1.2]
*
* // The `_.property` iteratee shorthand.
* _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
* // => [{ 'x': 2 }]
*/
var differenceBy = baseRest(function(array, values) {
var iteratee = last(values);
if (isArrayLikeObject(iteratee)) {
iteratee = undefined;
}
return isArrayLikeObject(array)
? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee, 2))
: [];
});
/**
* This method is like `_.difference` except that it accepts `comparator`
* which is invoked to compare elements of `array` to `values`. The order and
* references of result values are determined by the first array. The comparator
* is invoked with two arguments: (arrVal, othVal).
*
* **Note:** Unlike `_.pullAllWith`, this method returns a new array.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {Array} array The array to inspect.
* @param {...Array} [values] The values to exclude.
* @param {Function} [comparator] The comparator invoked per element.
* @returns {Array} Returns the new array of filtered values.
* @example
*
* var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
*
* _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual);
* // => [{ 'x': 2, 'y': 1 }]
*/
var differenceWith = baseRest(function(array, values) {
var comparator = last(values);
if (isArrayLikeObject(comparator)) {
comparator = undefined;
}
return isArrayLikeObject(array)
? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator)
: [];
});
/**
* Creates a slice of `array` with `n` elements dropped from the beginning.
*
* @static
* @memberOf _
* @since 0.5.0
* @category Array
* @param {Array} array The array to query.
* @param {number} [n=1] The number of elements to drop.
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
* @returns {Array} Returns the slice of `array`.
* @example
*
* _.drop([1, 2, 3]);
* // => [2, 3]
*
* _.drop([1, 2, 3], 2);
* // => [3]
*
* _.drop([1, 2, 3], 5);
* // => []
*
* _.drop([1, 2, 3], 0);
* // => [1, 2, 3]
*/
function drop(array, n, guard) {
var length = array == null ? 0 : array.length;
if (!length) {
return [];
}
n = (guard || n === undefined) ? 1 : toInteger(n);
return baseSlice(array, n < 0 ? 0 : n, length);
}
/**
* Creates a slice of `array` with `n` elements dropped from the end.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Array
* @param {Array} array The array to query.
* @param {number} [n=1] The number of elements to drop.
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
* @returns {Array} Returns the slice of `array`.
* @example
*
* _.dropRight([1, 2, 3]);
* // => [1, 2]
*
* _.dropRight([1, 2, 3], 2);
* // => [1]
*
* _.dropRight([1, 2, 3], 5);
* // => []
*
* _.dropRight([1, 2, 3], 0);
* // => [1, 2, 3]
*/
function dropRight(array, n, guard) {
var length = array == null ? 0 : array.length;
if (!length) {
return [];
}
n = (guard || n === undefined) ? 1 : toInteger(n);
n = length - n;
return baseSlice(array, 0, n < 0 ? 0 : n);
}
/**
* Creates a slice of `array` excluding elements dropped from the end.
* Elements are dropped until `predicate` returns falsey. The predicate is
* invoked with three arguments: (value, index, array).
*
* @static
* @memberOf _
* @since 3.0.0
* @category Array
* @param {Array} array The array to query.
* @param {Function} [predicate=_.identity] The function invoked per iteration.
* @returns {Array} Returns the slice of `array`.
* @example
*
* var users = [
* { 'user': 'barney', 'active': true },
* { 'user': 'fred', 'active': false },
* { 'user': 'pebbles', 'active': false }
* ];
*
* _.dropRightWhile(users, function(o) { return !o.active; });
* // => objects for ['barney']
*
* // The `_.matches` iteratee shorthand.
* _.dropRightWhile(users, { 'user': 'pebbles', 'active': false });
* // => objects for ['barney', 'fred']
*
* // The `_.matchesProperty` iteratee shorthand.
* _.dropRightWhile(users, ['active', false]);
* // => objects for ['barney']
*
* // The `_.property` iteratee shorthand.
* _.dropRightWhile(users, 'active');
* // => objects for ['barney', 'fred', 'pebbles']
*/
function dropRightWhile(array, predicate) {
return (array && array.length)
? baseWhile(array, getIteratee(predicate, 3), true, true)
: [];
}
/**
* Creates a slice of `array` excluding elements dropped from the beginning.
* Elements are dropped until `predicate` returns falsey. The predicate is
* invoked with three arguments: (value, index, array).
*
* @static
* @memberOf _
* @since 3.0.0
* @category Array
* @param {Array} array The array to query.
* @param {Function} [predicate=_.identity] The function invoked per iteration.
* @returns {Array} Returns the slice of `array`.
* @example
*
* var users = [
* { 'user': 'barney', 'active': false },
* { 'user': 'fred', 'active': false },
* { 'user': 'pebbles', 'active': true }
* ];
*
* _.dropWhile(users, function(o) { return !o.active; });
* // => objects for ['pebbles']
*
* // The `_.matches` iteratee shorthand.
* _.dropWhile(users, { 'user': 'barney', 'active': false });
* // => objects for ['fred', 'pebbles']
*
* // The `_.matchesProperty` iteratee shorthand.
* _.dropWhile(users, ['active', false]);
* // => objects for ['pebbles']
*
* // The `_.property` iteratee shorthand.
* _.dropWhile(users, 'active');
* // => objects for ['barney', 'fred', 'pebbles']
*/
function dropWhile(array, predicate) {
return (array && array.length)
? baseWhile(array, getIteratee(predicate, 3), true)
: [];
}
/**
* Fills elements of `array` with `value` from `start` up to, but not
* including, `end`.
*
* **Note:** This method mutates `array`.
*
* @static
* @memberOf _
* @since 3.2.0
* @category Array
* @param {Array} array The array to fill.
* @param {*} value The value to fill `array` with.
* @param {number} [start=0] The start position.
* @param {number} [end=array.length] The end position.
* @returns {Array} Returns `array`.
* @example
*
* var array = [1, 2, 3];
*
* _.fill(array, 'a');
* console.log(array);
* // => ['a', 'a', 'a']
*
* _.fill(Array(3), 2);
* // => [2, 2, 2]
*
* _.fill([4, 6, 8, 10], '*', 1, 3);
* // => [4, '*', '*', 10]
*/
function fill(array, value, start, end) {
var length = array == null ? 0 : array.length;
if (!length) {
return [];
}
if (start && typeof start != 'number' && isIterateeCall(array, value, start)) {
start = 0;
end = length;
}
return baseFill(array, value, start, end);
}
/**
* This method is like `_.find` except that it returns the index of the first
* element `predicate` returns truthy for instead of the element itself.
*
* @static
* @memberOf _
* @since 1.1.0
* @category Array
* @param {Array} array The array to inspect.
* @param {Function} [predicate=_.identity] The function invoked per iteration.
* @param {number} [fromIndex=0] The index to search from.
* @returns {number} Returns the index of the found element, else `-1`.
* @example
*
* var users = [
* { 'user': 'barney', 'active': false },
* { 'user': 'fred', 'active': false },
* { 'user': 'pebbles', 'active': true }
* ];
*
* _.findIndex(users, function(o) { return o.user == 'barney'; });
* // => 0
*
* // The `_.matches` iteratee shorthand.
* _.findIndex(users, { 'user': 'fred', 'active': false });
* // => 1
*
* // The `_.matchesProperty` iteratee shorthand.
* _.findIndex(users, ['active', false]);
* // => 0
*
* // The `_.property` iteratee shorthand.
* _.findIndex(users, 'active');
* // => 2
*/
function findIndex(array, predicate, fromIndex) {
var length = array == null ? 0 : array.length;
if (!length) {
return -1;
}
var index = fromIndex == null ? 0 : toInteger(fromIndex);
if (index < 0) {
index = nativeMax(length + index, 0);
}
return baseFindIndex(array, getIteratee(predicate, 3), index);
}
/**
* This method is like `_.findIndex` except that it iterates over elements
* of `collection` from right to left.
*
* @static
* @memberOf _
* @since 2.0.0
* @category Array
* @param {Array} array The array to inspect.
* @param {Function} [predicate=_.identity] The function invoked per iteration.
* @param {number} [fromIndex=array.length-1] The index to search from.
* @returns {number} Returns the index of the found element, else `-1`.
* @example
*
* var users = [
* { 'user': 'barney', 'active': true },
* { 'user': 'fred', 'active': false },
* { 'user': 'pebbles', 'active': false }
* ];
*
* _.findLastIndex(users, function(o) { return o.user == 'pebbles'; });
* // => 2
*
* // The `_.matches` iteratee shorthand.
* _.findLastIndex(users, { 'user': 'barney', 'active': true });
* // => 0
*
* // The `_.matchesProperty` iteratee shorthand.
* _.findLastIndex(users, ['active', false]);
* // => 2
*
* // The `_.property` iteratee shorthand.
* _.findLastIndex(users, 'active');
* // => 0
*/
function findLastIndex(array, predicate, fromIndex) {
var length = array == null ? 0 : array.length;
if (!length) {
return -1;
}
var index = length - 1;
if (fromIndex !== undefined) {
index = toInteger(fromIndex);
index = fromIndex < 0
? nativeMax(length + index, 0)
: nativeMin(index, length - 1);
}
return baseFindIndex(array, getIteratee(predicate, 3), index, true);
}
/**
* Flattens `array` a single level deep.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Array
* @param {Array} array The array to flatten.
* @returns {Array} Returns the new flattened array.
* @example
*
* _.flatten([1, [2, [3, [4]], 5]]);
* // => [1, 2, [3, [4]], 5]
*/
function flatten(array) {
var length = array == null ? 0 : array.length;
return length ? baseFlatten(array, 1) : [];
}
/**
* Recursively flattens `array`.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Array
* @param {Array} array The array to flatten.
* @returns {Array} Returns the new flattened array.
* @example
*
* _.flattenDeep([1, [2, [3, [4]], 5]]);
* // => [1, 2, 3, 4, 5]
*/
function flattenDeep(array) {
var length = array == null ? 0 : array.length;
return length ? baseFlatten(array, INFINITY) : [];
}
/**
* Recursively flatten `array` up to `depth` times.
*
* @static
* @memberOf _
* @since 4.4.0
* @category Array
* @param {Array} array The array to flatten.
* @param {number} [depth=1] The maximum recursion depth.
* @returns {Array} Returns the new flattened array.
* @example
*
* var array = [1, [2, [3, [4]], 5]];
*
* _.flattenDepth(array, 1);
* // => [1, 2, [3, [4]], 5]
*
* _.flattenDepth(array, 2);
* // => [1, 2, 3, [4], 5]
*/
function flattenDepth(array, depth) {
var length = array == null ? 0 : array.length;
if (!length) {
return [];
}
depth = depth === undefined ? 1 : toInteger(depth);
return baseFlatten(array, depth);
}
/**
* The inverse of `_.toPairs`; this method returns an object composed
* from key-value `pairs`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {Array} pairs The key-value pairs.
* @returns {Object} Returns the new object.
* @example
*
* _.fromPairs([['a', 1], ['b', 2]]);
* // => { 'a': 1, 'b': 2 }
*/
function fromPairs(pairs) {
var index = -1,
length = pairs == null ? 0 : pairs.length,
result = {};
while (++index < length) {
var pair = pairs[index];
result[pair[0]] = pair[1];
}
return result;
}
/**
* Gets the first element of `array`.
*
* @static
* @memberOf _
* @since 0.1.0
* @alias first
* @category Array
* @param {Array} array The array to query.
* @returns {*} Returns the first element of `array`.
* @example
*
* _.head([1, 2, 3]);
* // => 1
*
* _.head([]);
* // => undefined
*/
function head(array) {
return (array && array.length) ? array[0] : undefined;
}
/**
* Gets the index at which the first occurrence of `value` is found in `array`
* using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
* for equality comparisons. If `fromIndex` is negative, it's used as the
* offset from the end of `array`.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Array
* @param {Array} array The array to inspect.
* @param {*} value The value to search for.
* @param {number} [fromIndex=0] The index to search from.
* @returns {number} Returns the index of the matched value, else `-1`.
* @example
*
* _.indexOf([1, 2, 1, 2], 2);
* // => 1
*
* // Search from the `fromIndex`.
* _.indexOf([1, 2, 1, 2], 2, 2);
* // => 3
*/
function indexOf(array, value, fromIndex) {
var length = array == null ? 0 : array.length;
if (!length) {
return -1;
}
var index = fromIndex == null ? 0 : toInteger(fromIndex);
if (index < 0) {
index = nativeMax(length + index, 0);
}
return baseIndexOf(array, value, index);
}
/**
* Gets all but the last element of `array`.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Array
* @param {Array} array The array to query.
* @returns {Array} Returns the slice of `array`.
* @example
*
* _.initial([1, 2, 3]);
* // => [1, 2]
*/
function initial(array) {
var length = array == null ? 0 : array.length;
return length ? baseSlice(array, 0, -1) : [];
}
/**
* Creates an array of unique values that are included in all given arrays
* using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
* for equality comparisons. The order and references of result values are
* determined by the first array.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Array
* @param {...Array} [arrays] The arrays to inspect.
* @returns {Array} Returns the new array of intersecting values.
* @example
*
* _.intersection([2, 1], [2, 3]);
* // => [2]
*/
var intersection = baseRest(function(arrays) {
var mapped = arrayMap(arrays, castArrayLikeObject);
return (mapped.length && mapped[0] === arrays[0])
? baseIntersection(mapped)
: [];
});
/**
* This method is like `_.intersection` except that it accepts `iteratee`
* which is invoked for each element of each `arrays` to generate the criterion
* by which they're compared. The order and references of result values are
* determined by the first array. The iteratee is invoked with one argument:
* (value).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {...Array} [arrays] The arrays to inspect.
* @param {Function} [iteratee=_.identity] The iteratee invoked per element.
* @returns {Array} Returns the new array of intersecting values.
* @example
*
* _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor);
* // => [2.1]
*
* // The `_.property` iteratee shorthand.
* _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
* // => [{ 'x': 1 }]
*/
var intersectionBy = baseRest(function(arrays) {
var iteratee = last(arrays),
mapped = arrayMap(arrays, castArrayLikeObject);
if (iteratee === last(mapped)) {
iteratee = undefined;
} else {
mapped.pop();
}
return (mapped.length && mapped[0] === arrays[0])
? baseIntersection(mapped, getIteratee(iteratee, 2))
: [];
});
/**
* This method is like `_.intersection` except that it accepts `comparator`
* which is invoked to compare elements of `arrays`. The order and references
* of result values are determined by the first array. The comparator is
* invoked with two arguments: (arrVal, othVal).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {...Array} [arrays] The arrays to inspect.
* @param {Function} [comparator] The comparator invoked per element.
* @returns {Array} Returns the new array of intersecting values.
* @example
*
* var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
* var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
*
* _.intersectionWith(objects, others, _.isEqual);
* // => [{ 'x': 1, 'y': 2 }]
*/
var intersectionWith = baseRest(function(arrays) {
var comparator = last(arrays),
mapped = arrayMap(arrays, castArrayLikeObject);
comparator = typeof comparator == 'function' ? comparator : undefined;
if (comparator) {
mapped.pop();
}
return (mapped.length && mapped[0] === arrays[0])
? baseIntersection(mapped, undefined, comparator)
: [];
});
/**
* Converts all elements in `array` into a string separated by `separator`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {Array} array The array to convert.
* @param {string} [separator=','] The element separator.
* @returns {string} Returns the joined string.
* @example
*
* _.join(['a', 'b', 'c'], '~');
* // => 'a~b~c'
*/
function join(array, separator) {
return array == null ? '' : nativeJoin.call(array, separator);
}
/**
* Gets the last element of `array`.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Array
* @param {Array} array The array to query.
* @returns {*} Returns the last element of `array`.
* @example
*
* _.last([1, 2, 3]);
* // => 3
*/
function last(array) {
var length = array == null ? 0 : array.length;
return length ? array[length - 1] : undefined;
}
/**
* This method is like `_.indexOf` except that it iterates over elements of
* `array` from right to left.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Array
* @param {Array} array The array to inspect.
* @param {*} value The value to search for.
* @param {number} [fromIndex=array.length-1] The index to search from.
* @returns {number} Returns the index of the matched value, else `-1`.
* @example
*
* _.lastIndexOf([1, 2, 1, 2], 2);
* // => 3
*
* // Search from the `fromIndex`.
* _.lastIndexOf([1, 2, 1, 2], 2, 2);
* // => 1
*/
function lastIndexOf(array, value, fromIndex) {
var length = array == null ? 0 : array.length;
if (!length) {
return -1;
}
var index = length;
if (fromIndex !== undefined) {
index = toInteger(fromIndex);
index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1);
}
return value === value
? strictLastIndexOf(array, value, index)
: baseFindIndex(array, baseIsNaN, index, true);
}
/**
* Gets the element at index `n` of `array`. If `n` is negative, the nth
* element from the end is returned.
*
* @static
* @memberOf _
* @since 4.11.0
* @category Array
* @param {Array} array The array to query.
* @param {number} [n=0] The index of the element to return.
* @returns {*} Returns the nth element of `array`.
* @example
*
* var array = ['a', 'b', 'c', 'd'];
*
* _.nth(array, 1);
* // => 'b'
*
* _.nth(array, -2);
* // => 'c';
*/
function nth(array, n) {
return (array && array.length) ? baseNth(array, toInteger(n)) : undefined;
}
/**
* Removes all given values from `array` using
* [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
* for equality comparisons.
*
* **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove`
* to remove elements from an array by predicate.
*
* @static
* @memberOf _
* @since 2.0.0
* @category Array
* @param {Array} array The array to modify.
* @param {...*} [values] The values to remove.
* @returns {Array} Returns `array`.
* @example
*
* var array = ['a', 'b', 'c', 'a', 'b', 'c'];
*
* _.pull(array, 'a', 'c');
* console.log(array);
* // => ['b', 'b']
*/
var pull = baseRest(pullAll);
/**
* This method is like `_.pull` except that it accepts an array of values to remove.
*
* **Note:** Unlike `_.difference`, this method mutates `array`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {Array} array The array to modify.
* @param {Array} values The values to remove.
* @returns {Array} Returns `array`.
* @example
*
* var array = ['a', 'b', 'c', 'a', 'b', 'c'];
*
* _.pullAll(array, ['a', 'c']);
* console.log(array);
* // => ['b', 'b']
*/
function pullAll(array, values) {
return (array && array.length && values && values.length)
? basePullAll(array, values)
: array;
}
/**
* This method is like `_.pullAll` except that it accepts `iteratee` which is
* invoked for each element of `array` and `values` to generate the criterion
* by which they're compared. The iteratee is invoked with one argument: (value).
*
* **Note:** Unlike `_.differenceBy`, this method mutates `array`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {Array} array The array to modify.
* @param {Array} values The values to remove.
* @param {Function} [iteratee=_.identity] The iteratee invoked per element.
* @returns {Array} Returns `array`.
* @example
*
* var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }];
*
* _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x');
* console.log(array);
* // => [{ 'x': 2 }]
*/
function pullAllBy(array, values, iteratee) {
return (array && array.length && values && values.length)
? basePullAll(array, values, getIteratee(iteratee, 2))
: array;
}
/**
* This method is like `_.pullAll` except that it accepts `comparator` which
* is invoked to compare elements of `array` to `values`. The comparator is
* invoked with two arguments: (arrVal, othVal).
*
* **Note:** Unlike `_.differenceWith`, this method mutates `array`.
*
* @static
* @memberOf _
* @since 4.6.0
* @category Array
* @param {Array} array The array to modify.
* @param {Array} values The values to remove.
* @param {Function} [comparator] The comparator invoked per element.
* @returns {Array} Returns `array`.
* @example
*
* var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }];
*
* _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual);
* console.log(array);
* // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }]
*/
function pullAllWith(array, values, comparator) {
return (array && array.length && values && values.length)
? basePullAll(array, values, undefined, comparator)
: array;
}
/**
* Removes elements from `array` corresponding to `indexes` and returns an
* array of removed elements.
*
* **Note:** Unlike `_.at`, this method mutates `array`.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Array
* @param {Array} array The array to modify.
* @param {...(number|number[])} [indexes] The indexes of elements to remove.
* @returns {Array} Returns the new array of removed elements.
* @example
*
* var array = ['a', 'b', 'c', 'd'];
* var pulled = _.pullAt(array, [1, 3]);
*
* console.log(array);
* // => ['a', 'c']
*
* console.log(pulled);
* // => ['b', 'd']
*/
var pullAt = flatRest(function(array, indexes) {
var length = array == null ? 0 : array.length,
result = baseAt(array, indexes);
basePullAt(array, arrayMap(indexes, function(index) {
return isIndex(index, length) ? +index : index;
}).sort(compareAscending));
return result;
});
/**
* Removes all elements from `array` that `predicate` returns truthy for
* and returns an array of the removed elements. The predicate is invoked
* with three arguments: (value, index, array).
*
* **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull`
* to pull elements from an array by value.
*
* @static
* @memberOf _
* @since 2.0.0
* @category Array
* @param {Array} array The array to modify.
* @param {Function} [predicate=_.identity] The function invoked per iteration.
* @returns {Array} Returns the new array of removed elements.
* @example
*
* var array = [1, 2, 3, 4];
* var evens = _.remove(array, function(n) {
* return n % 2 == 0;
* });
*
* console.log(array);
* // => [1, 3]
*
* console.log(evens);
* // => [2, 4]
*/
function remove(array, predicate) {
var result = [];
if (!(array && array.length)) {
return result;
}
var index = -1,
indexes = [],
length = array.length;
predicate = getIteratee(predicate, 3);
while (++index < length) {
var value = array[index];
if (predicate(value, index, array)) {
result.push(value);
indexes.push(index);
}
}
basePullAt(array, indexes);
return result;
}
/**
* Reverses `array` so that the first element becomes the last, the second
* element becomes the second to last, and so on.
*
* **Note:** This method mutates `array` and is based on
* [`Array#reverse`](https://mdn.io/Array/reverse).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {Array} array The array to modify.
* @returns {Array} Returns `array`.
* @example
*
* var array = [1, 2, 3];
*
* _.reverse(array);
* // => [3, 2, 1]
*
* console.log(array);
* // => [3, 2, 1]
*/
function reverse(array) {
return array == null ? array : nativeReverse.call(array);
}
/**
* Creates a slice of `array` from `start` up to, but not including, `end`.
*
* **Note:** This method is used instead of
* [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are
* returned.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Array
* @param {Array} array The array to slice.
* @param {number} [start=0] The start position.
* @param {number} [end=array.length] The end position.
* @returns {Array} Returns the slice of `array`.
*/
function slice(array, start, end) {
var length = array == null ? 0 : array.length;
if (!length) {
return [];
}
if (end && typeof end != 'number' && isIterateeCall(array, start, end)) {
start = 0;
end = length;
}
else {
start = start == null ? 0 : toInteger(start);
end = end === undefined ? length : toInteger(end);
}
return baseSlice(array, start, end);
}
/**
* Uses a binary search to determine the lowest index at which `value`
* should be inserted into `array` in order to maintain its sort order.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Array
* @param {Array} array The sorted array to inspect.
* @param {*} value The value to evaluate.
* @returns {number} Returns the index at which `value` should be inserted
* into `array`.
* @example
*
* _.sortedIndex([30, 50], 40);
* // => 1
*/
function sortedIndex(array, value) {
return baseSortedIndex(array, value);
}
/**
* This method is like `_.sortedIndex` except that it accepts `iteratee`
* which is invoked for `value` and each element of `array` to compute their
* sort ranking. The iteratee is invoked with one argument: (value).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {Array} array The sorted array to inspect.
* @param {*} value The value to evaluate.
* @param {Function} [iteratee=_.identity] The iteratee invoked per element.
* @returns {number} Returns the index at which `value` should be inserted
* into `array`.
* @example
*
* var objects = [{ 'x': 4 }, { 'x': 5 }];
*
* _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
* // => 0
*
* // The `_.property` iteratee shorthand.
* _.sortedIndexBy(objects, { 'x': 4 }, 'x');
* // => 0
*/
function sortedIndexBy(array, value, iteratee) {
return baseSortedIndexBy(array, value, getIteratee(iteratee, 2));
}
/**
* This method is like `_.indexOf` except that it performs a binary
* search on a sorted `array`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {Array} array The array to inspect.
* @param {*} value The value to search for.
* @returns {number} Returns the index of the matched value, else `-1`.
* @example
*
* _.sortedIndexOf([4, 5, 5, 5, 6], 5);
* // => 1
*/
function sortedIndexOf(array, value) {
var length = array == null ? 0 : array.length;
if (length) {
var index = baseSortedIndex(array, value);
if (index < length && eq(array[index], value)) {
return index;
}
}
return -1;
}
/**
* This method is like `_.sortedIndex` except that it returns the highest
* index at which `value` should be inserted into `array` in order to
* maintain its sort order.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Array
* @param {Array} array The sorted array to inspect.
* @param {*} value The value to evaluate.
* @returns {number} Returns the index at which `value` should be inserted
* into `array`.
* @example
*
* _.sortedLastIndex([4, 5, 5, 5, 6], 5);
* // => 4
*/
function sortedLastIndex(array, value) {
return baseSortedIndex(array, value, true);
}
/**
* This method is like `_.sortedLastIndex` except that it accepts `iteratee`
* which is invoked for `value` and each element of `array` to compute their
* sort ranking. The iteratee is invoked with one argument: (value).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {Array} array The sorted array to inspect.
* @param {*} value The value to evaluate.
* @param {Function} [iteratee=_.identity] The iteratee invoked per element.
* @returns {number} Returns the index at which `value` should be inserted
* into `array`.
* @example
*
* var objects = [{ 'x': 4 }, { 'x': 5 }];
*
* _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
* // => 1
*
* // The `_.property` iteratee shorthand.
* _.sortedLastIndexBy(objects, { 'x': 4 }, 'x');
* // => 1
*/
function sortedLastIndexBy(array, value, iteratee) {
return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true);
}
/**
* This method is like `_.lastIndexOf` except that it performs a binary
* search on a sorted `array`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {Array} array The array to inspect.
* @param {*} value The value to search for.
* @returns {number} Returns the index of the matched value, else `-1`.
* @example
*
* _.sortedLastIndexOf([4, 5, 5, 5, 6], 5);
* // => 3
*/
function sortedLastIndexOf(array, value) {
var length = array == null ? 0 : array.length;
if (length) {
var index = baseSortedIndex(array, value, true) - 1;
if (eq(array[index], value)) {
return index;
}
}
return -1;
}
/**
* This method is like `_.uniq` except that it's designed and optimized
* for sorted arrays.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {Array} array The array to inspect.
* @returns {Array} Returns the new duplicate free array.
* @example
*
* _.sortedUniq([1, 1, 2]);
* // => [1, 2]
*/
function sortedUniq(array) {
return (array && array.length)
? baseSortedUniq(array)
: [];
}
/**
* This method is like `_.uniqBy` except that it's designed and optimized
* for sorted arrays.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {Array} array The array to inspect.
* @param {Function} [iteratee] The iteratee invoked per element.
* @returns {Array} Returns the new duplicate free array.
* @example
*
* _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor);
* // => [1.1, 2.3]
*/
function sortedUniqBy(array, iteratee) {
return (array && array.length)
? baseSortedUniq(array, getIteratee(iteratee, 2))
: [];
}
/**
* Gets all but the first element of `array`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {Array} array The array to query.
* @returns {Array} Returns the slice of `array`.
* @example
*
* _.tail([1, 2, 3]);
* // => [2, 3]
*/
function tail(array) {
var length = array == null ? 0 : array.length;
return length ? baseSlice(array, 1, length) : [];
}
/**
* Creates a slice of `array` with `n` elements taken from the beginning.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Array
* @param {Array} array The array to query.
* @param {number} [n=1] The number of elements to take.
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
* @returns {Array} Returns the slice of `array`.
* @example
*
* _.take([1, 2, 3]);
* // => [1]
*
* _.take([1, 2, 3], 2);
* // => [1, 2]
*
* _.take([1, 2, 3], 5);
* // => [1, 2, 3]
*
* _.take([1, 2, 3], 0);
* // => []
*/
function take(array, n, guard) {
if (!(array && array.length)) {
return [];
}
n = (guard || n === undefined) ? 1 : toInteger(n);
return baseSlice(array, 0, n < 0 ? 0 : n);
}
/**
* Creates a slice of `array` with `n` elements taken from the end.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Array
* @param {Array} array The array to query.
* @param {number} [n=1] The number of elements to take.
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
* @returns {Array} Returns the slice of `array`.
* @example
*
* _.takeRight([1, 2, 3]);
* // => [3]
*
* _.takeRight([1, 2, 3], 2);
* // => [2, 3]
*
* _.takeRight([1, 2, 3], 5);
* // => [1, 2, 3]
*
* _.takeRight([1, 2, 3], 0);
* // => []
*/
function takeRight(array, n, guard) {
var length = array == null ? 0 : array.length;
if (!length) {
return [];
}
n = (guard || n === undefined) ? 1 : toInteger(n);
n = length - n;
return baseSlice(array, n < 0 ? 0 : n, length);
}
/**
* Creates a slice of `array` with elements taken from the end. Elements are
* taken until `predicate` returns falsey. The predicate is invoked with
* three arguments: (value, index, array).
*
* @static
* @memberOf _
* @since 3.0.0
* @category Array
* @param {Array} array The array to query.
* @param {Function} [predicate=_.identity] The function invoked per iteration.
* @returns {Array} Returns the slice of `array`.
* @example
*
* var users = [
* { 'user': 'barney', 'active': true },
* { 'user': 'fred', 'active': false },
* { 'user': 'pebbles', 'active': false }
* ];
*
* _.takeRightWhile(users, function(o) { return !o.active; });
* // => objects for ['fred', 'pebbles']
*
* // The `_.matches` iteratee shorthand.
* _.takeRightWhile(users, { 'user': 'pebbles', 'active': false });
* // => objects for ['pebbles']
*
* // The `_.matchesProperty` iteratee shorthand.
* _.takeRightWhile(users, ['active', false]);
* // => objects for ['fred', 'pebbles']
*
* // The `_.property` iteratee shorthand.
* _.takeRightWhile(users, 'active');
* // => []
*/
function takeRightWhile(array, predicate) {
return (array && array.length)
? baseWhile(array, getIteratee(predicate, 3), false, true)
: [];
}
/**
* Creates a slice of `array` with elements taken from the beginning. Elements
* are taken until `predicate` returns falsey. The predicate is invoked with
* three arguments: (value, index, array).
*
* @static
* @memberOf _
* @since 3.0.0
* @category Array
* @param {Array} array The array to query.
* @param {Function} [predicate=_.identity] The function invoked per iteration.
* @returns {Array} Returns the slice of `array`.
* @example
*
* var users = [
* { 'user': 'barney', 'active': false },
* { 'user': 'fred', 'active': false },
* { 'user': 'pebbles', 'active': true }
* ];
*
* _.takeWhile(users, function(o) { return !o.active; });
* // => objects for ['barney', 'fred']
*
* // The `_.matches` iteratee shorthand.
* _.takeWhile(users, { 'user': 'barney', 'active': false });
* // => objects for ['barney']
*
* // The `_.matchesProperty` iteratee shorthand.
* _.takeWhile(users, ['active', false]);
* // => objects for ['barney', 'fred']
*
* // The `_.property` iteratee shorthand.
* _.takeWhile(users, 'active');
* // => []
*/
function takeWhile(array, predicate) {
return (array && array.length)
? baseWhile(array, getIteratee(predicate, 3))
: [];
}
/**
* Creates an array of unique values, in order, from all given arrays using
* [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
* for equality comparisons.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Array
* @param {...Array} [arrays] The arrays to inspect.
* @returns {Array} Returns the new array of combined values.
* @example
*
* _.union([2], [1, 2]);
* // => [2, 1]
*/
var union = baseRest(function(arrays) {
return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true));
});
/**
* This method is like `_.union` except that it accepts `iteratee` which is
* invoked for each element of each `arrays` to generate the criterion by
* which uniqueness is computed. Result values are chosen from the first
* array in which the value occurs. The iteratee is invoked with one argument:
* (value).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {...Array} [arrays] The arrays to inspect.
* @param {Function} [iteratee=_.identity] The iteratee invoked per element.
* @returns {Array} Returns the new array of combined values.
* @example
*
* _.unionBy([2.1], [1.2, 2.3], Math.floor);
* // => [2.1, 1.2]
*
* // The `_.property` iteratee shorthand.
* _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
* // => [{ 'x': 1 }, { 'x': 2 }]
*/
var unionBy = baseRest(function(arrays) {
var iteratee = last(arrays);
if (isArrayLikeObject(iteratee)) {
iteratee = undefined;
}
return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2));
});
/**
* This method is like `_.union` except that it accepts `comparator` which
* is invoked to compare elements of `arrays`. Result values are chosen from
* the first array in which the value occurs. The comparator is invoked
* with two arguments: (arrVal, othVal).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {...Array} [arrays] The arrays to inspect.
* @param {Function} [comparator] The comparator invoked per element.
* @returns {Array} Returns the new array of combined values.
* @example
*
* var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
* var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
*
* _.unionWith(objects, others, _.isEqual);
* // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
*/
var unionWith = baseRest(function(arrays) {
var comparator = last(arrays);
comparator = typeof comparator == 'function' ? comparator : undefined;
return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator);
});
/**
* Creates a duplicate-free version of an array, using
* [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
* for equality comparisons, in which only the first occurrence of each element
* is kept. The order of result values is determined by the order they occur
* in the array.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Array
* @param {Array} array The array to inspect.
* @returns {Array} Returns the new duplicate free array.
* @example
*
* _.uniq([2, 1, 2]);
* // => [2, 1]
*/
function uniq(array) {
return (array && array.length) ? baseUniq(array) : [];
}
/**
* This method is like `_.uniq` except that it accepts `iteratee` which is
* invoked for each element in `array` to generate the criterion by which
* uniqueness is computed. The order of result values is determined by the
* order they occur in the array. The iteratee is invoked with one argument:
* (value).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {Array} array The array to inspect.
* @param {Function} [iteratee=_.identity] The iteratee invoked per element.
* @returns {Array} Returns the new duplicate free array.
* @example
*
* _.uniqBy([2.1, 1.2, 2.3], Math.floor);
* // => [2.1, 1.2]
*
* // The `_.property` iteratee shorthand.
* _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
* // => [{ 'x': 1 }, { 'x': 2 }]
*/
function uniqBy(array, iteratee) {
return (array && array.length) ? baseUniq(array, getIteratee(iteratee, 2)) : [];
}
/**
* This method is like `_.uniq` except that it accepts `comparator` which
* is invoked to compare elements of `array`. The order of result values is
* determined by the order they occur in the array.The comparator is invoked
* with two arguments: (arrVal, othVal).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {Array} array The array to inspect.
* @param {Function} [comparator] The comparator invoked per element.
* @returns {Array} Returns the new duplicate free array.
* @example
*
* var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
*
* _.uniqWith(objects, _.isEqual);
* // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
*/
function uniqWith(array, comparator) {
comparator = typeof comparator == 'function' ? comparator : undefined;
return (array && array.length) ? baseUniq(array, undefined, comparator) : [];
}
/**
* This method is like `_.zip` except that it accepts an array of grouped
* elements and creates an array regrouping the elements to their pre-zip
* configuration.
*
* @static
* @memberOf _
* @since 1.2.0
* @category Array
* @param {Array} array The array of grouped elements to process.
* @returns {Array} Returns the new array of regrouped elements.
* @example
*
* var zipped = _.zip(['a', 'b'], [1, 2], [true, false]);
* // => [['a', 1, true], ['b', 2, false]]
*
* _.unzip(zipped);
* // => [['a', 'b'], [1, 2], [true, false]]
*/
function unzip(array) {
if (!(array && array.length)) {
return [];
}
var length = 0;
array = arrayFilter(array, function(group) {
if (isArrayLikeObject(group)) {
length = nativeMax(group.length, length);
return true;
}
});
return baseTimes(length, function(index) {
return arrayMap(array, baseProperty(index));
});
}
/**
* This method is like `_.unzip` except that it accepts `iteratee` to specify
* how regrouped values should be combined. The iteratee is invoked with the
* elements of each group: (...group).
*
* @static
* @memberOf _
* @since 3.8.0
* @category Array
* @param {Array} array The array of grouped elements to process.
* @param {Function} [iteratee=_.identity] The function to combine
* regrouped values.
* @returns {Array} Returns the new array of regrouped elements.
* @example
*
* var zipped = _.zip([1, 2], [10, 20], [100, 200]);
* // => [[1, 10, 100], [2, 20, 200]]
*
* _.unzipWith(zipped, _.add);
* // => [3, 30, 300]
*/
function unzipWith(array, iteratee) {
if (!(array && array.length)) {
return [];
}
var result = unzip(array);
if (iteratee == null) {
return result;
}
return arrayMap(result, function(group) {
return apply(iteratee, undefined, group);
});
}
/**
* Creates an array excluding all given values using
* [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
* for equality comparisons.
*
* **Note:** Unlike `_.pull`, this method returns a new array.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Array
* @param {Array} array The array to inspect.
* @param {...*} [values] The values to exclude.
* @returns {Array} Returns the new array of filtered values.
* @see _.difference, _.xor
* @example
*
* _.without([2, 1, 2, 3], 1, 2);
* // => [3]
*/
var without = baseRest(function(array, values) {
return isArrayLikeObject(array)
? baseDifference(array, values)
: [];
});
/**
* Creates an array of unique values that is the
* [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference)
* of the given arrays. The order of result values is determined by the order
* they occur in the arrays.
*
* @static
* @memberOf _
* @since 2.4.0
* @category Array
* @param {...Array} [arrays] The arrays to inspect.
* @returns {Array} Returns the new array of filtered values.
* @see _.difference, _.without
* @example
*
* _.xor([2, 1], [2, 3]);
* // => [1, 3]
*/
var xor = baseRest(function(arrays) {
return baseXor(arrayFilter(arrays, isArrayLikeObject));
});
/**
* This method is like `_.xor` except that it accepts `iteratee` which is
* invoked for each element of each `arrays` to generate the criterion by
* which by which they're compared. The order of result values is determined
* by the order they occur in the arrays. The iteratee is invoked with one
* argument: (value).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {...Array} [arrays] The arrays to inspect.
* @param {Function} [iteratee=_.identity] The iteratee invoked per element.
* @returns {Array} Returns the new array of filtered values.
* @example
*
* _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor);
* // => [1.2, 3.4]
*
* // The `_.property` iteratee shorthand.
* _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
* // => [{ 'x': 2 }]
*/
var xorBy = baseRest(function(arrays) {
var iteratee = last(arrays);
if (isArrayLikeObject(iteratee)) {
iteratee = undefined;
}
return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2));
});
/**
* This method is like `_.xor` except that it accepts `comparator` which is
* invoked to compare elements of `arrays`. The order of result values is
* determined by the order they occur in the arrays. The comparator is invoked
* with two arguments: (arrVal, othVal).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {...Array} [arrays] The arrays to inspect.
* @param {Function} [comparator] The comparator invoked per element.
* @returns {Array} Returns the new array of filtered values.
* @example
*
* var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
* var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
*
* _.xorWith(objects, others, _.isEqual);
* // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
*/
var xorWith = baseRest(function(arrays) {
var comparator = last(arrays);
comparator = typeof comparator == 'function' ? comparator : undefined;
return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator);
});
/**
* Creates an array of grouped elements, the first of which contains the
* first elements of the given arrays, the second of which contains the
* second elements of the given arrays, and so on.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Array
* @param {...Array} [arrays] The arrays to process.
* @returns {Array} Returns the new array of grouped elements.
* @example
*
* _.zip(['a', 'b'], [1, 2], [true, false]);
* // => [['a', 1, true], ['b', 2, false]]
*/
var zip = baseRest(unzip);
/**
* This method is like `_.fromPairs` except that it accepts two arrays,
* one of property identifiers and one of corresponding values.
*
* @static
* @memberOf _
* @since 0.4.0
* @category Array
* @param {Array} [props=[]] The property identifiers.
* @param {Array} [values=[]] The property values.
* @returns {Object} Returns the new object.
* @example
*
* _.zipObject(['a', 'b'], [1, 2]);
* // => { 'a': 1, 'b': 2 }
*/
function zipObject(props, values) {
return baseZipObject(props || [], values || [], assignValue);
}
/**
* This method is like `_.zipObject` except that it supports property paths.
*
* @static
* @memberOf _
* @since 4.1.0
* @category Array
* @param {Array} [props=[]] The property identifiers.
* @param {Array} [values=[]] The property values.
* @returns {Object} Returns the new object.
* @example
*
* _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]);
* // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } }
*/
function zipObjectDeep(props, values) {
return baseZipObject(props || [], values || [], baseSet);
}
/**
* This method is like `_.zip` except that it accepts `iteratee` to specify
* how grouped values should be combined. The iteratee is invoked with the
* elements of each group: (...group).
*
* @static
* @memberOf _
* @since 3.8.0
* @category Array
* @param {...Array} [arrays] The arrays to process.
* @param {Function} [iteratee=_.identity] The function to combine
* grouped values.
* @returns {Array} Returns the new array of grouped elements.
* @example
*
* _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) {
* return a + b + c;
* });
* // => [111, 222]
*/
var zipWith = baseRest(function(arrays) {
var length = arrays.length,
iteratee = length > 1 ? arrays[length - 1] : undefined;
iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined;
return unzipWith(arrays, iteratee);
});
/*------------------------------------------------------------------------*/
/**
* Creates a `lodash` wrapper instance that wraps `value` with explicit method
* chain sequences enabled. The result of such sequences must be unwrapped
* with `_#value`.
*
* @static
* @memberOf _
* @since 1.3.0
* @category Seq
* @param {*} value The value to wrap.
* @returns {Object} Returns the new `lodash` wrapper instance.
* @example
*
* var users = [
* { 'user': 'barney', 'age': 36 },
* { 'user': 'fred', 'age': 40 },
* { 'user': 'pebbles', 'age': 1 }
* ];
*
* var youngest = _
* .chain(users)
* .sortBy('age')
* .map(function(o) {
* return o.user + ' is ' + o.age;
* })
* .head()
* .value();
* // => 'pebbles is 1'
*/
function chain(value) {
var result = lodash(value);
result.__chain__ = true;
return result;
}
/**
* This method invokes `interceptor` and returns `value`. The interceptor
* is invoked with one argument; (value). The purpose of this method is to
* "tap into" a method chain sequence in order to modify intermediate results.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Seq
* @param {*} value The value to provide to `interceptor`.
* @param {Function} interceptor The function to invoke.
* @returns {*} Returns `value`.
* @example
*
* _([1, 2, 3])
* .tap(function(array) {
* // Mutate input array.
* array.pop();
* })
* .reverse()
* .value();
* // => [2, 1]
*/
function tap(value, interceptor) {
interceptor(value);
return value;
}
/**
* This method is like `_.tap` except that it returns the result of `interceptor`.
* The purpose of this method is to "pass thru" values replacing intermediate
* results in a method chain sequence.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Seq
* @param {*} value The value to provide to `interceptor`.
* @param {Function} interceptor The function to invoke.
* @returns {*} Returns the result of `interceptor`.
* @example
*
* _(' abc ')
* .chain()
* .trim()
* .thru(function(value) {
* return [value];
* })
* .value();
* // => ['abc']
*/
function thru(value, interceptor) {
return interceptor(value);
}
/**
* This method is the wrapper version of `_.at`.
*
* @name at
* @memberOf _
* @since 1.0.0
* @category Seq
* @param {...(string|string[])} [paths] The property paths to pick.
* @returns {Object} Returns the new `lodash` wrapper instance.
* @example
*
* var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
*
* _(object).at(['a[0].b.c', 'a[1]']).value();
* // => [3, 4]
*/
var wrapperAt = flatRest(function(paths) {
var length = paths.length,
start = length ? paths[0] : 0,
value = this.__wrapped__,
interceptor = function(object) { return baseAt(object, paths); };
if (length > 1 || this.__actions__.length ||
!(value instanceof LazyWrapper) || !isIndex(start)) {
return this.thru(interceptor);
}
value = value.slice(start, +start + (length ? 1 : 0));
value.__actions__.push({
'func': thru,
'args': [interceptor],
'thisArg': undefined
});
return new LodashWrapper(value, this.__chain__).thru(function(array) {
if (length && !array.length) {
array.push(undefined);
}
return array;
});
});
/**
* Creates a `lodash` wrapper instance with explicit method chain sequences enabled.
*
* @name chain
* @memberOf _
* @since 0.1.0
* @category Seq
* @returns {Object} Returns the new `lodash` wrapper instance.
* @example
*
* var users = [
* { 'user': 'barney', 'age': 36 },
* { 'user': 'fred', 'age': 40 }
* ];
*
* // A sequence without explicit chaining.
* _(users).head();
* // => { 'user': 'barney', 'age': 36 }
*
* // A sequence with explicit chaining.
* _(users)
* .chain()
* .head()
* .pick('user')
* .value();
* // => { 'user': 'barney' }
*/
function wrapperChain() {
return chain(this);
}
/**
* Executes the chain sequence and returns the wrapped result.
*
* @name commit
* @memberOf _
* @since 3.2.0
* @category Seq
* @returns {Object} Returns the new `lodash` wrapper instance.
* @example
*
* var array = [1, 2];
* var wrapped = _(array).push(3);
*
* console.log(array);
* // => [1, 2]
*
* wrapped = wrapped.commit();
* console.log(array);
* // => [1, 2, 3]
*
* wrapped.last();
* // => 3
*
* console.log(array);
* // => [1, 2, 3]
*/
function wrapperCommit() {
return new LodashWrapper(this.value(), this.__chain__);
}
/**
* Gets the next value on a wrapped object following the
* [iterator protocol](https://mdn.io/iteration_protocols#iterator).
*
* @name next
* @memberOf _
* @since 4.0.0
* @category Seq
* @returns {Object} Returns the next iterator value.
* @example
*
* var wrapped = _([1, 2]);
*
* wrapped.next();
* // => { 'done': false, 'value': 1 }
*
* wrapped.next();
* // => { 'done': false, 'value': 2 }
*
* wrapped.next();
* // => { 'done': true, 'value': undefined }
*/
function wrapperNext() {
if (this.__values__ === undefined) {
this.__values__ = toArray(this.value());
}
var done = this.__index__ >= this.__values__.length,
value = done ? undefined : this.__values__[this.__index__++];
return { 'done': done, 'value': value };
}
/**
* Enables the wrapper to be iterable.
*
* @name Symbol.iterator
* @memberOf _
* @since 4.0.0
* @category Seq
* @returns {Object} Returns the wrapper object.
* @example
*
* var wrapped = _([1, 2]);
*
* wrapped[Symbol.iterator]() === wrapped;
* // => true
*
* Array.from(wrapped);
* // => [1, 2]
*/
function wrapperToIterator() {
return this;
}
/**
* Creates a clone of the chain sequence planting `value` as the wrapped value.
*
* @name plant
* @memberOf _
* @since 3.2.0
* @category Seq
* @param {*} value The value to plant.
* @returns {Object} Returns the new `lodash` wrapper instance.
* @example
*
* function square(n) {
* return n * n;
* }
*
* var wrapped = _([1, 2]).map(square);
* var other = wrapped.plant([3, 4]);
*
* other.value();
* // => [9, 16]
*
* wrapped.value();
* // => [1, 4]
*/
function wrapperPlant(value) {
var result,
parent = this;
while (parent instanceof baseLodash) {
var clone = wrapperClone(parent);
clone.__index__ = 0;
clone.__values__ = undefined;
if (result) {
previous.__wrapped__ = clone;
} else {
result = clone;
}
var previous = clone;
parent = parent.__wrapped__;
}
previous.__wrapped__ = value;
return result;
}
/**
* This method is the wrapper version of `_.reverse`.
*
* **Note:** This method mutates the wrapped array.
*
* @name reverse
* @memberOf _
* @since 0.1.0
* @category Seq
* @returns {Object} Returns the new `lodash` wrapper instance.
* @example
*
* var array = [1, 2, 3];
*
* _(array).reverse().value()
* // => [3, 2, 1]
*
* console.log(array);
* // => [3, 2, 1]
*/
function wrapperReverse() {
var value = this.__wrapped__;
if (value instanceof LazyWrapper) {
var wrapped = value;
if (this.__actions__.length) {
wrapped = new LazyWrapper(this);
}
wrapped = wrapped.reverse();
wrapped.__actions__.push({
'func': thru,
'args': [reverse],
'thisArg': undefined
});
return new LodashWrapper(wrapped, this.__chain__);
}
return this.thru(reverse);
}
/**
* Executes the chain sequence to resolve the unwrapped value.
*
* @name value
* @memberOf _
* @since 0.1.0
* @alias toJSON, valueOf
* @category Seq
* @returns {*} Returns the resolved unwrapped value.
* @example
*
* _([1, 2, 3]).value();
* // => [1, 2, 3]
*/
function wrapperValue() {
return baseWrapperValue(this.__wrapped__, this.__actions__);
}
/*------------------------------------------------------------------------*/
/**
* Creates an object composed of keys generated from the results of running
* each element of `collection` thru `iteratee`. The corresponding value of
* each key is the number of times the key was returned by `iteratee`. The
* iteratee is invoked with one argument: (value).
*
* @static
* @memberOf _
* @since 0.5.0
* @category Collection
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} [iteratee=_.identity] The iteratee to transform keys.
* @returns {Object} Returns the composed aggregate object.
* @example
*
* _.countBy([6.1, 4.2, 6.3], Math.floor);
* // => { '4': 1, '6': 2 }
*
* // The `_.property` iteratee shorthand.
* _.countBy(['one', 'two', 'three'], 'length');
* // => { '3': 2, '5': 1 }
*/
var countBy = createAggregator(function(result, value, key) {
if (hasOwnProperty.call(result, key)) {
++result[key];
} else {
baseAssignValue(result, key, 1);
}
});
/**
* Checks if `predicate` returns truthy for **all** elements of `collection`.
* Iteration is stopped once `predicate` returns falsey. The predicate is
* invoked with three arguments: (value, index|key, collection).
*
* **Note:** This method returns `true` for
* [empty collections](https://en.wikipedia.org/wiki/Empty_set) because
* [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of
* elements of empty collections.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Collection
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} [predicate=_.identity] The function invoked per iteration.
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
* @returns {boolean} Returns `true` if all elements pass the predicate check,
* else `false`.
* @example
*
* _.every([true, 1, null, 'yes'], Boolean);
* // => false
*
* var users = [
* { 'user': 'barney', 'age': 36, 'active': false },
* { 'user': 'fred', 'age': 40, 'active': false }
* ];
*
* // The `_.matches` iteratee shorthand.
* _.every(users, { 'user': 'barney', 'active': false });
* // => false
*
* // The `_.matchesProperty` iteratee shorthand.
* _.every(users, ['active', false]);
* // => true
*
* // The `_.property` iteratee shorthand.
* _.every(users, 'active');
* // => false
*/
function every(collection, predicate, guard) {
var func = isArray(collection) ? arrayEvery : baseEvery;
if (guard && isIterateeCall(collection, predicate, guard)) {
predicate = undefined;
}
return func(collection, getIteratee(predicate, 3));
}
/**
* Iterates over elements of `collection`, returning an array of all elements
* `predicate` returns truthy for. The predicate is invoked with three
* arguments: (value, index|key, collection).
*
* **Note:** Unlike `_.remove`, this method returns a new array.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Collection
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} [predicate=_.identity] The function invoked per iteration.
* @returns {Array} Returns the new filtered array.
* @see _.reject
* @example
*
* var users = [
* { 'user': 'barney', 'age': 36, 'active': true },
* { 'user': 'fred', 'age': 40, 'active': false }
* ];
*
* _.filter(users, function(o) { return !o.active; });
* // => objects for ['fred']
*
* // The `_.matches` iteratee shorthand.
* _.filter(users, { 'age': 36, 'active': true });
* // => objects for ['barney']
*
* // The `_.matchesProperty` iteratee shorthand.
* _.filter(users, ['active', false]);
* // => objects for ['fred']
*
* // The `_.property` iteratee shorthand.
* _.filter(users, 'active');
* // => objects for ['barney']
*/
function filter(collection, predicate) {
var func = isArray(collection) ? arrayFilter : baseFilter;
return func(collection, getIteratee(predicate, 3));
}
/**
* Iterates over elements of `collection`, returning the first element
* `predicate` returns truthy for. The predicate is invoked with three
* arguments: (value, index|key, collection).
*
* @static
* @memberOf _
* @since 0.1.0
* @category Collection
* @param {Array|Object} collection The collection to inspect.
* @param {Function} [predicate=_.identity] The function invoked per iteration.
* @param {number} [fromIndex=0] The index to search from.
* @returns {*} Returns the matched element, else `undefined`.
* @example
*
* var users = [
* { 'user': 'barney', 'age': 36, 'active': true },
* { 'user': 'fred', 'age': 40, 'active': false },
* { 'user': 'pebbles', 'age': 1, 'active': true }
* ];
*
* _.find(users, function(o) { return o.age < 40; });
* // => object for 'barney'
*
* // The `_.matches` iteratee shorthand.
* _.find(users, { 'age': 1, 'active': true });
* // => object for 'pebbles'
*
* // The `_.matchesProperty` iteratee shorthand.
* _.find(users, ['active', false]);
* // => object for 'fred'
*
* // The `_.property` iteratee shorthand.
* _.find(users, 'active');
* // => object for 'barney'
*/
var find = createFind(findIndex);
/**
* This method is like `_.find` except that it iterates over elements of
* `collection` from right to left.
*
* @static
* @memberOf _
* @since 2.0.0
* @category Collection
* @param {Array|Object} collection The collection to inspect.
* @param {Function} [predicate=_.identity] The function invoked per iteration.
* @param {number} [fromIndex=collection.length-1] The index to search from.
* @returns {*} Returns the matched element, else `undefined`.
* @example
*
* _.findLast([1, 2, 3, 4], function(n) {
* return n % 2 == 1;
* });
* // => 3
*/
var findLast = createFind(findLastIndex);
/**
* Creates a flattened array of values by running each element in `collection`
* thru `iteratee` and flattening the mapped results. The iteratee is invoked
* with three arguments: (value, index|key, collection).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Collection
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
* @returns {Array} Returns the new flattened array.
* @example
*
* function duplicate(n) {
* return [n, n];
* }
*
* _.flatMap([1, 2], duplicate);
* // => [1, 1, 2, 2]
*/
function flatMap(collection, iteratee) {
return baseFlatten(map(collection, iteratee), 1);
}
/**
* This method is like `_.flatMap` except that it recursively flattens the
* mapped results.
*
* @static
* @memberOf _
* @since 4.7.0
* @category Collection
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
* @returns {Array} Returns the new flattened array.
* @example
*
* function duplicate(n) {
* return [[[n, n]]];
* }
*
* _.flatMapDeep([1, 2], duplicate);
* // => [1, 1, 2, 2]
*/
function flatMapDeep(collection, iteratee) {
return baseFlatten(map(collection, iteratee), INFINITY);
}
/**
* This method is like `_.flatMap` except that it recursively flattens the
* mapped results up to `depth` times.
*
* @static
* @memberOf _
* @since 4.7.0
* @category Collection
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
* @param {number} [depth=1] The maximum recursion depth.
* @returns {Array} Returns the new flattened array.
* @example
*
* function duplicate(n) {
* return [[[n, n]]];
* }
*
* _.flatMapDepth([1, 2], duplicate, 2);
* // => [[1, 1], [2, 2]]
*/
function flatMapDepth(collection, iteratee, depth) {
depth = depth === undefined ? 1 : toInteger(depth);
return baseFlatten(map(collection, iteratee), depth);
}
/**
* Iterates over elements of `collection` and invokes `iteratee` for each element.
* The iteratee is invoked with three arguments: (value, index|key, collection).
* Iteratee functions may exit iteration early by explicitly returning `false`.
*
* **Note:** As with other "Collections" methods, objects with a "length"
* property are iterated like arrays. To avoid this behavior use `_.forIn`
* or `_.forOwn` for object iteration.
*
* @static
* @memberOf _
* @since 0.1.0
* @alias each
* @category Collection
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
* @returns {Array|Object} Returns `collection`.
* @see _.forEachRight
* @example
*
* _.forEach([1, 2], function(value) {
* console.log(value);
* });
* // => Logs `1` then `2`.
*
* _.forEach({ 'a': 1, 'b': 2 }, function(value, key) {
* console.log(key);
* });
* // => Logs 'a' then 'b' (iteration order is not guaranteed).
*/
function forEach(collection, iteratee) {
var func = isArray(collection) ? arrayEach : baseEach;
return func(collection, getIteratee(iteratee, 3));
}
/**
* This method is like `_.forEach` except that it iterates over elements of
* `collection` from right to left.
*
* @static
* @memberOf _
* @since 2.0.0
* @alias eachRight
* @category Collection
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
* @returns {Array|Object} Returns `collection`.
* @see _.forEach
* @example
*
* _.forEachRight([1, 2], function(value) {
* console.log(value);
* });
* // => Logs `2` then `1`.
*/
function forEachRight(collection, iteratee) {
var func = isArray(collection) ? arrayEachRight : baseEachRight;
return func(collection, getIteratee(iteratee, 3));
}
/**
* Creates an object composed of keys generated from the results of running
* each element of `collection` thru `iteratee`. The order of grouped values
* is determined by the order they occur in `collection`. The corresponding
* value of each key is an array of elements responsible for generating the
* key. The iteratee is invoked with one argument: (value).
*
* @static
* @memberOf _
* @since 0.1.0
* @category Collection
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} [iteratee=_.identity] The iteratee to transform keys.
* @returns {Object} Returns the composed aggregate object.
* @example
*
* _.groupBy([6.1, 4.2, 6.3], Math.floor);
* // => { '4': [4.2], '6': [6.1, 6.3] }
*
* // The `_.property` iteratee shorthand.
* _.groupBy(['one', 'two', 'three'], 'length');
* // => { '3': ['one', 'two'], '5': ['three'] }
*/
var groupBy = createAggregator(function(result, value, key) {
if (hasOwnProperty.call(result, key)) {
result[key].push(value);
} else {
baseAssignValue(result, key, [value]);
}
});
/**
* Checks if `value` is in `collection`. If `collection` is a string, it's
* checked for a substring of `value`, otherwise
* [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
* is used for equality comparisons. If `fromIndex` is negative, it's used as
* the offset from the end of `collection`.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Collection
* @param {Array|Object|string} collection The collection to inspect.
* @param {*} value The value to search for.
* @param {number} [fromIndex=0] The index to search from.
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
* @returns {boolean} Returns `true` if `value` is found, else `false`.
* @example
*
* _.includes([1, 2, 3], 1);
* // => true
*
* _.includes([1, 2, 3], 1, 2);
* // => false
*
* _.includes({ 'a': 1, 'b': 2 }, 1);
* // => true
*
* _.includes('abcd', 'bc');
* // => true
*/
function includes(collection, value, fromIndex, guard) {
collection = isArrayLike(collection) ? collection : values(collection);
fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0;
var length = collection.length;
if (fromIndex < 0) {
fromIndex = nativeMax(length + fromIndex, 0);
}
return isString(collection)
? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1)
: (!!length && baseIndexOf(collection, value, fromIndex) > -1);
}
/**
* Invokes the method at `path` of each element in `collection`, returning
* an array of the results of each invoked method. Any additional arguments
* are provided to each invoked method. If `path` is a function, it's invoked
* for, and `this` bound to, each element in `collection`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Collection
* @param {Array|Object} collection The collection to iterate over.
* @param {Array|Function|string} path The path of the method to invoke or
* the function invoked per iteration.
* @param {...*} [args] The arguments to invoke each method with.
* @returns {Array} Returns the array of results.
* @example
*
* _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort');
* // => [[1, 5, 7], [1, 2, 3]]
*
* _.invokeMap([123, 456], String.prototype.split, '');
* // => [['1', '2', '3'], ['4', '5', '6']]
*/
var invokeMap = baseRest(function(collection, path, args) {
var index = -1,
isFunc = typeof path == 'function',
result = isArrayLike(collection) ? Array(collection.length) : [];
baseEach(collection, function(value) {
result[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args);
});
return result;
});
/**
* Creates an object composed of keys generated from the results of running
* each element of `collection` thru `iteratee`. The corresponding value of
* each key is the last element responsible for generating the key. The
* iteratee is invoked with one argument: (value).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Collection
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} [iteratee=_.identity] The iteratee to transform keys.
* @returns {Object} Returns the composed aggregate object.
* @example
*
* var array = [
* { 'dir': 'left', 'code': 97 },
* { 'dir': 'right', 'code': 100 }
* ];
*
* _.keyBy(array, function(o) {
* return String.fromCharCode(o.code);
* });
* // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
*
* _.keyBy(array, 'dir');
* // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
*/
var keyBy = createAggregator(function(result, value, key) {
baseAssignValue(result, key, value);
});
/**
* Creates an array of values by running each element in `collection` thru
* `iteratee`. The iteratee is invoked with three arguments:
* (value, index|key, collection).
*
* Many lodash methods are guarded to work as iteratees for methods like
* `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`.
*
* The guarded methods are:
* `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`,
* `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`,
* `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`,
* `template`, `trim`, `trimEnd`, `trimStart`, and `words`
*
* @static
* @memberOf _
* @since 0.1.0
* @category Collection
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
* @returns {Array} Returns the new mapped array.
* @example
*
* function square(n) {
* return n * n;
* }
*
* _.map([4, 8], square);
* // => [16, 64]
*
* _.map({ 'a': 4, 'b': 8 }, square);
* // => [16, 64] (iteration order is not guaranteed)
*
* var users = [
* { 'user': 'barney' },
* { 'user': 'fred' }
* ];
*
* // The `_.property` iteratee shorthand.
* _.map(users, 'user');
* // => ['barney', 'fred']
*/
function map(collection, iteratee) {
var func = isArray(collection) ? arrayMap : baseMap;
return func(collection, getIteratee(iteratee, 3));
}
/**
* This method is like `_.sortBy` except that it allows specifying the sort
* orders of the iteratees to sort by. If `orders` is unspecified, all values
* are sorted in ascending order. Otherwise, specify an order of "desc" for
* descending or "asc" for ascending sort order of corresponding values.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Collection
* @param {Array|Object} collection The collection to iterate over.
* @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]]
* The iteratees to sort by.
* @param {string[]} [orders] The sort orders of `iteratees`.
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
* @returns {Array} Returns the new sorted array.
* @example
*
* var users = [
* { 'user': 'fred', 'age': 48 },
* { 'user': 'barney', 'age': 34 },
* { 'user': 'fred', 'age': 40 },
* { 'user': 'barney', 'age': 36 }
* ];
*
* // Sort by `user` in ascending order and by `age` in descending order.
* _.orderBy(users, ['user', 'age'], ['asc', 'desc']);
* // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
*/
function orderBy(collection, iteratees, orders, guard) {
if (collection == null) {
return [];
}
if (!isArray(iteratees)) {
iteratees = iteratees == null ? [] : [iteratees];
}
orders = guard ? undefined : orders;
if (!isArray(orders)) {
orders = orders == null ? [] : [orders];
}
return baseOrderBy(collection, iteratees, orders);
}
/**
* Creates an array of elements split into two groups, the first of which
* contains elements `predicate` returns truthy for, the second of which
* contains elements `predicate` returns falsey for. The predicate is
* invoked with one argument: (value).
*
* @static
* @memberOf _
* @since 3.0.0
* @category Collection
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} [predicate=_.identity] The function invoked per iteration.
* @returns {Array} Returns the array of grouped elements.
* @example
*
* var users = [
* { 'user': 'barney', 'age': 36, 'active': false },
* { 'user': 'fred', 'age': 40, 'active': true },
* { 'user': 'pebbles', 'age': 1, 'active': false }
* ];
*
* _.partition(users, function(o) { return o.active; });
* // => objects for [['fred'], ['barney', 'pebbles']]
*
* // The `_.matches` iteratee shorthand.
* _.partition(users, { 'age': 1, 'active': false });
* // => objects for [['pebbles'], ['barney', 'fred']]
*
* // The `_.matchesProperty` iteratee shorthand.
* _.partition(users, ['active', false]);
* // => objects for [['barney', 'pebbles'], ['fred']]
*
* // The `_.property` iteratee shorthand.
* _.partition(users, 'active');
* // => objects for [['fred'], ['barney', 'pebbles']]
*/
var partition = createAggregator(function(result, value, key) {
result[key ? 0 : 1].push(value);
}, function() { return [[], []]; });
/**
* Reduces `collection` to a value which is the accumulated result of running
* each element in `collection` thru `iteratee`, where each successive
* invocation is supplied the return value of the previous. If `accumulator`
* is not given, the first element of `collection` is used as the initial
* value. The iteratee is invoked with four arguments:
* (accumulator, value, index|key, collection).
*
* Many lodash methods are guarded to work as iteratees for methods like
* `_.reduce`, `_.reduceRight`, and `_.transform`.
*
* The guarded methods are:
* `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`,
* and `sortBy`
*
* @static
* @memberOf _
* @since 0.1.0
* @category Collection
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
* @param {*} [accumulator] The initial value.
* @returns {*} Returns the accumulated value.
* @see _.reduceRight
* @example
*
* _.reduce([1, 2], function(sum, n) {
* return sum + n;
* }, 0);
* // => 3
*
* _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
* (result[value] || (result[value] = [])).push(key);
* return result;
* }, {});
* // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed)
*/
function reduce(collection, iteratee, accumulator) {
var func = isArray(collection) ? arrayReduce : baseReduce,
initAccum = arguments.length < 3;
return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach);
}
/**
* This method is like `_.reduce` except that it iterates over elements of
* `collection` from right to left.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Collection
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
* @param {*} [accumulator] The initial value.
* @returns {*} Returns the accumulated value.
* @see _.reduce
* @example
*
* var array = [[0, 1], [2, 3], [4, 5]];
*
* _.reduceRight(array, function(flattened, other) {
* return flattened.concat(other);
* }, []);
* // => [4, 5, 2, 3, 0, 1]
*/
function reduceRight(collection, iteratee, accumulator) {
var func = isArray(collection) ? arrayReduceRight : baseReduce,
initAccum = arguments.length < 3;
return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight);
}
/**
* The opposite of `_.filter`; this method returns the elements of `collection`
* that `predicate` does **not** return truthy for.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Collection
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} [predicate=_.identity] The function invoked per iteration.
* @returns {Array} Returns the new filtered array.
* @see _.filter
* @example
*
* var users = [
* { 'user': 'barney', 'age': 36, 'active': false },
* { 'user': 'fred', 'age': 40, 'active': true }
* ];
*
* _.reject(users, function(o) { return !o.active; });
* // => objects for ['fred']
*
* // The `_.matches` iteratee shorthand.
* _.reject(users, { 'age': 40, 'active': true });
* // => objects for ['barney']
*
* // The `_.matchesProperty` iteratee shorthand.
* _.reject(users, ['active', false]);
* // => objects for ['fred']
*
* // The `_.property` iteratee shorthand.
* _.reject(users, 'active');
* // => objects for ['barney']
*/
function reject(collection, predicate) {
var func = isArray(collection) ? arrayFilter : baseFilter;
return func(collection, negate(getIteratee(predicate, 3)));
}
/**
* Gets a random element from `collection`.
*
* @static
* @memberOf _
* @since 2.0.0
* @category Collection
* @param {Array|Object} collection The collection to sample.
* @returns {*} Returns the random element.
* @example
*
* _.sample([1, 2, 3, 4]);
* // => 2
*/
function sample(collection) {
var func = isArray(collection) ? arraySample : baseSample;
return func(collection);
}
/**
* Gets `n` random elements at unique keys from `collection` up to the
* size of `collection`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Collection
* @param {Array|Object} collection The collection to sample.
* @param {number} [n=1] The number of elements to sample.
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
* @returns {Array} Returns the random elements.
* @example
*
* _.sampleSize([1, 2, 3], 2);
* // => [3, 1]
*
* _.sampleSize([1, 2, 3], 4);
* // => [2, 3, 1]
*/
function sampleSize(collection, n, guard) {
if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) {
n = 1;
} else {
n = toInteger(n);
}
var func = isArray(collection) ? arraySampleSize : baseSampleSize;
return func(collection, n);
}
/**
* Creates an array of shuffled values, using a version of the
* [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle).
*
* @static
* @memberOf _
* @since 0.1.0
* @category Collection
* @param {Array|Object} collection The collection to shuffle.
* @returns {Array} Returns the new shuffled array.
* @example
*
* _.shuffle([1, 2, 3, 4]);
* // => [4, 1, 3, 2]
*/
function shuffle(collection) {
var func = isArray(collection) ? arrayShuffle : baseShuffle;
return func(collection);
}
/**
* Gets the size of `collection` by returning its length for array-like
* values or the number of own enumerable string keyed properties for objects.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Collection
* @param {Array|Object|string} collection The collection to inspect.
* @returns {number} Returns the collection size.
* @example
*
* _.size([1, 2, 3]);
* // => 3
*
* _.size({ 'a': 1, 'b': 2 });
* // => 2
*
* _.size('pebbles');
* // => 7
*/
function size(collection) {
if (collection == null) {
return 0;
}
if (isArrayLike(collection)) {
return isString(collection) ? stringSize(collection) : collection.length;
}
var tag = getTag(collection);
if (tag == mapTag || tag == setTag) {
return collection.size;
}
return baseKeys(collection).length;
}
/**
* Checks if `predicate` returns truthy for **any** element of `collection`.
* Iteration is stopped once `predicate` returns truthy. The predicate is
* invoked with three arguments: (value, index|key, collection).
*
* @static
* @memberOf _
* @since 0.1.0
* @category Collection
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} [predicate=_.identity] The function invoked per iteration.
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
* @returns {boolean} Returns `true` if any element passes the predicate check,
* else `false`.
* @example
*
* _.some([null, 0, 'yes', false], Boolean);
* // => true
*
* var users = [
* { 'user': 'barney', 'active': true },
* { 'user': 'fred', 'active': false }
* ];
*
* // The `_.matches` iteratee shorthand.
* _.some(users, { 'user': 'barney', 'active': false });
* // => false
*
* // The `_.matchesProperty` iteratee shorthand.
* _.some(users, ['active', false]);
* // => true
*
* // The `_.property` iteratee shorthand.
* _.some(users, 'active');
* // => true
*/
function some(collection, predicate, guard) {
var func = isArray(collection) ? arraySome : baseSome;
if (guard && isIterateeCall(collection, predicate, guard)) {
predicate = undefined;
}
return func(collection, getIteratee(predicate, 3));
}
/**
* Creates an array of elements, sorted in ascending order by the results of
* running each element in a collection thru each iteratee. This method
* performs a stable sort, that is, it preserves the original sort order of
* equal elements. The iteratees are invoked with one argument: (value).
*
* @static
* @memberOf _
* @since 0.1.0
* @category Collection
* @param {Array|Object} collection The collection to iterate over.
* @param {...(Function|Function[])} [iteratees=[_.identity]]
* The iteratees to sort by.
* @returns {Array} Returns the new sorted array.
* @example
*
* var users = [
* { 'user': 'fred', 'age': 48 },
* { 'user': 'barney', 'age': 36 },
* { 'user': 'fred', 'age': 40 },
* { 'user': 'barney', 'age': 34 }
* ];
*
* _.sortBy(users, [function(o) { return o.user; }]);
* // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
*
* _.sortBy(users, ['user', 'age']);
* // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]]
*/
var sortBy = baseRest(function(collection, iteratees) {
if (collection == null) {
return [];
}
var length = iteratees.length;
if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) {
iteratees = [];
} else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) {
iteratees = [iteratees[0]];
}
return baseOrderBy(collection, baseFlatten(iteratees, 1), []);
});
/*------------------------------------------------------------------------*/
/**
* Gets the timestamp of the number of milliseconds that have elapsed since
* the Unix epoch (1 January 1970 00:00:00 UTC).
*
* @static
* @memberOf _
* @since 2.4.0
* @category Date
* @returns {number} Returns the timestamp.
* @example
*
* _.defer(function(stamp) {
* console.log(_.now() - stamp);
* }, _.now());
* // => Logs the number of milliseconds it took for the deferred invocation.
*/
var now = ctxNow || function() {
return root.Date.now();
};
/*------------------------------------------------------------------------*/
/**
* The opposite of `_.before`; this method creates a function that invokes
* `func` once it's called `n` or more times.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Function
* @param {number} n The number of calls before `func` is invoked.
* @param {Function} func The function to restrict.
* @returns {Function} Returns the new restricted function.
* @example
*
* var saves = ['profile', 'settings'];
*
* var done = _.after(saves.length, function() {
* console.log('done saving!');
* });
*
* _.forEach(saves, function(type) {
* asyncSave({ 'type': type, 'complete': done });
* });
* // => Logs 'done saving!' after the two async saves have completed.
*/
function after(n, func) {
if (typeof func != 'function') {
throw new TypeError(FUNC_ERROR_TEXT);
}
n = toInteger(n);
return function() {
if (--n < 1) {
return func.apply(this, arguments);
}
};
}
/**
* Creates a function that invokes `func`, with up to `n` arguments,
* ignoring any additional arguments.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Function
* @param {Function} func The function to cap arguments for.
* @param {number} [n=func.length] The arity cap.
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
* @returns {Function} Returns the new capped function.
* @example
*
* _.map(['6', '8', '10'], _.ary(parseInt, 1));
* // => [6, 8, 10]
*/
function ary(func, n, guard) {
n = guard ? undefined : n;
n = (func && n == null) ? func.length : n;
return createWrap(func, WRAP_ARY_FLAG, undefined, undefined, undefined, undefined, n);
}
/**
* Creates a function that invokes `func`, with the `this` binding and arguments
* of the created function, while it's called less than `n` times. Subsequent
* calls to the created function return the result of the last `func` invocation.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Function
* @param {number} n The number of calls at which `func` is no longer invoked.
* @param {Function} func The function to restrict.
* @returns {Function} Returns the new restricted function.
* @example
*
* jQuery(element).on('click', _.before(5, addContactToList));
* // => Allows adding up to 4 contacts to the list.
*/
function before(n, func) {
var result;
if (typeof func != 'function') {
throw new TypeError(FUNC_ERROR_TEXT);
}
n = toInteger(n);
return function() {
if (--n > 0) {
result = func.apply(this, arguments);
}
if (n <= 1) {
func = undefined;
}
return result;
};
}
/**
* Creates a function that invokes `func` with the `this` binding of `thisArg`
* and `partials` prepended to the arguments it receives.
*
* The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
* may be used as a placeholder for partially applied arguments.
*
* **Note:** Unlike native `Function#bind`, this method doesn't set the "length"
* property of bound functions.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Function
* @param {Function} func The function to bind.
* @param {*} thisArg The `this` binding of `func`.
* @param {...*} [partials] The arguments to be partially applied.
* @returns {Function} Returns the new bound function.
* @example
*
* function greet(greeting, punctuation) {
* return greeting + ' ' + this.user + punctuation;
* }
*
* var object = { 'user': 'fred' };
*
* var bound = _.bind(greet, object, 'hi');
* bound('!');
* // => 'hi fred!'
*
* // Bound with placeholders.
* var bound = _.bind(greet, object, _, '!');
* bound('hi');
* // => 'hi fred!'
*/
var bind = baseRest(function(func, thisArg, partials) {
var bitmask = WRAP_BIND_FLAG;
if (partials.length) {
var holders = replaceHolders(partials, getHolder(bind));
bitmask |= WRAP_PARTIAL_FLAG;
}
return createWrap(func, bitmask, thisArg, partials, holders);
});
/**
* Creates a function that invokes the method at `object[key]` with `partials`
* prepended to the arguments it receives.
*
* This method differs from `_.bind` by allowing bound functions to reference
* methods that may be redefined or don't yet exist. See
* [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern)
* for more details.
*
* The `_.bindKey.placeholder` value, which defaults to `_` in monolithic
* builds, may be used as a placeholder for partially applied arguments.
*
* @static
* @memberOf _
* @since 0.10.0
* @category Function
* @param {Object} object The object to invoke the method on.
* @param {string} key The key of the method.
* @param {...*} [partials] The arguments to be partially applied.
* @returns {Function} Returns the new bound function.
* @example
*
* var object = {
* 'user': 'fred',
* 'greet': function(greeting, punctuation) {
* return greeting + ' ' + this.user + punctuation;
* }
* };
*
* var bound = _.bindKey(object, 'greet', 'hi');
* bound('!');
* // => 'hi fred!'
*
* object.greet = function(greeting, punctuation) {
* return greeting + 'ya ' + this.user + punctuation;
* };
*
* bound('!');
* // => 'hiya fred!'
*
* // Bound with placeholders.
* var bound = _.bindKey(object, 'greet', _, '!');
* bound('hi');
* // => 'hiya fred!'
*/
var bindKey = baseRest(function(object, key, partials) {
var bitmask = WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG;
if (partials.length) {
var holders = replaceHolders(partials, getHolder(bindKey));
bitmask |= WRAP_PARTIAL_FLAG;
}
return createWrap(key, bitmask, object, partials, holders);
});
/**
* Creates a function that accepts arguments of `func` and either invokes
* `func` returning its result, if at least `arity` number of arguments have
* been provided, or returns a function that accepts the remaining `func`
* arguments, and so on. The arity of `func` may be specified if `func.length`
* is not sufficient.
*
* The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
* may be used as a placeholder for provided arguments.
*
* **Note:** This method doesn't set the "length" property of curried functions.
*
* @static
* @memberOf _
* @since 2.0.0
* @category Function
* @param {Function} func The function to curry.
* @param {number} [arity=func.length] The arity of `func`.
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
* @returns {Function} Returns the new curried function.
* @example
*
* var abc = function(a, b, c) {
* return [a, b, c];
* };
*
* var curried = _.curry(abc);
*
* curried(1)(2)(3);
* // => [1, 2, 3]
*
* curried(1, 2)(3);
* // => [1, 2, 3]
*
* curried(1, 2, 3);
* // => [1, 2, 3]
*
* // Curried with placeholders.
* curried(1)(_, 3)(2);
* // => [1, 2, 3]
*/
function curry(func, arity, guard) {
arity = guard ? undefined : arity;
var result = createWrap(func, WRAP_CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
result.placeholder = curry.placeholder;
return result;
}
/**
* This method is like `_.curry` except that arguments are applied to `func`
* in the manner of `_.partialRight` instead of `_.partial`.
*
* The `_.curryRight.placeholder` value, which defaults to `_` in monolithic
* builds, may be used as a placeholder for provided arguments.
*
* **Note:** This method doesn't set the "length" property of curried functions.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Function
* @param {Function} func The function to curry.
* @param {number} [arity=func.length] The arity of `func`.
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
* @returns {Function} Returns the new curried function.
* @example
*
* var abc = function(a, b, c) {
* return [a, b, c];
* };
*
* var curried = _.curryRight(abc);
*
* curried(3)(2)(1);
* // => [1, 2, 3]
*
* curried(2, 3)(1);
* // => [1, 2, 3]
*
* curried(1, 2, 3);
* // => [1, 2, 3]
*
* // Curried with placeholders.
* curried(3)(1, _)(2);
* // => [1, 2, 3]
*/
function curryRight(func, arity, guard) {
arity = guard ? undefined : arity;
var result = createWrap(func, WRAP_CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
result.placeholder = curryRight.placeholder;
return result;
}
/**
* Creates a debounced function that delays invoking `func` until after `wait`
* milliseconds have elapsed since the last time the debounced function was
* invoked. The debounced function comes with a `cancel` method to cancel
* delayed `func` invocations and a `flush` method to immediately invoke them.
* Provide `options` to indicate whether `func` should be invoked on the
* leading and/or trailing edge of the `wait` timeout. The `func` is invoked
* with the last arguments provided to the debounced function. Subsequent
* calls to the debounced function return the result of the last `func`
* invocation.
*
* **Note:** If `leading` and `trailing` options are `true`, `func` is
* invoked on the trailing edge of the timeout only if the debounced function
* is invoked more than once during the `wait` timeout.
*
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
* until to the next tick, similar to `setTimeout` with a timeout of `0`.
*
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
* for details over the differences between `_.debounce` and `_.throttle`.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Function
* @param {Function} func The function to debounce.
* @param {number} [wait=0] The number of milliseconds to delay.
* @param {Object} [options={}] The options object.
* @param {boolean} [options.leading=false]
* Specify invoking on the leading edge of the timeout.
* @param {number} [options.maxWait]
* The maximum time `func` is allowed to be delayed before it's invoked.
* @param {boolean} [options.trailing=true]
* Specify invoking on the trailing edge of the timeout.
* @returns {Function} Returns the new debounced function.
* @example
*
* // Avoid costly calculations while the window size is in flux.
* jQuery(window).on('resize', _.debounce(calculateLayout, 150));
*
* // Invoke `sendMail` when clicked, debouncing subsequent calls.
* jQuery(element).on('click', _.debounce(sendMail, 300, {
* 'leading': true,
* 'trailing': false
* }));
*
* // Ensure `batchLog` is invoked once after 1 second of debounced calls.
* var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
* var source = new EventSource('/stream');
* jQuery(source).on('message', debounced);
*
* // Cancel the trailing debounced invocation.
* jQuery(window).on('popstate', debounced.cancel);
*/
function debounce(func, wait, options) {
var lastArgs,
lastThis,
maxWait,
result,
timerId,
lastCallTime,
lastInvokeTime = 0,
leading = false,
maxing = false,
trailing = true;
if (typeof func != 'function') {
throw new TypeError(FUNC_ERROR_TEXT);
}
wait = toNumber(wait) || 0;
if (isObject(options)) {
leading = !!options.leading;
maxing = 'maxWait' in options;
maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
trailing = 'trailing' in options ? !!options.trailing : trailing;
}
function invokeFunc(time) {
var args = lastArgs,
thisArg = lastThis;
lastArgs = lastThis = undefined;
lastInvokeTime = time;
result = func.apply(thisArg, args);
return result;
}
function leadingEdge(time) {
// Reset any `maxWait` timer.
lastInvokeTime = time;
// Start the timer for the trailing edge.
timerId = setTimeout(timerExpired, wait);
// Invoke the leading edge.
return leading ? invokeFunc(time) : result;
}
function remainingWait(time) {
var timeSinceLastCall = time - lastCallTime,
timeSinceLastInvoke = time - lastInvokeTime,
timeWaiting = wait - timeSinceLastCall;
return maxing
? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)
: timeWaiting;
}
function shouldInvoke(time) {
var timeSinceLastCall = time - lastCallTime,
timeSinceLastInvoke = time - lastInvokeTime;
// Either this is the first call, activity has stopped and we're at the
// trailing edge, the system time has gone backwards and we're treating
// it as the trailing edge, or we've hit the `maxWait` limit.
return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
(timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
}
function timerExpired() {
var time = now();
if (shouldInvoke(time)) {
return trailingEdge(time);
}
// Restart the timer.
timerId = setTimeout(timerExpired, remainingWait(time));
}
function trailingEdge(time) {
timerId = undefined;
// Only invoke if we have `lastArgs` which means `func` has been
// debounced at least once.
if (trailing && lastArgs) {
return invokeFunc(time);
}
lastArgs = lastThis = undefined;
return result;
}
function cancel() {
if (timerId !== undefined) {
clearTimeout(timerId);
}
lastInvokeTime = 0;
lastArgs = lastCallTime = lastThis = timerId = undefined;
}
function flush() {
return timerId === undefined ? result : trailingEdge(now());
}
function debounced() {
var time = now(),
isInvoking = shouldInvoke(time);
lastArgs = arguments;
lastThis = this;
lastCallTime = time;
if (isInvoking) {
if (timerId === undefined) {
return leadingEdge(lastCallTime);
}
if (maxing) {
// Handle invocations in a tight loop.
timerId = setTimeout(timerExpired, wait);
return invokeFunc(lastCallTime);
}
}
if (timerId === undefined) {
timerId = setTimeout(timerExpired, wait);
}
return result;
}
debounced.cancel = cancel;
debounced.flush = flush;
return debounced;
}
/**
* Defers invoking the `func` until the current call stack has cleared. Any
* additional arguments are provided to `func` when it's invoked.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Function
* @param {Function} func The function to defer.
* @param {...*} [args] The arguments to invoke `func` with.
* @returns {number} Returns the timer id.
* @example
*
* _.defer(function(text) {
* console.log(text);
* }, 'deferred');
* // => Logs 'deferred' after one millisecond.
*/
var defer = baseRest(function(func, args) {
return baseDelay(func, 1, args);
});
/**
* Invokes `func` after `wait` milliseconds. Any additional arguments are
* provided to `func` when it's invoked.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Function
* @param {Function} func The function to delay.
* @param {number} wait The number of milliseconds to delay invocation.
* @param {...*} [args] The arguments to invoke `func` with.
* @returns {number} Returns the timer id.
* @example
*
* _.delay(function(text) {
* console.log(text);
* }, 1000, 'later');
* // => Logs 'later' after one second.
*/
var delay = baseRest(function(func, wait, args) {
return baseDelay(func, toNumber(wait) || 0, args);
});
/**
* Creates a function that invokes `func` with arguments reversed.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Function
* @param {Function} func The function to flip arguments for.
* @returns {Function} Returns the new flipped function.
* @example
*
* var flipped = _.flip(function() {
* return _.toArray(arguments);
* });
*
* flipped('a', 'b', 'c', 'd');
* // => ['d', 'c', 'b', 'a']
*/
function flip(func) {
return createWrap(func, WRAP_FLIP_FLAG);
}
/**
* Creates a function that memoizes the result of `func`. If `resolver` is
* provided, it determines the cache key for storing the result based on the
* arguments provided to the memoized function. By default, the first argument
* provided to the memoized function is used as the map cache key. The `func`
* is invoked with the `this` binding of the memoized function.
*
* **Note:** The cache is exposed as the `cache` property on the memoized
* function. Its creation may be customized by replacing the `_.memoize.Cache`
* constructor with one whose instances implement the
* [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
* method interface of `clear`, `delete`, `get`, `has`, and `set`.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Function
* @param {Function} func The function to have its output memoized.
* @param {Function} [resolver] The function to resolve the cache key.
* @returns {Function} Returns the new memoized function.
* @example
*
* var object = { 'a': 1, 'b': 2 };
* var other = { 'c': 3, 'd': 4 };
*
* var values = _.memoize(_.values);
* values(object);
* // => [1, 2]
*
* values(other);
* // => [3, 4]
*
* object.a = 2;
* values(object);
* // => [1, 2]
*
* // Modify the result cache.
* values.cache.set(object, ['a', 'b']);
* values(object);
* // => ['a', 'b']
*
* // Replace `_.memoize.Cache`.
* _.memoize.Cache = WeakMap;
*/
function memoize(func, resolver) {
if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {
throw new TypeError(FUNC_ERROR_TEXT);
}
var memoized = function() {
var args = arguments,
key = resolver ? resolver.apply(this, args) : args[0],
cache = memoized.cache;
if (cache.has(key)) {
return cache.get(key);
}
var result = func.apply(this, args);
memoized.cache = cache.set(key, result) || cache;
return result;
};
memoized.cache = new (memoize.Cache || MapCache);
return memoized;
}
// Expose `MapCache`.
memoize.Cache = MapCache;
/**
* Creates a function that negates the result of the predicate `func`. The
* `func` predicate is invoked with the `this` binding and arguments of the
* created function.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Function
* @param {Function} predicate The predicate to negate.
* @returns {Function} Returns the new negated function.
* @example
*
* function isEven(n) {
* return n % 2 == 0;
* }
*
* _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
* // => [1, 3, 5]
*/
function negate(predicate) {
if (typeof predicate != 'function') {
throw new TypeError(FUNC_ERROR_TEXT);
}
return function() {
var args = arguments;
switch (args.length) {
case 0: return !predicate.call(this);
case 1: return !predicate.call(this, args[0]);
case 2: return !predicate.call(this, args[0], args[1]);
case 3: return !predicate.call(this, args[0], args[1], args[2]);
}
return !predicate.apply(this, args);
};
}
/**
* Creates a function that is restricted to invoking `func` once. Repeat calls
* to the function return the value of the first invocation. The `func` is
* invoked with the `this` binding and arguments of the created function.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Function
* @param {Function} func The function to restrict.
* @returns {Function} Returns the new restricted function.
* @example
*
* var initialize = _.once(createApplication);
* initialize();
* initialize();
* // => `createApplication` is invoked once
*/
function once(func) {
return before(2, func);
}
/**
* Creates a function that invokes `func` with its arguments transformed.
*
* @static
* @since 4.0.0
* @memberOf _
* @category Function
* @param {Function} func The function to wrap.
* @param {...(Function|Function[])} [transforms=[_.identity]]
* The argument transforms.
* @returns {Function} Returns the new function.
* @example
*
* function doubled(n) {
* return n * 2;
* }
*
* function square(n) {
* return n * n;
* }
*
* var func = _.overArgs(function(x, y) {
* return [x, y];
* }, [square, doubled]);
*
* func(9, 3);
* // => [81, 6]
*
* func(10, 5);
* // => [100, 10]
*/
var overArgs = castRest(function(func, transforms) {
transforms = (transforms.length == 1 && isArray(transforms[0]))
? arrayMap(transforms[0], baseUnary(getIteratee()))
: arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee()));
var funcsLength = transforms.length;
return baseRest(function(args) {
var index = -1,
length = nativeMin(args.length, funcsLength);
while (++index < length) {
args[index] = transforms[index].call(this, args[index]);
}
return apply(func, this, args);
});
});
/**
* Creates a function that invokes `func` with `partials` prepended to the
* arguments it receives. This method is like `_.bind` except it does **not**
* alter the `this` binding.
*
* The `_.partial.placeholder` value, which defaults to `_` in monolithic
* builds, may be used as a placeholder for partially applied arguments.
*
* **Note:** This method doesn't set the "length" property of partially
* applied functions.
*
* @static
* @memberOf _
* @since 0.2.0
* @category Function
* @param {Function} func The function to partially apply arguments to.
* @param {...*} [partials] The arguments to be partially applied.
* @returns {Function} Returns the new partially applied function.
* @example
*
* function greet(greeting, name) {
* return greeting + ' ' + name;
* }
*
* var sayHelloTo = _.partial(greet, 'hello');
* sayHelloTo('fred');
* // => 'hello fred'
*
* // Partially applied with placeholders.
* var greetFred = _.partial(greet, _, 'fred');
* greetFred('hi');
* // => 'hi fred'
*/
var partial = baseRest(function(func, partials) {
var holders = replaceHolders(partials, getHolder(partial));
return createWrap(func, WRAP_PARTIAL_FLAG, undefined, partials, holders);
});
/**
* This method is like `_.partial` except that partially applied arguments
* are appended to the arguments it receives.
*
* The `_.partialRight.placeholder` value, which defaults to `_` in monolithic
* builds, may be used as a placeholder for partially applied arguments.
*
* **Note:** This method doesn't set the "length" property of partially
* applied functions.
*
* @static
* @memberOf _
* @since 1.0.0
* @category Function
* @param {Function} func The function to partially apply arguments to.
* @param {...*} [partials] The arguments to be partially applied.
* @returns {Function} Returns the new partially applied function.
* @example
*
* function greet(greeting, name) {
* return greeting + ' ' + name;
* }
*
* var greetFred = _.partialRight(greet, 'fred');
* greetFred('hi');
* // => 'hi fred'
*
* // Partially applied with placeholders.
* var sayHelloTo = _.partialRight(greet, 'hello', _);
* sayHelloTo('fred');
* // => 'hello fred'
*/
var partialRight = baseRest(function(func, partials) {
var holders = replaceHolders(partials, getHolder(partialRight));
return createWrap(func, WRAP_PARTIAL_RIGHT_FLAG, undefined, partials, holders);
});
/**
* Creates a function that invokes `func` with arguments arranged according
* to the specified `indexes` where the argument value at the first index is
* provided as the first argument, the argument value at the second index is
* provided as the second argument, and so on.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Function
* @param {Function} func The function to rearrange arguments for.
* @param {...(number|number[])} indexes The arranged argument indexes.
* @returns {Function} Returns the new function.
* @example
*
* var rearged = _.rearg(function(a, b, c) {
* return [a, b, c];
* }, [2, 0, 1]);
*
* rearged('b', 'c', 'a')
* // => ['a', 'b', 'c']
*/
var rearg = flatRest(function(func, indexes) {
return createWrap(func, WRAP_REARG_FLAG, undefined, undefined, undefined, indexes);
});
/**
* Creates a function that invokes `func` with the `this` binding of the
* created function and arguments from `start` and beyond provided as
* an array.
*
* **Note:** This method is based on the
* [rest parameter](https://mdn.io/rest_parameters).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Function
* @param {Function} func The function to apply a rest parameter to.
* @param {number} [start=func.length-1] The start position of the rest parameter.
* @returns {Function} Returns the new function.
* @example
*
* var say = _.rest(function(what, names) {
* return what + ' ' + _.initial(names).join(', ') +
* (_.size(names) > 1 ? ', & ' : '') + _.last(names);
* });
*
* say('hello', 'fred', 'barney', 'pebbles');
* // => 'hello fred, barney, & pebbles'
*/
function rest(func, start) {
if (typeof func != 'function') {
throw new TypeError(FUNC_ERROR_TEXT);
}
start = start === undefined ? start : toInteger(start);
return baseRest(func, start);
}
/**
* Creates a function that invokes `func` with the `this` binding of the
* create function and an array of arguments much like
* [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply).
*
* **Note:** This method is based on the
* [spread operator](https://mdn.io/spread_operator).
*
* @static
* @memberOf _
* @since 3.2.0
* @category Function
* @param {Function} func The function to spread arguments over.
* @param {number} [start=0] The start position of the spread.
* @returns {Function} Returns the new function.
* @example
*
* var say = _.spread(function(who, what) {
* return who + ' says ' + what;
* });
*
* say(['fred', 'hello']);
* // => 'fred says hello'
*
* var numbers = Promise.all([
* Promise.resolve(40),
* Promise.resolve(36)
* ]);
*
* numbers.then(_.spread(function(x, y) {
* return x + y;
* }));
* // => a Promise of 76
*/
function spread(func, start) {
if (typeof func != 'function') {
throw new TypeError(FUNC_ERROR_TEXT);
}
start = start == null ? 0 : nativeMax(toInteger(start), 0);
return baseRest(function(args) {
var array = args[start],
otherArgs = castSlice(args, 0, start);
if (array) {
arrayPush(otherArgs, array);
}
return apply(func, this, otherArgs);
});
}
/**
* Creates a throttled function that only invokes `func` at most once per
* every `wait` milliseconds. The throttled function comes with a `cancel`
* method to cancel delayed `func` invocations and a `flush` method to
* immediately invoke them. Provide `options` to indicate whether `func`
* should be invoked on the leading and/or trailing edge of the `wait`
* timeout. The `func` is invoked with the last arguments provided to the
* throttled function. Subsequent calls to the throttled function return the
* result of the last `func` invocation.
*
* **Note:** If `leading` and `trailing` options are `true`, `func` is
* invoked on the trailing edge of the timeout only if the throttled function
* is invoked more than once during the `wait` timeout.
*
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
* until to the next tick, similar to `setTimeout` with a timeout of `0`.
*
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
* for details over the differences between `_.throttle` and `_.debounce`.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Function
* @param {Function} func The function to throttle.
* @param {number} [wait=0] The number of milliseconds to throttle invocations to.
* @param {Object} [options={}] The options object.
* @param {boolean} [options.leading=true]
* Specify invoking on the leading edge of the timeout.
* @param {boolean} [options.trailing=true]
* Specify invoking on the trailing edge of the timeout.
* @returns {Function} Returns the new throttled function.
* @example
*
* // Avoid excessively updating the position while scrolling.
* jQuery(window).on('scroll', _.throttle(updatePosition, 100));
*
* // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
* var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
* jQuery(element).on('click', throttled);
*
* // Cancel the trailing throttled invocation.
* jQuery(window).on('popstate', throttled.cancel);
*/
function throttle(func, wait, options) {
var leading = true,
trailing = true;
if (typeof func != 'function') {
throw new TypeError(FUNC_ERROR_TEXT);
}
if (isObject(options)) {
leading = 'leading' in options ? !!options.leading : leading;
trailing = 'trailing' in options ? !!options.trailing : trailing;
}
return debounce(func, wait, {
'leading': leading,
'maxWait': wait,
'trailing': trailing
});
}
/**
* Creates a function that accepts up to one argument, ignoring any
* additional arguments.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Function
* @param {Function} func The function to cap arguments for.
* @returns {Function} Returns the new capped function.
* @example
*
* _.map(['6', '8', '10'], _.unary(parseInt));
* // => [6, 8, 10]
*/
function unary(func) {
return ary(func, 1);
}
/**
* Creates a function that provides `value` to `wrapper` as its first
* argument. Any additional arguments provided to the function are appended
* to those provided to the `wrapper`. The wrapper is invoked with the `this`
* binding of the created function.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Function
* @param {*} value The value to wrap.
* @param {Function} [wrapper=identity] The wrapper function.
* @returns {Function} Returns the new function.
* @example
*
* var p = _.wrap(_.escape, function(func, text) {
* return '<p>' + func(text) + '</p>';
* });
*
* p('fred, barney, & pebbles');
* // => '<p>fred, barney, &amp; pebbles</p>'
*/
function wrap(value, wrapper) {
return partial(castFunction(wrapper), value);
}
/*------------------------------------------------------------------------*/
/**
* Casts `value` as an array if it's not one.
*
* @static
* @memberOf _
* @since 4.4.0
* @category Lang
* @param {*} value The value to inspect.
* @returns {Array} Returns the cast array.
* @example
*
* _.castArray(1);
* // => [1]
*
* _.castArray({ 'a': 1 });
* // => [{ 'a': 1 }]
*
* _.castArray('abc');
* // => ['abc']
*
* _.castArray(null);
* // => [null]
*
* _.castArray(undefined);
* // => [undefined]
*
* _.castArray();
* // => []
*
* var array = [1, 2, 3];
* console.log(_.castArray(array) === array);
* // => true
*/
function castArray() {
if (!arguments.length) {
return [];
}
var value = arguments[0];
return isArray(value) ? value : [value];
}
/**
* Creates a shallow clone of `value`.
*
* **Note:** This method is loosely based on the
* [structured clone algorithm](https://mdn.io/Structured_clone_algorithm)
* and supports cloning arrays, array buffers, booleans, date objects, maps,
* numbers, `Object` objects, regexes, sets, strings, symbols, and typed
* arrays. The own enumerable properties of `arguments` objects are cloned
* as plain objects. An empty object is returned for uncloneable values such
* as error objects, functions, DOM nodes, and WeakMaps.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to clone.
* @returns {*} Returns the cloned value.
* @see _.cloneDeep
* @example
*
* var objects = [{ 'a': 1 }, { 'b': 2 }];
*
* var shallow = _.clone(objects);
* console.log(shallow[0] === objects[0]);
* // => true
*/
function clone(value) {
return baseClone(value, CLONE_SYMBOLS_FLAG);
}
/**
* This method is like `_.clone` except that it accepts `customizer` which
* is invoked to produce the cloned value. If `customizer` returns `undefined`,
* cloning is handled by the method instead. The `customizer` is invoked with
* up to four arguments; (value [, index|key, object, stack]).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to clone.
* @param {Function} [customizer] The function to customize cloning.
* @returns {*} Returns the cloned value.
* @see _.cloneDeepWith
* @example
*
* function customizer(value) {
* if (_.isElement(value)) {
* return value.cloneNode(false);
* }
* }
*
* var el = _.cloneWith(document.body, customizer);
*
* console.log(el === document.body);
* // => false
* console.log(el.nodeName);
* // => 'BODY'
* console.log(el.childNodes.length);
* // => 0
*/
function cloneWith(value, customizer) {
customizer = typeof customizer == 'function' ? customizer : undefined;
return baseClone(value, CLONE_SYMBOLS_FLAG, customizer);
}
/**
* This method is like `_.clone` except that it recursively clones `value`.
*
* @static
* @memberOf _
* @since 1.0.0
* @category Lang
* @param {*} value The value to recursively clone.
* @returns {*} Returns the deep cloned value.
* @see _.clone
* @example
*
* var objects = [{ 'a': 1 }, { 'b': 2 }];
*
* var deep = _.cloneDeep(objects);
* console.log(deep[0] === objects[0]);
* // => false
*/
function cloneDeep(value) {
return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);
}
/**
* This method is like `_.cloneWith` except that it recursively clones `value`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to recursively clone.
* @param {Function} [customizer] The function to customize cloning.
* @returns {*} Returns the deep cloned value.
* @see _.cloneWith
* @example
*
* function customizer(value) {
* if (_.isElement(value)) {
* return value.cloneNode(true);
* }
* }
*
* var el = _.cloneDeepWith(document.body, customizer);
*
* console.log(el === document.body);
* // => false
* console.log(el.nodeName);
* // => 'BODY'
* console.log(el.childNodes.length);
* // => 20
*/
function cloneDeepWith(value, customizer) {
customizer = typeof customizer == 'function' ? customizer : undefined;
return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer);
}
/**
* Checks if `object` conforms to `source` by invoking the predicate
* properties of `source` with the corresponding property values of `object`.
*
* **Note:** This method is equivalent to `_.conforms` when `source` is
* partially applied.
*
* @static
* @memberOf _
* @since 4.14.0
* @category Lang
* @param {Object} object The object to inspect.
* @param {Object} source The object of property predicates to conform to.
* @returns {boolean} Returns `true` if `object` conforms, else `false`.
* @example
*
* var object = { 'a': 1, 'b': 2 };
*
* _.conformsTo(object, { 'b': function(n) { return n > 1; } });
* // => true
*
* _.conformsTo(object, { 'b': function(n) { return n > 2; } });
* // => false
*/
function conformsTo(object, source) {
return source == null || baseConformsTo(object, source, keys(source));
}
/**
* Performs a
* [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
* comparison between two values to determine if they are equivalent.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to compare.
* @param {*} other The other value to compare.
* @returns {boolean} Returns `true` if the values are equivalent, else `false`.
* @example
*
* var object = { 'a': 1 };
* var other = { 'a': 1 };
*
* _.eq(object, object);
* // => true
*
* _.eq(object, other);
* // => false
*
* _.eq('a', 'a');
* // => true
*
* _.eq('a', Object('a'));
* // => false
*
* _.eq(NaN, NaN);
* // => true
*/
function eq(value, other) {
return value === other || (value !== value && other !== other);
}
/**
* Checks if `value` is greater than `other`.
*
* @static
* @memberOf _
* @since 3.9.0
* @category Lang
* @param {*} value The value to compare.
* @param {*} other The other value to compare.
* @returns {boolean} Returns `true` if `value` is greater than `other`,
* else `false`.
* @see _.lt
* @example
*
* _.gt(3, 1);
* // => true
*
* _.gt(3, 3);
* // => false
*
* _.gt(1, 3);
* // => false
*/
var gt = createRelationalOperation(baseGt);
/**
* Checks if `value` is greater than or equal to `other`.
*
* @static
* @memberOf _
* @since 3.9.0
* @category Lang
* @param {*} value The value to compare.
* @param {*} other The other value to compare.
* @returns {boolean} Returns `true` if `value` is greater than or equal to
* `other`, else `false`.
* @see _.lte
* @example
*
* _.gte(3, 1);
* // => true
*
* _.gte(3, 3);
* // => true
*
* _.gte(1, 3);
* // => false
*/
var gte = createRelationalOperation(function(value, other) {
return value >= other;
});
/**
* Checks if `value` is likely an `arguments` object.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an `arguments` object,
* else `false`.
* @example
*
* _.isArguments(function() { return arguments; }());
* // => true
*
* _.isArguments([1, 2, 3]);
* // => false
*/
var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {
return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&
!propertyIsEnumerable.call(value, 'callee');
};
/**
* Checks if `value` is classified as an `Array` object.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an array, else `false`.
* @example
*
* _.isArray([1, 2, 3]);
* // => true
*
* _.isArray(document.body.children);
* // => false
*
* _.isArray('abc');
* // => false
*
* _.isArray(_.noop);
* // => false
*/
var isArray = Array.isArray;
/**
* Checks if `value` is classified as an `ArrayBuffer` object.
*
* @static
* @memberOf _
* @since 4.3.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
* @example
*
* _.isArrayBuffer(new ArrayBuffer(2));
* // => true
*
* _.isArrayBuffer(new Array(2));
* // => false
*/
var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer;
/**
* Checks if `value` is array-like. A value is considered array-like if it's
* not a function and has a `value.length` that's an integer greater than or
* equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is array-like, else `false`.
* @example
*
* _.isArrayLike([1, 2, 3]);
* // => true
*
* _.isArrayLike(document.body.children);
* // => true
*
* _.isArrayLike('abc');
* // => true
*
* _.isArrayLike(_.noop);
* // => false
*/
function isArrayLike(value) {
return value != null && isLength(value.length) && !isFunction(value);
}
/**
* This method is like `_.isArrayLike` except that it also checks if `value`
* is an object.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an array-like object,
* else `false`.
* @example
*
* _.isArrayLikeObject([1, 2, 3]);
* // => true
*
* _.isArrayLikeObject(document.body.children);
* // => true
*
* _.isArrayLikeObject('abc');
* // => false
*
* _.isArrayLikeObject(_.noop);
* // => false
*/
function isArrayLikeObject(value) {
return isObjectLike(value) && isArrayLike(value);
}
/**
* Checks if `value` is classified as a boolean primitive or object.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a boolean, else `false`.
* @example
*
* _.isBoolean(false);
* // => true
*
* _.isBoolean(null);
* // => false
*/
function isBoolean(value) {
return value === true || value === false ||
(isObjectLike(value) && baseGetTag(value) == boolTag);
}
/**
* Checks if `value` is a buffer.
*
* @static
* @memberOf _
* @since 4.3.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a buffer, else `false`.
* @example
*
* _.isBuffer(new Buffer(2));
* // => true
*
* _.isBuffer(new Uint8Array(2));
* // => false
*/
var isBuffer = nativeIsBuffer || stubFalse;
/**
* Checks if `value` is classified as a `Date` object.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a date object, else `false`.
* @example
*
* _.isDate(new Date);
* // => true
*
* _.isDate('Mon April 23 2012');
* // => false
*/
var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate;
/**
* Checks if `value` is likely a DOM element.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.
* @example
*
* _.isElement(document.body);
* // => true
*
* _.isElement('<body>');
* // => false
*/
function isElement(value) {
return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value);
}
/**
* Checks if `value` is an empty object, collection, map, or set.
*
* Objects are considered empty if they have no own enumerable string keyed
* properties.
*
* Array-like values such as `arguments` objects, arrays, buffers, strings, or
* jQuery-like collections are considered empty if they have a `length` of `0`.
* Similarly, maps and sets are considered empty if they have a `size` of `0`.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is empty, else `false`.
* @example
*
* _.isEmpty(null);
* // => true
*
* _.isEmpty(true);
* // => true
*
* _.isEmpty(1);
* // => true
*
* _.isEmpty([1, 2, 3]);
* // => false
*
* _.isEmpty({ 'a': 1 });
* // => false
*/
function isEmpty(value) {
if (value == null) {
return true;
}
if (isArrayLike(value) &&
(isArray(value) || typeof value == 'string' || typeof value.splice == 'function' ||
isBuffer(value) || isTypedArray(value) || isArguments(value))) {
return !value.length;
}
var tag = getTag(value);
if (tag == mapTag || tag == setTag) {
return !value.size;
}
if (isPrototype(value)) {
return !baseKeys(value).length;
}
for (var key in value) {
if (hasOwnProperty.call(value, key)) {
return false;
}
}
return true;
}
/**
* Performs a deep comparison between two values to determine if they are
* equivalent.
*
* **Note:** This method supports comparing arrays, array buffers, booleans,
* date objects, error objects, maps, numbers, `Object` objects, regexes,
* sets, strings, symbols, and typed arrays. `Object` objects are compared
* by their own, not inherited, enumerable properties. Functions and DOM
* nodes are compared by strict equality, i.e. `===`.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to compare.
* @param {*} other The other value to compare.
* @returns {boolean} Returns `true` if the values are equivalent, else `false`.
* @example
*
* var object = { 'a': 1 };
* var other = { 'a': 1 };
*
* _.isEqual(object, other);
* // => true
*
* object === other;
* // => false
*/
function isEqual(value, other) {
return baseIsEqual(value, other);
}
/**
* This method is like `_.isEqual` except that it accepts `customizer` which
* is invoked to compare values. If `customizer` returns `undefined`, comparisons
* are handled by the method instead. The `customizer` is invoked with up to
* six arguments: (objValue, othValue [, index|key, object, other, stack]).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to compare.
* @param {*} other The other value to compare.
* @param {Function} [customizer] The function to customize comparisons.
* @returns {boolean} Returns `true` if the values are equivalent, else `false`.
* @example
*
* function isGreeting(value) {
* return /^h(?:i|ello)$/.test(value);
* }
*
* function customizer(objValue, othValue) {
* if (isGreeting(objValue) && isGreeting(othValue)) {
* return true;
* }
* }
*
* var array = ['hello', 'goodbye'];
* var other = ['hi', 'goodbye'];
*
* _.isEqualWith(array, other, customizer);
* // => true
*/
function isEqualWith(value, other, customizer) {
customizer = typeof customizer == 'function' ? customizer : undefined;
var result = customizer ? customizer(value, other) : undefined;
return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result;
}
/**
* Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,
* `SyntaxError`, `TypeError`, or `URIError` object.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an error object, else `false`.
* @example
*
* _.isError(new Error);
* // => true
*
* _.isError(Error);
* // => false
*/
function isError(value) {
if (!isObjectLike(value)) {
return false;
}
var tag = baseGetTag(value);
return tag == errorTag || tag == domExcTag ||
(typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value));
}
/**
* Checks if `value` is a finite primitive number.
*
* **Note:** This method is based on
* [`Number.isFinite`](https://mdn.io/Number/isFinite).
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a finite number, else `false`.
* @example
*
* _.isFinite(3);
* // => true
*
* _.isFinite(Number.MIN_VALUE);
* // => true
*
* _.isFinite(Infinity);
* // => false
*
* _.isFinite('3');
* // => false
*/
function isFinite(value) {
return typeof value == 'number' && nativeIsFinite(value);
}
/**
* Checks if `value` is classified as a `Function` object.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a function, else `false`.
* @example
*
* _.isFunction(_);
* // => true
*
* _.isFunction(/abc/);
* // => false
*/
function isFunction(value) {
if (!isObject(value)) {
return false;
}
// The use of `Object#toString` avoids issues with the `typeof` operator
// in Safari 9 which returns 'object' for typed arrays and other constructors.
var tag = baseGetTag(value);
return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
}
/**
* Checks if `value` is an integer.
*
* **Note:** This method is based on
* [`Number.isInteger`](https://mdn.io/Number/isInteger).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an integer, else `false`.
* @example
*
* _.isInteger(3);
* // => true
*
* _.isInteger(Number.MIN_VALUE);
* // => false
*
* _.isInteger(Infinity);
* // => false
*
* _.isInteger('3');
* // => false
*/
function isInteger(value) {
return typeof value == 'number' && value == toInteger(value);
}
/**
* Checks if `value` is a valid array-like length.
*
* **Note:** This method is loosely based on
* [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
* @example
*
* _.isLength(3);
* // => true
*
* _.isLength(Number.MIN_VALUE);
* // => false
*
* _.isLength(Infinity);
* // => false
*
* _.isLength('3');
* // => false
*/
function isLength(value) {
return typeof value == 'number' &&
value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
}
/**
* Checks if `value` is the
* [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
* _.isObject({});
* // => true
*
* _.isObject([1, 2, 3]);
* // => true
*
* _.isObject(_.noop);
* // => true
*
* _.isObject(null);
* // => false
*/
function isObject(value) {
var type = typeof value;
return value != null && (type == 'object' || type == 'function');
}
/**
* Checks if `value` is object-like. A value is object-like if it's not `null`
* and has a `typeof` result of "object".
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
* @example
*
* _.isObjectLike({});
* // => true
*
* _.isObjectLike([1, 2, 3]);
* // => true
*
* _.isObjectLike(_.noop);
* // => false
*
* _.isObjectLike(null);
* // => false
*/
function isObjectLike(value) {
return value != null && typeof value == 'object';
}
/**
* Checks if `value` is classified as a `Map` object.
*
* @static
* @memberOf _
* @since 4.3.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a map, else `false`.
* @example
*
* _.isMap(new Map);
* // => true
*
* _.isMap(new WeakMap);
* // => false
*/
var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap;
/**
* Performs a partial deep comparison between `object` and `source` to
* determine if `object` contains equivalent property values.
*
* **Note:** This method is equivalent to `_.matches` when `source` is
* partially applied.
*
* Partial comparisons will match empty array and empty object `source`
* values against any array or object value, respectively. See `_.isEqual`
* for a list of supported value comparisons.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Lang
* @param {Object} object The object to inspect.
* @param {Object} source The object of property values to match.
* @returns {boolean} Returns `true` if `object` is a match, else `false`.
* @example
*
* var object = { 'a': 1, 'b': 2 };
*
* _.isMatch(object, { 'b': 2 });
* // => true
*
* _.isMatch(object, { 'b': 1 });
* // => false
*/
function isMatch(object, source) {
return object === source || baseIsMatch(object, source, getMatchData(source));
}
/**
* This method is like `_.isMatch` except that it accepts `customizer` which
* is invoked to compare values. If `customizer` returns `undefined`, comparisons
* are handled by the method instead. The `customizer` is invoked with five
* arguments: (objValue, srcValue, index|key, object, source).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {Object} object The object to inspect.
* @param {Object} source The object of property values to match.
* @param {Function} [customizer] The function to customize comparisons.
* @returns {boolean} Returns `true` if `object` is a match, else `false`.
* @example
*
* function isGreeting(value) {
* return /^h(?:i|ello)$/.test(value);
* }
*
* function customizer(objValue, srcValue) {
* if (isGreeting(objValue) && isGreeting(srcValue)) {
* return true;
* }
* }
*
* var object = { 'greeting': 'hello' };
* var source = { 'greeting': 'hi' };
*
* _.isMatchWith(object, source, customizer);
* // => true
*/
function isMatchWith(object, source, customizer) {
customizer = typeof customizer == 'function' ? customizer : undefined;
return baseIsMatch(object, source, getMatchData(source), customizer);
}
/**
* Checks if `value` is `NaN`.
*
* **Note:** This method is based on
* [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as
* global [`isNaN`](https://mdn.io/isNaN) which returns `true` for
* `undefined` and other non-number values.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
* @example
*
* _.isNaN(NaN);
* // => true
*
* _.isNaN(new Number(NaN));
* // => true
*
* isNaN(undefined);
* // => true
*
* _.isNaN(undefined);
* // => false
*/
function isNaN(value) {
// An `NaN` primitive is the only value that is not equal to itself.
// Perform the `toStringTag` check first to avoid errors with some
// ActiveX objects in IE.
return isNumber(value) && value != +value;
}
/**
* Checks if `value` is a pristine native function.
*
* **Note:** This method can't reliably detect native functions in the presence
* of the core-js package because core-js circumvents this kind of detection.
* Despite multiple requests, the core-js maintainer has made it clear: any
* attempt to fix the detection will be obstructed. As a result, we're left
* with little choice but to throw an error. Unfortunately, this also affects
* packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill),
* which rely on core-js.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a native function,
* else `false`.
* @example
*
* _.isNative(Array.prototype.push);
* // => true
*
* _.isNative(_);
* // => false
*/
function isNative(value) {
if (isMaskable(value)) {
throw new Error(CORE_ERROR_TEXT);
}
return baseIsNative(value);
}
/**
* Checks if `value` is `null`.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is `null`, else `false`.
* @example
*
* _.isNull(null);
* // => true
*
* _.isNull(void 0);
* // => false
*/
function isNull(value) {
return value === null;
}
/**
* Checks if `value` is `null` or `undefined`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is nullish, else `false`.
* @example
*
* _.isNil(null);
* // => true
*
* _.isNil(void 0);
* // => true
*
* _.isNil(NaN);
* // => false
*/
function isNil(value) {
return value == null;
}
/**
* Checks if `value` is classified as a `Number` primitive or object.
*
* **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are
* classified as numbers, use the `_.isFinite` method.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a number, else `false`.
* @example
*
* _.isNumber(3);
* // => true
*
* _.isNumber(Number.MIN_VALUE);
* // => true
*
* _.isNumber(Infinity);
* // => true
*
* _.isNumber('3');
* // => false
*/
function isNumber(value) {
return typeof value == 'number' ||
(isObjectLike(value) && baseGetTag(value) == numberTag);
}
/**
* Checks if `value` is a plain object, that is, an object created by the
* `Object` constructor or one with a `[[Prototype]]` of `null`.
*
* @static
* @memberOf _
* @since 0.8.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
* @example
*
* function Foo() {
* this.a = 1;
* }
*
* _.isPlainObject(new Foo);
* // => false
*
* _.isPlainObject([1, 2, 3]);
* // => false
*
* _.isPlainObject({ 'x': 0, 'y': 0 });
* // => true
*
* _.isPlainObject(Object.create(null));
* // => true
*/
function isPlainObject(value) {
if (!isObjectLike(value) || baseGetTag(value) != objectTag) {
return false;
}
var proto = getPrototype(value);
if (proto === null) {
return true;
}
var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;
return typeof Ctor == 'function' && Ctor instanceof Ctor &&
funcToString.call(Ctor) == objectCtorString;
}
/**
* Checks if `value` is classified as a `RegExp` object.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
* @example
*
* _.isRegExp(/abc/);
* // => true
*
* _.isRegExp('/abc/');
* // => false
*/
var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp;
/**
* Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754
* double precision number which isn't the result of a rounded unsafe integer.
*
* **Note:** This method is based on
* [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a safe integer, else `false`.
* @example
*
* _.isSafeInteger(3);
* // => true
*
* _.isSafeInteger(Number.MIN_VALUE);
* // => false
*
* _.isSafeInteger(Infinity);
* // => false
*
* _.isSafeInteger('3');
* // => false
*/
function isSafeInteger(value) {
return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER;
}
/**
* Checks if `value` is classified as a `Set` object.
*
* @static
* @memberOf _
* @since 4.3.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a set, else `false`.
* @example
*
* _.isSet(new Set);
* // => true
*
* _.isSet(new WeakSet);
* // => false
*/
var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet;
/**
* Checks if `value` is classified as a `String` primitive or object.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a string, else `false`.
* @example
*
* _.isString('abc');
* // => true
*
* _.isString(1);
* // => false
*/
function isString(value) {
return typeof value == 'string' ||
(!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag);
}
/**
* Checks if `value` is classified as a `Symbol` primitive or object.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
* @example
*
* _.isSymbol(Symbol.iterator);
* // => true
*
* _.isSymbol('abc');
* // => false
*/
function isSymbol(value) {
return typeof value == 'symbol' ||
(isObjectLike(value) && baseGetTag(value) == symbolTag);
}
/**
* Checks if `value` is classified as a typed array.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
* @example
*
* _.isTypedArray(new Uint8Array);
* // => true
*
* _.isTypedArray([]);
* // => false
*/
var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;
/**
* Checks if `value` is `undefined`.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
* @example
*
* _.isUndefined(void 0);
* // => true
*
* _.isUndefined(null);
* // => false
*/
function isUndefined(value) {
return value === undefined;
}
/**
* Checks if `value` is classified as a `WeakMap` object.
*
* @static
* @memberOf _
* @since 4.3.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a weak map, else `false`.
* @example
*
* _.isWeakMap(new WeakMap);
* // => true
*
* _.isWeakMap(new Map);
* // => false
*/
function isWeakMap(value) {
return isObjectLike(value) && getTag(value) == weakMapTag;
}
/**
* Checks if `value` is classified as a `WeakSet` object.
*
* @static
* @memberOf _
* @since 4.3.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a weak set, else `false`.
* @example
*
* _.isWeakSet(new WeakSet);
* // => true
*
* _.isWeakSet(new Set);
* // => false
*/
function isWeakSet(value) {
return isObjectLike(value) && baseGetTag(value) == weakSetTag;
}
/**
* Checks if `value` is less than `other`.
*
* @static
* @memberOf _
* @since 3.9.0
* @category Lang
* @param {*} value The value to compare.
* @param {*} other The other value to compare.
* @returns {boolean} Returns `true` if `value` is less than `other`,
* else `false`.
* @see _.gt
* @example
*
* _.lt(1, 3);
* // => true
*
* _.lt(3, 3);
* // => false
*
* _.lt(3, 1);
* // => false
*/
var lt = createRelationalOperation(baseLt);
/**
* Checks if `value` is less than or equal to `other`.
*
* @static
* @memberOf _
* @since 3.9.0
* @category Lang
* @param {*} value The value to compare.
* @param {*} other The other value to compare.
* @returns {boolean} Returns `true` if `value` is less than or equal to
* `other`, else `false`.
* @see _.gte
* @example
*
* _.lte(1, 3);
* // => true
*
* _.lte(3, 3);
* // => true
*
* _.lte(3, 1);
* // => false
*/
var lte = createRelationalOperation(function(value, other) {
return value <= other;
});
/**
* Converts `value` to an array.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Lang
* @param {*} value The value to convert.
* @returns {Array} Returns the converted array.
* @example
*
* _.toArray({ 'a': 1, 'b': 2 });
* // => [1, 2]
*
* _.toArray('abc');
* // => ['a', 'b', 'c']
*
* _.toArray(1);
* // => []
*
* _.toArray(null);
* // => []
*/
function toArray(value) {
if (!value) {
return [];
}
if (isArrayLike(value)) {
return isString(value) ? stringToArray(value) : copyArray(value);
}
if (symIterator && value[symIterator]) {
return iteratorToArray(value[symIterator]());
}
var tag = getTag(value),
func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values);
return func(value);
}
/**
* Converts `value` to a finite number.
*
* @static
* @memberOf _
* @since 4.12.0
* @category Lang
* @param {*} value The value to convert.
* @returns {number} Returns the converted number.
* @example
*
* _.toFinite(3.2);
* // => 3.2
*
* _.toFinite(Number.MIN_VALUE);
* // => 5e-324
*
* _.toFinite(Infinity);
* // => 1.7976931348623157e+308
*
* _.toFinite('3.2');
* // => 3.2
*/
function toFinite(value) {
if (!value) {
return value === 0 ? value : 0;
}
value = toNumber(value);
if (value === INFINITY || value === -INFINITY) {
var sign = (value < 0 ? -1 : 1);
return sign * MAX_INTEGER;
}
return value === value ? value : 0;
}
/**
* Converts `value` to an integer.
*
* **Note:** This method is loosely based on
* [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to convert.
* @returns {number} Returns the converted integer.
* @example
*
* _.toInteger(3.2);
* // => 3
*
* _.toInteger(Number.MIN_VALUE);
* // => 0
*
* _.toInteger(Infinity);
* // => 1.7976931348623157e+308
*
* _.toInteger('3.2');
* // => 3
*/
function toInteger(value) {
var result = toFinite(value),
remainder = result % 1;
return result === result ? (remainder ? result - remainder : result) : 0;
}
/**
* Converts `value` to an integer suitable for use as the length of an
* array-like object.
*
* **Note:** This method is based on
* [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to convert.
* @returns {number} Returns the converted integer.
* @example
*
* _.toLength(3.2);
* // => 3
*
* _.toLength(Number.MIN_VALUE);
* // => 0
*
* _.toLength(Infinity);
* // => 4294967295
*
* _.toLength('3.2');
* // => 3
*/
function toLength(value) {
return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0;
}
/**
* Converts `value` to a number.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to process.
* @returns {number} Returns the number.
* @example
*
* _.toNumber(3.2);
* // => 3.2
*
* _.toNumber(Number.MIN_VALUE);
* // => 5e-324
*
* _.toNumber(Infinity);
* // => Infinity
*
* _.toNumber('3.2');
* // => 3.2
*/
function toNumber(value) {
if (typeof value == 'number') {
return value;
}
if (isSymbol(value)) {
return NAN;
}
if (isObject(value)) {
var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
value = isObject(other) ? (other + '') : other;
}
if (typeof value != 'string') {
return value === 0 ? value : +value;
}
value = value.replace(reTrim, '');
var isBinary = reIsBinary.test(value);
return (isBinary || reIsOctal.test(value))
? freeParseInt(value.slice(2), isBinary ? 2 : 8)
: (reIsBadHex.test(value) ? NAN : +value);
}
/**
* Converts `value` to a plain object flattening inherited enumerable string
* keyed properties of `value` to own properties of the plain object.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Lang
* @param {*} value The value to convert.
* @returns {Object} Returns the converted plain object.
* @example
*
* function Foo() {
* this.b = 2;
* }
*
* Foo.prototype.c = 3;
*
* _.assign({ 'a': 1 }, new Foo);
* // => { 'a': 1, 'b': 2 }
*
* _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
* // => { 'a': 1, 'b': 2, 'c': 3 }
*/
function toPlainObject(value) {
return copyObject(value, keysIn(value));
}
/**
* Converts `value` to a safe integer. A safe integer can be compared and
* represented correctly.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to convert.
* @returns {number} Returns the converted integer.
* @example
*
* _.toSafeInteger(3.2);
* // => 3
*
* _.toSafeInteger(Number.MIN_VALUE);
* // => 0
*
* _.toSafeInteger(Infinity);
* // => 9007199254740991
*
* _.toSafeInteger('3.2');
* // => 3
*/
function toSafeInteger(value) {
return value
? baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER)
: (value === 0 ? value : 0);
}
/**
* Converts `value` to a string. An empty string is returned for `null`
* and `undefined` values. The sign of `-0` is preserved.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to convert.
* @returns {string} Returns the converted string.
* @example
*
* _.toString(null);
* // => ''
*
* _.toString(-0);
* // => '-0'
*
* _.toString([1, 2, 3]);
* // => '1,2,3'
*/
function toString(value) {
return value == null ? '' : baseToString(value);
}
/*------------------------------------------------------------------------*/
/**
* Assigns own enumerable string keyed properties of source objects to the
* destination object. Source objects are applied from left to right.
* Subsequent sources overwrite property assignments of previous sources.
*
* **Note:** This method mutates `object` and is loosely based on
* [`Object.assign`](https://mdn.io/Object/assign).
*
* @static
* @memberOf _
* @since 0.10.0
* @category Object
* @param {Object} object The destination object.
* @param {...Object} [sources] The source objects.
* @returns {Object} Returns `object`.
* @see _.assignIn
* @example
*
* function Foo() {
* this.a = 1;
* }
*
* function Bar() {
* this.c = 3;
* }
*
* Foo.prototype.b = 2;
* Bar.prototype.d = 4;
*
* _.assign({ 'a': 0 }, new Foo, new Bar);
* // => { 'a': 1, 'c': 3 }
*/
var assign = createAssigner(function(object, source) {
if (isPrototype(source) || isArrayLike(source)) {
copyObject(source, keys(source), object);
return;
}
for (var key in source) {
if (hasOwnProperty.call(source, key)) {
assignValue(object, key, source[key]);
}
}
});
/**
* This method is like `_.assign` except that it iterates over own and
* inherited source properties.
*
* **Note:** This method mutates `object`.
*
* @static
* @memberOf _
* @since 4.0.0
* @alias extend
* @category Object
* @param {Object} object The destination object.
* @param {...Object} [sources] The source objects.
* @returns {Object} Returns `object`.
* @see _.assign
* @example
*
* function Foo() {
* this.a = 1;
* }
*
* function Bar() {
* this.c = 3;
* }
*
* Foo.prototype.b = 2;
* Bar.prototype.d = 4;
*
* _.assignIn({ 'a': 0 }, new Foo, new Bar);
* // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }
*/
var assignIn = createAssigner(function(object, source) {
copyObject(source, keysIn(source), object);
});
/**
* This method is like `_.assignIn` except that it accepts `customizer`
* which is invoked to produce the assigned values. If `customizer` returns
* `undefined`, assignment is handled by the method instead. The `customizer`
* is invoked with five arguments: (objValue, srcValue, key, object, source).
*
* **Note:** This method mutates `object`.
*
* @static
* @memberOf _
* @since 4.0.0
* @alias extendWith
* @category Object
* @param {Object} object The destination object.
* @param {...Object} sources The source objects.
* @param {Function} [customizer] The function to customize assigned values.
* @returns {Object} Returns `object`.
* @see _.assignWith
* @example
*
* function customizer(objValue, srcValue) {
* return _.isUndefined(objValue) ? srcValue : objValue;
* }
*
* var defaults = _.partialRight(_.assignInWith, customizer);
*
* defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
* // => { 'a': 1, 'b': 2 }
*/
var assignInWith = createAssigner(function(object, source, srcIndex, customizer) {
copyObject(source, keysIn(source), object, customizer);
});
/**
* This method is like `_.assign` except that it accepts `customizer`
* which is invoked to produce the assigned values. If `customizer` returns
* `undefined`, assignment is handled by the method instead. The `customizer`
* is invoked with five arguments: (objValue, srcValue, key, object, source).
*
* **Note:** This method mutates `object`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Object
* @param {Object} object The destination object.
* @param {...Object} sources The source objects.
* @param {Function} [customizer] The function to customize assigned values.
* @returns {Object} Returns `object`.
* @see _.assignInWith
* @example
*
* function customizer(objValue, srcValue) {
* return _.isUndefined(objValue) ? srcValue : objValue;
* }
*
* var defaults = _.partialRight(_.assignWith, customizer);
*
* defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
* // => { 'a': 1, 'b': 2 }
*/
var assignWith = createAssigner(function(object, source, srcIndex, customizer) {
copyObject(source, keys(source), object, customizer);
});
/**
* Creates an array of values corresponding to `paths` of `object`.
*
* @static
* @memberOf _
* @since 1.0.0
* @category Object
* @param {Object} object The object to iterate over.
* @param {...(string|string[])} [paths] The property paths to pick.
* @returns {Array} Returns the picked values.
* @example
*
* var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
*
* _.at(object, ['a[0].b.c', 'a[1]']);
* // => [3, 4]
*/
var at = flatRest(baseAt);
/**
* Creates an object that inherits from the `prototype` object. If a
* `properties` object is given, its own enumerable string keyed properties
* are assigned to the created object.
*
* @static
* @memberOf _
* @since 2.3.0
* @category Object
* @param {Object} prototype The object to inherit from.
* @param {Object} [properties] The properties to assign to the object.
* @returns {Object} Returns the new object.
* @example
*
* function Shape() {
* this.x = 0;
* this.y = 0;
* }
*
* function Circle() {
* Shape.call(this);
* }
*
* Circle.prototype = _.create(Shape.prototype, {
* 'constructor': Circle
* });
*
* var circle = new Circle;
* circle instanceof Circle;
* // => true
*
* circle instanceof Shape;
* // => true
*/
function create(prototype, properties) {
var result = baseCreate(prototype);
return properties == null ? result : baseAssign(result, properties);
}
/**
* Assigns own and inherited enumerable string keyed properties of source
* objects to the destination object for all destination properties that
* resolve to `undefined`. Source objects are applied from left to right.
* Once a property is set, additional values of the same property are ignored.
*
* **Note:** This method mutates `object`.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Object
* @param {Object} object The destination object.
* @param {...Object} [sources] The source objects.
* @returns {Object} Returns `object`.
* @see _.defaultsDeep
* @example
*
* _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
* // => { 'a': 1, 'b': 2 }
*/
var defaults = baseRest(function(object, sources) {
object = Object(object);
var index = -1;
var length = sources.length;
var guard = length > 2 ? sources[2] : undefined;
if (guard && isIterateeCall(sources[0], sources[1], guard)) {
length = 1;
}
while (++index < length) {
var source = sources[index];
var props = keysIn(source);
var propsIndex = -1;
var propsLength = props.length;
while (++propsIndex < propsLength) {
var key = props[propsIndex];
var value = object[key];
if (value === undefined ||
(eq(value, objectProto[key]) && !hasOwnProperty.call(object, key))) {
object[key] = source[key];
}
}
}
return object;
});
/**
* This method is like `_.defaults` except that it recursively assigns
* default properties.
*
* **Note:** This method mutates `object`.
*
* @static
* @memberOf _
* @since 3.10.0
* @category Object
* @param {Object} object The destination object.
* @param {...Object} [sources] The source objects.
* @returns {Object} Returns `object`.
* @see _.defaults
* @example
*
* _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } });
* // => { 'a': { 'b': 2, 'c': 3 } }
*/
var defaultsDeep = baseRest(function(args) {
args.push(undefined, customDefaultsMerge);
return apply(mergeWith, undefined, args);
});
/**
* This method is like `_.find` except that it returns the key of the first
* element `predicate` returns truthy for instead of the element itself.
*
* @static
* @memberOf _
* @since 1.1.0
* @category Object
* @param {Object} object The object to inspect.
* @param {Function} [predicate=_.identity] The function invoked per iteration.
* @returns {string|undefined} Returns the key of the matched element,
* else `undefined`.
* @example
*
* var users = {
* 'barney': { 'age': 36, 'active': true },
* 'fred': { 'age': 40, 'active': false },
* 'pebbles': { 'age': 1, 'active': true }
* };
*
* _.findKey(users, function(o) { return o.age < 40; });
* // => 'barney' (iteration order is not guaranteed)
*
* // The `_.matches` iteratee shorthand.
* _.findKey(users, { 'age': 1, 'active': true });
* // => 'pebbles'
*
* // The `_.matchesProperty` iteratee shorthand.
* _.findKey(users, ['active', false]);
* // => 'fred'
*
* // The `_.property` iteratee shorthand.
* _.findKey(users, 'active');
* // => 'barney'
*/
function findKey(object, predicate) {
return baseFindKey(object, getIteratee(predicate, 3), baseForOwn);
}
/**
* This method is like `_.findKey` except that it iterates over elements of
* a collection in the opposite order.
*
* @static
* @memberOf _
* @since 2.0.0
* @category Object
* @param {Object} object The object to inspect.
* @param {Function} [predicate=_.identity] The function invoked per iteration.
* @returns {string|undefined} Returns the key of the matched element,
* else `undefined`.
* @example
*
* var users = {
* 'barney': { 'age': 36, 'active': true },
* 'fred': { 'age': 40, 'active': false },
* 'pebbles': { 'age': 1, 'active': true }
* };
*
* _.findLastKey(users, function(o) { return o.age < 40; });
* // => returns 'pebbles' assuming `_.findKey` returns 'barney'
*
* // The `_.matches` iteratee shorthand.
* _.findLastKey(users, { 'age': 36, 'active': true });
* // => 'barney'
*
* // The `_.matchesProperty` iteratee shorthand.
* _.findLastKey(users, ['active', false]);
* // => 'fred'
*
* // The `_.property` iteratee shorthand.
* _.findLastKey(users, 'active');
* // => 'pebbles'
*/
function findLastKey(object, predicate) {
return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight);
}
/**
* Iterates over own and inherited enumerable string keyed properties of an
* object and invokes `iteratee` for each property. The iteratee is invoked
* with three arguments: (value, key, object). Iteratee functions may exit
* iteration early by explicitly returning `false`.
*
* @static
* @memberOf _
* @since 0.3.0
* @category Object
* @param {Object} object The object to iterate over.
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
* @returns {Object} Returns `object`.
* @see _.forInRight
* @example
*
* function Foo() {
* this.a = 1;
* this.b = 2;
* }
*
* Foo.prototype.c = 3;
*
* _.forIn(new Foo, function(value, key) {
* console.log(key);
* });
* // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed).
*/
function forIn(object, iteratee) {
return object == null
? object
: baseFor(object, getIteratee(iteratee, 3), keysIn);
}
/**
* This method is like `_.forIn` except that it iterates over properties of
* `object` in the opposite order.
*
* @static
* @memberOf _
* @since 2.0.0
* @category Object
* @param {Object} object The object to iterate over.
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
* @returns {Object} Returns `object`.
* @see _.forIn
* @example
*
* function Foo() {
* this.a = 1;
* this.b = 2;
* }
*
* Foo.prototype.c = 3;
*
* _.forInRight(new Foo, function(value, key) {
* console.log(key);
* });
* // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'.
*/
function forInRight(object, iteratee) {
return object == null
? object
: baseForRight(object, getIteratee(iteratee, 3), keysIn);
}
/**
* Iterates over own enumerable string keyed properties of an object and
* invokes `iteratee` for each property. The iteratee is invoked with three
* arguments: (value, key, object). Iteratee functions may exit iteration
* early by explicitly returning `false`.
*
* @static
* @memberOf _
* @since 0.3.0
* @category Object
* @param {Object} object The object to iterate over.
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
* @returns {Object} Returns `object`.
* @see _.forOwnRight
* @example
*
* function Foo() {
* this.a = 1;
* this.b = 2;
* }
*
* Foo.prototype.c = 3;
*
* _.forOwn(new Foo, function(value, key) {
* console.log(key);
* });
* // => Logs 'a' then 'b' (iteration order is not guaranteed).
*/
function forOwn(object, iteratee) {
return object && baseForOwn(object, getIteratee(iteratee, 3));
}
/**
* This method is like `_.forOwn` except that it iterates over properties of
* `object` in the opposite order.
*
* @static
* @memberOf _
* @since 2.0.0
* @category Object
* @param {Object} object The object to iterate over.
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
* @returns {Object} Returns `object`.
* @see _.forOwn
* @example
*
* function Foo() {
* this.a = 1;
* this.b = 2;
* }
*
* Foo.prototype.c = 3;
*
* _.forOwnRight(new Foo, function(value, key) {
* console.log(key);
* });
* // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'.
*/
function forOwnRight(object, iteratee) {
return object && baseForOwnRight(object, getIteratee(iteratee, 3));
}
/**
* Creates an array of function property names from own enumerable properties
* of `object`.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Object
* @param {Object} object The object to inspect.
* @returns {Array} Returns the function names.
* @see _.functionsIn
* @example
*
* function Foo() {
* this.a = _.constant('a');
* this.b = _.constant('b');
* }
*
* Foo.prototype.c = _.constant('c');
*
* _.functions(new Foo);
* // => ['a', 'b']
*/
function functions(object) {
return object == null ? [] : baseFunctions(object, keys(object));
}
/**
* Creates an array of function property names from own and inherited
* enumerable properties of `object`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Object
* @param {Object} object The object to inspect.
* @returns {Array} Returns the function names.
* @see _.functions
* @example
*
* function Foo() {
* this.a = _.constant('a');
* this.b = _.constant('b');
* }
*
* Foo.prototype.c = _.constant('c');
*
* _.functionsIn(new Foo);
* // => ['a', 'b', 'c']
*/
function functionsIn(object) {
return object == null ? [] : baseFunctions(object, keysIn(object));
}
/**
* Gets the value at `path` of `object`. If the resolved value is
* `undefined`, the `defaultValue` is returned in its place.
*
* @static
* @memberOf _
* @since 3.7.0
* @category Object
* @param {Object} object The object to query.
* @param {Array|string} path The path of the property to get.
* @param {*} [defaultValue] The value returned for `undefined` resolved values.
* @returns {*} Returns the resolved value.
* @example
*
* var object = { 'a': [{ 'b': { 'c': 3 } }] };
*
* _.get(object, 'a[0].b.c');
* // => 3
*
* _.get(object, ['a', '0', 'b', 'c']);
* // => 3
*
* _.get(object, 'a.b.c', 'default');
* // => 'default'
*/
function get(object, path, defaultValue) {
var result = object == null ? undefined : baseGet(object, path);
return result === undefined ? defaultValue : result;
}
/**
* Checks if `path` is a direct property of `object`.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Object
* @param {Object} object The object to query.
* @param {Array|string} path The path to check.
* @returns {boolean} Returns `true` if `path` exists, else `false`.
* @example
*
* var object = { 'a': { 'b': 2 } };
* var other = _.create({ 'a': _.create({ 'b': 2 }) });
*
* _.has(object, 'a');
* // => true
*
* _.has(object, 'a.b');
* // => true
*
* _.has(object, ['a', 'b']);
* // => true
*
* _.has(other, 'a');
* // => false
*/
function has(object, path) {
return object != null && hasPath(object, path, baseHas);
}
/**
* Checks if `path` is a direct or inherited property of `object`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Object
* @param {Object} object The object to query.
* @param {Array|string} path The path to check.
* @returns {boolean} Returns `true` if `path` exists, else `false`.
* @example
*
* var object = _.create({ 'a': _.create({ 'b': 2 }) });
*
* _.hasIn(object, 'a');
* // => true
*
* _.hasIn(object, 'a.b');
* // => true
*
* _.hasIn(object, ['a', 'b']);
* // => true
*
* _.hasIn(object, 'b');
* // => false
*/
function hasIn(object, path) {
return object != null && hasPath(object, path, baseHasIn);
}
/**
* Creates an object composed of the inverted keys and values of `object`.
* If `object` contains duplicate values, subsequent values overwrite
* property assignments of previous values.
*
* @static
* @memberOf _
* @since 0.7.0
* @category Object
* @param {Object} object The object to invert.
* @returns {Object} Returns the new inverted object.
* @example
*
* var object = { 'a': 1, 'b': 2, 'c': 1 };
*
* _.invert(object);
* // => { '1': 'c', '2': 'b' }
*/
var invert = createInverter(function(result, value, key) {
if (value != null &&
typeof value.toString != 'function') {
value = nativeObjectToString.call(value);
}
result[value] = key;
}, constant(identity));
/**
* This method is like `_.invert` except that the inverted object is generated
* from the results of running each element of `object` thru `iteratee`. The
* corresponding inverted value of each inverted key is an array of keys
* responsible for generating the inverted value. The iteratee is invoked
* with one argument: (value).
*
* @static
* @memberOf _
* @since 4.1.0
* @category Object
* @param {Object} object The object to invert.
* @param {Function} [iteratee=_.identity] The iteratee invoked per element.
* @returns {Object} Returns the new inverted object.
* @example
*
* var object = { 'a': 1, 'b': 2, 'c': 1 };
*
* _.invertBy(object);
* // => { '1': ['a', 'c'], '2': ['b'] }
*
* _.invertBy(object, function(value) {
* return 'group' + value;
* });
* // => { 'group1': ['a', 'c'], 'group2': ['b'] }
*/
var invertBy = createInverter(function(result, value, key) {
if (value != null &&
typeof value.toString != 'function') {
value = nativeObjectToString.call(value);
}
if (hasOwnProperty.call(result, value)) {
result[value].push(key);
} else {
result[value] = [key];
}
}, getIteratee);
/**
* Invokes the method at `path` of `object`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Object
* @param {Object} object The object to query.
* @param {Array|string} path The path of the method to invoke.
* @param {...*} [args] The arguments to invoke the method with.
* @returns {*} Returns the result of the invoked method.
* @example
*
* var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] };
*
* _.invoke(object, 'a[0].b.c.slice', 1, 3);
* // => [2, 3]
*/
var invoke = baseRest(baseInvoke);
/**
* Creates an array of the own enumerable property names of `object`.
*
* **Note:** Non-object values are coerced to objects. See the
* [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
* for more details.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Object
* @param {Object} object The object to query.
* @returns {Array} Returns the array of property names.
* @example
*
* function Foo() {
* this.a = 1;
* this.b = 2;
* }
*
* Foo.prototype.c = 3;
*
* _.keys(new Foo);
* // => ['a', 'b'] (iteration order is not guaranteed)
*
* _.keys('hi');
* // => ['0', '1']
*/
function keys(object) {
return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);
}
/**
* Creates an array of the own and inherited enumerable property names of `object`.
*
* **Note:** Non-object values are coerced to objects.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Object
* @param {Object} object The object to query.
* @returns {Array} Returns the array of property names.
* @example
*
* function Foo() {
* this.a = 1;
* this.b = 2;
* }
*
* Foo.prototype.c = 3;
*
* _.keysIn(new Foo);
* // => ['a', 'b', 'c'] (iteration order is not guaranteed)
*/
function keysIn(object) {
return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);
}
/**
* The opposite of `_.mapValues`; this method creates an object with the
* same values as `object` and keys generated by running each own enumerable
* string keyed property of `object` thru `iteratee`. The iteratee is invoked
* with three arguments: (value, key, object).
*
* @static
* @memberOf _
* @since 3.8.0
* @category Object
* @param {Object} object The object to iterate over.
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
* @returns {Object} Returns the new mapped object.
* @see _.mapValues
* @example
*
* _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) {
* return key + value;
* });
* // => { 'a1': 1, 'b2': 2 }
*/
function mapKeys(object, iteratee) {
var result = {};
iteratee = getIteratee(iteratee, 3);
baseForOwn(object, function(value, key, object) {
baseAssignValue(result, iteratee(value, key, object), value);
});
return result;
}
/**
* Creates an object with the same keys as `object` and values generated
* by running each own enumerable string keyed property of `object` thru
* `iteratee`. The iteratee is invoked with three arguments:
* (value, key, object).
*
* @static
* @memberOf _
* @since 2.4.0
* @category Object
* @param {Object} object The object to iterate over.
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
* @returns {Object} Returns the new mapped object.
* @see _.mapKeys
* @example
*
* var users = {
* 'fred': { 'user': 'fred', 'age': 40 },
* 'pebbles': { 'user': 'pebbles', 'age': 1 }
* };
*
* _.mapValues(users, function(o) { return o.age; });
* // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
*
* // The `_.property` iteratee shorthand.
* _.mapValues(users, 'age');
* // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
*/
function mapValues(object, iteratee) {
var result = {};
iteratee = getIteratee(iteratee, 3);
baseForOwn(object, function(value, key, object) {
baseAssignValue(result, key, iteratee(value, key, object));
});
return result;
}
/**
* This method is like `_.assign` except that it recursively merges own and
* inherited enumerable string keyed properties of source objects into the
* destination object. Source properties that resolve to `undefined` are
* skipped if a destination value exists. Array and plain object properties
* are merged recursively. Other objects and value types are overridden by
* assignment. Source objects are applied from left to right. Subsequent
* sources overwrite property assignments of previous sources.
*
* **Note:** This method mutates `object`.
*
* @static
* @memberOf _
* @since 0.5.0
* @category Object
* @param {Object} object The destination object.
* @param {...Object} [sources] The source objects.
* @returns {Object} Returns `object`.
* @example
*
* var object = {
* 'a': [{ 'b': 2 }, { 'd': 4 }]
* };
*
* var other = {
* 'a': [{ 'c': 3 }, { 'e': 5 }]
* };
*
* _.merge(object, other);
* // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
*/
var merge = createAssigner(function(object, source, srcIndex) {
baseMerge(object, source, srcIndex);
});
/**
* This method is like `_.merge` except that it accepts `customizer` which
* is invoked to produce the merged values of the destination and source
* properties. If `customizer` returns `undefined`, merging is handled by the
* method instead. The `customizer` is invoked with six arguments:
* (objValue, srcValue, key, object, source, stack).
*
* **Note:** This method mutates `object`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Object
* @param {Object} object The destination object.
* @param {...Object} sources The source objects.
* @param {Function} customizer The function to customize assigned values.
* @returns {Object} Returns `object`.
* @example
*
* function customizer(objValue, srcValue) {
* if (_.isArray(objValue)) {
* return objValue.concat(srcValue);
* }
* }
*
* var object = { 'a': [1], 'b': [2] };
* var other = { 'a': [3], 'b': [4] };
*
* _.mergeWith(object, other, customizer);
* // => { 'a': [1, 3], 'b': [2, 4] }
*/
var mergeWith = createAssigner(function(object, source, srcIndex, customizer) {
baseMerge(object, source, srcIndex, customizer);
});
/**
* The opposite of `_.pick`; this method creates an object composed of the
* own and inherited enumerable property paths of `object` that are not omitted.
*
* **Note:** This method is considerably slower than `_.pick`.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Object
* @param {Object} object The source object.
* @param {...(string|string[])} [paths] The property paths to omit.
* @returns {Object} Returns the new object.
* @example
*
* var object = { 'a': 1, 'b': '2', 'c': 3 };
*
* _.omit(object, ['a', 'c']);
* // => { 'b': '2' }
*/
var omit = flatRest(function(object, paths) {
var result = {};
if (object == null) {
return result;
}
var isDeep = false;
paths = arrayMap(paths, function(path) {
path = castPath(path, object);
isDeep || (isDeep = path.length > 1);
return path;
});
copyObject(object, getAllKeysIn(object), result);
if (isDeep) {
result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone);
}
var length = paths.length;
while (length--) {
baseUnset(result, paths[length]);
}
return result;
});
/**
* The opposite of `_.pickBy`; this method creates an object composed of
* the own and inherited enumerable string keyed properties of `object` that
* `predicate` doesn't return truthy for. The predicate is invoked with two
* arguments: (value, key).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Object
* @param {Object} object The source object.
* @param {Function} [predicate=_.identity] The function invoked per property.
* @returns {Object} Returns the new object.
* @example
*
* var object = { 'a': 1, 'b': '2', 'c': 3 };
*
* _.omitBy(object, _.isNumber);
* // => { 'b': '2' }
*/
function omitBy(object, predicate) {
return pickBy(object, negate(getIteratee(predicate)));
}
/**
* Creates an object composed of the picked `object` properties.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Object
* @param {Object} object The source object.
* @param {...(string|string[])} [paths] The property paths to pick.
* @returns {Object} Returns the new object.
* @example
*
* var object = { 'a': 1, 'b': '2', 'c': 3 };
*
* _.pick(object, ['a', 'c']);
* // => { 'a': 1, 'c': 3 }
*/
var pick = flatRest(function(object, paths) {
return object == null ? {} : basePick(object, paths);
});
/**
* Creates an object composed of the `object` properties `predicate` returns
* truthy for. The predicate is invoked with two arguments: (value, key).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Object
* @param {Object} object The source object.
* @param {Function} [predicate=_.identity] The function invoked per property.
* @returns {Object} Returns the new object.
* @example
*
* var object = { 'a': 1, 'b': '2', 'c': 3 };
*
* _.pickBy(object, _.isNumber);
* // => { 'a': 1, 'c': 3 }
*/
function pickBy(object, predicate) {
if (object == null) {
return {};
}
var props = arrayMap(getAllKeysIn(object), function(prop) {
return [prop];
});
predicate = getIteratee(predicate);
return basePickBy(object, props, function(value, path) {
return predicate(value, path[0]);
});
}
/**
* This method is like `_.get` except that if the resolved value is a
* function it's invoked with the `this` binding of its parent object and
* its result is returned.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Object
* @param {Object} object The object to query.
* @param {Array|string} path The path of the property to resolve.
* @param {*} [defaultValue] The value returned for `undefined` resolved values.
* @returns {*} Returns the resolved value.
* @example
*
* var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] };
*
* _.result(object, 'a[0].b.c1');
* // => 3
*
* _.result(object, 'a[0].b.c2');
* // => 4
*
* _.result(object, 'a[0].b.c3', 'default');
* // => 'default'
*
* _.result(object, 'a[0].b.c3', _.constant('default'));
* // => 'default'
*/
function result(object, path, defaultValue) {
path = castPath(path, object);
var index = -1,
length = path.length;
// Ensure the loop is entered when path is empty.
if (!length) {
length = 1;
object = undefined;
}
while (++index < length) {
var value = object == null ? undefined : object[toKey(path[index])];
if (value === undefined) {
index = length;
value = defaultValue;
}
object = isFunction(value) ? value.call(object) : value;
}
return object;
}
/**
* Sets the value at `path` of `object`. If a portion of `path` doesn't exist,
* it's created. Arrays are created for missing index properties while objects
* are created for all other missing properties. Use `_.setWith` to customize
* `path` creation.
*
* **Note:** This method mutates `object`.
*
* @static
* @memberOf _
* @since 3.7.0
* @category Object
* @param {Object} object The object to modify.
* @param {Array|string} path The path of the property to set.
* @param {*} value The value to set.
* @returns {Object} Returns `object`.
* @example
*
* var object = { 'a': [{ 'b': { 'c': 3 } }] };
*
* _.set(object, 'a[0].b.c', 4);
* console.log(object.a[0].b.c);
* // => 4
*
* _.set(object, ['x', '0', 'y', 'z'], 5);
* console.log(object.x[0].y.z);
* // => 5
*/
function set(object, path, value) {
return object == null ? object : baseSet(object, path, value);
}
/**
* This method is like `_.set` except that it accepts `customizer` which is
* invoked to produce the objects of `path`. If `customizer` returns `undefined`
* path creation is handled by the method instead. The `customizer` is invoked
* with three arguments: (nsValue, key, nsObject).
*
* **Note:** This method mutates `object`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Object
* @param {Object} object The object to modify.
* @param {Array|string} path The path of the property to set.
* @param {*} value The value to set.
* @param {Function} [customizer] The function to customize assigned values.
* @returns {Object} Returns `object`.
* @example
*
* var object = {};
*
* _.setWith(object, '[0][1]', 'a', Object);
* // => { '0': { '1': 'a' } }
*/
function setWith(object, path, value, customizer) {
customizer = typeof customizer == 'function' ? customizer : undefined;
return object == null ? object : baseSet(object, path, value, customizer);
}
/**
* Creates an array of own enumerable string keyed-value pairs for `object`
* which can be consumed by `_.fromPairs`. If `object` is a map or set, its
* entries are returned.
*
* @static
* @memberOf _
* @since 4.0.0
* @alias entries
* @category Object
* @param {Object} object The object to query.
* @returns {Array} Returns the key-value pairs.
* @example
*
* function Foo() {
* this.a = 1;
* this.b = 2;
* }
*
* Foo.prototype.c = 3;
*
* _.toPairs(new Foo);
* // => [['a', 1], ['b', 2]] (iteration order is not guaranteed)
*/
var toPairs = createToPairs(keys);
/**
* Creates an array of own and inherited enumerable string keyed-value pairs
* for `object` which can be consumed by `_.fromPairs`. If `object` is a map
* or set, its entries are returned.
*
* @static
* @memberOf _
* @since 4.0.0
* @alias entriesIn
* @category Object
* @param {Object} object The object to query.
* @returns {Array} Returns the key-value pairs.
* @example
*
* function Foo() {
* this.a = 1;
* this.b = 2;
* }
*
* Foo.prototype.c = 3;
*
* _.toPairsIn(new Foo);
* // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed)
*/
var toPairsIn = createToPairs(keysIn);
/**
* An alternative to `_.reduce`; this method transforms `object` to a new
* `accumulator` object which is the result of running each of its own
* enumerable string keyed properties thru `iteratee`, with each invocation
* potentially mutating the `accumulator` object. If `accumulator` is not
* provided, a new object with the same `[[Prototype]]` will be used. The
* iteratee is invoked with four arguments: (accumulator, value, key, object).
* Iteratee functions may exit iteration early by explicitly returning `false`.
*
* @static
* @memberOf _
* @since 1.3.0
* @category Object
* @param {Object} object The object to iterate over.
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
* @param {*} [accumulator] The custom accumulator value.
* @returns {*} Returns the accumulated value.
* @example
*
* _.transform([2, 3, 4], function(result, n) {
* result.push(n *= n);
* return n % 2 == 0;
* }, []);
* // => [4, 9]
*
* _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
* (result[value] || (result[value] = [])).push(key);
* }, {});
* // => { '1': ['a', 'c'], '2': ['b'] }
*/
function transform(object, iteratee, accumulator) {
var isArr = isArray(object),
isArrLike = isArr || isBuffer(object) || isTypedArray(object);
iteratee = getIteratee(iteratee, 4);
if (accumulator == null) {
var Ctor = object && object.constructor;
if (isArrLike) {
accumulator = isArr ? new Ctor : [];
}
else if (isObject(object)) {
accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {};
}
else {
accumulator = {};
}
}
(isArrLike ? arrayEach : baseForOwn)(object, function(value, index, object) {
return iteratee(accumulator, value, index, object);
});
return accumulator;
}
/**
* Removes the property at `path` of `object`.
*
* **Note:** This method mutates `object`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Object
* @param {Object} object The object to modify.
* @param {Array|string} path The path of the property to unset.
* @returns {boolean} Returns `true` if the property is deleted, else `false`.
* @example
*
* var object = { 'a': [{ 'b': { 'c': 7 } }] };
* _.unset(object, 'a[0].b.c');
* // => true
*
* console.log(object);
* // => { 'a': [{ 'b': {} }] };
*
* _.unset(object, ['a', '0', 'b', 'c']);
* // => true
*
* console.log(object);
* // => { 'a': [{ 'b': {} }] };
*/
function unset(object, path) {
return object == null ? true : baseUnset(object, path);
}
/**
* This method is like `_.set` except that accepts `updater` to produce the
* value to set. Use `_.updateWith` to customize `path` creation. The `updater`
* is invoked with one argument: (value).
*
* **Note:** This method mutates `object`.
*
* @static
* @memberOf _
* @since 4.6.0
* @category Object
* @param {Object} object The object to modify.
* @param {Array|string} path The path of the property to set.
* @param {Function} updater The function to produce the updated value.
* @returns {Object} Returns `object`.
* @example
*
* var object = { 'a': [{ 'b': { 'c': 3 } }] };
*
* _.update(object, 'a[0].b.c', function(n) { return n * n; });
* console.log(object.a[0].b.c);
* // => 9
*
* _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; });
* console.log(object.x[0].y.z);
* // => 0
*/
function update(object, path, updater) {
return object == null ? object : baseUpdate(object, path, castFunction(updater));
}
/**
* This method is like `_.update` except that it accepts `customizer` which is
* invoked to produce the objects of `path`. If `customizer` returns `undefined`
* path creation is handled by the method instead. The `customizer` is invoked
* with three arguments: (nsValue, key, nsObject).
*
* **Note:** This method mutates `object`.
*
* @static
* @memberOf _
* @since 4.6.0
* @category Object
* @param {Object} object The object to modify.
* @param {Array|string} path The path of the property to set.
* @param {Function} updater The function to produce the updated value.
* @param {Function} [customizer] The function to customize assigned values.
* @returns {Object} Returns `object`.
* @example
*
* var object = {};
*
* _.updateWith(object, '[0][1]', _.constant('a'), Object);
* // => { '0': { '1': 'a' } }
*/
function updateWith(object, path, updater, customizer) {
customizer = typeof customizer == 'function' ? customizer : undefined;
return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer);
}
/**
* Creates an array of the own enumerable string keyed property values of `object`.
*
* **Note:** Non-object values are coerced to objects.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Object
* @param {Object} object The object to query.
* @returns {Array} Returns the array of property values.
* @example
*
* function Foo() {
* this.a = 1;
* this.b = 2;
* }
*
* Foo.prototype.c = 3;
*
* _.values(new Foo);
* // => [1, 2] (iteration order is not guaranteed)
*
* _.values('hi');
* // => ['h', 'i']
*/
function values(object) {
return object == null ? [] : baseValues(object, keys(object));
}
/**
* Creates an array of the own and inherited enumerable string keyed property
* values of `object`.
*
* **Note:** Non-object values are coerced to objects.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Object
* @param {Object} object The object to query.
* @returns {Array} Returns the array of property values.
* @example
*
* function Foo() {
* this.a = 1;
* this.b = 2;
* }
*
* Foo.prototype.c = 3;
*
* _.valuesIn(new Foo);
* // => [1, 2, 3] (iteration order is not guaranteed)
*/
function valuesIn(object) {
return object == null ? [] : baseValues(object, keysIn(object));
}
/*------------------------------------------------------------------------*/
/**
* Clamps `number` within the inclusive `lower` and `upper` bounds.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Number
* @param {number} number The number to clamp.
* @param {number} [lower] The lower bound.
* @param {number} upper The upper bound.
* @returns {number} Returns the clamped number.
* @example
*
* _.clamp(-10, -5, 5);
* // => -5
*
* _.clamp(10, -5, 5);
* // => 5
*/
function clamp(number, lower, upper) {
if (upper === undefined) {
upper = lower;
lower = undefined;
}
if (upper !== undefined) {
upper = toNumber(upper);
upper = upper === upper ? upper : 0;
}
if (lower !== undefined) {
lower = toNumber(lower);
lower = lower === lower ? lower : 0;
}
return baseClamp(toNumber(number), lower, upper);
}
/**
* Checks if `n` is between `start` and up to, but not including, `end`. If
* `end` is not specified, it's set to `start` with `start` then set to `0`.
* If `start` is greater than `end` the params are swapped to support
* negative ranges.
*
* @static
* @memberOf _
* @since 3.3.0
* @category Number
* @param {number} number The number to check.
* @param {number} [start=0] The start of the range.
* @param {number} end The end of the range.
* @returns {boolean} Returns `true` if `number` is in the range, else `false`.
* @see _.range, _.rangeRight
* @example
*
* _.inRange(3, 2, 4);
* // => true
*
* _.inRange(4, 8);
* // => true
*
* _.inRange(4, 2);
* // => false
*
* _.inRange(2, 2);
* // => false
*
* _.inRange(1.2, 2);
* // => true
*
* _.inRange(5.2, 4);
* // => false
*
* _.inRange(-3, -2, -6);
* // => true
*/
function inRange(number, start, end) {
start = toFinite(start);
if (end === undefined) {
end = start;
start = 0;
} else {
end = toFinite(end);
}
number = toNumber(number);
return baseInRange(number, start, end);
}
/**
* Produces a random number between the inclusive `lower` and `upper` bounds.
* If only one argument is provided a number between `0` and the given number
* is returned. If `floating` is `true`, or either `lower` or `upper` are
* floats, a floating-point number is returned instead of an integer.
*
* **Note:** JavaScript follows the IEEE-754 standard for resolving
* floating-point values which can produce unexpected results.
*
* @static
* @memberOf _
* @since 0.7.0
* @category Number
* @param {number} [lower=0] The lower bound.
* @param {number} [upper=1] The upper bound.
* @param {boolean} [floating] Specify returning a floating-point number.
* @returns {number} Returns the random number.
* @example
*
* _.random(0, 5);
* // => an integer between 0 and 5
*
* _.random(5);
* // => also an integer between 0 and 5
*
* _.random(5, true);
* // => a floating-point number between 0 and 5
*
* _.random(1.2, 5.2);
* // => a floating-point number between 1.2 and 5.2
*/
function random(lower, upper, floating) {
if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) {
upper = floating = undefined;
}
if (floating === undefined) {
if (typeof upper == 'boolean') {
floating = upper;
upper = undefined;
}
else if (typeof lower == 'boolean') {
floating = lower;
lower = undefined;
}
}
if (lower === undefined && upper === undefined) {
lower = 0;
upper = 1;
}
else {
lower = toFinite(lower);
if (upper === undefined) {
upper = lower;
lower = 0;
} else {
upper = toFinite(upper);
}
}
if (lower > upper) {
var temp = lower;
lower = upper;
upper = temp;
}
if (floating || lower % 1 || upper % 1) {
var rand = nativeRandom();
return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper);
}
return baseRandom(lower, upper);
}
/*------------------------------------------------------------------------*/
/**
* Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase).
*
* @static
* @memberOf _
* @since 3.0.0
* @category String
* @param {string} [string=''] The string to convert.
* @returns {string} Returns the camel cased string.
* @example
*
* _.camelCase('Foo Bar');
* // => 'fooBar'
*
* _.camelCase('--foo-bar--');
* // => 'fooBar'
*
* _.camelCase('__FOO_BAR__');
* // => 'fooBar'
*/
var camelCase = createCompounder(function(result, word, index) {
word = word.toLowerCase();
return result + (index ? capitalize(word) : word);
});
/**
* Converts the first character of `string` to upper case and the remaining
* to lower case.
*
* @static
* @memberOf _
* @since 3.0.0
* @category String
* @param {string} [string=''] The string to capitalize.
* @returns {string} Returns the capitalized string.
* @example
*
* _.capitalize('FRED');
* // => 'Fred'
*/
function capitalize(string) {
return upperFirst(toString(string).toLowerCase());
}
/**
* Deburrs `string` by converting
* [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
* and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A)
* letters to basic Latin letters and removing
* [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
*
* @static
* @memberOf _
* @since 3.0.0
* @category String
* @param {string} [string=''] The string to deburr.
* @returns {string} Returns the deburred string.
* @example
*
* _.deburr('déjà vu');
* // => 'deja vu'
*/
function deburr(string) {
string = toString(string);
return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');
}
/**
* Checks if `string` ends with the given target string.
*
* @static
* @memberOf _
* @since 3.0.0
* @category String
* @param {string} [string=''] The string to inspect.
* @param {string} [target] The string to search for.
* @param {number} [position=string.length] The position to search up to.
* @returns {boolean} Returns `true` if `string` ends with `target`,
* else `false`.
* @example
*
* _.endsWith('abc', 'c');
* // => true
*
* _.endsWith('abc', 'b');
* // => false
*
* _.endsWith('abc', 'b', 2);
* // => true
*/
function endsWith(string, target, position) {
string = toString(string);
target = baseToString(target);
var length = string.length;
position = position === undefined
? length
: baseClamp(toInteger(position), 0, length);
var end = position;
position -= target.length;
return position >= 0 && string.slice(position, end) == target;
}
/**
* Converts the characters "&", "<", ">", '"', and "'" in `string` to their
* corresponding HTML entities.
*
* **Note:** No other characters are escaped. To escape additional
* characters use a third-party library like [_he_](https://mths.be/he).
*
* Though the ">" character is escaped for symmetry, characters like
* ">" and "/" don't need escaping in HTML and have no special meaning
* unless they're part of a tag or unquoted attribute value. See
* [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands)
* (under "semi-related fun fact") for more details.
*
* When working with HTML you should always
* [quote attribute values](http://wonko.com/post/html-escaping) to reduce
* XSS vectors.
*
* @static
* @since 0.1.0
* @memberOf _
* @category String
* @param {string} [string=''] The string to escape.
* @returns {string} Returns the escaped string.
* @example
*
* _.escape('fred, barney, & pebbles');
* // => 'fred, barney, &amp; pebbles'
*/
function escape(string) {
string = toString(string);
return (string && reHasUnescapedHtml.test(string))
? string.replace(reUnescapedHtml, escapeHtmlChar)
: string;
}
/**
* Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+",
* "?", "(", ")", "[", "]", "{", "}", and "|" in `string`.
*
* @static
* @memberOf _
* @since 3.0.0
* @category String
* @param {string} [string=''] The string to escape.
* @returns {string} Returns the escaped string.
* @example
*
* _.escapeRegExp('[lodash](https://lodash.com/)');
* // => '\[lodash\]\(https://lodash\.com/\)'
*/
function escapeRegExp(string) {
string = toString(string);
return (string && reHasRegExpChar.test(string))
? string.replace(reRegExpChar, '\\$&')
: string;
}
/**
* Converts `string` to
* [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles).
*
* @static
* @memberOf _
* @since 3.0.0
* @category String
* @param {string} [string=''] The string to convert.
* @returns {string} Returns the kebab cased string.
* @example
*
* _.kebabCase('Foo Bar');
* // => 'foo-bar'
*
* _.kebabCase('fooBar');
* // => 'foo-bar'
*
* _.kebabCase('__FOO_BAR__');
* // => 'foo-bar'
*/
var kebabCase = createCompounder(function(result, word, index) {
return result + (index ? '-' : '') + word.toLowerCase();
});
/**
* Converts `string`, as space separated words, to lower case.
*
* @static
* @memberOf _
* @since 4.0.0
* @category String
* @param {string} [string=''] The string to convert.
* @returns {string} Returns the lower cased string.
* @example
*
* _.lowerCase('--Foo-Bar--');
* // => 'foo bar'
*
* _.lowerCase('fooBar');
* // => 'foo bar'
*
* _.lowerCase('__FOO_BAR__');
* // => 'foo bar'
*/
var lowerCase = createCompounder(function(result, word, index) {
return result + (index ? ' ' : '') + word.toLowerCase();
});
/**
* Converts the first character of `string` to lower case.
*
* @static
* @memberOf _
* @since 4.0.0
* @category String
* @param {string} [string=''] The string to convert.
* @returns {string} Returns the converted string.
* @example
*
* _.lowerFirst('Fred');
* // => 'fred'
*
* _.lowerFirst('FRED');
* // => 'fRED'
*/
var lowerFirst = createCaseFirst('toLowerCase');
/**
* Pads `string` on the left and right sides if it's shorter than `length`.
* Padding characters are truncated if they can't be evenly divided by `length`.
*
* @static
* @memberOf _
* @since 3.0.0
* @category String
* @param {string} [string=''] The string to pad.
* @param {number} [length=0] The padding length.
* @param {string} [chars=' '] The string used as padding.
* @returns {string} Returns the padded string.
* @example
*
* _.pad('abc', 8);
* // => ' abc '
*
* _.pad('abc', 8, '_-');
* // => '_-abc_-_'
*
* _.pad('abc', 3);
* // => 'abc'
*/
function pad(string, length, chars) {
string = toString(string);
length = toInteger(length);
var strLength = length ? stringSize(string) : 0;
if (!length || strLength >= length) {
return string;
}
var mid = (length - strLength) / 2;
return (
createPadding(nativeFloor(mid), chars) +
string +
createPadding(nativeCeil(mid), chars)
);
}
/**
* Pads `string` on the right side if it's shorter than `length`. Padding
* characters are truncated if they exceed `length`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category String
* @param {string} [string=''] The string to pad.
* @param {number} [length=0] The padding length.
* @param {string} [chars=' '] The string used as padding.
* @returns {string} Returns the padded string.
* @example
*
* _.padEnd('abc', 6);
* // => 'abc '
*
* _.padEnd('abc', 6, '_-');
* // => 'abc_-_'
*
* _.padEnd('abc', 3);
* // => 'abc'
*/
function padEnd(string, length, chars) {
string = toString(string);
length = toInteger(length);
var strLength = length ? stringSize(string) : 0;
return (length && strLength < length)
? (string + createPadding(length - strLength, chars))
: string;
}
/**
* Pads `string` on the left side if it's shorter than `length`. Padding
* characters are truncated if they exceed `length`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category String
* @param {string} [string=''] The string to pad.
* @param {number} [length=0] The padding length.
* @param {string} [chars=' '] The string used as padding.
* @returns {string} Returns the padded string.
* @example
*
* _.padStart('abc', 6);
* // => ' abc'
*
* _.padStart('abc', 6, '_-');
* // => '_-_abc'
*
* _.padStart('abc', 3);
* // => 'abc'
*/
function padStart(string, length, chars) {
string = toString(string);
length = toInteger(length);
var strLength = length ? stringSize(string) : 0;
return (length && strLength < length)
? (createPadding(length - strLength, chars) + string)
: string;
}
/**
* Converts `string` to an integer of the specified radix. If `radix` is
* `undefined` or `0`, a `radix` of `10` is used unless `value` is a
* hexadecimal, in which case a `radix` of `16` is used.
*
* **Note:** This method aligns with the
* [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`.
*
* @static
* @memberOf _
* @since 1.1.0
* @category String
* @param {string} string The string to convert.
* @param {number} [radix=10] The radix to interpret `value` by.
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
* @returns {number} Returns the converted integer.
* @example
*
* _.parseInt('08');
* // => 8
*
* _.map(['6', '08', '10'], _.parseInt);
* // => [6, 8, 10]
*/
function parseInt(string, radix, guard) {
if (guard || radix == null) {
radix = 0;
} else if (radix) {
radix = +radix;
}
return nativeParseInt(toString(string).replace(reTrimStart, ''), radix || 0);
}
/**
* Repeats the given string `n` times.
*
* @static
* @memberOf _
* @since 3.0.0
* @category String
* @param {string} [string=''] The string to repeat.
* @param {number} [n=1] The number of times to repeat the string.
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
* @returns {string} Returns the repeated string.
* @example
*
* _.repeat('*', 3);
* // => '***'
*
* _.repeat('abc', 2);
* // => 'abcabc'
*
* _.repeat('abc', 0);
* // => ''
*/
function repeat(string, n, guard) {
if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) {
n = 1;
} else {
n = toInteger(n);
}
return baseRepeat(toString(string), n);
}
/**
* Replaces matches for `pattern` in `string` with `replacement`.
*
* **Note:** This method is based on
* [`String#replace`](https://mdn.io/String/replace).
*
* @static
* @memberOf _
* @since 4.0.0
* @category String
* @param {string} [string=''] The string to modify.
* @param {RegExp|string} pattern The pattern to replace.
* @param {Function|string} replacement The match replacement.
* @returns {string} Returns the modified string.
* @example
*
* _.replace('Hi Fred', 'Fred', 'Barney');
* // => 'Hi Barney'
*/
function replace() {
var args = arguments,
string = toString(args[0]);
return args.length < 3 ? string : string.replace(args[1], args[2]);
}
/**
* Converts `string` to
* [snake case](https://en.wikipedia.org/wiki/Snake_case).
*
* @static
* @memberOf _
* @since 3.0.0
* @category String
* @param {string} [string=''] The string to convert.
* @returns {string} Returns the snake cased string.
* @example
*
* _.snakeCase('Foo Bar');
* // => 'foo_bar'
*
* _.snakeCase('fooBar');
* // => 'foo_bar'
*
* _.snakeCase('--FOO-BAR--');
* // => 'foo_bar'
*/
var snakeCase = createCompounder(function(result, word, index) {
return result + (index ? '_' : '') + word.toLowerCase();
});
/**
* Splits `string` by `separator`.
*
* **Note:** This method is based on
* [`String#split`](https://mdn.io/String/split).
*
* @static
* @memberOf _
* @since 4.0.0
* @category String
* @param {string} [string=''] The string to split.
* @param {RegExp|string} separator The separator pattern to split by.
* @param {number} [limit] The length to truncate results to.
* @returns {Array} Returns the string segments.
* @example
*
* _.split('a-b-c', '-', 2);
* // => ['a', 'b']
*/
function split(string, separator, limit) {
if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) {
separator = limit = undefined;
}
limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0;
if (!limit) {
return [];
}
string = toString(string);
if (string && (
typeof separator == 'string' ||
(separator != null && !isRegExp(separator))
)) {
separator = baseToString(separator);
if (!separator && hasUnicode(string)) {
return castSlice(stringToArray(string), 0, limit);
}
}
return string.split(separator, limit);
}
/**
* Converts `string` to
* [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage).
*
* @static
* @memberOf _
* @since 3.1.0
* @category String
* @param {string} [string=''] The string to convert.
* @returns {string} Returns the start cased string.
* @example
*
* _.startCase('--foo-bar--');
* // => 'Foo Bar'
*
* _.startCase('fooBar');
* // => 'Foo Bar'
*
* _.startCase('__FOO_BAR__');
* // => 'FOO BAR'
*/
var startCase = createCompounder(function(result, word, index) {
return result + (index ? ' ' : '') + upperFirst(word);
});
/**
* Checks if `string` starts with the given target string.
*
* @static
* @memberOf _
* @since 3.0.0
* @category String
* @param {string} [string=''] The string to inspect.
* @param {string} [target] The string to search for.
* @param {number} [position=0] The position to search from.
* @returns {boolean} Returns `true` if `string` starts with `target`,
* else `false`.
* @example
*
* _.startsWith('abc', 'a');
* // => true
*
* _.startsWith('abc', 'b');
* // => false
*
* _.startsWith('abc', 'b', 1);
* // => true
*/
function startsWith(string, target, position) {
string = toString(string);
position = position == null
? 0
: baseClamp(toInteger(position), 0, string.length);
target = baseToString(target);
return string.slice(position, position + target.length) == target;
}
/**
* Creates a compiled template function that can interpolate data properties
* in "interpolate" delimiters, HTML-escape interpolated data properties in
* "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data
* properties may be accessed as free variables in the template. If a setting
* object is given, it takes precedence over `_.templateSettings` values.
*
* **Note:** In the development build `_.template` utilizes
* [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl)
* for easier debugging.
*
* For more information on precompiling templates see
* [lodash's custom builds documentation](https://lodash.com/custom-builds).
*
* For more information on Chrome extension sandboxes see
* [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval).
*
* @static
* @since 0.1.0
* @memberOf _
* @category String
* @param {string} [string=''] The template string.
* @param {Object} [options={}] The options object.
* @param {RegExp} [options.escape=_.templateSettings.escape]
* The HTML "escape" delimiter.
* @param {RegExp} [options.evaluate=_.templateSettings.evaluate]
* The "evaluate" delimiter.
* @param {Object} [options.imports=_.templateSettings.imports]
* An object to import into the template as free variables.
* @param {RegExp} [options.interpolate=_.templateSettings.interpolate]
* The "interpolate" delimiter.
* @param {string} [options.sourceURL='lodash.templateSources[n]']
* The sourceURL of the compiled template.
* @param {string} [options.variable='obj']
* The data object variable name.
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
* @returns {Function} Returns the compiled template function.
* @example
*
* // Use the "interpolate" delimiter to create a compiled template.
* var compiled = _.template('hello <%= user %>!');
* compiled({ 'user': 'fred' });
* // => 'hello fred!'
*
* // Use the HTML "escape" delimiter to escape data property values.
* var compiled = _.template('<b><%- value %></b>');
* compiled({ 'value': '<script>' });
* // => '<b>&lt;script&gt;</b>'
*
* // Use the "evaluate" delimiter to execute JavaScript and generate HTML.
* var compiled = _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>');
* compiled({ 'users': ['fred', 'barney'] });
* // => '<li>fred</li><li>barney</li>'
*
* // Use the internal `print` function in "evaluate" delimiters.
* var compiled = _.template('<% print("hello " + user); %>!');
* compiled({ 'user': 'barney' });
* // => 'hello barney!'
*
* // Use the ES template literal delimiter as an "interpolate" delimiter.
* // Disable support by replacing the "interpolate" delimiter.
* var compiled = _.template('hello ${ user }!');
* compiled({ 'user': 'pebbles' });
* // => 'hello pebbles!'
*
* // Use backslashes to treat delimiters as plain text.
* var compiled = _.template('<%= "\\<%- value %\\>" %>');
* compiled({ 'value': 'ignored' });
* // => '<%- value %>'
*
* // Use the `imports` option to import `jQuery` as `jq`.
* var text = '<% jq.each(users, function(user) { %><li><%- user %></li><% }); %>';
* var compiled = _.template(text, { 'imports': { 'jq': jQuery } });
* compiled({ 'users': ['fred', 'barney'] });
* // => '<li>fred</li><li>barney</li>'
*
* // Use the `sourceURL` option to specify a custom sourceURL for the template.
* var compiled = _.template('hello <%= user %>!', { 'sourceURL': '/basic/greeting.jst' });
* compiled(data);
* // => Find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector.
*
* // Use the `variable` option to ensure a with-statement isn't used in the compiled template.
* var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' });
* compiled.source;
* // => function(data) {
* // var __t, __p = '';
* // __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!';
* // return __p;
* // }
*
* // Use custom template delimiters.
* _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
* var compiled = _.template('hello {{ user }}!');
* compiled({ 'user': 'mustache' });
* // => 'hello mustache!'
*
* // Use the `source` property to inline compiled templates for meaningful
* // line numbers in error messages and stack traces.
* fs.writeFileSync(path.join(process.cwd(), 'jst.js'), '\
* var JST = {\
* "main": ' + _.template(mainText).source + '\
* };\
* ');
*/
function template(string, options, guard) {
// Based on John Resig's `tmpl` implementation
// (http://ejohn.org/blog/javascript-micro-templating/)
// and Laura Doktorova's doT.js (https://github.com/olado/doT).
var settings = lodash.templateSettings;
if (guard && isIterateeCall(string, options, guard)) {
options = undefined;
}
string = toString(string);
options = assignInWith({}, options, settings, customDefaultsAssignIn);
var imports = assignInWith({}, options.imports, settings.imports, customDefaultsAssignIn),
importsKeys = keys(imports),
importsValues = baseValues(imports, importsKeys);
var isEscaping,
isEvaluating,
index = 0,
interpolate = options.interpolate || reNoMatch,
source = "__p += '";
// Compile the regexp to match each delimiter.
var reDelimiters = RegExp(
(options.escape || reNoMatch).source + '|' +
interpolate.source + '|' +
(interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
(options.evaluate || reNoMatch).source + '|$'
, 'g');
// Use a sourceURL for easier debugging.
var sourceURL = '//# sourceURL=' +
('sourceURL' in options
? options.sourceURL
: ('lodash.templateSources[' + (++templateCounter) + ']')
) + '\n';
string.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
interpolateValue || (interpolateValue = esTemplateValue);
// Escape characters that can't be included in string literals.
source += string.slice(index, offset).replace(reUnescapedString, escapeStringChar);
// Replace delimiters with snippets.
if (escapeValue) {
isEscaping = true;
source += "' +\n__e(" + escapeValue + ") +\n'";
}
if (evaluateValue) {
isEvaluating = true;
source += "';\n" + evaluateValue + ";\n__p += '";
}
if (interpolateValue) {
source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
}
index = offset + match.length;
// The JS engine embedded in Adobe products needs `match` returned in
// order to produce the correct `offset` value.
return match;
});
source += "';\n";
// If `variable` is not specified wrap a with-statement around the generated
// code to add the data object to the top of the scope chain.
var variable = options.variable;
if (!variable) {
source = 'with (obj) {\n' + source + '\n}\n';
}
// Cleanup code by stripping empty strings.
source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
.replace(reEmptyStringMiddle, '$1')
.replace(reEmptyStringTrailing, '$1;');
// Frame code as the function body.
source = 'function(' + (variable || 'obj') + ') {\n' +
(variable
? ''
: 'obj || (obj = {});\n'
) +
"var __t, __p = ''" +
(isEscaping
? ', __e = _.escape'
: ''
) +
(isEvaluating
? ', __j = Array.prototype.join;\n' +
"function print() { __p += __j.call(arguments, '') }\n"
: ';\n'
) +
source +
'return __p\n}';
var result = attempt(function() {
return Function(importsKeys, sourceURL + 'return ' + source)
.apply(undefined, importsValues);
});
// Provide the compiled function's source by its `toString` method or
// the `source` property as a convenience for inlining compiled templates.
result.source = source;
if (isError(result)) {
throw result;
}
return result;
}
/**
* Converts `string`, as a whole, to lower case just like
* [String#toLowerCase](https://mdn.io/toLowerCase).
*
* @static
* @memberOf _
* @since 4.0.0
* @category String
* @param {string} [string=''] The string to convert.
* @returns {string} Returns the lower cased string.
* @example
*
* _.toLower('--Foo-Bar--');
* // => '--foo-bar--'
*
* _.toLower('fooBar');
* // => 'foobar'
*
* _.toLower('__FOO_BAR__');
* // => '__foo_bar__'
*/
function toLower(value) {
return toString(value).toLowerCase();
}
/**
* Converts `string`, as a whole, to upper case just like
* [String#toUpperCase](https://mdn.io/toUpperCase).
*
* @static
* @memberOf _
* @since 4.0.0
* @category String
* @param {string} [string=''] The string to convert.
* @returns {string} Returns the upper cased string.
* @example
*
* _.toUpper('--foo-bar--');
* // => '--FOO-BAR--'
*
* _.toUpper('fooBar');
* // => 'FOOBAR'
*
* _.toUpper('__foo_bar__');
* // => '__FOO_BAR__'
*/
function toUpper(value) {
return toString(value).toUpperCase();
}
/**
* Removes leading and trailing whitespace or specified characters from `string`.
*
* @static
* @memberOf _
* @since 3.0.0
* @category String
* @param {string} [string=''] The string to trim.
* @param {string} [chars=whitespace] The characters to trim.
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
* @returns {string} Returns the trimmed string.
* @example
*
* _.trim(' abc ');
* // => 'abc'
*
* _.trim('-_-abc-_-', '_-');
* // => 'abc'
*
* _.map([' foo ', ' bar '], _.trim);
* // => ['foo', 'bar']
*/
function trim(string, chars, guard) {
string = toString(string);
if (string && (guard || chars === undefined)) {
return string.replace(reTrim, '');
}
if (!string || !(chars = baseToString(chars))) {
return string;
}
var strSymbols = stringToArray(string),
chrSymbols = stringToArray(chars),
start = charsStartIndex(strSymbols, chrSymbols),
end = charsEndIndex(strSymbols, chrSymbols) + 1;
return castSlice(strSymbols, start, end).join('');
}
/**
* Removes trailing whitespace or specified characters from `string`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category String
* @param {string} [string=''] The string to trim.
* @param {string} [chars=whitespace] The characters to trim.
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
* @returns {string} Returns the trimmed string.
* @example
*
* _.trimEnd(' abc ');
* // => ' abc'
*
* _.trimEnd('-_-abc-_-', '_-');
* // => '-_-abc'
*/
function trimEnd(string, chars, guard) {
string = toString(string);
if (string && (guard || chars === undefined)) {
return string.replace(reTrimEnd, '');
}
if (!string || !(chars = baseToString(chars))) {
return string;
}
var strSymbols = stringToArray(string),
end = charsEndIndex(strSymbols, stringToArray(chars)) + 1;
return castSlice(strSymbols, 0, end).join('');
}
/**
* Removes leading whitespace or specified characters from `string`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category String
* @param {string} [string=''] The string to trim.
* @param {string} [chars=whitespace] The characters to trim.
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
* @returns {string} Returns the trimmed string.
* @example
*
* _.trimStart(' abc ');
* // => 'abc '
*
* _.trimStart('-_-abc-_-', '_-');
* // => 'abc-_-'
*/
function trimStart(string, chars, guard) {
string = toString(string);
if (string && (guard || chars === undefined)) {
return string.replace(reTrimStart, '');
}
if (!string || !(chars = baseToString(chars))) {
return string;
}
var strSymbols = stringToArray(string),
start = charsStartIndex(strSymbols, stringToArray(chars));
return castSlice(strSymbols, start).join('');
}
/**
* Truncates `string` if it's longer than the given maximum string length.
* The last characters of the truncated string are replaced with the omission
* string which defaults to "...".
*
* @static
* @memberOf _
* @since 4.0.0
* @category String
* @param {string} [string=''] The string to truncate.
* @param {Object} [options={}] The options object.
* @param {number} [options.length=30] The maximum string length.
* @param {string} [options.omission='...'] The string to indicate text is omitted.
* @param {RegExp|string} [options.separator] The separator pattern to truncate to.
* @returns {string} Returns the truncated string.
* @example
*
* _.truncate('hi-diddly-ho there, neighborino');
* // => 'hi-diddly-ho there, neighbo...'
*
* _.truncate('hi-diddly-ho there, neighborino', {
* 'length': 24,
* 'separator': ' '
* });
* // => 'hi-diddly-ho there,...'
*
* _.truncate('hi-diddly-ho there, neighborino', {
* 'length': 24,
* 'separator': /,? +/
* });
* // => 'hi-diddly-ho there...'
*
* _.truncate('hi-diddly-ho there, neighborino', {
* 'omission': ' [...]'
* });
* // => 'hi-diddly-ho there, neig [...]'
*/
function truncate(string, options) {
var length = DEFAULT_TRUNC_LENGTH,
omission = DEFAULT_TRUNC_OMISSION;
if (isObject(options)) {
var separator = 'separator' in options ? options.separator : separator;
length = 'length' in options ? toInteger(options.length) : length;
omission = 'omission' in options ? baseToString(options.omission) : omission;
}
string = toString(string);
var strLength = string.length;
if (hasUnicode(string)) {
var strSymbols = stringToArray(string);
strLength = strSymbols.length;
}
if (length >= strLength) {
return string;
}
var end = length - stringSize(omission);
if (end < 1) {
return omission;
}
var result = strSymbols
? castSlice(strSymbols, 0, end).join('')
: string.slice(0, end);
if (separator === undefined) {
return result + omission;
}
if (strSymbols) {
end += (result.length - end);
}
if (isRegExp(separator)) {
if (string.slice(end).search(separator)) {
var match,
substring = result;
if (!separator.global) {
separator = RegExp(separator.source, toString(reFlags.exec(separator)) + 'g');
}
separator.lastIndex = 0;
while ((match = separator.exec(substring))) {
var newEnd = match.index;
}
result = result.slice(0, newEnd === undefined ? end : newEnd);
}
} else if (string.indexOf(baseToString(separator), end) != end) {
var index = result.lastIndexOf(separator);
if (index > -1) {
result = result.slice(0, index);
}
}
return result + omission;
}
/**
* The inverse of `_.escape`; this method converts the HTML entities
* `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#39;` in `string` to
* their corresponding characters.
*
* **Note:** No other HTML entities are unescaped. To unescape additional
* HTML entities use a third-party library like [_he_](https://mths.be/he).
*
* @static
* @memberOf _
* @since 0.6.0
* @category String
* @param {string} [string=''] The string to unescape.
* @returns {string} Returns the unescaped string.
* @example
*
* _.unescape('fred, barney, &amp; pebbles');
* // => 'fred, barney, & pebbles'
*/
function unescape(string) {
string = toString(string);
return (string && reHasEscapedHtml.test(string))
? string.replace(reEscapedHtml, unescapeHtmlChar)
: string;
}
/**
* Converts `string`, as space separated words, to upper case.
*
* @static
* @memberOf _
* @since 4.0.0
* @category String
* @param {string} [string=''] The string to convert.
* @returns {string} Returns the upper cased string.
* @example
*
* _.upperCase('--foo-bar');
* // => 'FOO BAR'
*
* _.upperCase('fooBar');
* // => 'FOO BAR'
*
* _.upperCase('__foo_bar__');
* // => 'FOO BAR'
*/
var upperCase = createCompounder(function(result, word, index) {
return result + (index ? ' ' : '') + word.toUpperCase();
});
/**
* Converts the first character of `string` to upper case.
*
* @static
* @memberOf _
* @since 4.0.0
* @category String
* @param {string} [string=''] The string to convert.
* @returns {string} Returns the converted string.
* @example
*
* _.upperFirst('fred');
* // => 'Fred'
*
* _.upperFirst('FRED');
* // => 'FRED'
*/
var upperFirst = createCaseFirst('toUpperCase');
/**
* Splits `string` into an array of its words.
*
* @static
* @memberOf _
* @since 3.0.0
* @category String
* @param {string} [string=''] The string to inspect.
* @param {RegExp|string} [pattern] The pattern to match words.
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
* @returns {Array} Returns the words of `string`.
* @example
*
* _.words('fred, barney, & pebbles');
* // => ['fred', 'barney', 'pebbles']
*
* _.words('fred, barney, & pebbles', /[^, ]+/g);
* // => ['fred', 'barney', '&', 'pebbles']
*/
function words(string, pattern, guard) {
string = toString(string);
pattern = guard ? undefined : pattern;
if (pattern === undefined) {
return hasUnicodeWord(string) ? unicodeWords(string) : asciiWords(string);
}
return string.match(pattern) || [];
}
/*------------------------------------------------------------------------*/
/**
* Attempts to invoke `func`, returning either the result or the caught error
* object. Any additional arguments are provided to `func` when it's invoked.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Util
* @param {Function} func The function to attempt.
* @param {...*} [args] The arguments to invoke `func` with.
* @returns {*} Returns the `func` result or error object.
* @example
*
* // Avoid throwing errors for invalid selectors.
* var elements = _.attempt(function(selector) {
* return document.querySelectorAll(selector);
* }, '>_>');
*
* if (_.isError(elements)) {
* elements = [];
* }
*/
var attempt = baseRest(function(func, args) {
try {
return apply(func, undefined, args);
} catch (e) {
return isError(e) ? e : new Error(e);
}
});
/**
* Binds methods of an object to the object itself, overwriting the existing
* method.
*
* **Note:** This method doesn't set the "length" property of bound functions.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Util
* @param {Object} object The object to bind and assign the bound methods to.
* @param {...(string|string[])} methodNames The object method names to bind.
* @returns {Object} Returns `object`.
* @example
*
* var view = {
* 'label': 'docs',
* 'click': function() {
* console.log('clicked ' + this.label);
* }
* };
*
* _.bindAll(view, ['click']);
* jQuery(element).on('click', view.click);
* // => Logs 'clicked docs' when clicked.
*/
var bindAll = flatRest(function(object, methodNames) {
arrayEach(methodNames, function(key) {
key = toKey(key);
baseAssignValue(object, key, bind(object[key], object));
});
return object;
});
/**
* Creates a function that iterates over `pairs` and invokes the corresponding
* function of the first predicate to return truthy. The predicate-function
* pairs are invoked with the `this` binding and arguments of the created
* function.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Util
* @param {Array} pairs The predicate-function pairs.
* @returns {Function} Returns the new composite function.
* @example
*
* var func = _.cond([
* [_.matches({ 'a': 1 }), _.constant('matches A')],
* [_.conforms({ 'b': _.isNumber }), _.constant('matches B')],
* [_.stubTrue, _.constant('no match')]
* ]);
*
* func({ 'a': 1, 'b': 2 });
* // => 'matches A'
*
* func({ 'a': 0, 'b': 1 });
* // => 'matches B'
*
* func({ 'a': '1', 'b': '2' });
* // => 'no match'
*/
function cond(pairs) {
var length = pairs == null ? 0 : pairs.length,
toIteratee = getIteratee();
pairs = !length ? [] : arrayMap(pairs, function(pair) {
if (typeof pair[1] != 'function') {
throw new TypeError(FUNC_ERROR_TEXT);
}
return [toIteratee(pair[0]), pair[1]];
});
return baseRest(function(args) {
var index = -1;
while (++index < length) {
var pair = pairs[index];
if (apply(pair[0], this, args)) {
return apply(pair[1], this, args);
}
}
});
}
/**
* Creates a function that invokes the predicate properties of `source` with
* the corresponding property values of a given object, returning `true` if
* all predicates return truthy, else `false`.
*
* **Note:** The created function is equivalent to `_.conformsTo` with
* `source` partially applied.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Util
* @param {Object} source The object of property predicates to conform to.
* @returns {Function} Returns the new spec function.
* @example
*
* var objects = [
* { 'a': 2, 'b': 1 },
* { 'a': 1, 'b': 2 }
* ];
*
* _.filter(objects, _.conforms({ 'b': function(n) { return n > 1; } }));
* // => [{ 'a': 1, 'b': 2 }]
*/
function conforms(source) {
return baseConforms(baseClone(source, CLONE_DEEP_FLAG));
}
/**
* Creates a function that returns `value`.
*
* @static
* @memberOf _
* @since 2.4.0
* @category Util
* @param {*} value The value to return from the new function.
* @returns {Function} Returns the new constant function.
* @example
*
* var objects = _.times(2, _.constant({ 'a': 1 }));
*
* console.log(objects);
* // => [{ 'a': 1 }, { 'a': 1 }]
*
* console.log(objects[0] === objects[1]);
* // => true
*/
function constant(value) {
return function() {
return value;
};
}
/**
* Checks `value` to determine whether a default value should be returned in
* its place. The `defaultValue` is returned if `value` is `NaN`, `null`,
* or `undefined`.
*
* @static
* @memberOf _
* @since 4.14.0
* @category Util
* @param {*} value The value to check.
* @param {*} defaultValue The default value.
* @returns {*} Returns the resolved value.
* @example
*
* _.defaultTo(1, 10);
* // => 1
*
* _.defaultTo(undefined, 10);
* // => 10
*/
function defaultTo(value, defaultValue) {
return (value == null || value !== value) ? defaultValue : value;
}
/**
* Creates a function that returns the result of invoking the given functions
* with the `this` binding of the created function, where each successive
* invocation is supplied the return value of the previous.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Util
* @param {...(Function|Function[])} [funcs] The functions to invoke.
* @returns {Function} Returns the new composite function.
* @see _.flowRight
* @example
*
* function square(n) {
* return n * n;
* }
*
* var addSquare = _.flow([_.add, square]);
* addSquare(1, 2);
* // => 9
*/
var flow = createFlow();
/**
* This method is like `_.flow` except that it creates a function that
* invokes the given functions from right to left.
*
* @static
* @since 3.0.0
* @memberOf _
* @category Util
* @param {...(Function|Function[])} [funcs] The functions to invoke.
* @returns {Function} Returns the new composite function.
* @see _.flow
* @example
*
* function square(n) {
* return n * n;
* }
*
* var addSquare = _.flowRight([square, _.add]);
* addSquare(1, 2);
* // => 9
*/
var flowRight = createFlow(true);
/**
* This method returns the first argument it receives.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Util
* @param {*} value Any value.
* @returns {*} Returns `value`.
* @example
*
* var object = { 'a': 1 };
*
* console.log(_.identity(object) === object);
* // => true
*/
function identity(value) {
return value;
}
/**
* Creates a function that invokes `func` with the arguments of the created
* function. If `func` is a property name, the created function returns the
* property value for a given element. If `func` is an array or object, the
* created function returns `true` for elements that contain the equivalent
* source properties, otherwise it returns `false`.
*
* @static
* @since 4.0.0
* @memberOf _
* @category Util
* @param {*} [func=_.identity] The value to convert to a callback.
* @returns {Function} Returns the callback.
* @example
*
* var users = [
* { 'user': 'barney', 'age': 36, 'active': true },
* { 'user': 'fred', 'age': 40, 'active': false }
* ];
*
* // The `_.matches` iteratee shorthand.
* _.filter(users, _.iteratee({ 'user': 'barney', 'active': true }));
* // => [{ 'user': 'barney', 'age': 36, 'active': true }]
*
* // The `_.matchesProperty` iteratee shorthand.
* _.filter(users, _.iteratee(['user', 'fred']));
* // => [{ 'user': 'fred', 'age': 40 }]
*
* // The `_.property` iteratee shorthand.
* _.map(users, _.iteratee('user'));
* // => ['barney', 'fred']
*
* // Create custom iteratee shorthands.
* _.iteratee = _.wrap(_.iteratee, function(iteratee, func) {
* return !_.isRegExp(func) ? iteratee(func) : function(string) {
* return func.test(string);
* };
* });
*
* _.filter(['abc', 'def'], /ef/);
* // => ['def']
*/
function iteratee(func) {
return baseIteratee(typeof func == 'function' ? func : baseClone(func, CLONE_DEEP_FLAG));
}
/**
* Creates a function that performs a partial deep comparison between a given
* object and `source`, returning `true` if the given object has equivalent
* property values, else `false`.
*
* **Note:** The created function is equivalent to `_.isMatch` with `source`
* partially applied.
*
* Partial comparisons will match empty array and empty object `source`
* values against any array or object value, respectively. See `_.isEqual`
* for a list of supported value comparisons.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Util
* @param {Object} source The object of property values to match.
* @returns {Function} Returns the new spec function.
* @example
*
* var objects = [
* { 'a': 1, 'b': 2, 'c': 3 },
* { 'a': 4, 'b': 5, 'c': 6 }
* ];
*
* _.filter(objects, _.matches({ 'a': 4, 'c': 6 }));
* // => [{ 'a': 4, 'b': 5, 'c': 6 }]
*/
function matches(source) {
return baseMatches(baseClone(source, CLONE_DEEP_FLAG));
}
/**
* Creates a function that performs a partial deep comparison between the
* value at `path` of a given object to `srcValue`, returning `true` if the
* object value is equivalent, else `false`.
*
* **Note:** Partial comparisons will match empty array and empty object
* `srcValue` values against any array or object value, respectively. See
* `_.isEqual` for a list of supported value comparisons.
*
* @static
* @memberOf _
* @since 3.2.0
* @category Util
* @param {Array|string} path The path of the property to get.
* @param {*} srcValue The value to match.
* @returns {Function} Returns the new spec function.
* @example
*
* var objects = [
* { 'a': 1, 'b': 2, 'c': 3 },
* { 'a': 4, 'b': 5, 'c': 6 }
* ];
*
* _.find(objects, _.matchesProperty('a', 4));
* // => { 'a': 4, 'b': 5, 'c': 6 }
*/
function matchesProperty(path, srcValue) {
return baseMatchesProperty(path, baseClone(srcValue, CLONE_DEEP_FLAG));
}
/**
* Creates a function that invokes the method at `path` of a given object.
* Any additional arguments are provided to the invoked method.
*
* @static
* @memberOf _
* @since 3.7.0
* @category Util
* @param {Array|string} path The path of the method to invoke.
* @param {...*} [args] The arguments to invoke the method with.
* @returns {Function} Returns the new invoker function.
* @example
*
* var objects = [
* { 'a': { 'b': _.constant(2) } },
* { 'a': { 'b': _.constant(1) } }
* ];
*
* _.map(objects, _.method('a.b'));
* // => [2, 1]
*
* _.map(objects, _.method(['a', 'b']));
* // => [2, 1]
*/
var method = baseRest(function(path, args) {
return function(object) {
return baseInvoke(object, path, args);
};
});
/**
* The opposite of `_.method`; this method creates a function that invokes
* the method at a given path of `object`. Any additional arguments are
* provided to the invoked method.
*
* @static
* @memberOf _
* @since 3.7.0
* @category Util
* @param {Object} object The object to query.
* @param {...*} [args] The arguments to invoke the method with.
* @returns {Function} Returns the new invoker function.
* @example
*
* var array = _.times(3, _.constant),
* object = { 'a': array, 'b': array, 'c': array };
*
* _.map(['a[2]', 'c[0]'], _.methodOf(object));
* // => [2, 0]
*
* _.map([['a', '2'], ['c', '0']], _.methodOf(object));
* // => [2, 0]
*/
var methodOf = baseRest(function(object, args) {
return function(path) {
return baseInvoke(object, path, args);
};
});
/**
* Adds all own enumerable string keyed function properties of a source
* object to the destination object. If `object` is a function, then methods
* are added to its prototype as well.
*
* **Note:** Use `_.runInContext` to create a pristine `lodash` function to
* avoid conflicts caused by modifying the original.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Util
* @param {Function|Object} [object=lodash] The destination object.
* @param {Object} source The object of functions to add.
* @param {Object} [options={}] The options object.
* @param {boolean} [options.chain=true] Specify whether mixins are chainable.
* @returns {Function|Object} Returns `object`.
* @example
*
* function vowels(string) {
* return _.filter(string, function(v) {
* return /[aeiou]/i.test(v);
* });
* }
*
* _.mixin({ 'vowels': vowels });
* _.vowels('fred');
* // => ['e']
*
* _('fred').vowels().value();
* // => ['e']
*
* _.mixin({ 'vowels': vowels }, { 'chain': false });
* _('fred').vowels();
* // => ['e']
*/
function mixin(object, source, options) {
var props = keys(source),
methodNames = baseFunctions(source, props);
if (options == null &&
!(isObject(source) && (methodNames.length || !props.length))) {
options = source;
source = object;
object = this;
methodNames = baseFunctions(source, keys(source));
}
var chain = !(isObject(options) && 'chain' in options) || !!options.chain,
isFunc = isFunction(object);
arrayEach(methodNames, function(methodName) {
var func = source[methodName];
object[methodName] = func;
if (isFunc) {
object.prototype[methodName] = function() {
var chainAll = this.__chain__;
if (chain || chainAll) {
var result = object(this.__wrapped__),
actions = result.__actions__ = copyArray(this.__actions__);
actions.push({ 'func': func, 'args': arguments, 'thisArg': object });
result.__chain__ = chainAll;
return result;
}
return func.apply(object, arrayPush([this.value()], arguments));
};
}
});
return object;
}
/**
* Reverts the `_` variable to its previous value and returns a reference to
* the `lodash` function.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Util
* @returns {Function} Returns the `lodash` function.
* @example
*
* var lodash = _.noConflict();
*/
function noConflict() {
if (root._ === this) {
root._ = oldDash;
}
return this;
}
/**
* This method returns `undefined`.
*
* @static
* @memberOf _
* @since 2.3.0
* @category Util
* @example
*
* _.times(2, _.noop);
* // => [undefined, undefined]
*/
function noop() {
// No operation performed.
}
/**
* Creates a function that gets the argument at index `n`. If `n` is negative,
* the nth argument from the end is returned.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Util
* @param {number} [n=0] The index of the argument to return.
* @returns {Function} Returns the new pass-thru function.
* @example
*
* var func = _.nthArg(1);
* func('a', 'b', 'c', 'd');
* // => 'b'
*
* var func = _.nthArg(-2);
* func('a', 'b', 'c', 'd');
* // => 'c'
*/
function nthArg(n) {
n = toInteger(n);
return baseRest(function(args) {
return baseNth(args, n);
});
}
/**
* Creates a function that invokes `iteratees` with the arguments it receives
* and returns their results.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Util
* @param {...(Function|Function[])} [iteratees=[_.identity]]
* The iteratees to invoke.
* @returns {Function} Returns the new function.
* @example
*
* var func = _.over([Math.max, Math.min]);
*
* func(1, 2, 3, 4);
* // => [4, 1]
*/
var over = createOver(arrayMap);
/**
* Creates a function that checks if **all** of the `predicates` return
* truthy when invoked with the arguments it receives.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Util
* @param {...(Function|Function[])} [predicates=[_.identity]]
* The predicates to check.
* @returns {Function} Returns the new function.
* @example
*
* var func = _.overEvery([Boolean, isFinite]);
*
* func('1');
* // => true
*
* func(null);
* // => false
*
* func(NaN);
* // => false
*/
var overEvery = createOver(arrayEvery);
/**
* Creates a function that checks if **any** of the `predicates` return
* truthy when invoked with the arguments it receives.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Util
* @param {...(Function|Function[])} [predicates=[_.identity]]
* The predicates to check.
* @returns {Function} Returns the new function.
* @example
*
* var func = _.overSome([Boolean, isFinite]);
*
* func('1');
* // => true
*
* func(null);
* // => true
*
* func(NaN);
* // => false
*/
var overSome = createOver(arraySome);
/**
* Creates a function that returns the value at `path` of a given object.
*
* @static
* @memberOf _
* @since 2.4.0
* @category Util
* @param {Array|string} path The path of the property to get.
* @returns {Function} Returns the new accessor function.
* @example
*
* var objects = [
* { 'a': { 'b': 2 } },
* { 'a': { 'b': 1 } }
* ];
*
* _.map(objects, _.property('a.b'));
* // => [2, 1]
*
* _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b');
* // => [1, 2]
*/
function property(path) {
return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path);
}
/**
* The opposite of `_.property`; this method creates a function that returns
* the value at a given path of `object`.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Util
* @param {Object} object The object to query.
* @returns {Function} Returns the new accessor function.
* @example
*
* var array = [0, 1, 2],
* object = { 'a': array, 'b': array, 'c': array };
*
* _.map(['a[2]', 'c[0]'], _.propertyOf(object));
* // => [2, 0]
*
* _.map([['a', '2'], ['c', '0']], _.propertyOf(object));
* // => [2, 0]
*/
function propertyOf(object) {
return function(path) {
return object == null ? undefined : baseGet(object, path);
};
}
/**
* Creates an array of numbers (positive and/or negative) progressing from
* `start` up to, but not including, `end`. A step of `-1` is used if a negative
* `start` is specified without an `end` or `step`. If `end` is not specified,
* it's set to `start` with `start` then set to `0`.
*
* **Note:** JavaScript follows the IEEE-754 standard for resolving
* floating-point values which can produce unexpected results.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Util
* @param {number} [start=0] The start of the range.
* @param {number} end The end of the range.
* @param {number} [step=1] The value to increment or decrement by.
* @returns {Array} Returns the range of numbers.
* @see _.inRange, _.rangeRight
* @example
*
* _.range(4);
* // => [0, 1, 2, 3]
*
* _.range(-4);
* // => [0, -1, -2, -3]
*
* _.range(1, 5);
* // => [1, 2, 3, 4]
*
* _.range(0, 20, 5);
* // => [0, 5, 10, 15]
*
* _.range(0, -4, -1);
* // => [0, -1, -2, -3]
*
* _.range(1, 4, 0);
* // => [1, 1, 1]
*
* _.range(0);
* // => []
*/
var range = createRange();
/**
* This method is like `_.range` except that it populates values in
* descending order.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Util
* @param {number} [start=0] The start of the range.
* @param {number} end The end of the range.
* @param {number} [step=1] The value to increment or decrement by.
* @returns {Array} Returns the range of numbers.
* @see _.inRange, _.range
* @example
*
* _.rangeRight(4);
* // => [3, 2, 1, 0]
*
* _.rangeRight(-4);
* // => [-3, -2, -1, 0]
*
* _.rangeRight(1, 5);
* // => [4, 3, 2, 1]
*
* _.rangeRight(0, 20, 5);
* // => [15, 10, 5, 0]
*
* _.rangeRight(0, -4, -1);
* // => [-3, -2, -1, 0]
*
* _.rangeRight(1, 4, 0);
* // => [1, 1, 1]
*
* _.rangeRight(0);
* // => []
*/
var rangeRight = createRange(true);
/**
* This method returns a new empty array.
*
* @static
* @memberOf _
* @since 4.13.0
* @category Util
* @returns {Array} Returns the new empty array.
* @example
*
* var arrays = _.times(2, _.stubArray);
*
* console.log(arrays);
* // => [[], []]
*
* console.log(arrays[0] === arrays[1]);
* // => false
*/
function stubArray() {
return [];
}
/**
* This method returns `false`.
*
* @static
* @memberOf _
* @since 4.13.0
* @category Util
* @returns {boolean} Returns `false`.
* @example
*
* _.times(2, _.stubFalse);
* // => [false, false]
*/
function stubFalse() {
return false;
}
/**
* This method returns a new empty object.
*
* @static
* @memberOf _
* @since 4.13.0
* @category Util
* @returns {Object} Returns the new empty object.
* @example
*
* var objects = _.times(2, _.stubObject);
*
* console.log(objects);
* // => [{}, {}]
*
* console.log(objects[0] === objects[1]);
* // => false
*/
function stubObject() {
return {};
}
/**
* This method returns an empty string.
*
* @static
* @memberOf _
* @since 4.13.0
* @category Util
* @returns {string} Returns the empty string.
* @example
*
* _.times(2, _.stubString);
* // => ['', '']
*/
function stubString() {
return '';
}
/**
* This method returns `true`.
*
* @static
* @memberOf _
* @since 4.13.0
* @category Util
* @returns {boolean} Returns `true`.
* @example
*
* _.times(2, _.stubTrue);
* // => [true, true]
*/
function stubTrue() {
return true;
}
/**
* Invokes the iteratee `n` times, returning an array of the results of
* each invocation. The iteratee is invoked with one argument; (index).
*
* @static
* @since 0.1.0
* @memberOf _
* @category Util
* @param {number} n The number of times to invoke `iteratee`.
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
* @returns {Array} Returns the array of results.
* @example
*
* _.times(3, String);
* // => ['0', '1', '2']
*
* _.times(4, _.constant(0));
* // => [0, 0, 0, 0]
*/
function times(n, iteratee) {
n = toInteger(n);
if (n < 1 || n > MAX_SAFE_INTEGER) {
return [];
}
var index = MAX_ARRAY_LENGTH,
length = nativeMin(n, MAX_ARRAY_LENGTH);
iteratee = getIteratee(iteratee);
n -= MAX_ARRAY_LENGTH;
var result = baseTimes(length, iteratee);
while (++index < n) {
iteratee(index);
}
return result;
}
/**
* Converts `value` to a property path array.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Util
* @param {*} value The value to convert.
* @returns {Array} Returns the new property path array.
* @example
*
* _.toPath('a.b.c');
* // => ['a', 'b', 'c']
*
* _.toPath('a[0].b.c');
* // => ['a', '0', 'b', 'c']
*/
function toPath(value) {
if (isArray(value)) {
return arrayMap(value, toKey);
}
return isSymbol(value) ? [value] : copyArray(stringToPath(toString(value)));
}
/**
* Generates a unique ID. If `prefix` is given, the ID is appended to it.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Util
* @param {string} [prefix=''] The value to prefix the ID with.
* @returns {string} Returns the unique ID.
* @example
*
* _.uniqueId('contact_');
* // => 'contact_104'
*
* _.uniqueId();
* // => '105'
*/
function uniqueId(prefix) {
var id = ++idCounter;
return toString(prefix) + id;
}
/*------------------------------------------------------------------------*/
/**
* Adds two numbers.
*
* @static
* @memberOf _
* @since 3.4.0
* @category Math
* @param {number} augend The first number in an addition.
* @param {number} addend The second number in an addition.
* @returns {number} Returns the total.
* @example
*
* _.add(6, 4);
* // => 10
*/
var add = createMathOperation(function(augend, addend) {
return augend + addend;
}, 0);
/**
* Computes `number` rounded up to `precision`.
*
* @static
* @memberOf _
* @since 3.10.0
* @category Math
* @param {number} number The number to round up.
* @param {number} [precision=0] The precision to round up to.
* @returns {number} Returns the rounded up number.
* @example
*
* _.ceil(4.006);
* // => 5
*
* _.ceil(6.004, 2);
* // => 6.01
*
* _.ceil(6040, -2);
* // => 6100
*/
var ceil = createRound('ceil');
/**
* Divide two numbers.
*
* @static
* @memberOf _
* @since 4.7.0
* @category Math
* @param {number} dividend The first number in a division.
* @param {number} divisor The second number in a division.
* @returns {number} Returns the quotient.
* @example
*
* _.divide(6, 4);
* // => 1.5
*/
var divide = createMathOperation(function(dividend, divisor) {
return dividend / divisor;
}, 1);
/**
* Computes `number` rounded down to `precision`.
*
* @static
* @memberOf _
* @since 3.10.0
* @category Math
* @param {number} number The number to round down.
* @param {number} [precision=0] The precision to round down to.
* @returns {number} Returns the rounded down number.
* @example
*
* _.floor(4.006);
* // => 4
*
* _.floor(0.046, 2);
* // => 0.04
*
* _.floor(4060, -2);
* // => 4000
*/
var floor = createRound('floor');
/**
* Computes the maximum value of `array`. If `array` is empty or falsey,
* `undefined` is returned.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Math
* @param {Array} array The array to iterate over.
* @returns {*} Returns the maximum value.
* @example
*
* _.max([4, 2, 8, 6]);
* // => 8
*
* _.max([]);
* // => undefined
*/
function max(array) {
return (array && array.length)
? baseExtremum(array, identity, baseGt)
: undefined;
}
/**
* This method is like `_.max` except that it accepts `iteratee` which is
* invoked for each element in `array` to generate the criterion by which
* the value is ranked. The iteratee is invoked with one argument: (value).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Math
* @param {Array} array The array to iterate over.
* @param {Function} [iteratee=_.identity] The iteratee invoked per element.
* @returns {*} Returns the maximum value.
* @example
*
* var objects = [{ 'n': 1 }, { 'n': 2 }];
*
* _.maxBy(objects, function(o) { return o.n; });
* // => { 'n': 2 }
*
* // The `_.property` iteratee shorthand.
* _.maxBy(objects, 'n');
* // => { 'n': 2 }
*/
function maxBy(array, iteratee) {
return (array && array.length)
? baseExtremum(array, getIteratee(iteratee, 2), baseGt)
: undefined;
}
/**
* Computes the mean of the values in `array`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Math
* @param {Array} array The array to iterate over.
* @returns {number} Returns the mean.
* @example
*
* _.mean([4, 2, 8, 6]);
* // => 5
*/
function mean(array) {
return baseMean(array, identity);
}
/**
* This method is like `_.mean` except that it accepts `iteratee` which is
* invoked for each element in `array` to generate the value to be averaged.
* The iteratee is invoked with one argument: (value).
*
* @static
* @memberOf _
* @since 4.7.0
* @category Math
* @param {Array} array The array to iterate over.
* @param {Function} [iteratee=_.identity] The iteratee invoked per element.
* @returns {number} Returns the mean.
* @example
*
* var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
*
* _.meanBy(objects, function(o) { return o.n; });
* // => 5
*
* // The `_.property` iteratee shorthand.
* _.meanBy(objects, 'n');
* // => 5
*/
function meanBy(array, iteratee) {
return baseMean(array, getIteratee(iteratee, 2));
}
/**
* Computes the minimum value of `array`. If `array` is empty or falsey,
* `undefined` is returned.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Math
* @param {Array} array The array to iterate over.
* @returns {*} Returns the minimum value.
* @example
*
* _.min([4, 2, 8, 6]);
* // => 2
*
* _.min([]);
* // => undefined
*/
function min(array) {
return (array && array.length)
? baseExtremum(array, identity, baseLt)
: undefined;
}
/**
* This method is like `_.min` except that it accepts `iteratee` which is
* invoked for each element in `array` to generate the criterion by which
* the value is ranked. The iteratee is invoked with one argument: (value).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Math
* @param {Array} array The array to iterate over.
* @param {Function} [iteratee=_.identity] The iteratee invoked per element.
* @returns {*} Returns the minimum value.
* @example
*
* var objects = [{ 'n': 1 }, { 'n': 2 }];
*
* _.minBy(objects, function(o) { return o.n; });
* // => { 'n': 1 }
*
* // The `_.property` iteratee shorthand.
* _.minBy(objects, 'n');
* // => { 'n': 1 }
*/
function minBy(array, iteratee) {
return (array && array.length)
? baseExtremum(array, getIteratee(iteratee, 2), baseLt)
: undefined;
}
/**
* Multiply two numbers.
*
* @static
* @memberOf _
* @since 4.7.0
* @category Math
* @param {number} multiplier The first number in a multiplication.
* @param {number} multiplicand The second number in a multiplication.
* @returns {number} Returns the product.
* @example
*
* _.multiply(6, 4);
* // => 24
*/
var multiply = createMathOperation(function(multiplier, multiplicand) {
return multiplier * multiplicand;
}, 1);
/**
* Computes `number` rounded to `precision`.
*
* @static
* @memberOf _
* @since 3.10.0
* @category Math
* @param {number} number The number to round.
* @param {number} [precision=0] The precision to round to.
* @returns {number} Returns the rounded number.
* @example
*
* _.round(4.006);
* // => 4
*
* _.round(4.006, 2);
* // => 4.01
*
* _.round(4060, -2);
* // => 4100
*/
var round = createRound('round');
/**
* Subtract two numbers.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Math
* @param {number} minuend The first number in a subtraction.
* @param {number} subtrahend The second number in a subtraction.
* @returns {number} Returns the difference.
* @example
*
* _.subtract(6, 4);
* // => 2
*/
var subtract = createMathOperation(function(minuend, subtrahend) {
return minuend - subtrahend;
}, 0);
/**
* Computes the sum of the values in `array`.
*
* @static
* @memberOf _
* @since 3.4.0
* @category Math
* @param {Array} array The array to iterate over.
* @returns {number} Returns the sum.
* @example
*
* _.sum([4, 2, 8, 6]);
* // => 20
*/
function sum(array) {
return (array && array.length)
? baseSum(array, identity)
: 0;
}
/**
* This method is like `_.sum` except that it accepts `iteratee` which is
* invoked for each element in `array` to generate the value to be summed.
* The iteratee is invoked with one argument: (value).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Math
* @param {Array} array The array to iterate over.
* @param {Function} [iteratee=_.identity] The iteratee invoked per element.
* @returns {number} Returns the sum.
* @example
*
* var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
*
* _.sumBy(objects, function(o) { return o.n; });
* // => 20
*
* // The `_.property` iteratee shorthand.
* _.sumBy(objects, 'n');
* // => 20
*/
function sumBy(array, iteratee) {
return (array && array.length)
? baseSum(array, getIteratee(iteratee, 2))
: 0;
}
/*------------------------------------------------------------------------*/
// Add methods that return wrapped values in chain sequences.
lodash.after = after;
lodash.ary = ary;
lodash.assign = assign;
lodash.assignIn = assignIn;
lodash.assignInWith = assignInWith;
lodash.assignWith = assignWith;
lodash.at = at;
lodash.before = before;
lodash.bind = bind;
lodash.bindAll = bindAll;
lodash.bindKey = bindKey;
lodash.castArray = castArray;
lodash.chain = chain;
lodash.chunk = chunk;
lodash.compact = compact;
lodash.concat = concat;
lodash.cond = cond;
lodash.conforms = conforms;
lodash.constant = constant;
lodash.countBy = countBy;
lodash.create = create;
lodash.curry = curry;
lodash.curryRight = curryRight;
lodash.debounce = debounce;
lodash.defaults = defaults;
lodash.defaultsDeep = defaultsDeep;
lodash.defer = defer;
lodash.delay = delay;
lodash.difference = difference;
lodash.differenceBy = differenceBy;
lodash.differenceWith = differenceWith;
lodash.drop = drop;
lodash.dropRight = dropRight;
lodash.dropRightWhile = dropRightWhile;
lodash.dropWhile = dropWhile;
lodash.fill = fill;
lodash.filter = filter;
lodash.flatMap = flatMap;
lodash.flatMapDeep = flatMapDeep;
lodash.flatMapDepth = flatMapDepth;
lodash.flatten = flatten;
lodash.flattenDeep = flattenDeep;
lodash.flattenDepth = flattenDepth;
lodash.flip = flip;
lodash.flow = flow;
lodash.flowRight = flowRight;
lodash.fromPairs = fromPairs;
lodash.functions = functions;
lodash.functionsIn = functionsIn;
lodash.groupBy = groupBy;
lodash.initial = initial;
lodash.intersection = intersection;
lodash.intersectionBy = intersectionBy;
lodash.intersectionWith = intersectionWith;
lodash.invert = invert;
lodash.invertBy = invertBy;
lodash.invokeMap = invokeMap;
lodash.iteratee = iteratee;
lodash.keyBy = keyBy;
lodash.keys = keys;
lodash.keysIn = keysIn;
lodash.map = map;
lodash.mapKeys = mapKeys;
lodash.mapValues = mapValues;
lodash.matches = matches;
lodash.matchesProperty = matchesProperty;
lodash.memoize = memoize;
lodash.merge = merge;
lodash.mergeWith = mergeWith;
lodash.method = method;
lodash.methodOf = methodOf;
lodash.mixin = mixin;
lodash.negate = negate;
lodash.nthArg = nthArg;
lodash.omit = omit;
lodash.omitBy = omitBy;
lodash.once = once;
lodash.orderBy = orderBy;
lodash.over = over;
lodash.overArgs = overArgs;
lodash.overEvery = overEvery;
lodash.overSome = overSome;
lodash.partial = partial;
lodash.partialRight = partialRight;
lodash.partition = partition;
lodash.pick = pick;
lodash.pickBy = pickBy;
lodash.property = property;
lodash.propertyOf = propertyOf;
lodash.pull = pull;
lodash.pullAll = pullAll;
lodash.pullAllBy = pullAllBy;
lodash.pullAllWith = pullAllWith;
lodash.pullAt = pullAt;
lodash.range = range;
lodash.rangeRight = rangeRight;
lodash.rearg = rearg;
lodash.reject = reject;
lodash.remove = remove;
lodash.rest = rest;
lodash.reverse = reverse;
lodash.sampleSize = sampleSize;
lodash.set = set;
lodash.setWith = setWith;
lodash.shuffle = shuffle;
lodash.slice = slice;
lodash.sortBy = sortBy;
lodash.sortedUniq = sortedUniq;
lodash.sortedUniqBy = sortedUniqBy;
lodash.split = split;
lodash.spread = spread;
lodash.tail = tail;
lodash.take = take;
lodash.takeRight = takeRight;
lodash.takeRightWhile = takeRightWhile;
lodash.takeWhile = takeWhile;
lodash.tap = tap;
lodash.throttle = throttle;
lodash.thru = thru;
lodash.toArray = toArray;
lodash.toPairs = toPairs;
lodash.toPairsIn = toPairsIn;
lodash.toPath = toPath;
lodash.toPlainObject = toPlainObject;
lodash.transform = transform;
lodash.unary = unary;
lodash.union = union;
lodash.unionBy = unionBy;
lodash.unionWith = unionWith;
lodash.uniq = uniq;
lodash.uniqBy = uniqBy;
lodash.uniqWith = uniqWith;
lodash.unset = unset;
lodash.unzip = unzip;
lodash.unzipWith = unzipWith;
lodash.update = update;
lodash.updateWith = updateWith;
lodash.values = values;
lodash.valuesIn = valuesIn;
lodash.without = without;
lodash.words = words;
lodash.wrap = wrap;
lodash.xor = xor;
lodash.xorBy = xorBy;
lodash.xorWith = xorWith;
lodash.zip = zip;
lodash.zipObject = zipObject;
lodash.zipObjectDeep = zipObjectDeep;
lodash.zipWith = zipWith;
// Add aliases.
lodash.entries = toPairs;
lodash.entriesIn = toPairsIn;
lodash.extend = assignIn;
lodash.extendWith = assignInWith;
// Add methods to `lodash.prototype`.
mixin(lodash, lodash);
/*------------------------------------------------------------------------*/
// Add methods that return unwrapped values in chain sequences.
lodash.add = add;
lodash.attempt = attempt;
lodash.camelCase = camelCase;
lodash.capitalize = capitalize;
lodash.ceil = ceil;
lodash.clamp = clamp;
lodash.clone = clone;
lodash.cloneDeep = cloneDeep;
lodash.cloneDeepWith = cloneDeepWith;
lodash.cloneWith = cloneWith;
lodash.conformsTo = conformsTo;
lodash.deburr = deburr;
lodash.defaultTo = defaultTo;
lodash.divide = divide;
lodash.endsWith = endsWith;
lodash.eq = eq;
lodash.escape = escape;
lodash.escapeRegExp = escapeRegExp;
lodash.every = every;
lodash.find = find;
lodash.findIndex = findIndex;
lodash.findKey = findKey;
lodash.findLast = findLast;
lodash.findLastIndex = findLastIndex;
lodash.findLastKey = findLastKey;
lodash.floor = floor;
lodash.forEach = forEach;
lodash.forEachRight = forEachRight;
lodash.forIn = forIn;
lodash.forInRight = forInRight;
lodash.forOwn = forOwn;
lodash.forOwnRight = forOwnRight;
lodash.get = get;
lodash.gt = gt;
lodash.gte = gte;
lodash.has = has;
lodash.hasIn = hasIn;
lodash.head = head;
lodash.identity = identity;
lodash.includes = includes;
lodash.indexOf = indexOf;
lodash.inRange = inRange;
lodash.invoke = invoke;
lodash.isArguments = isArguments;
lodash.isArray = isArray;
lodash.isArrayBuffer = isArrayBuffer;
lodash.isArrayLike = isArrayLike;
lodash.isArrayLikeObject = isArrayLikeObject;
lodash.isBoolean = isBoolean;
lodash.isBuffer = isBuffer;
lodash.isDate = isDate;
lodash.isElement = isElement;
lodash.isEmpty = isEmpty;
lodash.isEqual = isEqual;
lodash.isEqualWith = isEqualWith;
lodash.isError = isError;
lodash.isFinite = isFinite;
lodash.isFunction = isFunction;
lodash.isInteger = isInteger;
lodash.isLength = isLength;
lodash.isMap = isMap;
lodash.isMatch = isMatch;
lodash.isMatchWith = isMatchWith;
lodash.isNaN = isNaN;
lodash.isNative = isNative;
lodash.isNil = isNil;
lodash.isNull = isNull;
lodash.isNumber = isNumber;
lodash.isObject = isObject;
lodash.isObjectLike = isObjectLike;
lodash.isPlainObject = isPlainObject;
lodash.isRegExp = isRegExp;
lodash.isSafeInteger = isSafeInteger;
lodash.isSet = isSet;
lodash.isString = isString;
lodash.isSymbol = isSymbol;
lodash.isTypedArray = isTypedArray;
lodash.isUndefined = isUndefined;
lodash.isWeakMap = isWeakMap;
lodash.isWeakSet = isWeakSet;
lodash.join = join;
lodash.kebabCase = kebabCase;
lodash.last = last;
lodash.lastIndexOf = lastIndexOf;
lodash.lowerCase = lowerCase;
lodash.lowerFirst = lowerFirst;
lodash.lt = lt;
lodash.lte = lte;
lodash.max = max;
lodash.maxBy = maxBy;
lodash.mean = mean;
lodash.meanBy = meanBy;
lodash.min = min;
lodash.minBy = minBy;
lodash.stubArray = stubArray;
lodash.stubFalse = stubFalse;
lodash.stubObject = stubObject;
lodash.stubString = stubString;
lodash.stubTrue = stubTrue;
lodash.multiply = multiply;
lodash.nth = nth;
lodash.noConflict = noConflict;
lodash.noop = noop;
lodash.now = now;
lodash.pad = pad;
lodash.padEnd = padEnd;
lodash.padStart = padStart;
lodash.parseInt = parseInt;
lodash.random = random;
lodash.reduce = reduce;
lodash.reduceRight = reduceRight;
lodash.repeat = repeat;
lodash.replace = replace;
lodash.result = result;
lodash.round = round;
lodash.runInContext = runInContext;
lodash.sample = sample;
lodash.size = size;
lodash.snakeCase = snakeCase;
lodash.some = some;
lodash.sortedIndex = sortedIndex;
lodash.sortedIndexBy = sortedIndexBy;
lodash.sortedIndexOf = sortedIndexOf;
lodash.sortedLastIndex = sortedLastIndex;
lodash.sortedLastIndexBy = sortedLastIndexBy;
lodash.sortedLastIndexOf = sortedLastIndexOf;
lodash.startCase = startCase;
lodash.startsWith = startsWith;
lodash.subtract = subtract;
lodash.sum = sum;
lodash.sumBy = sumBy;
lodash.template = template;
lodash.times = times;
lodash.toFinite = toFinite;
lodash.toInteger = toInteger;
lodash.toLength = toLength;
lodash.toLower = toLower;
lodash.toNumber = toNumber;
lodash.toSafeInteger = toSafeInteger;
lodash.toString = toString;
lodash.toUpper = toUpper;
lodash.trim = trim;
lodash.trimEnd = trimEnd;
lodash.trimStart = trimStart;
lodash.truncate = truncate;
lodash.unescape = unescape;
lodash.uniqueId = uniqueId;
lodash.upperCase = upperCase;
lodash.upperFirst = upperFirst;
// Add aliases.
lodash.each = forEach;
lodash.eachRight = forEachRight;
lodash.first = head;
mixin(lodash, (function() {
var source = {};
baseForOwn(lodash, function(func, methodName) {
if (!hasOwnProperty.call(lodash.prototype, methodName)) {
source[methodName] = func;
}
});
return source;
}()), { 'chain': false });
/*------------------------------------------------------------------------*/
/**
* The semantic version number.
*
* @static
* @memberOf _
* @type {string}
*/
lodash.VERSION = VERSION;
// Assign default placeholders.
arrayEach(['bind', 'bindKey', 'curry', 'curryRight', 'partial', 'partialRight'], function(methodName) {
lodash[methodName].placeholder = lodash;
});
// Add `LazyWrapper` methods for `_.drop` and `_.take` variants.
arrayEach(['drop', 'take'], function(methodName, index) {
LazyWrapper.prototype[methodName] = function(n) {
n = n === undefined ? 1 : nativeMax(toInteger(n), 0);
var result = (this.__filtered__ && !index)
? new LazyWrapper(this)
: this.clone();
if (result.__filtered__) {
result.__takeCount__ = nativeMin(n, result.__takeCount__);
} else {
result.__views__.push({
'size': nativeMin(n, MAX_ARRAY_LENGTH),
'type': methodName + (result.__dir__ < 0 ? 'Right' : '')
});
}
return result;
};
LazyWrapper.prototype[methodName + 'Right'] = function(n) {
return this.reverse()[methodName](n).reverse();
};
});
// Add `LazyWrapper` methods that accept an `iteratee` value.
arrayEach(['filter', 'map', 'takeWhile'], function(methodName, index) {
var type = index + 1,
isFilter = type == LAZY_FILTER_FLAG || type == LAZY_WHILE_FLAG;
LazyWrapper.prototype[methodName] = function(iteratee) {
var result = this.clone();
result.__iteratees__.push({
'iteratee': getIteratee(iteratee, 3),
'type': type
});
result.__filtered__ = result.__filtered__ || isFilter;
return result;
};
});
// Add `LazyWrapper` methods for `_.head` and `_.last`.
arrayEach(['head', 'last'], function(methodName, index) {
var takeName = 'take' + (index ? 'Right' : '');
LazyWrapper.prototype[methodName] = function() {
return this[takeName](1).value()[0];
};
});
// Add `LazyWrapper` methods for `_.initial` and `_.tail`.
arrayEach(['initial', 'tail'], function(methodName, index) {
var dropName = 'drop' + (index ? '' : 'Right');
LazyWrapper.prototype[methodName] = function() {
return this.__filtered__ ? new LazyWrapper(this) : this[dropName](1);
};
});
LazyWrapper.prototype.compact = function() {
return this.filter(identity);
};
LazyWrapper.prototype.find = function(predicate) {
return this.filter(predicate).head();
};
LazyWrapper.prototype.findLast = function(predicate) {
return this.reverse().find(predicate);
};
LazyWrapper.prototype.invokeMap = baseRest(function(path, args) {
if (typeof path == 'function') {
return new LazyWrapper(this);
}
return this.map(function(value) {
return baseInvoke(value, path, args);
});
});
LazyWrapper.prototype.reject = function(predicate) {
return this.filter(negate(getIteratee(predicate)));
};
LazyWrapper.prototype.slice = function(start, end) {
start = toInteger(start);
var result = this;
if (result.__filtered__ && (start > 0 || end < 0)) {
return new LazyWrapper(result);
}
if (start < 0) {
result = result.takeRight(-start);
} else if (start) {
result = result.drop(start);
}
if (end !== undefined) {
end = toInteger(end);
result = end < 0 ? result.dropRight(-end) : result.take(end - start);
}
return result;
};
LazyWrapper.prototype.takeRightWhile = function(predicate) {
return this.reverse().takeWhile(predicate).reverse();
};
LazyWrapper.prototype.toArray = function() {
return this.take(MAX_ARRAY_LENGTH);
};
// Add `LazyWrapper` methods to `lodash.prototype`.
baseForOwn(LazyWrapper.prototype, function(func, methodName) {
var checkIteratee = /^(?:filter|find|map|reject)|While$/.test(methodName),
isTaker = /^(?:head|last)$/.test(methodName),
lodashFunc = lodash[isTaker ? ('take' + (methodName == 'last' ? 'Right' : '')) : methodName],
retUnwrapped = isTaker || /^find/.test(methodName);
if (!lodashFunc) {
return;
}
lodash.prototype[methodName] = function() {
var value = this.__wrapped__,
args = isTaker ? [1] : arguments,
isLazy = value instanceof LazyWrapper,
iteratee = args[0],
useLazy = isLazy || isArray(value);
var interceptor = function(value) {
var result = lodashFunc.apply(lodash, arrayPush([value], args));
return (isTaker && chainAll) ? result[0] : result;
};
if (useLazy && checkIteratee && typeof iteratee == 'function' && iteratee.length != 1) {
// Avoid lazy use if the iteratee has a "length" value other than `1`.
isLazy = useLazy = false;
}
var chainAll = this.__chain__,
isHybrid = !!this.__actions__.length,
isUnwrapped = retUnwrapped && !chainAll,
onlyLazy = isLazy && !isHybrid;
if (!retUnwrapped && useLazy) {
value = onlyLazy ? value : new LazyWrapper(this);
var result = func.apply(value, args);
result.__actions__.push({ 'func': thru, 'args': [interceptor], 'thisArg': undefined });
return new LodashWrapper(result, chainAll);
}
if (isUnwrapped && onlyLazy) {
return func.apply(this, args);
}
result = this.thru(interceptor);
return isUnwrapped ? (isTaker ? result.value()[0] : result.value()) : result;
};
});
// Add `Array` methods to `lodash.prototype`.
arrayEach(['pop', 'push', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
var func = arrayProto[methodName],
chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru',
retUnwrapped = /^(?:pop|shift)$/.test(methodName);
lodash.prototype[methodName] = function() {
var args = arguments;
if (retUnwrapped && !this.__chain__) {
var value = this.value();
return func.apply(isArray(value) ? value : [], args);
}
return this[chainName](function(value) {
return func.apply(isArray(value) ? value : [], args);
});
};
});
// Map minified method names to their real names.
baseForOwn(LazyWrapper.prototype, function(func, methodName) {
var lodashFunc = lodash[methodName];
if (lodashFunc) {
var key = (lodashFunc.name + ''),
names = realNames[key] || (realNames[key] = []);
names.push({ 'name': methodName, 'func': lodashFunc });
}
});
realNames[createHybrid(undefined, WRAP_BIND_KEY_FLAG).name] = [{
'name': 'wrapper',
'func': undefined
}];
// Add methods to `LazyWrapper`.
LazyWrapper.prototype.clone = lazyClone;
LazyWrapper.prototype.reverse = lazyReverse;
LazyWrapper.prototype.value = lazyValue;
// Add chain sequence methods to the `lodash` wrapper.
lodash.prototype.at = wrapperAt;
lodash.prototype.chain = wrapperChain;
lodash.prototype.commit = wrapperCommit;
lodash.prototype.next = wrapperNext;
lodash.prototype.plant = wrapperPlant;
lodash.prototype.reverse = wrapperReverse;
lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue;
// Add lazy aliases.
lodash.prototype.first = lodash.prototype.head;
if (symIterator) {
lodash.prototype[symIterator] = wrapperToIterator;
}
return lodash;
});
/*--------------------------------------------------------------------------*/
// Export lodash.
var _ = runInContext();
// Some AMD build optimizers, like r.js, check for condition patterns like:
if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
// Expose Lodash on the global object to prevent errors when Lodash is
// loaded by a script tag in the presence of an AMD loader.
// See http://requirejs.org/docs/errors.html#mismatch for more details.
// Use `_.noConflict` to remove Lodash from the global object.
root._ = _;
// Define as an anonymous module so, through path mapping, it can be
// referenced as the "underscore" module.
define(function() {
return _;
});
}
// Check for `exports` after `define` in case a build optimizer adds it.
else if (freeModule) {
// Export for Node.js.
(freeModule.exports = _)._ = _;
// Export for CommonJS support.
freeExports._ = _;
}
else {
// Export to the global object.
root._ = _;
}
}.call(this));
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],17:[function(require,module,exports){
/*
* Lexical analysis and token construction.
*/
"use strict";
var _ = require("lodash");
var events = require("events");
var reg = require("./reg.js");
var state = require("./state.js").state;
var unicodeData = require("../data/ascii-identifier-data.js");
var asciiIdentifierStartTable = unicodeData.asciiIdentifierStartTable;
var asciiIdentifierPartTable = unicodeData.asciiIdentifierPartTable;
var nonAsciiIdentifierStartTable = require("../data/non-ascii-identifier-start.js");
var nonAsciiIdentifierPartTable = require("../data/non-ascii-identifier-part-only.js");
// Loading of this module is deferred as an optimization for ES2015 input
var es5IdentifierNames;
// Some of these token types are from JavaScript Parser API
// while others are specific to JSHint parser.
// JS Parser API: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API
var Token = {
Identifier: 1,
Punctuator: 2,
NumericLiteral: 3,
StringLiteral: 4,
Comment: 5,
Keyword: 6,
RegExp: 9,
TemplateHead: 10,
TemplateMiddle: 11,
TemplateTail: 12,
NoSubstTemplate: 13
};
var Context = {
Block: 1,
Template: 2
};
function isHex(str) {
return /^[0-9a-fA-F]+$/.test(str);
}
function isHexDigit(str) {
return str.length === 1 && isHex(str);
}
// Object that handles postponed lexing verifications that checks the parsed
// environment state.
function asyncTrigger() {
var _checks = [];
return {
push: function(fn) {
_checks.push(fn);
},
check: function() {
for (var check = 0; check < _checks.length; ++check) {
_checks[check]();
}
_checks.splice(0, _checks.length);
}
};
}
/*
* Lexer for JSHint.
*
* This object does a char-by-char scan of the provided source code
* and produces a sequence of tokens.
*
* var lex = new Lexer("var i = 0;");
* lex.start();
* lex.token(); // returns the next token
*
* You have to use the token() method to move the lexer forward
* but you don't have to use its return value to get tokens. In addition
* to token() method returning the next token, the Lexer object also
* emits events.
*
* lex.on("Identifier", function(data) {
* if (data.name.indexOf("_") >= 0) {
* // Produce a warning.
* }
* });
*
* Note that the token() method returns tokens in a JSLint-compatible
* format while the event emitter uses a slightly modified version of
* Mozilla's JavaScript Parser API. Eventually, we will move away from
* JSLint format.
*/
function Lexer(source) {
var lines = source;
if (typeof lines === "string") {
lines = lines
.replace(/\r\n/g, "\n")
.replace(/\r/g, "\n")
.split("\n");
}
// If the first line is a shebang (#!), make it a blank and move on.
// Shebangs are used by Node scripts.
if (lines[0] && lines[0].substr(0, 2) === "#!") {
if (lines[0].indexOf("node") !== -1) {
state.option.node = true;
}
lines[0] = "";
}
this.emitter = new events.EventEmitter();
this.source = source;
this.setLines(lines);
this.prereg = true;
this.line = 0;
this.char = 1;
this.from = 1;
this.input = "";
this.inComment = false;
this.context = [];
this.templateStarts = [];
for (var i = 0; i < state.option.indent; i += 1) {
state.tab += " ";
}
}
Lexer.prototype = {
_lines: [],
inContext: function(ctxType) {
return this.context.length > 0 && this.context[this.context.length - 1].type === ctxType;
},
pushContext: function(ctxType) {
this.context.push({ type: ctxType });
},
popContext: function() {
return this.context.pop();
},
currentContext: function() {
return this.context.length > 0 && this.context[this.context.length - 1];
},
getLines: function() {
this._lines = state.lines;
return this._lines;
},
setLines: function(val) {
this._lines = val;
state.lines = this._lines;
},
/*
* Return the next i character without actually moving the
* char pointer.
*/
peek: function(i) {
return this.input.charAt(i || 0);
},
/*
* Move the char pointer forward i times.
*/
skip: function(i) {
i = i || 1;
this.char += i;
this.input = this.input.slice(i);
},
/*
* Subscribe to a token event. The API for this method is similar
* Underscore.js i.e. you can subscribe to multiple events with
* one call:
*
* lex.on("Identifier Number", function(data) {
* // ...
* });
*/
on: function(names, listener) {
names.split(" ").forEach(function(name) {
this.emitter.on(name, listener);
}.bind(this));
},
/*
* Trigger a token event. All arguments will be passed to each
* listener.
*/
trigger: function() {
this.emitter.emit.apply(this.emitter, Array.prototype.slice.call(arguments));
},
/*
* Postpone a token event. the checking condition is set as
* last parameter, and the trigger function is called in a
* stored callback. To be later called using the check() function
* by the parser. This avoids parser's peek() to give the lexer
* a false context.
*/
triggerAsync: function(type, args, checks, fn) {
checks.push(function() {
if (fn()) {
this.trigger(type, args);
}
}.bind(this));
},
/*
* Extract a punctuator out of the next sequence of characters
* or return 'null' if its not possible.
*
* This method's implementation was heavily influenced by the
* scanPunctuator function in the Esprima parser's source code.
*/
scanPunctuator: function() {
var ch1 = this.peek();
var ch2, ch3, ch4;
switch (ch1) {
// Most common single-character punctuators
case ".":
if ((/^[0-9]$/).test(this.peek(1))) {
return null;
}
if (this.peek(1) === "." && this.peek(2) === ".") {
return {
type: Token.Punctuator,
value: "..."
};
}
/* falls through */
case "(":
case ")":
case ";":
case ",":
case "[":
case "]":
case ":":
case "~":
case "?":
return {
type: Token.Punctuator,
value: ch1
};
// A block/object opener
case "{":
this.pushContext(Context.Block);
return {
type: Token.Punctuator,
value: ch1
};
// A block/object closer
case "}":
if (this.inContext(Context.Block)) {
this.popContext();
}
return {
type: Token.Punctuator,
value: ch1
};
// A pound sign (for Node shebangs)
case "#":
return {
type: Token.Punctuator,
value: ch1
};
// We're at the end of input
case "":
return null;
}
// Peek more characters
ch2 = this.peek(1);
ch3 = this.peek(2);
ch4 = this.peek(3);
// 4-character punctuator: >>>=
if (ch1 === ">" && ch2 === ">" && ch3 === ">" && ch4 === "=") {
return {
type: Token.Punctuator,
value: ">>>="
};
}
// 3-character punctuators: === !== >>> <<= >>=
if (ch1 === "=" && ch2 === "=" && ch3 === "=") {
return {
type: Token.Punctuator,
value: "==="
};
}
if (ch1 === "!" && ch2 === "=" && ch3 === "=") {
return {
type: Token.Punctuator,
value: "!=="
};
}
if (ch1 === ">" && ch2 === ">" && ch3 === ">") {
return {
type: Token.Punctuator,
value: ">>>"
};
}
if (ch1 === "<" && ch2 === "<" && ch3 === "=") {
return {
type: Token.Punctuator,
value: "<<="
};
}
if (ch1 === ">" && ch2 === ">" && ch3 === "=") {
return {
type: Token.Punctuator,
value: ">>="
};
}
// Fat arrow punctuator
if (ch1 === "=" && ch2 === ">") {
return {
type: Token.Punctuator,
value: ch1 + ch2
};
}
// 2-character punctuators: ++ -- << >> && || **
if (ch1 === ch2 && ("+-<>&|*".indexOf(ch1) >= 0)) {
if (ch1 === "*" && ch3 === "=") {
return {
type: Token.Punctuator,
value: ch1 + ch2 + ch3
};
}
return {
type: Token.Punctuator,
value: ch1 + ch2
};
}
// <= >= != += -= *= %= &= |= ^= /=
if ("<>=!+-*%&|^/".indexOf(ch1) >= 0) {
if (ch2 === "=") {
return {
type: Token.Punctuator,
value: ch1 + ch2
};
}
return {
type: Token.Punctuator,
value: ch1
};
}
return null;
},
/*
* Extract a comment out of the next sequence of characters and/or
* lines or return 'null' if its not possible. Since comments can
* span across multiple lines this method has to move the char
* pointer.
*
* In addition to normal JavaScript comments (// and /*) this method
* also recognizes JSHint- and JSLint-specific comments such as
* /*jshint, /*jslint, /*globals and so on.
*/
scanComments: function(checks) {
var ch1 = this.peek();
var ch2 = this.peek(1);
var rest = this.input.substr(2);
var startLine = this.line;
var startChar = this.char;
var self = this;
// Create a comment token object and make sure it
// has all the data JSHint needs to work with special
// comments.
function commentToken(label, body, opt) {
var special = [
"jshint", "jshint.unstable", "jslint", "members", "member", "globals",
"global", "exported"
];
var isSpecial = false;
var value = label + body;
var commentType = "plain";
opt = opt || {};
if (opt.isMultiline) {
value += "*/";
}
body = body.replace(/\n/g, " ");
if (label === "/*" && reg.fallsThrough.test(body)) {
isSpecial = true;
commentType = "falls through";
}
special.forEach(function(str) {
if (isSpecial) {
return;
}
// Don't recognize any special comments other than jshint for single-line
// comments. This introduced many problems with legit comments.
if (label === "//" && str !== "jshint" && str !== "jshint.unstable") {
return;
}
if (body.charAt(str.length) === " " && body.substr(0, str.length) === str) {
isSpecial = true;
label = label + str;
body = body.substr(str.length);
}
if (!isSpecial && body.charAt(0) === " " && body.charAt(str.length + 1) === " " &&
body.substr(1, str.length) === str) {
isSpecial = true;
label = label + " " + str;
body = body.substr(str.length + 1);
}
// To handle rarer case when special word is separated from label by
// multiple spaces or tabs
var strIndex = body.indexOf(str);
if (!isSpecial && strIndex >= 0 && body.charAt(strIndex + str.length) === " ") {
var isAllWhitespace = body.substr(0, strIndex).trim().length === 0;
if (isAllWhitespace) {
isSpecial = true;
body = body.substr(str.length + strIndex);
}
}
if (!isSpecial) {
return;
}
switch (str) {
case "member":
commentType = "members";
break;
case "global":
commentType = "globals";
break;
default:
var options = body.split(":").map(function(v) {
return v.replace(/^\s+/, "").replace(/\s+$/, "");
});
if (options.length === 2) {
switch (options[0]) {
case "ignore":
switch (options[1]) {
case "start":
self.ignoringLinterErrors = true;
isSpecial = false;
break;
case "end":
self.ignoringLinterErrors = false;
isSpecial = false;
break;
}
}
}
commentType = str;
}
});
return {
type: Token.Comment,
commentType: commentType,
value: value,
body: body,
isSpecial: isSpecial,
isMalformed: opt.isMalformed || false
};
}
// End of unbegun comment. Raise an error and skip that input.
if (ch1 === "*" && ch2 === "/") {
this.trigger("error", {
code: "E018",
line: startLine,
character: startChar
});
this.skip(2);
return null;
}
// Comments must start either with // or /*
if (ch1 !== "/" || (ch2 !== "*" && ch2 !== "/")) {
return null;
}
// One-line comment
if (ch2 === "/") {
this.skip(this.input.length); // Skip to the EOL.
return commentToken("//", rest);
}
var body = "";
/* Multi-line comment */
if (ch2 === "*") {
this.inComment = true;
this.skip(2);
while (this.peek() !== "*" || this.peek(1) !== "/") {
if (this.peek() === "") { // End of Line
body += "\n";
// If we hit EOF and our comment is still unclosed,
// trigger an error and end the comment implicitly.
if (!this.nextLine(checks)) {
this.trigger("error", {
code: "E017",
line: startLine,
character: startChar
});
this.inComment = false;
return commentToken("/*", body, {
isMultiline: true,
isMalformed: true
});
}
} else {
body += this.peek();
this.skip();
}
}
this.skip(2);
this.inComment = false;
return commentToken("/*", body, { isMultiline: true });
}
},
/*
* Extract a keyword out of the next sequence of characters or
* return 'null' if its not possible.
*/
scanKeyword: function() {
var result = /^[a-zA-Z_$][a-zA-Z0-9_$]*/.exec(this.input);
var keywords = [
"if", "in", "do", "var", "for", "new",
"try", "let", "this", "else", "case",
"void", "with", "enum", "while", "break",
"catch", "throw", "const", "yield", "class",
"super", "return", "typeof", "delete",
"switch", "export", "import", "default",
"finally", "extends", "function", "continue",
"debugger", "instanceof", "true", "false", "null", "async", "await"
];
if (result && keywords.indexOf(result[0]) >= 0) {
return {
type: Token.Keyword,
value: result[0]
};
}
return null;
},
/*
* Extract a JavaScript identifier out of the next sequence of
* characters or return 'null' if its not possible.
*/
scanIdentifier: function(checks) {
var id = "";
var index = 0;
var char, value;
function isNonAsciiIdentifierStart(code) {
return nonAsciiIdentifierStartTable.indexOf(code) > -1;
}
function isNonAsciiIdentifierPart(code) {
return isNonAsciiIdentifierStart(code) || nonAsciiIdentifierPartTable.indexOf(code) > -1;
}
var readUnicodeEscapeSequence = function() {
/*jshint validthis:true */
index += 1;
if (this.peek(index) !== "u") {
return null;
}
var sequence = this.peek(index + 1) + this.peek(index + 2) +
this.peek(index + 3) + this.peek(index + 4);
var code;
if (isHex(sequence)) {
code = parseInt(sequence, 16);
if (asciiIdentifierPartTable[code] || isNonAsciiIdentifierPart(code)) {
index += 5;
return "\\u" + sequence;
}
return null;
}
return null;
}.bind(this);
var getIdentifierStart = function() {
/*jshint validthis:true */
var chr = this.peek(index);
var code = chr.charCodeAt(0);
if (code === 92) {
return readUnicodeEscapeSequence();
}
if (code < 128) {
if (asciiIdentifierStartTable[code]) {
index += 1;
return chr;
}
return null;
}
if (isNonAsciiIdentifierStart(code)) {
index += 1;
return chr;
}
return null;
}.bind(this);
var getIdentifierPart = function() {
/*jshint validthis:true */
var chr = this.peek(index);
var code = chr.charCodeAt(0);
if (code === 92) {
return readUnicodeEscapeSequence();
}
if (code < 128) {
if (asciiIdentifierPartTable[code]) {
index += 1;
return chr;
}
return null;
}
if (isNonAsciiIdentifierPart(code)) {
index += 1;
return chr;
}
return null;
}.bind(this);
function removeEscapeSequences(id) {
return id.replace(/\\u([0-9a-fA-F]{4})/g, function(m0, codepoint) {
return String.fromCharCode(parseInt(codepoint, 16));
});
}
char = getIdentifierStart();
if (char === null) {
return null;
}
id = char;
for (;;) {
char = getIdentifierPart();
if (char === null) {
break;
}
id += char;
}
value = removeEscapeSequences(id);
if (!state.inES6(true)) {
es5IdentifierNames = require("../data/es5-identifier-names.js");
if (!es5IdentifierNames.test(value)) {
this.triggerAsync(
"warning",
{
code: "W119",
line: this.line,
character: this.char,
data: ["unicode 8", "6"]
},
checks,
function() { return true; }
);
}
}
return {
type: Token.Identifier,
value: value,
text: id,
tokenLength: id.length
};
},
/*
* Extract a numeric literal out of the next sequence of
* characters or return 'null' if its not possible. This method
* supports all numeric literals described in section 7.8.3
* of the EcmaScript 5 specification.
*
* This method's implementation was heavily influenced by the
* scanNumericLiteral function in the Esprima parser's source code.
*/
scanNumericLiteral: function(checks) {
var index = 0;
var value = "";
var length = this.input.length;
var char = this.peek(index);
var isAllowedDigit = isDecimalDigit;
var base = 10;
var isLegacy = false;
function isDecimalDigit(str) {
return (/^[0-9]$/).test(str);
}
function isOctalDigit(str) {
return (/^[0-7]$/).test(str);
}
function isBinaryDigit(str) {
return (/^[01]$/).test(str);
}
function isIdentifierStart(ch) {
return (ch === "$") || (ch === "_") || (ch === "\\") ||
(ch >= "a" && ch <= "z") || (ch >= "A" && ch <= "Z");
}
// Numbers must start either with a decimal digit or a point.
if (char !== "." && !isDecimalDigit(char)) {
return null;
}
if (char !== ".") {
value = this.peek(index);
index += 1;
char = this.peek(index);
if (value === "0") {
// Base-16 numbers.
if (char === "x" || char === "X") {
isAllowedDigit = isHexDigit;
base = 16;
index += 1;
value += char;
}
// Base-8 numbers.
if (char === "o" || char === "O") {
isAllowedDigit = isOctalDigit;
base = 8;
if (!state.inES6(true)) {
this.triggerAsync(
"warning",
{
code: "W119",
line: this.line,
character: this.char,
data: [ "Octal integer literal", "6" ]
},
checks,
function() { return true; }
);
}
index += 1;
value += char;
}
// Base-2 numbers.
if (char === "b" || char === "B") {
isAllowedDigit = isBinaryDigit;
base = 2;
if (!state.inES6(true)) {
this.triggerAsync(
"warning",
{
code: "W119",
line: this.line,
character: this.char,
data: [ "Binary integer literal", "6" ]
},
checks,
function() { return true; }
);
}
index += 1;
value += char;
}
// Legacy base-8 numbers.
if (isOctalDigit(char)) {
isAllowedDigit = isOctalDigit;
base = 8;
isLegacy = true;
index += 1;
value += char;
}
// Decimal numbers that start with '0' such as '09' are illegal
// but we still parse them and return as malformed.
if (!isOctalDigit(char) && isDecimalDigit(char)) {
index += 1;
value += char;
}
}
while (index < length) {
char = this.peek(index);
// Numbers like '019' (note the 9) are not valid octals
// but we still parse them and mark as malformed.
if (!(isLegacy && isDecimalDigit(char)) && !isAllowedDigit(char)) {
break;
}
value += char;
index += 1;
}
var isBigInt = this.peek(index) === 'n';
if (isAllowedDigit !== isDecimalDigit || isBigInt) {
if (isBigInt) {
if (!state.option.unstable.bigint) {
this.triggerAsync(
"warning",
{
code: "W144",
line: this.line,
character: this.char,
data: [ "BigInt", "bigint" ]
},
checks,
function() { return true; }
);
}
value += char;
index += 1;
} else if (!isLegacy && value.length <= 2) { // 0x
return {
type: Token.NumericLiteral,
value: value,
isMalformed: true
};
}
if (index < length) {
char = this.peek(index);
if (isIdentifierStart(char)) {
return null;
}
}
return {
type: Token.NumericLiteral,
value: value,
base: base,
isLegacy: isLegacy,
isMalformed: false
};
}
}
// Decimal digits.
if (char === ".") {
value += char;
index += 1;
while (index < length) {
char = this.peek(index);
if (!isDecimalDigit(char)) {
break;
}
value += char;
index += 1;
}
}
// Exponent part.
if (char === "e" || char === "E") {
value += char;
index += 1;
char = this.peek(index);
if (char === "+" || char === "-") {
value += this.peek(index);
index += 1;
}
char = this.peek(index);
if (isDecimalDigit(char)) {
value += char;
index += 1;
while (index < length) {
char = this.peek(index);
if (!isDecimalDigit(char)) {
break;
}
value += char;
index += 1;
}
} else {
return null;
}
}
if (index < length) {
char = this.peek(index);
if (isIdentifierStart(char)) {
return null;
}
}
return {
type: Token.NumericLiteral,
value: value,
base: base,
isMalformed: !isFinite(value)
};
},
// Assumes previously parsed character was \ (=== '\\') and was not skipped.
scanEscapeSequence: function(checks) {
var allowNewLine = false;
var jump = 1;
this.skip();
var char = this.peek();
switch (char) {
case "'":
this.triggerAsync("warning", {
code: "W114",
line: this.line,
character: this.char,
data: [ "\\'" ]
}, checks, function() {return state.jsonMode; });
break;
case "b":
char = "\\b";
break;
case "f":
char = "\\f";
break;
case "n":
char = "\\n";
break;
case "r":
char = "\\r";
break;
case "t":
char = "\\t";
break;
case "0":
char = "\\0";
// Octal literals fail in strict mode.
// Check if the number is between 00 and 07.
var n = parseInt(this.peek(1), 10);
this.triggerAsync("warning", {
code: "W115",
line: this.line,
character: this.char
}, checks,
function() { return n >= 0 && n <= 7 && state.isStrict(); });
break;
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7":
char = "\\" + char;
this.triggerAsync("warning", {
code: "W115",
line: this.line,
character: this.char
}, checks,
function() { return state.isStrict(); });
break;
case "u":
var sequence = this.input.substr(1, 4);
var code = parseInt(sequence, 16);
if (!isHex(sequence)) {
// This condition unequivocally describes a syntax error.
// TODO: Re-factor as an "error" (not a "warning").
this.trigger("warning", {
code: "W052",
line: this.line,
character: this.char,
data: [ "u" + sequence ]
});
}
char = String.fromCharCode(code);
jump = 5;
break;
case "v":
this.triggerAsync("warning", {
code: "W114",
line: this.line,
character: this.char,
data: [ "\\v" ]
}, checks, function() { return state.jsonMode; });
char = "\v";
break;
case "x":
var x = parseInt(this.input.substr(1, 2), 16);
this.triggerAsync("warning", {
code: "W114",
line: this.line,
character: this.char,
data: [ "\\x-" ]
}, checks, function() { return state.jsonMode; });
char = String.fromCharCode(x);
jump = 3;
break;
case "\\":
char = "\\\\";
break;
case "\"":
char = "\\\"";
break;
case "/":
break;
case "":
allowNewLine = true;
char = "";
break;
}
return { char: char, jump: jump, allowNewLine: allowNewLine };
},
/*
* Extract a template literal out of the next sequence of characters
* and/or lines or return 'null' if its not possible. Since template
* literals can span across multiple lines, this method has to move
* the char pointer.
*/
scanTemplateLiteral: function(checks) {
var tokenType;
var value = "";
var ch;
var startLine = this.line;
var startChar = this.char;
var depth = this.templateStarts.length;
if (this.peek() === "`") {
if (!state.inES6(true)) {
this.triggerAsync(
"warning",
{
code: "W119",
line: this.line,
character: this.char,
data: ["template literal syntax", "6"]
},
checks,
function() { return true; }
);
}
// Template must start with a backtick.
tokenType = Token.TemplateHead;
this.templateStarts.push({ line: this.line, char: this.char });
depth = this.templateStarts.length;
this.skip(1);
this.pushContext(Context.Template);
} else if (this.inContext(Context.Template) && this.peek() === "}") {
// If we're in a template context, and we have a '}', lex a TemplateMiddle.
tokenType = Token.TemplateMiddle;
} else {
// Go lex something else.
return null;
}
while (this.peek() !== "`") {
while ((ch = this.peek()) === "") {
value += "\n";
if (!this.nextLine(checks)) {
// Unclosed template literal --- point to the starting "`"
var startPos = this.templateStarts.pop();
this.trigger("error", {
code: "E052",
line: startPos.line,
character: startPos.char
});
return {
type: tokenType,
value: value,
startLine: startLine,
startChar: startChar,
isUnclosed: true,
depth: depth,
context: this.popContext()
};
}
}
if (ch === '$' && this.peek(1) === '{') {
value += '${';
this.skip(2);
return {
type: tokenType,
value: value,
startLine: startLine,
startChar: startChar,
isUnclosed: false,
depth: depth,
context: this.currentContext()
};
} else if (ch === '\\') {
var escape = this.scanEscapeSequence(checks);
value += escape.char;
this.skip(escape.jump);
} else if (ch !== '`') {
// Otherwise, append the value and continue.
value += ch;
this.skip(1);
}
}
// Final value is either NoSubstTemplate or TemplateTail
tokenType = tokenType === Token.TemplateHead ? Token.NoSubstTemplate : Token.TemplateTail;
this.skip(1);
this.templateStarts.pop();
return {
type: tokenType,
value: value,
startLine: startLine,
startChar: startChar,
isUnclosed: false,
depth: depth,
context: this.popContext()
};
},
/*
* Extract a string out of the next sequence of characters and/or
* lines or return 'null' if its not possible. Since strings can
* span across multiple lines this method has to move the char
* pointer.
*
* This method recognizes pseudo-multiline JavaScript strings:
*
* var str = "hello\
* world";
*/
scanStringLiteral: function(checks) {
/*jshint loopfunc:true */
var quote = this.peek();
// String must start with a quote.
if (quote !== "\"" && quote !== "'") {
return null;
}
// In JSON strings must always use double quotes.
this.triggerAsync("warning", {
code: "W108",
line: this.line,
character: this.char // +1?
}, checks, function() { return state.jsonMode && quote !== "\""; });
var value = "";
var startLine = this.line;
var startChar = this.char;
var allowNewLine = false;
this.skip();
while (this.peek() !== quote) {
if (this.peek() === "") { // End Of Line
// If an EOL is not preceded by a backslash, show a warning
// and proceed like it was a legit multi-line string where
// author simply forgot to escape the newline symbol.
//
// Another approach is to implicitly close a string on EOL
// but it generates too many false positives.
if (!allowNewLine) {
// This condition unequivocally describes a syntax error.
// TODO: Emit error E029 and remove W112.
this.trigger("warning", {
code: "W112",
line: this.line,
character: this.char
});
} else {
allowNewLine = false;
// Otherwise show a warning if multistr option was not set.
// For JSON, show warning no matter what.
this.triggerAsync("warning", {
code: "W043",
line: this.line,
character: this.char
}, checks, function() { return !state.option.multistr; });
this.triggerAsync("warning", {
code: "W042",
line: this.line,
character: this.char
}, checks, function() { return state.jsonMode && state.option.multistr; });
}
// If we get an EOF inside of an unclosed string, show an
// error and implicitly close it at the EOF point.
if (!this.nextLine(checks)) {
return {
type: Token.StringLiteral,
value: value,
startLine: startLine,
startChar: startChar,
isUnclosed: true,
quote: quote
};
}
} else { // Any character other than End Of Line
allowNewLine = false;
var char = this.peek();
var jump = 1; // A length of a jump, after we're done
// parsing this character.
if (char < " ") {
// Warn about a control character in a string.
this.triggerAsync(
"warning",
{
code: "W113",
line: this.line,
character: this.char,
data: [ "<non-printable>" ]
},
checks,
function() { return true; }
);
}
// Special treatment for some escaped characters.
if (char === "\\") {
var parsed = this.scanEscapeSequence(checks);
char = parsed.char;
jump = parsed.jump;
allowNewLine = parsed.allowNewLine;
}
// If char is the empty string, end of the line has been reached. In
// this case, `this.char` should not be incremented so that warnings
// and errors reported in the subsequent loop iteration have the
// correct character column offset.
if (char !== "") {
value += char;
this.skip(jump);
}
}
}
this.skip();
return {
type: Token.StringLiteral,
value: value,
startLine: startLine,
startChar: startChar,
isUnclosed: false,
quote: quote
};
},
/*
* Extract a regular expression out of the next sequence of
* characters and/or lines or return 'null' if its not possible.
*
* This method is platform dependent: it accepts almost any
* regular expression values but then tries to compile and run
* them using system's RegExp object. This means that there are
* rare edge cases where one JavaScript engine complains about
* your regular expression while others don't.
*/
scanRegExp: function(checks) {
var index = 0;
var length = this.input.length;
var char = this.peek();
var value = char;
var body = "";
var groupReferences = [];
var allFlags = "";
var es5Flags = "";
var malformed = false;
var isCharSet = false;
var isCharSetRange = false;
var isGroup = false;
var isQuantifiable = false;
var hasInvalidQuantifier = false;
var escapedChars = "";
var hasUFlag = function() { return allFlags.indexOf("u") > -1; };
var escapeSequence;
var groupCount = 0;
var terminated, malformedDesc;
var scanRegexpEscapeSequence = function() {
var next, sequence;
index += 1;
char = this.peek(index);
if (reg.nonzeroDigit.test(char)) {
sequence = char;
next = this.peek(index + 1);
while (reg.nonzeroDigit.test(next) || next === "0") {
index += 1;
char = next;
sequence += char;
body += char;
value += char;
next = this.peek(index + 1);
}
groupReferences.push(Number(sequence));
return sequence;
}
escapedChars += char;
if (char === "u" && this.peek(index + 1) === "{") {
var x = index + 2;
sequence = "u{";
next = this.peek(x);
while (isHex(next)) {
sequence += next;
x += 1;
next = this.peek(x);
}
if (next !== "}") {
this.triggerAsync(
"error",
{
code: "E016",
line: this.line,
character: this.char,
data: [ "Invalid Unicode escape sequence" ]
},
checks,
hasUFlag
);
} else if (sequence.length > 2) {
sequence += "}";
body += sequence;
value += sequence;
index = x + 1;
return sequence;
}
}
// Unexpected control character
if (char < " ") {
malformed = true;
this.triggerAsync(
"warning",
{
code: "W048",
line: this.line,
character: this.char
},
checks,
function() { return true; }
);
}
// Unexpected escaped character
if (char === "<") {
malformed = true;
this.triggerAsync(
"warning",
{
code: "W049",
line: this.line,
character: this.char,
data: [ char ]
},
checks,
function() { return true; }
);
} else if (char === "0" && reg.decimalDigit.test(this.peek(index + 1))) {
this.triggerAsync(
"error",
{
code: "E016",
line: this.line,
character: this.char,
data: [ "Invalid decimal escape sequence" ]
},
checks,
hasUFlag
);
}
index += 1;
body += char;
value += char;
return char;
}.bind(this);
var checkQuantifier = function() {
var lookahead = index;
var lowerBound = "";
var upperBound = "";
var next;
next = this.peek(lookahead + 1);
while (reg.decimalDigit.test(next)) {
lookahead += 1;
lowerBound += next;
next = this.peek(lookahead + 1);
}
if (!lowerBound) {
return false;
}
if (next === "}") {
return true;
}
if (next !== ",") {
return false;
}
lookahead += 1;
next = this.peek(lookahead + 1);
while (reg.decimalDigit.test(next)) {
lookahead += 1;
upperBound += next;
next = this.peek(lookahead + 1);
}
if (next !== "}") {
return false;
}
if (upperBound) {
return Number(lowerBound) <= Number(upperBound);
}
return true;
}.bind(this);
var translateUFlag = function(body) {
// The BMP character to use as a replacement for astral symbols when
// translating an ES6 "u"-flagged pattern to an ES5-compatible
// approximation.
// Note: replacing with '\uFFFF' enables false positives in unlikely
// scenarios. For example, `[\u{1044f}-\u{10440}]` is an invalid pattern
// that would not be detected by this substitution.
var astralSubstitute = "\uFFFF";
return body
// Replace every Unicode escape sequence with the equivalent BMP
// character or a constant ASCII code point in the case of astral
// symbols. (See the above note on `astralSubstitute` for more
// information.)
.replace(/\\u\{([0-9a-fA-F]+)\}|\\u([a-fA-F0-9]{4})/g, function($0, $1, $2) {
var codePoint = parseInt($1 || $2, 16);
var literal;
if (codePoint > 0x10FFFF) {
malformed = true;
this.trigger("error", {
code: "E016",
line: this.line,
character: this.char,
data: [ char ]
});
return;
}
literal = String.fromCharCode(codePoint);
if (reg.regexpSyntaxChars.test(literal)) {
return $0;
}
if (codePoint <= 0xFFFF) {
return String.fromCharCode(codePoint);
}
return astralSubstitute;
}.bind(this))
// Replace each paired surrogate with a single ASCII symbol to avoid
// throwing on regular expressions that are only valid in combination
// with the "u" flag.
.replace(
/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
astralSubstitute
);
}.bind(this);
// Regular expressions must start with '/'
if (!this.prereg || char !== "/") {
return null;
}
index += 1;
terminated = false;
// Try to get everything in between slashes. A couple of
// cases aside (see scanRegexpEscapeSequence) we don't really
// care whether the resulting expression is valid or not.
// We will check that later using the RegExp object.
while (index < length) {
// Because an iteration of this loop may terminate in a number of
// distinct locations, `isCharSetRange` is re-set at the onset of
// iteration.
isCharSetRange &= char === "-";
char = this.peek(index);
value += char;
body += char;
if (isCharSet) {
if (char === "]") {
if (this.peek(index - 1) !== "\\" || this.peek(index - 2) === "\\") {
isCharSet = false;
}
} else if (char === "-") {
isCharSetRange = true;
}
}
if (char === "\\") {
escapeSequence = scanRegexpEscapeSequence();
if (isCharSet && (this.peek(index) === "-" || isCharSetRange) &&
reg.regexpCharClasses.test(escapeSequence)) {
this.triggerAsync(
"error",
{
code: "E016",
line: this.line,
character: this.char,
data: [ "Character class used in range" ]
},
checks,
hasUFlag
);
}
continue;
}
if (isCharSet) {
index += 1;
continue;
}
if (char === "{" && !hasInvalidQuantifier) {
hasInvalidQuantifier = !checkQuantifier();
}
if (char === "[") {
isCharSet = true;
index += 1;
continue;
} else if (char === "(") {
isGroup = true;
if (this.peek(index + 1) === "?" &&
(this.peek(index + 2) === "=" || this.peek(index + 2) === "!")) {
isQuantifiable = true;
}
} else if (char === ")") {
if (isQuantifiable) {
isQuantifiable = false;
if (reg.regexpQuantifiers.test(this.peek(index + 1))) {
this.triggerAsync(
"error",
{
code: "E016",
line: this.line,
character: this.char,
data: [ "Quantified quantifiable" ]
},
checks,
hasUFlag
);
}
} else {
groupCount += 1;
}
isGroup = false;
} else if (char === "/") {
body = body.substr(0, body.length - 1);
terminated = true;
index += 1;
break;
}
index += 1;
}
// A regular expression that was never closed is an
// error from which we cannot recover.
if (!terminated) {
this.trigger("error", {
code: "E015",
line: this.line,
character: this.from
});
return void this.trigger("fatal", {
line: this.line,
from: this.from
});
}
// Parse flags (if any).
while (index < length) {
char = this.peek(index);
if (!/[gimyus]/.test(char)) {
break;
}
if (char === "y") {
if (!state.inES6(true)) {
this.triggerAsync(
"warning",
{
code: "W119",
line: this.line,
character: this.char,
data: [ "Sticky RegExp flag", "6" ]
},
checks,
function() { return true; }
);
}
} else if (char === "u") {
if (!state.inES6(true)) {
this.triggerAsync(
"warning",
{
code: "W119",
line: this.line,
character: this.char,
data: [ "Unicode RegExp flag", "6" ]
},
checks,
function() { return true; }
);
}
var hasInvalidEscape = (function(groupReferences, groupCount, escapedChars, reg) {
var hasInvalidGroup = groupReferences.some(function(groupReference) {
if (groupReference > groupCount) {
return true;
}
});
if (hasInvalidGroup) {
return true;
}
return !escapedChars.split("").every(function(escapedChar) {
return escapedChar === "u" ||
escapedChar === "/" ||
escapedChar === "0" ||
reg.regexpControlEscapes.test(escapedChar) ||
reg.regexpCharClasses.test(escapedChar) ||
reg.regexpSyntaxChars.test(escapedChar);
});
}(groupReferences, groupCount, escapedChars, reg));
if (hasInvalidEscape) {
malformedDesc = "Invalid escape";
} else if (hasInvalidQuantifier) {
malformedDesc = "Invalid quantifier";
}
body = translateUFlag(body);
} else if (char === "s") {
if (!state.inES9()) {
this.triggerAsync(
"warning",
{
code: "W119",
line: this.line,
character: this.char,
data: [ "DotAll RegExp flag", "9" ]
},
checks,
function() { return true; }
);
}
if (value.indexOf("s") > -1) {
malformedDesc = "Duplicate RegExp flag";
}
} else {
es5Flags += char;
}
if (allFlags.indexOf(char) > -1) {
malformedDesc = "Duplicate RegExp flag";
}
allFlags += char;
value += char;
allFlags += char;
index += 1;
}
if (allFlags.indexOf("u") === -1) {
this.triggerAsync("warning", {
code: "W147",
line: this.line,
character: this.char
}, checks, function() { return state.option.regexpu; });
}
// Check regular expression for correctness.
try {
new RegExp(body, es5Flags);
} catch (err) {
/**
* Because JSHint relies on the current engine's RegExp parser to
* validate RegExp literals, the description (exposed as the "data"
* property on the error object) is platform dependent.
*/
malformedDesc = err.message;
}
if (malformedDesc) {
malformed = true;
this.trigger("error", {
code: "E016",
line: this.line,
character: this.char,
data: [ malformedDesc ]
});
} else if (allFlags.indexOf("s") > -1 && !reg.regexpDot.test(body)) {
this.trigger("warning", {
code: "W148",
line: this.line,
character: this.char
});
}
return {
type: Token.RegExp,
value: value,
isMalformed: malformed
};
},
/*
* Scan for any occurrence of non-breaking spaces. Non-breaking spaces
* can be mistakenly typed on OS X with option-space. Non UTF-8 web
* pages with non-breaking pages produce syntax errors.
*/
scanNonBreakingSpaces: function() {
return state.option.nonbsp ?
this.input.search(/(\u00A0)/) : -1;
},
/*
* Produce the next raw token or return 'null' if no tokens can be matched.
* This method skips over all space characters.
*/
next: function(checks) {
this.from = this.char;
// Move to the next non-space character.
while (reg.whitespace.test(this.peek())) {
this.from += 1;
this.skip();
}
// Methods that work with multi-line structures and move the
// character pointer.
var match = this.scanComments(checks) ||
this.scanStringLiteral(checks) ||
this.scanTemplateLiteral(checks);
if (match) {
return match;
}
// Methods that don't move the character pointer.
match =
this.scanRegExp(checks) ||
this.scanPunctuator() ||
this.scanKeyword() ||
this.scanIdentifier(checks) ||
this.scanNumericLiteral(checks);
if (match) {
this.skip(match.tokenLength || match.value.length);
return match;
}
// No token could be matched, give up.
return null;
},
/*
* Switch to the next line and reset all char pointers. Once
* switched, this method also checks for other minor warnings.
*/
nextLine: function(checks) {
var char;
if (this.line >= this.getLines().length) {
return false;
}
this.input = this.getLines()[this.line];
this.line += 1;
this.char = 1;
this.from = 1;
var inputTrimmed = this.input.trim();
var startsWith = function() {
return _.some(arguments, function(prefix) {
return inputTrimmed.indexOf(prefix) === 0;
});
};
var endsWith = function() {
return _.some(arguments, function(suffix) {
return inputTrimmed.indexOf(suffix, inputTrimmed.length - suffix.length) !== -1;
});
};
// If we are ignoring linter errors, replace the input with empty string
// if it doesn't already at least start or end a multi-line comment
if (this.ignoringLinterErrors === true) {
if (!startsWith("/*", "//") && !(this.inComment && endsWith("*/"))) {
this.input = "";
}
}
char = this.scanNonBreakingSpaces();
if (char >= 0) {
this.triggerAsync(
"warning",
{ code: "W125", line: this.line, character: char + 1 },
checks,
function() { return true; }
);
}
this.input = this.input.replace(/\t/g, state.tab);
// If there is a limit on line length, warn when lines get too
// long.
if (!this.ignoringLinterErrors && state.option.maxlen &&
state.option.maxlen < this.input.length) {
var inComment = this.inComment ||
startsWith.call(inputTrimmed, "//") ||
startsWith.call(inputTrimmed, "/*");
var shouldTriggerError = !inComment || !reg.maxlenException.test(inputTrimmed);
if (shouldTriggerError) {
this.triggerAsync(
"warning",
{ code: "W101", line: this.line, character: this.input.length },
checks,
function() { return true; }
);
}
}
return true;
},
/*
* Produce the next token. This function is called by advance() to get
* the next token. It returns a token in a JSLint-compatible format.
*/
token: function() {
/*jshint loopfunc:true */
var checks = asyncTrigger();
var token;
// Produce a token object.
var create = function(type, value, isProperty, token) {
/*jshint validthis:true */
var obj;
if (type !== "(endline)" && type !== "(end)") {
this.prereg = false;
}
if (type === "(punctuator)") {
switch (value) {
case ".":
case ")":
case "~":
case "#":
case "]":
case "}":
case "++":
case "--":
this.prereg = false;
break;
default:
this.prereg = true;
}
obj = Object.create(state.syntax[value] || state.syntax["(error)"]);
}
if (type === "(identifier)") {
if (value === "return" || value === "case" || value === "yield" ||
value === "typeof" || value === "instanceof" || value === "void" ||
value === "await") {
this.prereg = true;
}
if (_.has(state.syntax, value)) {
obj = Object.create(state.syntax[value] || state.syntax["(error)"]);
}
}
if (type === "(template)" || type === "(template middle)") {
this.prereg = true;
}
if (!obj) {
obj = Object.create(state.syntax[type]);
}
obj.identifier = (type === "(identifier)");
obj.type = obj.type || type;
obj.value = value;
obj.line = this.line;
obj.character = this.char;
obj.from = this.from;
if (obj.identifier && token) obj.raw_text = token.text || token.value;
if (token && token.startLine && token.startLine !== this.line) {
obj.startLine = token.startLine;
}
if (token && token.context) {
// Context of current token
obj.context = token.context;
}
if (token && token.depth) {
// Nested template depth
obj.depth = token.depth;
}
if (token && token.isUnclosed) {
// Mark token as unclosed string / template literal
obj.isUnclosed = token.isUnclosed;
}
if (isProperty && obj.identifier) {
obj.isProperty = isProperty;
}
obj.check = checks.check;
return obj;
}.bind(this);
for (;;) {
if (!this.input.length) {
if (this.nextLine(checks)) {
return create("(endline)", "");
}
if (this.exhausted) {
return null;
}
this.exhausted = true;
return create("(end)", "");
}
token = this.next(checks);
if (!token) {
if (this.input.length) {
// Unexpected character.
this.trigger("error", {
code: "E024",
line: this.line,
character: this.char,
data: [ this.peek() ]
});
this.input = "";
}
continue;
}
switch (token.type) {
case Token.StringLiteral:
this.triggerAsync("String", {
line: this.line,
char: this.char,
from: this.from,
startLine: token.startLine,
startChar: token.startChar,
value: token.value,
quote: token.quote
}, checks, function() { return true; });
return create("(string)", token.value, null, token);
case Token.TemplateHead:
this.trigger("TemplateHead", {
line: this.line,
char: this.char,
from: this.from,
startLine: token.startLine,
startChar: token.startChar,
value: token.value
});
return create("(template)", token.value, null, token);
case Token.TemplateMiddle:
this.trigger("TemplateMiddle", {
line: this.line,
char: this.char,
from: this.from,
startLine: token.startLine,
startChar: token.startChar,
value: token.value
});
return create("(template middle)", token.value, null, token);
case Token.TemplateTail:
this.trigger("TemplateTail", {
line: this.line,
char: this.char,
from: this.from,
startLine: token.startLine,
startChar: token.startChar,
value: token.value
});
return create("(template tail)", token.value, null, token);
case Token.NoSubstTemplate:
this.trigger("NoSubstTemplate", {
line: this.line,
char: this.char,
from: this.from,
startLine: token.startLine,
startChar: token.startChar,
value: token.value
});
return create("(no subst template)", token.value, null, token);
case Token.Identifier:
this.triggerAsync("Identifier", {
line: this.line,
char: this.char,
from: this.from,
name: token.value,
raw_name: token.text,
isProperty: state.tokens.curr.id === "."
}, checks, function() { return true; });
/* falls through */
case Token.Keyword:
return create("(identifier)", token.value, state.tokens.curr.id === ".", token);
case Token.NumericLiteral:
if (token.isMalformed) {
// This condition unequivocally describes a syntax error.
// TODO: Re-factor as an "error" (not a "warning").
this.trigger("warning", {
code: "W045",
line: this.line,
character: this.char,
data: [ token.value ]
});
}
this.triggerAsync("warning", {
code: "W114",
line: this.line,
character: this.char,
data: [ "0x-" ]
}, checks, function() { return token.base === 16 && state.jsonMode; });
this.triggerAsync("warning", {
code: "W115",
line: this.line,
character: this.char
}, checks, function() {
return state.isStrict() && token.base === 8 && token.isLegacy;
});
this.trigger("Number", {
line: this.line,
char: this.char,
from: this.from,
value: token.value,
base: token.base,
isMalformed: token.isMalformed
});
return create("(number)", token.value);
case Token.RegExp:
return create("(regexp)", token.value);
case Token.Comment:
if (token.isSpecial) {
return {
id: '(comment)',
value: token.value,
body: token.body,
type: token.commentType,
isSpecial: token.isSpecial,
line: this.line,
character: this.char,
from: this.from
};
}
break;
default:
return create("(punctuator)", token.value);
}
}
}
};
exports.Lexer = Lexer;
exports.Context = Context;
},{"../data/ascii-identifier-data.js":1,"../data/es5-identifier-names.js":2,"../data/non-ascii-identifier-part-only.js":3,"../data/non-ascii-identifier-start.js":4,"./reg.js":22,"./state.js":24,"events":9,"lodash":16}],18:[function(require,module,exports){
"use strict";
var _ = require("lodash");
var errors = {
// JSHint options
E001: "Bad {a}option: '{b}'.",
E002: "Bad option value.",
// JSHint input
E003: "Expected a JSON value.",
E004: "Input is neither a string nor an array of strings.",
E005: "Input is empty.",
E006: "Unexpected early end of program.",
// Strict mode
E007: "Missing \"use strict\" statement.",
E008: "Strict violation.",
E009: "Option 'validthis' can't be used in a global scope.",
E010: "'with' is not allowed in strict mode.",
// Constants
E011: "'{a}' has already been declared.",
E012: "const '{a}' is initialized to 'undefined'.",
E013: "Attempting to override '{a}' which is a constant.",
// Regular expressions
E014: "A regular expression literal can be confused with '/='.",
E015: "Unclosed regular expression.",
E016: "Invalid regular expression.",
// Tokens
E017: "Unclosed comment.",
E018: "Unbegun comment.",
E019: "Unmatched '{a}'.",
E020: "Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.",
E021: "Expected '{a}' and instead saw '{b}'.",
E022: "Line breaking error '{a}'.",
E023: "Missing '{a}'.",
E024: "Unexpected '{a}'.",
E025: "Missing ':' on a case clause.",
E026: "Missing '}' to match '{' from line {a}.",
E027: "Missing ']' to match '[' from line {a}.",
E028: "Illegal comma.",
E029: "Unclosed string.",
// Everything else
E030: "Expected an identifier and instead saw '{a}'.",
E031: "Bad assignment.", // FIXME: Rephrase
E032: "Expected a small integer or 'false' and instead saw '{a}'.",
E033: "Expected an operator and instead saw '{a}'.",
E034: "get/set are ES5 features.",
E035: "Missing property name.",
E036: "Expected to see a statement and instead saw a block.",
E037: null,
E038: null,
E039: "Function declarations are not invocable. Wrap the whole function invocation in parens.",
E040: "Each value should have its own case label.",
E041: "Unrecoverable syntax error.",
E042: "Stopping.",
E043: "Too many errors.",
E044: null,
E045: "Invalid for each loop.",
E046: "Yield expressions may only occur within generator functions.",
E047: null,
E048: "{a} declaration not directly within block.",
E049: "A {a} cannot be named '{b}'.",
E050: "Mozilla requires the yield expression to be parenthesized here.",
E051: null,
E052: "Unclosed template literal.",
E053: "{a} declarations are only allowed at the top level of module scope.",
E054: "Class properties must be methods. Expected '(' but instead saw '{a}'.",
E055: "The '{a}' option cannot be set after any executable code.",
E056: "'{a}' was used before it was declared, which is illegal for '{b}' variables.",
E057: "Invalid meta property: '{a}.{b}'.",
E058: "Missing semicolon.",
E059: "Incompatible values for the '{a}' and '{b}' linting options.",
E060: "Non-callable values cannot be used as the second operand to instanceof.",
E061: "Invalid position for 'yield' expression (consider wrapping in parenthesis).",
E062: "Rest parameter does not a support default value.",
E063: "Super property may only be used within method bodies.",
E064: "Super call may only be used within class method bodies.",
E065: "Functions defined outside of strict mode with non-simple parameter lists may not " +
"enable strict mode.",
E066: "Asynchronous iteration is only available with for-of loops."
};
var warnings = {
W001: "'hasOwnProperty' is a really bad name.",
W002: "Value of '{a}' may be overwritten in IE 8 and earlier.",
W003: "'{a}' was used before it was defined.",
W004: "'{a}' is already defined.",
W005: "A dot following a number can be confused with a decimal point.",
W006: "Confusing minuses.",
W007: "Confusing plusses.",
W008: "A leading decimal point can be confused with a dot: '{a}'.",
W009: "The array literal notation [] is preferable.",
W010: "The object literal notation {} is preferable.",
W011: null,
W012: null,
W013: null,
W014: "Misleading line break before '{a}'; readers may interpret this as an expression boundary.",
W015: null,
W016: "Unexpected use of '{a}'.",
W017: "Bad operand.",
W018: "Confusing use of '{a}'.",
W019: "Use the isNaN function to compare with NaN.",
W020: "Read only.",
W021: "Reassignment of '{a}', which is a {b}. " +
"Use 'var' or 'let' to declare bindings that may change.",
W022: "Do not assign to the exception parameter.",
W023: null,
W024: "Expected an identifier and instead saw '{a}' (a reserved word).",
W025: "Missing name in function declaration.",
W026: "Inner functions should be listed at the top of the outer function.",
W027: "Unreachable '{a}' after '{b}'.",
W028: "Label '{a}' on {b} statement.",
W030: "Expected an assignment or function call and instead saw an expression.",
W031: "Do not use 'new' for side effects.",
W032: "Unnecessary semicolon.",
W033: "Missing semicolon.",
W034: "Unnecessary directive \"{a}\".",
W035: "Empty block.",
W036: "Unexpected /*member '{a}'.",
W037: "'{a}' is a statement label.",
W038: "'{a}' used out of scope.",
W039: null,
W040: "If a strict mode function is executed using function invocation, " +
"its 'this' value will be undefined.",
W041: null,
W042: "Avoid EOL escaping.",
W043: "Bad escaping of EOL. Use option multistr if needed.",
W044: "Bad or unnecessary escaping.", /* TODO(caitp): remove W044 */
W045: "Bad number '{a}'.",
W046: "Don't use extra leading zeros '{a}'.",
W047: "A trailing decimal point can be confused with a dot: '{a}'.",
W048: "Unexpected control character in regular expression.",
W049: "Unexpected escaped character '{a}' in regular expression.",
W050: "JavaScript URL.",
W051: "Variables should not be deleted.",
W052: "Unexpected '{a}'.",
W053: "Do not use {a} as a constructor.",
W054: "The Function constructor is a form of eval.",
W055: "A constructor name should start with an uppercase letter.",
W056: "Bad constructor.",
W057: "Weird construction. Is 'new' necessary?",
W058: "Missing '()' invoking a constructor.",
W059: "Avoid arguments.{a}.",
W060: "document.write can be a form of eval.",
W061: "eval can be harmful.",
W062: "Wrap an immediate function invocation in parens " +
"to assist the reader in understanding that the expression " +
"is the result of a function, and not the function itself.",
W063: "Math is not a function.",
W064: "Missing 'new' prefix when invoking a constructor.",
W065: "Missing radix parameter.",
W066: "Implied eval. Consider passing a function instead of a string.",
W067: "Bad invocation.",
W068: "Wrapping non-IIFE function literals in parens is unnecessary.",
W069: "['{a}'] is better written in dot notation.",
W070: "Extra comma. (it breaks older versions of IE)",
W071: "This function has too many statements. ({a})",
W072: "This function has too many parameters. ({a})",
W073: "Blocks are nested too deeply. ({a})",
W074: "This function's cyclomatic complexity is too high. ({a})",
W075: "Duplicate {a} '{b}'.",
W076: "Unexpected parameter '{a}' in get {b} function.",
W077: "Expected a single parameter in set {a} function.",
W078: "Setter is defined without getter.",
W079: "Redefinition of '{a}'.",
W080: "It's not necessary to initialize '{a}' to 'undefined'.",
W081: null,
W082: "Function declarations should not be placed in blocks. " +
"Use a function expression or move the statement to the top of " +
"the outer function.",
W083: "Functions declared within loops referencing an outer scoped " +
"variable may lead to confusing semantics. ({a})",
W084: "Expected a conditional expression and instead saw an assignment.",
W085: "Don't use 'with'.",
W086: "Expected a 'break' statement before '{a}'.",
W087: "Forgotten 'debugger' statement?",
W088: "Creating global 'for' variable. Should be 'for (var {a} ...'.",
W089: "The body of a for in should be wrapped in an if statement to filter " +
"unwanted properties from the prototype.",
W090: "'{a}' is not a statement label.",
W091: null,
W093: "Did you mean to return a conditional instead of an assignment?",
W094: "Unexpected comma.",
W095: "Expected a string and instead saw {a}.",
W096: "The '{a}' key may produce unexpected results.",
W097: "Use the function form of \"use strict\".",
W098: "'{a}' is defined but never used.",
W099: null,
W100: null,
W101: "Line is too long.",
W102: null,
W103: "The '{a}' property is deprecated.",
W104: "'{a}' is available in ES{b} (use 'esversion: {b}') or Mozilla JS extensions (use moz).",
W105: null,
W106: "Identifier '{a}' is not in camel case.",
W107: "Script URL.",
W108: "Strings must use doublequote.",
W109: "Strings must use singlequote.",
W110: "Mixed double and single quotes.",
W112: "Unclosed string.",
W113: "Control character in string: {a}.",
W114: "Avoid {a}.",
W115: "Octal literals are not allowed in strict mode.",
W116: "Expected '{a}' and instead saw '{b}'.",
W117: "'{a}' is not defined.",
W118: "'{a}' is only available in Mozilla JavaScript extensions (use moz option).",
W119: "'{a}' is only available in ES{b} (use 'esversion: {b}').",
W120: "You might be leaking a variable ({a}) here.",
W121: "Extending prototype of native object: '{a}'.",
W122: "Invalid typeof value '{a}'",
W123: "'{a}' is already defined in outer scope.",
W124: "A generator function should contain at least one yield expression.",
W125: "This line contains non-breaking spaces: http://jshint.com/docs/options/#nonbsp",
W126: "Unnecessary grouping operator.",
W127: "Unexpected use of a comma operator.",
W128: "Empty array elements require elision=true.",
W129: "'{a}' is defined in a future version of JavaScript. Use a " +
"different variable name to avoid migration issues.",
W130: "Invalid element after rest element.",
W131: "Invalid parameter after rest parameter.",
W132: "`var` declarations are forbidden. Use `let` or `const` instead.",
W133: "Invalid for-{a} loop left-hand-side: {b}.",
W134: "The '{a}' option is only available when linting ECMAScript {b} code.",
W135: "{a} may not be supported by non-browser environments.",
W136: "'{a}' must be in function scope.",
W137: "Empty destructuring: this is unnecessary and can be removed.",
W138: "Regular parameters should not come after default parameters.",
W139: "Function expressions should not be used as the second operand to instanceof.",
W140: "Missing comma.",
W141: "Empty {a}: this is unnecessary and can be removed.",
W142: "Empty {a}: consider replacing with `import '{b}';`.",
W143: "Assignment to properties of a mapped arguments object may cause " +
"unexpected changes to formal parameters.",
W144: "'{a}' is a non-standard language feature. Enable it using the '{b}' unstable option.",
W145: "Superfluous 'case' clause.",
W146: "Unnecessary `await` expression.",
W147: "Regular expressions should include the 'u' flag.",
W148: "Unnecessary RegExp 's' flag."
};
var info = {
I001: "Comma warnings can be turned off with 'laxcomma'.",
I002: null,
I003: "ES5 option is now set per default"
};
exports.errors = {};
exports.warnings = {};
exports.info = {};
_.each(errors, function(desc, code) {
exports.errors[code] = { code: code, desc: desc };
});
_.each(warnings, function(desc, code) {
exports.warnings[code] = { code: code, desc: desc };
});
_.each(info, function(desc, code) {
exports.info[code] = { code: code, desc: desc };
});
},{"lodash":16}],19:[function(require,module,exports){
/**
* The NameStack class is used to approximate function name inference as
* introduced by ECMAScript 2015. In that edition, the `name` property of
* function objects is set according to the function's syntactic form. For
* certain forms, this value depends on values available to the runtime during
* execution. For example:
*
* var fnName = function() {};
*
* In the program code above, the function object's `name` property is set to
* `"fnName"` during execution.
*
* This general "name inference" behavior extends to a number of additional
* syntactic forms, not all of which can be implemented statically. `NameStack`
* is a support class representing a "best-effort" attempt to implement the
* specified behavior in cases where this may be done statically.
*
* For more information on this behavior, see the following blog post:
* https://bocoup.com/blog/whats-in-a-function-name
*/
"use strict";
function NameStack() {
this._stack = [];
}
Object.defineProperty(NameStack.prototype, "length", {
get: function() {
return this._stack.length;
}
});
/**
* Create a new entry in the stack. Useful for tracking names across
* expressions.
*/
NameStack.prototype.push = function() {
this._stack.push(null);
};
/**
* Discard the most recently-created name on the stack.
*/
NameStack.prototype.pop = function() {
this._stack.pop();
};
/**
* Update the most recent name on the top of the stack.
*
* @param {object} token The token to consider as the source for the most
* recent name.
*/
NameStack.prototype.set = function(token) {
this._stack[this.length - 1] = token;
};
/**
* Generate a string representation of the most recent name.
*
* @returns {string}
*/
NameStack.prototype.infer = function() {
var nameToken = this._stack[this.length - 1];
var prefix = "";
var type;
// During expected operation, the topmost entry on the stack will only
// reflect the current function's name when the function is declared without
// the `function` keyword (i.e. for in-line accessor methods). In other
// cases, the `function` expression itself will introduce an empty entry on
// the top of the stack, and this should be ignored.
if (!nameToken || nameToken.type === "class") {
nameToken = this._stack[this.length - 2];
}
if (!nameToken) {
return "(empty)";
}
type = nameToken.type;
if (type !== "(string)" && type !== "(number)" && type !== "(identifier)" && type !== "default") {
return "(expression)";
}
if (nameToken.accessorType) {
prefix = nameToken.accessorType + " ";
}
return prefix + nameToken.value;
};
module.exports = NameStack;
},{}],20:[function(require,module,exports){
"use strict";
// These are the JSHint boolean options.
exports.bool = {
enforcing: {
/**
* This option prohibits the use of bitwise operators such as `^` (XOR),
* `|` (OR) and others. Bitwise operators are very rare in JavaScript
* programs and quite often `&` is simply a mistyped `&&`.
*/
bitwise : true,
/**
*
* This options prohibits overwriting prototypes of native objects such as
* `Array`, `Date` and so on.
*
* // jshint freeze:true
* Array.prototype.count = function (value) { return 4; };
* // -> Warning: Extending prototype of native object: 'Array'.
*/
freeze : true,
/**
* This option allows you to force all variable names to use either
* camelCase style or UPPER_CASE with underscores.
*
* @deprecated JSHint is limiting its scope to issues of code correctness.
* If you would like to enforce rules relating to code style,
* check out [the JSCS
* project](https://github.com/jscs-dev/node-jscs).
*/
camelcase : true,
/**
* This option requires you to always put curly braces around blocks in
* loops and conditionals. JavaScript allows you to omit curly braces when
* the block consists of only one statement, for example:
*
* while (day)
* shuffle();
*
* However, in some circumstances, it can lead to bugs (you'd think that
* `sleep()` is a part of the loop while in reality it is not):
*
* while (day)
* shuffle();
* sleep();
*/
curly : true,
/**
* This options prohibits the use of `==` and `!=` in favor of `===` and
* `!==`. The former try to coerce values before comparing them which can
* lead to some unexpected results. The latter don't do any coercion so
* they are generally safer. If you would like to learn more about type
* coercion in JavaScript, we recommend [Truth, Equality and
* JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/)
* by Angus Croll.
*/
eqeqeq : true,
/**
* This option enables warnings about the use of identifiers which are
* defined in future versions of JavaScript. Although overwriting them has
* no effect in contexts where they are not implemented, this practice can
* cause issues when migrating codebases to newer versions of the language.
*/
futurehostile: true,
/**
* This option tells JSHint that your code needs to adhere to ECMAScript 3
* specification. Use this option if you need your program to be executable
* in older browserssuch as Internet Explorer 6/7/8/9and other legacy
* JavaScript environments.
*
* @deprecated Use `esversion: 3` instead.
*/
es3 : true,
/**
* This option enables syntax first defined in [the ECMAScript 5.1
* specification](http://es5.github.io/). This includes allowing reserved
* keywords as object properties.
*
* @deprecated Use `esversion: 5` instead.
*/
es5 : true,
/**
* This option requires all `for in` loops to filter object's items. The
* for in statement allows for looping through the names of all of the
* properties of an object including those inherited through the prototype
* chain. This behavior can lead to unexpected items in your object so it
* is generally safer to always filter inherited properties out as shown in
* the example:
*
* for (key in obj) {
* if (obj.hasOwnProperty(key)) {
* // We are sure that obj[key] belongs to the object and was not inherited.
* }
* }
*
* For more in-depth understanding of `for in` loops in JavaScript, read
* [Exploring JavaScript for-in
* loops](http://javascriptweblog.wordpress.com/2011/01/04/exploring-javascript-for-in-loops/)
* by Angus Croll.
*/
forin : true,
/**
* This option prohibits the use of immediate function invocations without
* wrapping them in parentheses. Wrapping parentheses assists readers of
* your code in understanding that the expression is the result of a
* function, and not the function itself.
*
* @deprecated JSHint is limiting its scope to issues of code correctness.
* If you would like to enforce rules relating to code style,
* check out [the JSCS
* project](https://github.com/jscs-dev/node-jscs).
*/
immed : true,
/**
* This option prohibits unnecessary clauses within `switch` statements,
* e.g.
*
* switch (x) {
* case 1:
* default:
* z();
* }
*
* While clauses like these are techincally valid, they do not effect
* program behavior and may indicate an erroneous refactoring.
*/
leanswitch : true,
/**
* This option requires you to capitalize names of constructor functions.
* Capitalizing functions that are intended to be used with `new` operator
* is just a convention that helps programmers to visually distinguish
* constructor functions from other types of functions to help spot
* mistakes when using `this`.
*
* Not doing so won't break your code in any browsers or environments but
* it will be a bit harder to figure outby reading the codeif the
* function was supposed to be used with or without new. And this is
* important because when the function that was intended to be used with
* `new` is used without it, `this` will point to the global object instead
* of a new object.
*
* @deprecated JSHint is limiting its scope to issues of code correctness.
* If you would like to enforce rules relating to code style,
* check out [the JSCS
* project](https://github.com/jscs-dev/node-jscs).
*/
newcap : true,
/**
* This option prohibits the use of `arguments.caller` and
* `arguments.callee`. Both `.caller` and `.callee` make quite a few
* optimizations impossible so they were deprecated in future versions of
* JavaScript. In fact, ECMAScript 5 forbids the use of `arguments.callee`
* in strict mode.
*/
noarg : true,
/**
* This option prohibits the use of the comma operator. When misused, the
* comma operator can obscure the value of a statement and promote
* incorrect code.
*/
nocomma : true,
/**
* This option warns when you have an empty block in your code. JSLint was
* originally warning for all empty blocks and we simply made it optional.
* There were no studies reporting that empty blocks in JavaScript break
* your code in any way.
*
* @deprecated JSHint is limiting its scope to issues of code correctness.
* If you would like to enforce rules relating to code style,
* check out [the JSCS
* project](https://github.com/jscs-dev/node-jscs).
*/
noempty : true,
/**
* This option warns about "non-breaking whitespace" characters. These
* characters can be entered with option-space on Mac computers and have a
* potential of breaking non-UTF8 web pages.
*/
nonbsp : true,
/**
* This option prohibits the use of constructor functions for side-effects.
* Some people like to call constructor functions without assigning its
* result to any variable:
*
* new MyConstructor();
*
* There is no advantage in this approach over simply calling
* `MyConstructor` since the object that the operator `new` creates isn't
* used anywhere so you should generally avoid constructors like this one.
*/
nonew : true,
/**
* Async functions resolve on their return value. In most cases, this makes
* returning the result of an AwaitExpression (which is itself a Promise
* instance) unnecessary. For clarity, it's often preferable to return the
* result of the asynchronous operation directly. The notable exception is
* within the `try` clause of a TryStatement--for more, see "await vs
* return vs return await":
*
* https://jakearchibald.com/2017/await-vs-return-vs-return-await/
*/
noreturnawait: true,
/**
* This option enables warnings for regular expressions which do not
* include the "u" flag. The "u" flag extends support for Unicode and also
* enables more strict parsing rules. JSHint will enforce these rules even
* if it is executed in a JavaScript engine which does not support the "u"
* flag.
*/
regexpu : true,
/**
* This option prohibits the use of explicitly undeclared variables. This
* option is very useful for spotting leaking and mistyped variables.
*
* // jshint undef:true
*
* function test() {
* var myVar = 'Hello, World';
* console.log(myvar); // Oops, typoed here. JSHint with undef will complain
* }
*
* If your variable is defined in another file, you can use the `global`
* directive to tell JSHint about it.
*/
undef : true,
/**
* This option prohibits the use of the grouping operator when it is not
* strictly required. Such usage commonly reflects a misunderstanding of
* unary operators, for example:
*
* // jshint singleGroups: true
*
* delete(obj.attr); // Warning: Unnecessary grouping operator.
*/
singleGroups: false,
/**
* When set to true, the use of VariableStatements are forbidden.
* For example:
*
* // jshint varstmt: true
*
* var a; // Warning: `var` declarations are forbidden. Use `let` or `const` instead.
*/
varstmt: false,
/**
* This option is a short hand for the most strict JSHint configuration as
* available in JSHint version 2.6.3. It enables all enforcing options and
* disables all relaxing options that were defined in that release.
*
* @deprecated The option cannot be maintained without automatically opting
* users in to new features. This can lead to unexpected
* warnings/errors in when upgrading between minor versions of
* JSHint.
*/
enforceall : false,
/**
* This option warns when a comma is not placed after the last element in an
* array or object literal. Due to bugs in old versions of IE, trailing
* commas used to be discouraged, but since ES5 their semantics were
* standardized. (See
* [#11.1.4](http://www.ecma-international.org/ecma-262/5.1/#sec-11.1.4) and
* [#11.1.5](http://www.ecma-international.org/ecma-262/5.1/#sec-11.1.5).)
* Now, they help to prevent the same [visual
* ambiguities](http://www.ecma-international.org/ecma-262/5.1/#sec-7.9.2)
* that the strict usage of semicolons helps prevent.
*
* For example, this code might have worked last Tuesday:
*
* [
* b + c
* ].forEach(print);
*
* But if one adds an element to the array and forgets to compensate for the
* missing comma, no syntax error is thrown, and a linter cannot determine
* if this was a mistake or an intentional function invocation.
*
* [
* b + c
* (d + e)
* ].forEach(print);
*
* If one always appends a list item with a comma, this ambiguity cannot
* occur:
*
* [
* b + c,
* ].forEach(print);
*
* [
* b + c,
* (d + e),
* ].forEach(print);
*/
trailingcomma: false
},
relaxing: {
/**
* This option suppresses warnings about missing semicolons. There is a lot
* of FUD about semicolon spread by quite a few people in the community.
* The common myths are that semicolons are required all the time (they are
* not) and that they are unreliable. JavaScript has rules about semicolons
* which are followed by *all* browsers so it is up to you to decide
* whether you should or should not use semicolons in your code.
*
* For more information about semicolons in JavaScript read [An Open Letter
* to JavaScript Leaders Regarding
* Semicolons](http://blog.izs.me/post/2353458699/an-open-letter-to-javascript-leaders-regarding)
* by Isaac Schlueter and [JavaScript Semicolon
* Insertion](http://inimino.org/~inimino/blog/javascript_semicolons).
*/
asi : true,
/**
* This option suppresses warnings about multi-line strings. Multi-line
* strings can be dangerous in JavaScript because all hell breaks loose if
* you accidentally put a whitespace in between the escape character (`\`)
* and a new line.
*
* Note that even though this option allows correct multi-line strings, it
* still warns about multi-line strings without escape characters or with
* anything in between the escape character and a whitespace.
*
* // jshint multistr:true
*
* var text = "Hello\
* World"; // All good.
*
* text = "Hello
* World"; // Warning, no escape character.
*
* text = "Hello\
* World"; // Warning, there is a space after \
*
* @deprecated JSHint is limiting its scope to issues of code correctness.
* If you would like to enforce rules relating to code style,
* check out [the JSCS
* project](https://github.com/jscs-dev/node-jscs).
*/
multistr : true,
/**
* This option suppresses warnings about the `debugger` statements in your
* code.
*/
debug : true,
/**
* This option suppresses warnings about the use of assignments in cases
* where comparisons are expected. More often than not, code like `if (a =
* 10) {}` is a typo. However, it can be useful in cases like this one:
*
* for (var i = 0, person; person = people[i]; i++) {}
*
* You can silence this error on a per-use basis by surrounding the assignment
* with parenthesis, such as:
*
* for (var i = 0, person; (person = people[i]); i++) {}
*/
boss : true,
/**
* This option suppresses warnings about the use of `eval`. The use of
* `eval` is discouraged because it can make your code vulnerable to
* various injection attacks and it makes it hard for JavaScript
* interpreter to do certain optimizations.
*/
evil : true,
/**
* This option suppresses warnings about declaring variables inside
* of control structures while accessing them later from the outside.
* Even though identifiers declared with `var` have two real scopesglobal
* and functionsuch practice leads to confusion among people new to
* the language and hard-to-debug bugs. This is why, by default, JSHint
* warns about variables that are used outside of their intended scope.
*
* function test() {
* if (true) {
* var x = 0;
* }
*
* x += 1; // Default: 'x' used out of scope.
* // No warning when funcscope:true
* }
*/
funcscope : true,
/**
* This option suppresses warnings about the use of global strict mode.
* Global strict mode can break third-party widgets so it is not
* recommended.
*
* For more info about strict mode see the `strict` option.
*
* @deprecated Use `strict: "global"`.
*/
globalstrict: true,
/**
* This option suppresses warnings about the `__iterator__` property. This
* property is not supported by all browsers so use it carefully.
*/
iterator : true,
/**
* This option suppresses warnings about invalid `typeof` operator values.
* This operator has only [a limited set of possible return
* values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof).
* By default, JSHint warns when you compare its result with an invalid
* value which often can be a typo.
*
* // 'fuction' instead of 'function'
* if (typeof a == "fuction") { // Invalid typeof value 'fuction'
* // ...
* }
*
* Do not use this option unless you're absolutely sure you don't want
* these checks.
*/
notypeof : true,
/**
* This option prohibits the use of unary increment and decrement
* operators. Some people think that `++` and `--` reduces the quality of
* their coding styles and there are programming languagessuch as
* Pythonthat go completely without these operators.
*/
plusplus : true,
/**
* This option suppresses warnings about the `__proto__` property.
*/
proto : true,
/**
* This option suppresses warnings about the use of script-targeted
* URLssuch as `javascript:...`.
*/
scripturl : true,
/**
* This option suppresses warnings about using `[]` notation when it can be
* expressed in dot notation: `person['name']` vs. `person.name`.
*
* @deprecated JSHint is limiting its scope to issues of code correctness.
* If you would like to enforce rules relating to code style,
* check out [the JSCS
* project](https://github.com/jscs-dev/node-jscs).
*/
sub : true,
/**
* This option suppresses warnings about "weird" constructions like
* `new function () { ... }` and `new Object;`. Such constructions are
* sometimes used to produce singletons in JavaScript:
*
* var singleton = new function() {
* var privateVar;
*
* this.publicMethod = function () {}
* this.publicMethod2 = function () {}
* };
*/
supernew : true,
/**
* This option suppresses most of the warnings about possibly unsafe line
* breakings in your code. It doesn't suppress warnings about comma-first
* coding style. To suppress those you have to use `laxcomma` (see below).
*
* @deprecated JSHint is limiting its scope to issues of code correctness.
* If you would like to enforce rules relating to code style,
* check out [the JSCS
* project](https://github.com/jscs-dev/node-jscs).
*/
laxbreak : true,
/**
* This option suppresses warnings about comma-first coding style:
*
* var obj = {
* name: 'Anton'
* , handle: 'valueof'
* , role: 'SW Engineer'
* };
*
* @deprecated JSHint is limiting its scope to issues of code correctness.
* If you would like to enforce rules relating to code style,
* check out [the JSCS
* project](https://github.com/jscs-dev/node-jscs).
*/
laxcomma : true,
/**
* This option suppresses warnings about possible strict violations when
* the code is running in strict mode and you use `this` in a
* non-constructor function. You should use this optionin a function scope
* onlywhen you are positive that your use of `this` is valid in the
* strict mode (for example, if you call your function using
* `Function.call`).
*
* **Note:** This option can be used only inside of a function scope.
* JSHint will fail with an error if you will try to set this option
* globally.
*/
validthis : true,
/**
* This option suppresses warnings about the use of the `with` statement.
* The semantics of the `with` statement can cause confusion among
* developers and accidental definition of global variables.
*
* More info:
*
* * [with Statement Considered
* Harmful](http://yuiblog.com/blog/2006/04/11/with-statement-considered-harmful/)
*/
withstmt : true,
/**
* This options tells JSHint that your code uses Mozilla JavaScript
* extensions. Unless you develop specifically for the Firefox web browser
* you don't need this option.
*
* More info:
*
* * [New in JavaScript
* 1.7](https://developer.mozilla.org/en-US/docs/JavaScript/New_in_JavaScript/1.7)
*/
moz : true,
/**
* This option suppresses warnings about generator functions with no
* `yield` statement in them.
*/
noyield : true,
/**
* This option suppresses warnings about `== null` comparisons. Such
* comparisons are often useful when you want to check if a variable is
* `null` or `undefined`.
*/
eqnull : true,
/**
* This option suppresses warnings about missing semicolons, but only when
* the semicolon is omitted for the last statement in a one-line block:
*
* var name = (function() { return 'Anton' }());
*
* This is a very niche use case that is useful only when you use automatic
* JavaScript code generators.
*/
lastsemic : true,
/**
* This option suppresses warnings about functions inside of loops.
* Defining functions inside of loops can lead to bugs such as this one:
*
* var nums = [];
*
* for (var i = 0; i < 10; i++) {
* nums[i] = function (j) {
* return i + j;
* };
* }
*
* nums[0](2); // Prints 12 instead of 2
*
* To fix the code above you need to copy the value of `i`:
*
* var nums = [];
*
* for (var i = 0; i < 10; i++) {
* (function (i) {
* nums[i] = function (j) {
* return i + j;
* };
* }(i));
* }
*/
loopfunc : true,
/**
* This option suppresses warnings about the use of expressions where
* normally you would expect to see assignments or function calls. Most of
* the time, such code is a typo. However, it is not forbidden by the spec
* and that's why this warning is optional.
*/
expr : true,
/**
* This option tells JSHint that your code uses ECMAScript 6 specific
* syntax. Note that not all browsers implement these features.
*
* More info:
*
* * [Specification for ECMAScript
* 6](http://www.ecma-international.org/ecma-262/6.0/index.html)
*
* @deprecated Use `esversion: 6` instead.
*/
esnext : true,
/**
* This option tells JSHint that your code uses ES3 array elision elements,
* or empty elements (for example, `[1, , , 4, , , 7]`).
*/
elision : true,
},
// Third party globals
environments: {
/**
* This option defines globals exposed by the
* [MooTools](http://mootools.net/) JavaScript framework.
*/
mootools : true,
/**
* This option defines globals exposed by
* [CouchDB](http://couchdb.apache.org/). CouchDB is a document-oriented
* database that can be queried and indexed in a MapReduce fashion using
* JavaScript.
*/
couch : true,
/**
* This option defines globals exposed by [the Jasmine unit testing
* framework](https://jasmine.github.io/).
*/
jasmine : true,
/**
* This option defines globals exposed by the [jQuery](http://jquery.com/)
* JavaScript library.
*/
jquery : true,
/**
* This option defines globals available when your code is running inside
* of the Node runtime environment. [Node.js](http://nodejs.org/) is a
* server-side JavaScript environment that uses an asynchronous
* event-driven model. This option also skips some warnings that make sense
* in the browser environments but don't make sense in Node such as
* file-level `use strict` pragmas and `console.log` statements.
*/
node : true,
/**
* This option defines globals exposed by [the QUnit unit testing
* framework](http://qunitjs.com/).
*/
qunit : true,
/**
* This option defines globals available when your code is running inside
* of the Rhino runtime environment. [Rhino](http://www.mozilla.org/rhino/)
* is an open-source implementation of JavaScript written entirely in Java.
*/
rhino : true,
/**
* This option defines globals exposed by [the ShellJS
* library](http://documentup.com/arturadib/shelljs).
*/
shelljs : true,
/**
* This option defines globals exposed by the
* [Prototype](http://www.prototypejs.org/) JavaScript framework.
*/
prototypejs : true,
/**
* This option defines globals exposed by the [YUI](http://yuilibrary.com/)
* JavaScript framework.
*/
yui : true,
/**
* This option defines globals exposed by the "BDD" and "TDD" UIs of the
* [Mocha unit testing framework](http://mochajs.org/).
*/
mocha : true,
/**
* This option informs JSHint that the input code describes an ECMAScript 6
* module. All module code is interpreted as strict mode code.
*/
module : true,
/**
* This option defines globals available when your code is running as a
* script for the [Windows Script
* Host](http://en.wikipedia.org/wiki/Windows_Script_Host).
*/
wsh : true,
/**
* This option defines globals available when your code is running inside
* of a Web Worker. [Web
* Workers](https://developer.mozilla.org/en/Using_web_workers) provide a
* simple means for web content to run scripts in background threads.
*/
worker : true,
/**
* This option defines non-standard but widely adopted globals such as
* `escape` and `unescape`.
*/
nonstandard : true,
/**
* This option defines globals exposed by modern browsers: all the way from
* good old `document` and `navigator` to the HTML5 `FileReader` and other
* new developments in the browser world.
*
* **Note:** This option doesn't expose variables like `alert` or
* `console`. See option `devel` for more information.
*/
browser : true,
/**
* This option defines globals available when using [the Browserify
* tool](http://browserify.org/) to build a project.
*/
browserify : true,
/**
* This option defines globals that are usually used for logging poor-man's
* debugging: `console`, `alert`, etc. It is usually a good idea to not
* ship them in production because, for example, `console.log` breaks in
* legacy versions of Internet Explorer.
*/
devel : true,
/**
* This option defines globals exposed by the [Dojo
* Toolkit](http://dojotoolkit.org/).
*/
dojo : true,
/**
* This option defines globals for typed array constructors.
*
* More info:
*
* * [JavaScript typed
* arrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays)
*/
typed : true,
/**
* This option defines globals available when your core is running inside
* of the PhantomJS runtime environment. [PhantomJS](http://phantomjs.org/)
* is a headless WebKit scriptable with a JavaScript API. It has fast and
* native support for various web standards: DOM handling, CSS selector,
* JSON, Canvas, and SVG.
*/
phantom : true
},
// Obsolete options
obsolete: {
onecase : true, // if one case switch statements should be allowed
regexp : true, // if the . should not be allowed in regexp literals
regexdash : true // if unescaped first/last dash (-) inside brackets
// should be tolerated
}
};
// These are the JSHint options that can take any value
// (we use this object to detect invalid options)
exports.val = {
/**
* This option lets you set the maximum length of a line.
*
* @deprecated JSHint is limiting its scope to issues of code correctness. If
* you would like to enforce rules relating to code style, check
* out [the JSCS project](https://github.com/jscs-dev/node-jscs).
*/
maxlen : false,
/**
* This option sets a specific tab width for your code.
*
* @deprecated JSHint is limiting its scope to issues of code correctness. If
* you would like to enforce rules relating to code style, check
* out [the JSCS project](https://github.com/jscs-dev/node-jscs).
*/
indent : false,
/**
* This options allows you to set the maximum amount of warnings JSHint will
* produce before giving up. Default is 50.
*/
maxerr : false,
/**
* This option allows you to control which variables JSHint considers to be
* implicitly defined in the environment. Configure it with an array of
* string values. Prefixing a variable name with a hyphen (-) character will
* remove that name from the collection of predefined variables.
*
* JSHint will consider variables declared in this way to be read-only.
*
* This option cannot be specified in-line; it may only be used via the
* JavaScript API or from an external configuration file.
*/
predef : false,
/**
* This option can be used to specify a white list of global variables that
* are not formally defined in the source code. This is most useful when
* combined with the `undef` option in order to suppress warnings for
* project-specific global variables.
*
* Setting an entry to `true` enables reading and writing to that variable.
* Setting it to `false` will trigger JSHint to consider that variable
* read-only.
*
* See also the "environment" options: a set of options to be used as short
* hand for enabling global variables defined in common JavaScript
* environments.
*
* To configure `globals` within an individual file, see [Inline
* Configuration](http://jshint.com/docs/#inline-configuration).
*/
globals : false,
/**
* This option enforces the consistency of quotation marks used throughout
* your code. It accepts three values: `true` if you don't want to enforce
* one particular style but want some consistency, `"single"` if you want to
* allow only single quotes and `"double"` if you want to allow only double
* quotes.
*
* @deprecated JSHint is limiting its scope to issues of code correctness. If
* you would like to enforce rules relating to code style, check
* out [the JSCS project](https://github.com/jscs-dev/node-jscs).
*/
quotmark : false,
scope : false,
/**
* This option lets you set the max number of statements allowed per function:
*
* // jshint maxstatements:4
*
* function main() {
* var i = 0;
* var j = 0;
*
* // Function declarations count as one statement. Their bodies
* // don't get taken into account for the outer function.
* function inner() {
* var i2 = 1;
* var j2 = 1;
*
* return i2 + j2;
* }
*
* j = i + j;
* return j; // JSHint: Too many statements per function. (5)
* }
*/
maxstatements: false,
/**
* This option lets you control how nested do you want your blocks to be:
*
* // jshint maxdepth:2
*
* function main(meaning) {
* var day = true;
*
* if (meaning === 42) {
* while (day) {
* shuffle();
*
* if (tired) { // JSHint: Blocks are nested too deeply (3).
* sleep();
* }
* }
* }
* }
*/
maxdepth : false,
/**
* This option lets you set the max number of formal parameters allowed per
* function:
*
* // jshint maxparams:3
*
* function login(request, onSuccess) {
* // ...
* }
*
* // JSHint: Too many parameters per function (4).
* function logout(request, isManual, whereAmI, onSuccess) {
* // ...
* }
*/
maxparams : false,
/**
* This option lets you control cyclomatic complexity throughout your code.
* Cyclomatic complexity measures the number of linearly independent paths
* through a program's source code. Read more about [cyclomatic complexity on
* Wikipedia](http://en.wikipedia.org/wiki/Cyclomatic_complexity).
*/
maxcomplexity: false,
/**
* This option suppresses warnings about variable shadowing i.e. declaring a
* variable that had been already declared somewhere in the outer scope.
*
* - "inner" - check for variables defined in the same scope only
* - "outer" - check for variables defined in outer scopes as well
* - false - same as inner
* - true - allow variable shadowing
*/
shadow : false,
/**
* This option requires the code to run in ECMAScript 5's strict mode.
* [Strict mode](https://developer.mozilla.org/en/JavaScript/Strict_mode)
* is a way to opt in to a restricted variant of JavaScript. Strict mode
* eliminates some JavaScript pitfalls that didn't cause errors by changing
* them to produce errors. It also fixes mistakes that made it difficult
* for the JavaScript engines to perform certain optimizations.
*
* - "global" - there must be a `"use strict";` directive at global level
* - "implied" - lint the code as if there is the `"use strict";` directive
* - false - disable warnings about strict mode
* - true - there must be a `"use strict";` directive at function level;
* this is preferable for scripts intended to be loaded in web
* browsers directly because enabling strict mode globally
* could adversely effect other scripts running on the same
* page
*/
strict : true,
/**
* This option warns when you define and never use your variables. It is very
* useful for general code cleanup, especially when used in addition to
* `undef`.
*
* // jshint unused:true
*
* function test(a, b) {
* var c, d = 2;
*
* return a + d;
* }
*
* test(1, 2);
*
* // Line 3: 'b' was defined but never used.
* // Line 4: 'c' was defined but never used.
*
* In addition to that, this option will warn you about unused global
* variables declared via the `global` directive.
*
* When set to `true`, unused parameters that are followed by a used
* parameter will not produce warnings. This option can be set to `vars` to
* only check for variables, not function parameters, or `strict` to check
* all variables and parameters.
*/
unused : true,
/**
* This option prohibits the use of a variable before it was defined.
* JavaScript has function scope only and, in addition to that, all variables
* are always movedor hoisted to the top of the function. This behavior can
* lead to some very nasty bugs and that's why it is safer to always use
* variable only after they have been explicitly defined.
*
* Setting this option to "nofunc" will allow function declarations to be
* ignored.
*
* For more in-depth understanding of scoping and hoisting in JavaScript,
* read [JavaScript Scoping and
* Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting)
* by Ben Cherry.
*/
latedef : false,
ignore : false, // start/end ignoring lines of code, bypassing the lexer
// start - start ignoring lines, including the current line
// end - stop ignoring lines, starting on the next line
// line - ignore warnings / errors for just a single line
// (this option does not bypass the lexer)
ignoreDelimiters: false, // array of start/end delimiters used to ignore
// certain chunks from code
/**
* This option is used to specify the ECMAScript version to which the code
* must adhere. It can assume one of the following values:
* - `3` - If you need your program to be executable
* in older browserssuch as Internet Explorer 6/7/8/9and other legacy
* JavaScript environments
* - `5` - To enable syntax first defined in [the ECMAScript 5.1
* specification](http://www.ecma-international.org/ecma-262/5.1/index.html).
* This includes allowing reserved keywords as object properties.
* - `6` - To tell JSHint that your code uses [ECMAScript
* 6](http://www.ecma-international.org/ecma-262/6.0/index.html) specific
* syntax. Note that not all browsers implement them.
* - `7` - To enable language features introduced by [ECMAScript
* 7](https://www.ecma-international.org/ecma-262/7.0/index.html). Notable
* additions: the exponentiation operator.
* - `8` - To enable language features introduced by [ECMAScript
* 8](https://www.ecma-international.org/ecma-262/8.0/index.html). Notable
* additions: async functions, shared memory, and atomics
* - `9` - To enable language features introduced by [ECMAScript
* 9](https://www.ecma-international.org/ecma-262/9.0/index.html). Notable
* additions: asynchronous iteration, rest/spread properties, and various
* RegExp extensions
* - `10` - To enable language features introduced by ECMAScript
* 10](https://www.ecma-international.org/ecma-262/10.0/index.html).
* Notable additions: optional catch bindings.
*/
esversion: 5
};
/**
* Unstable options allow control for parsing and linting of proposed additions
* to the JavaScript language. Just like the language features they describe,
* the presence and behavior of these options is volatile; JSHint reserves the
* right to remove or modify them between major version releases.
*/
exports.unstable = {
/**
* [The BigInt proposal](https://github.com/tc39/proposal-bigint) extends the
* language's grammer for numeric literals to support integer values of
* arbitrary precision. It also introduces a new value of the `typeof`
* operator, "bigint".
*
* Mathematical operations which use both BigInt and traditional ECMAScript
* Number values may not have the intended effect. Due to the weakly-typed
* nature of the language, JSHint is unable to identify such cases.
*/
bigint: true
};
// These are JSHint boolean options which are shared with JSLint
// where the definition in JSHint is opposite JSLint
exports.inverted = {
bitwise : true,
forin : true,
newcap : true,
plusplus: true,
regexp : true,
undef : true,
// Inverted and renamed, use JSHint name here
eqeqeq : true,
strict : true
};
exports.validNames = Object.keys(exports.val)
.concat(Object.keys(exports.bool.relaxing))
.concat(Object.keys(exports.bool.enforcing))
.concat(Object.keys(exports.bool.obsolete))
.concat(Object.keys(exports.bool.environments))
.concat(["unstable"]);
exports.unstableNames = Object.keys(exports.unstable);
// These are JSHint boolean options which are shared with JSLint
// where the name has been changed but the effect is unchanged
exports.renamed = {
eqeq : "eqeqeq",
windows: "wsh",
sloppy : "strict"
};
exports.removed = {
nomen: true,
onevar: true,
passfail: true,
white: true,
gcl: true,
smarttabs: true,
trailing: true
};
// Add options here which should not be automatically enforced by
// `enforceall`.
exports.noenforceall = {
varstmt: true,
strict: true,
regexpu: true
};
},{}],21:[function(require,module,exports){
/**
* This module defines a set of enum-like values intended for use as bit
* "flags" during parsing. The ECMAScript grammar defines a number of such
* "production parameters" to control how certain forms are parsed in context.
* JSHint implements additional parameters to facilitate detection of lint
* warnings.
*
* An equivalent implementation which described the context in terms of a
* "lookup table" object would be more idiomatic for a JavaScript project like
* JSHint. However, because the number of contexts scales with the number of
* expressions in the input program, this would have non-negligible impact on
* the process's memory footprint.
*/
module.exports = {
/**
* Enabled when parsing expressions within ES2015 "export" declarations,
* allowing otherwise-unreferenced bindings to be considered "used".
*/
export: 1,
/**
* Enabled when parsing expressions within the head of `for` statements,
* allowing to distinguish between `for-in` and "C-style" `for` statements.
*/
noin: 2,
/**
* Enabled when the expression begins the statement, allowing the parser to
* correctly select between the null denotation ("nud") and first null
* denotation ("fud") parsing strategy.
*/
initial: 4,
preAsync: 8,
async: 16,
/**
* Enabled when any exception thrown by the expression will be caught by a
* TryStatement.
*/
tryClause: 32,
/**
* Enabled when parsing the body of a generator function.
*/
yield: 64
};
},{}],22:[function(require,module,exports){
/*
* Regular expressions. Some of these are stupidly long.
*/
/*jshint maxlen:1000 */
"use strict";
// Unsafe comment or string (ax)
exports.unsafeString =
/@cc|<\/?|script|\]\s*\]|<\s*!|&lt/i;
// Characters in strings that need escaping (nx and nxg)
exports.needEsc =
/[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
exports.needEscGlobal =
/[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
// Star slash (lx)
exports.starSlash = /\*\//;
// Identifier (ix)
exports.identifier = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/;
// JavaScript URL (jx)
exports.javascriptURL = /^(?:javascript|jscript|ecmascript|vbscript|livescript)\s*:/i;
// Catches /* falls through */ comments (ft)
exports.fallsThrough = /^\s*falls?\sthrough\s*$/;
// very conservative rule (eg: only one space between the start of the comment and the first character)
// to relax the maxlen option
exports.maxlenException = /^(?:(?:\/\/|\/\*|\*) ?)?[^ ]+$/;
// Node.js releases prior to version 8 include a version of the V8 engine which
// incorrectly interprets the character class escape `\s`. The following
// regular expression may be replaced with `/\s/` when JSHint removes support
// for Node.js versions prior to 8.
// Source:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp
exports.whitespace = /[ \f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]/;
exports.nonzeroDigit = /^[1-9]$/;
exports.decimalDigit = /^[0-9]$/;
exports.regexpSyntaxChars = /[\^$\\.*+?()[\]{}|]/;
exports.regexpQuantifiers = /[*+?{]/;
exports.regexpControlEscapes = /[fnrtv]/;
exports.regexpCharClasses = /[dDsSwW]/;
// Identifies the "dot" atom in regular expressions
exports.regexpDot = /(^|[^\\])(\\\\)*\./;
},{}],23:[function(require,module,exports){
"use strict";
var _ = require("lodash");
var events = require("events");
// Used to denote membership in lookup tables (a primitive value such as `true`
// would be silently rejected for the property name "__proto__" in some
// environments)
var marker = {};
/**
* A factory function for creating scope managers. A scope manager tracks
* bindings, detecting when variables are referenced (through "usages").
*
* @param {object} state - the global state object (see `state.js`)
* @param {Array} predefined - a set of binding names for built-in bindings
* provided by the environment
* @param {object} exported - a hash for binding names that are intended to be
* referenced in contexts beyond the current program
* code
* @param {object} declared - a hash for binding names that were defined as
* global bindings via linting configuration
*
* @returns {object} - a scope manager
*/
var scopeManager = function(state, predefined, exported, declared) {
var _current;
var _scopeStack = [];
function _newScope(type) {
_current = {
"(bindings)": Object.create(null),
"(usages)": Object.create(null),
"(labels)": Object.create(null),
"(parent)": _current,
"(type)": type,
"(params)": (type === "functionparams" || type === "catchparams") ? [] : null
};
_scopeStack.push(_current);
}
_newScope("global");
_current["(predefined)"] = predefined;
var _currentFunctBody = _current; // this is the block after the params = function
var usedPredefinedAndGlobals = Object.create(null);
var impliedGlobals = Object.create(null);
var unuseds = [];
var emitter = new events.EventEmitter();
function warning(code, token) {
emitter.emit("warning", {
code: code,
token: token,
data: _.slice(arguments, 2)
});
}
function error(code, token) {
emitter.emit("warning", {
code: code,
token: token,
data: _.slice(arguments, 2)
});
}
function _setupUsages(bindingName) {
if (!_current["(usages)"][bindingName]) {
_current["(usages)"][bindingName] = {
"(modified)": [],
"(reassigned)": [],
"(tokens)": []
};
}
}
var _getUnusedOption = function(unused_opt) {
if (unused_opt === undefined) {
unused_opt = state.option.unused;
}
if (unused_opt === true) {
unused_opt = "last-param";
}
return unused_opt;
};
var _warnUnused = function(name, tkn, type, unused_opt) {
var line = tkn.line;
var chr = tkn.from;
var raw_name = tkn.raw_text || name;
unused_opt = _getUnusedOption(unused_opt);
var warnable_types = {
"vars": ["var"],
"last-param": ["var", "param"],
"strict": ["var", "param", "last-param"]
};
if (unused_opt) {
if (warnable_types[unused_opt] && warnable_types[unused_opt].indexOf(type) !== -1) {
warning("W098", { line: line, from: chr }, raw_name);
}
}
// inconsistent - see gh-1894
if (unused_opt || type === "var") {
unuseds.push({
name: name,
line: line,
character: chr
});
}
};
/**
* Check the current scope for unused identifiers
*/
function _checkForUnused() {
// function parameters are validated by a dedicated function
// assume that parameters are the only thing declared in the param scope
if (_current["(type)"] === "functionparams") {
_checkParams();
return;
}
var currentBindings = _current["(bindings)"];
for (var bindingName in currentBindings) {
if (currentBindings[bindingName]["(type)"] !== "exception" &&
currentBindings[bindingName]["(unused)"]) {
_warnUnused(bindingName, currentBindings[bindingName]["(token)"], "var");
}
}
}
/**
* Check the current scope for unused parameters and issue warnings as
* necessary. This function may only be invoked when the current scope is a
* "function parameter" scope.
*/
function _checkParams() {
var params = _current["(params)"];
if (!params) {
/* istanbul ignore next */
return;
}
var param = params.pop();
var unused_opt;
while (param) {
var binding = _current["(bindings)"][param];
unused_opt = _getUnusedOption(state.funct["(unusedOption)"]);
// 'undefined' is a special case for the common pattern where `undefined`
// is used as a formal parameter name to defend against global
// re-assignment, e.g.
//
// (function(window, undefined) {
// })();
if (param === "undefined")
return;
if (binding["(unused)"]) {
_warnUnused(param, binding["(token)"], "param", state.funct["(unusedOption)"]);
} else if (unused_opt === "last-param") {
return;
}
param = params.pop();
}
}
/**
* Find the relevant binding's scope. The owning scope is located by first
* inspecting the current scope and then moving "downward" through the stack
* of scopes.
*
* @param {string} bindingName - the value of the identifier
*
* @returns {Object} - the scope in which the binding was found
*/
function _getBinding(bindingName) {
for (var i = _scopeStack.length - 1 ; i >= 0; --i) {
var scopeBindings = _scopeStack[i]["(bindings)"];
if (scopeBindings[bindingName]) {
return scopeBindings;
}
}
}
/**
* Determine if a given binding name has been referenced within the current
* function or any function defined within.
*
* @param {string} bindingName - the value of the identifier
*
* @returns {boolean}
*/
function usedSoFarInCurrentFunction(bindingName) {
for (var i = _scopeStack.length - 1; i >= 0; i--) {
var current = _scopeStack[i];
if (current["(usages)"][bindingName]) {
return current["(usages)"][bindingName];
}
if (current === _currentFunctBody) {
break;
}
}
return false;
}
function _checkOuterShadow(bindingName, token) {
// only check if shadow is outer
if (state.option.shadow !== "outer") {
return;
}
var isGlobal = _currentFunctBody["(type)"] === "global",
isNewFunction = _current["(type)"] === "functionparams";
var outsideCurrentFunction = !isGlobal;
for (var i = 0; i < _scopeStack.length; i++) {
var stackItem = _scopeStack[i];
if (!isNewFunction && _scopeStack[i + 1] === _currentFunctBody) {
outsideCurrentFunction = false;
}
if (outsideCurrentFunction && stackItem["(bindings)"][bindingName]) {
warning("W123", token, bindingName);
}
if (stackItem["(labels)"][bindingName]) {
warning("W123", token, bindingName);
}
}
}
function _latedefWarning(type, bindingName, token) {
var isFunction;
if (state.option.latedef) {
isFunction = type === "function" || type === "generator function" ||
type === "async function";
// if either latedef is strict and this is a function
// or this is not a function
if ((state.option.latedef === true && isFunction) || !isFunction) {
warning("W003", token, bindingName);
}
}
}
var scopeManagerInst = {
on: function(names, listener) {
names.split(" ").forEach(function(name) {
emitter.on(name, listener);
});
},
isPredefined: function(bindingName) {
return !this.has(bindingName) && _.has(_scopeStack[0]["(predefined)"], bindingName);
},
/**
* Create a new scope within the current scope. As the topmost value, the
* new scope will be interpreted as the current scope until it is
* exited--see the `unstack` method.
*
* @param {string} [type] - The type of the scope. Valid values are
* "functionparams", "catchparams" and
* "functionouter"
*/
stack: function(type) {
var previousScope = _current;
_newScope(type);
if (!type && previousScope["(type)"] === "functionparams") {
_current["(isFuncBody)"] = true;
_currentFunctBody = _current;
}
},
/**
* Valldate all binding references and declarations in the current scope
* and set the next scope on the stack as the active scope.
*/
unstack: function() {
// jshint proto: true
var subScope = _scopeStack.length > 1 ? _scopeStack[_scopeStack.length - 2] : null;
var isUnstackingFunctionBody = _current === _currentFunctBody,
isUnstackingFunctionParams = _current["(type)"] === "functionparams",
isUnstackingFunctionOuter = _current["(type)"] === "functionouter";
var i, j, isImmutable, isFunction;
var currentUsages = _current["(usages)"];
var currentBindings = _current["(bindings)"];
var usedBindingNameList = Object.keys(currentUsages);
/* istanbul ignore if */
if (currentUsages.__proto__ && usedBindingNameList.indexOf("__proto__") === -1) {
usedBindingNameList.push("__proto__");
}
for (i = 0; i < usedBindingNameList.length; i++) {
var usedBindingName = usedBindingNameList[i];
var usage = currentUsages[usedBindingName];
var usedBinding = currentBindings[usedBindingName];
if (usedBinding) {
var usedBindingType = usedBinding["(type)"];
isImmutable = usedBindingType === "const" || usedBindingType === "import";
if (usedBinding["(useOutsideOfScope)"] && !state.option.funcscope) {
var usedTokens = usage["(tokens)"];
for (j = 0; j < usedTokens.length; j++) {
// Keep the consistency of https://github.com/jshint/jshint/issues/2409
if (usedBinding["(function)"] === usedTokens[j]["(function)"]) {
error("W038", usedTokens[j], usedBindingName);
}
}
}
// mark the binding used
_current["(bindings)"][usedBindingName]["(unused)"] = false;
// check for modifying a const
if (isImmutable && usage["(modified)"]) {
for (j = 0; j < usage["(modified)"].length; j++) {
error("E013", usage["(modified)"][j], usedBindingName);
}
}
isFunction = usedBindingType === "function" ||
usedBindingType === "generator function" ||
usedBindingType === "async function";
// check for re-assigning a function declaration
if ((isFunction || usedBindingType === "class") && usage["(reassigned)"]) {
for (j = 0; j < usage["(reassigned)"].length; j++) {
if (!usage["(reassigned)"][j].ignoreW021) {
warning("W021", usage["(reassigned)"][j], usedBindingName, usedBindingType);
}
}
}
continue;
}
if (subScope) {
var bindingType = this.bindingtype(usedBindingName);
isImmutable = bindingType === "const" ||
(bindingType === null && _scopeStack[0]["(predefined)"][usedBindingName] === false);
if (isUnstackingFunctionOuter && !isImmutable) {
if (!state.funct["(outerMutables)"]) {
state.funct["(outerMutables)"] = [];
}
state.funct["(outerMutables)"].push(usedBindingName);
}
// not exiting the global scope, so copy the usage down in case its an out of scope usage
if (!subScope["(usages)"][usedBindingName]) {
subScope["(usages)"][usedBindingName] = usage;
if (isUnstackingFunctionBody) {
subScope["(usages)"][usedBindingName]["(onlyUsedSubFunction)"] = true;
}
} else {
var subScopeUsage = subScope["(usages)"][usedBindingName];
subScopeUsage["(modified)"] = subScopeUsage["(modified)"].concat(usage["(modified)"]);
subScopeUsage["(tokens)"] = subScopeUsage["(tokens)"].concat(usage["(tokens)"]);
subScopeUsage["(reassigned)"] =
subScopeUsage["(reassigned)"].concat(usage["(reassigned)"]);
}
} else {
// this is exiting global scope, so we finalise everything here - we are at the end of the file
if (typeof _current["(predefined)"][usedBindingName] === "boolean") {
// remove the declared token, so we know it is used
delete declared[usedBindingName];
// note it as used so it can be reported
usedPredefinedAndGlobals[usedBindingName] = marker;
// check for re-assigning a read-only (set to false) predefined
if (_current["(predefined)"][usedBindingName] === false && usage["(reassigned)"]) {
for (j = 0; j < usage["(reassigned)"].length; j++) {
if (!usage["(reassigned)"][j].ignoreW020) {
warning("W020", usage["(reassigned)"][j]);
}
}
}
}
else {
// binding usage is not predefined and we have not found a declaration
// so report as undeclared
for (j = 0; j < usage["(tokens)"].length; j++) {
var undefinedToken = usage["(tokens)"][j];
// if its not a forgiven undefined (e.g. typof x)
if (!undefinedToken.forgiveUndef) {
// if undef is on and undef was on when the token was defined
if (state.option.undef && !undefinedToken.ignoreUndef) {
warning("W117", undefinedToken, usedBindingName);
}
if (impliedGlobals[usedBindingName]) {
impliedGlobals[usedBindingName].line.push(undefinedToken.line);
} else {
impliedGlobals[usedBindingName] = {
name: usedBindingName,
line: [undefinedToken.line]
};
}
}
}
}
}
}
// if exiting the global scope, we can warn about declared globals that haven't been used yet
if (!subScope) {
Object.keys(declared)
.forEach(function(bindingNotUsed) {
_warnUnused(bindingNotUsed, declared[bindingNotUsed], "var");
});
}
// If this is not a function boundary, transfer function-scoped bindings to
// the parent block (a rough simulation of variable hoisting). Previously
// existing bindings in the parent block should take precedence so that
// prior usages are not discarded.
if (subScope && !isUnstackingFunctionBody &&
!isUnstackingFunctionParams && !isUnstackingFunctionOuter) {
var bindingNames = Object.keys(currentBindings);
for (i = 0; i < bindingNames.length; i++) {
var defBindingName = bindingNames[i];
var defBinding = currentBindings[defBindingName];
if (!defBinding["(blockscoped)"] && defBinding["(type)"] !== "exception") {
var shadowed = subScope["(bindings)"][defBindingName];
// Do not overwrite a binding if it exists in the parent scope
// because it is shared by adjacent blocks. Copy the `unused`
// property so that any references found within the current block
// are counted toward that higher-level declaration.
if (shadowed) {
shadowed["(unused)"] &= defBinding["(unused)"];
// "Hoist" the variable to the parent block, decorating the binding
// so that future references, though technically valid, can be
// reported as "out-of-scope" in the absence of the `funcscope`
// option.
} else {
defBinding["(useOutsideOfScope)"] =
// Do not warn about out-of-scope usages in the global scope
_currentFunctBody["(type)"] !== "global" &&
// When a higher scope contains a binding for the binding, the
// binding is a re-declaration and should not prompt "used
// out-of-scope" warnings.
!this.funct.has(defBindingName, { excludeCurrent: true });
subScope["(bindings)"][defBindingName] = defBinding;
}
delete currentBindings[defBindingName];
}
}
}
_checkForUnused();
_scopeStack.pop();
if (isUnstackingFunctionBody) {
_currentFunctBody = _scopeStack[_.findLastIndex(_scopeStack, function(scope) {
// if function or if global (which is at the bottom so it will only return true if we call back)
return scope["(isFuncBody)"] || scope["(type)"] === "global";
})];
}
_current = subScope;
},
/**
* Add a function parameter to the current scope.
*
* @param {string} bindingName - the value of the identifier
* @param {Token} token
* @param {string} [type] - binding type; defaults to "param"
*/
addParam: function(bindingName, token, type) {
type = type || "param";
if (type === "exception") {
// if defined in the current function
var previouslyDefinedBindingType = this.funct.bindingtype(bindingName);
if (previouslyDefinedBindingType && previouslyDefinedBindingType !== "exception") {
// and has not been used yet in the current function scope
if (!state.option.node) {
warning("W002", state.tokens.next, bindingName);
}
}
if (state.isStrict() && (bindingName === "arguments" || bindingName === "eval")) {
warning("E008", token);
}
}
// The variable was declared in the current scope
if (_.has(_current["(bindings)"], bindingName)) {
_current["(bindings)"][bindingName].duplicated = true;
// The variable was declared in an outer scope
} else {
// if this scope has the variable defined, it's a re-definition error
_checkOuterShadow(bindingName, token);
_current["(bindings)"][bindingName] = {
"(type)" : type,
"(token)": token,
"(unused)": true };
_current["(params)"].push(bindingName);
}
if (_.has(_current["(usages)"], bindingName)) {
var usage = _current["(usages)"][bindingName];
// if its in a sub function it is not necessarily an error, just latedef
if (usage["(onlyUsedSubFunction)"]) {
_latedefWarning(type, bindingName, token);
} else {
// this is a clear illegal usage for block scoped variables
warning("E056", token, bindingName, type);
}
}
},
validateParams: function(isArrow) {
var isStrict = state.isStrict();
var currentFunctParamScope = _currentFunctBody["(parent)"];
// From ECMAScript 2017:
//
// > 14.1.2Static Semantics: Early Errors
// >
// > [...]
// > - It is a Syntax Error if IsSimpleParameterList of
// > FormalParameterList is false and BoundNames of FormalParameterList
// > contains any duplicate elements.
var isSimple = state.funct['(hasSimpleParams)'];
// Method definitions are defined in terms of UniqueFormalParameters, so
// they cannot support duplicate parameter names regardless of strict
// mode.
var isMethod = state.funct["(method)"];
if (!currentFunctParamScope["(params)"]) {
/* istanbul ignore next */
return;
}
currentFunctParamScope["(params)"].forEach(function(bindingName) {
var binding = currentFunctParamScope["(bindings)"][bindingName];
if (binding.duplicated) {
if (isStrict || isArrow || isMethod || !isSimple) {
warning("E011", binding["(token)"], bindingName);
} else if (state.option.shadow !== true) {
warning("W004", binding["(token)"], bindingName);
}
}
if (isStrict && (bindingName === "arguments" || bindingName === "eval")) {
warning("E008", binding["(token)"]);
}
});
},
getUsedOrDefinedGlobals: function() {
// jshint proto: true
var list = Object.keys(usedPredefinedAndGlobals);
// If `__proto__` is used as a global variable name, its entry in the
// lookup table may not be enumerated by `Object.keys` (depending on the
// environment).
/* istanbul ignore if */
if (usedPredefinedAndGlobals.__proto__ === marker &&
list.indexOf("__proto__") === -1) {
list.push("__proto__");
}
return list;
},
/**
* Get an array of implied globals
*
* @returns {Array.<{ name: string, line: Array.<number>}>}
*/
getImpliedGlobals: function() {
// jshint proto: true
var values = _.values(impliedGlobals);
var hasProto = false;
// If `__proto__` is an implied global variable, its entry in the lookup
// table may not be enumerated by `_.values` (depending on the
// environment).
if (impliedGlobals.__proto__) {
hasProto = values.some(function(value) {
return value.name === "__proto__";
});
/* istanbul ignore if */
if (!hasProto) {
values.push(impliedGlobals.__proto__);
}
}
return values;
},
/**
* Get an array of objects describing unused bindings.
*
* @returns {Array<Object>}
*/
getUnuseds: function() {
return unuseds;
},
/**
* Determine if a given name has been defined in the current scope or any
* lower scope.
*
* @param {string} bindingName - the value of the identifier
*
* @return {boolean}
*/
has: function(bindingName) {
return Boolean(_getBinding(bindingName));
},
/**
* Retrieve binding described by `bindingName` or null
*
* @param {string} bindingName - the value of the identifier
*
* @returns {string|null} - the type of the binding or `null` if no such
* binding exists
*/
bindingtype: function(bindingName) {
var scopeBindings = _getBinding(bindingName);
if (scopeBindings) {
return scopeBindings[bindingName]["(type)"];
}
return null;
},
/**
* For the exported options, indicating a variable is used outside the file
*
* @param {string} bindingName - the value of the identifier
*/
addExported: function(bindingName) {
var globalBindings = _scopeStack[0]["(bindings)"];
if (_.has(declared, bindingName)) {
// remove the declared token, so we know it is used
delete declared[bindingName];
} else if (_.has(globalBindings, bindingName)) {
globalBindings[bindingName]["(unused)"] = false;
} else {
for (var i = 1; i < _scopeStack.length; i++) {
var scope = _scopeStack[i];
// if `scope.(type)` is not defined, it is a block scope
if (!scope["(type)"]) {
if (_.has(scope["(bindings)"], bindingName) &&
!scope["(bindings)"][bindingName]["(blockscoped)"]) {
scope["(bindings)"][bindingName]["(unused)"] = false;
return;
}
} else {
/* istanbul ignore next */
break;
}
}
exported[bindingName] = true;
}
},
/**
* Mark a binding as "exported" by an ES2015 module
*
* @param {string} bindingName - the value of the identifier
* @param {object} token
*/
setExported: function(bindingName, token) {
this.block.use(bindingName, token);
},
/**
* Mark a binding as "initialized." This is necessary to enforce the
* "temporal dead zone" (TDZ) of block-scoped bindings which are not
* hoisted.
*
* @param {string} bindingName - the value of the identifier
*/
initialize: function(bindingName) {
if (_current["(bindings)"][bindingName]) {
_current["(bindings)"][bindingName]["(initialized)"] = true;
}
},
/**
* Create a new binding and add it to the current scope. Delegates to the
* internal `block.add` or `func.add` methods depending on the type.
* Produces warnings and errors as necessary.
*
* @param {string} bindingName
* @param {Object} opts
* @param {String} opts.type - the type of the binding e.g. "param", "var",
* "let, "const", "import", "function",
* "generator function", "async function",
* "async generator function"
* @param {object} opts.token - the token pointing at the declaration
* @param {boolean} opts.initialized - whether the binding should be
* created in an "initialized" state.
*/
addbinding: function(bindingName, opts) {
var type = opts.type;
var token = opts.token;
var isblockscoped = type === "let" || type === "const" ||
type === "class" || type === "import" || type === "generator function" ||
type === "async function" || type === "async generator function";
var ishoisted = type === "function" || type === "generator function" ||
type === "async function" || type === "import";
var isexported = (isblockscoped ? _current : _currentFunctBody)["(type)"] === "global" &&
_.has(exported, bindingName);
// outer shadow check (inner is only on non-block scoped)
_checkOuterShadow(bindingName, token);
if (state.isStrict() && (bindingName === "arguments" || bindingName === "eval")) {
warning("E008", token);
}
if (isblockscoped) {
var declaredInCurrentScope = _current["(bindings)"][bindingName];
// for block scoped variables, params are seen in the current scope as the root function
// scope, so check these too.
if (!declaredInCurrentScope && _current === _currentFunctBody &&
_current["(type)"] !== "global") {
declaredInCurrentScope = !!_currentFunctBody["(parent)"]["(bindings)"][bindingName];
}
// if its not already defined (which is an error, so ignore) and is used in TDZ
if (!declaredInCurrentScope && _current["(usages)"][bindingName]) {
var usage = _current["(usages)"][bindingName];
// if its in a sub function it is not necessarily an error, just latedef
if (usage["(onlyUsedSubFunction)"] || ishoisted) {
_latedefWarning(type, bindingName, token);
} else if (!ishoisted) {
// this is a clear illegal usage for block scoped variables
warning("E056", token, bindingName, type);
}
}
// If this scope has already declared a binding with the same name,
// then this represents a redeclaration error if:
//
// 1. it is a "hoisted" block-scoped binding within a block. For
// instance: generator functions may be redeclared in the global
// scope but not within block statements
// 2. this is not a "hoisted" block-scoped binding
if (declaredInCurrentScope &&
(!ishoisted || (_current["(type)"] !== "global" || type === "import"))) {
warning("E011", token, bindingName);
}
else if (state.option.shadow === "outer") {
// if shadow is outer, for block scope we want to detect any shadowing within this function
if (scopeManagerInst.funct.has(bindingName)) {
warning("W004", token, bindingName);
}
}
scopeManagerInst.block.add(
bindingName, type, token, !isexported, opts.initialized
);
} else {
var declaredInCurrentFunctionScope = scopeManagerInst.funct.has(bindingName);
// check for late definition, ignore if already declared
if (!declaredInCurrentFunctionScope && usedSoFarInCurrentFunction(bindingName)) {
_latedefWarning(type, bindingName, token);
}
// defining with a var or a function when a block scope variable of the same name
// is in scope is an error
if (scopeManagerInst.funct.has(bindingName, { onlyBlockscoped: true })) {
warning("E011", token, bindingName);
} else if (state.option.shadow !== true) {
// now since we didn't get any block scope variables, test for var/function
// shadowing
if (declaredInCurrentFunctionScope && bindingName !== "__proto__") {
// see https://github.com/jshint/jshint/issues/2400
if (_currentFunctBody["(type)"] !== "global") {
warning("W004", token, bindingName);
}
}
}
scopeManagerInst.funct.add(bindingName, type, token, !isexported);
if (_currentFunctBody["(type)"] === "global" && !state.impliedClosure()) {
usedPredefinedAndGlobals[bindingName] = marker;
}
}
},
funct: {
/**
* Return the type of the provided binding given certain options
*
* @param {string} bindingName
* @param {Object=} [options]
* @param {boolean} [options.onlyBlockscoped] - only include block scoped
* bindings
* @param {boolean} [options.excludeParams] - exclude the param scope
* @param {boolean} [options.excludeCurrent] - exclude the current scope
*
* @returns {String}
*/
bindingtype: function(bindingName, options) {
var onlyBlockscoped = options && options.onlyBlockscoped;
var excludeParams = options && options.excludeParams;
var currentScopeIndex = _scopeStack.length - (options && options.excludeCurrent ? 2 : 1);
for (var i = currentScopeIndex; i >= 0; i--) {
var current = _scopeStack[i];
if (current["(bindings)"][bindingName] &&
(!onlyBlockscoped || current["(bindings)"][bindingName]["(blockscoped)"])) {
return current["(bindings)"][bindingName]["(type)"];
}
var scopeCheck = excludeParams ? _scopeStack[ i - 1 ] : current;
if (scopeCheck && scopeCheck["(type)"] === "functionparams") {
return null;
}
}
return null;
},
/**
* Determine whether a `break` statement label exists in the function
* scope.
*
* @param {string} labelName - the value of the identifier
*
* @returns {boolean}
*/
hasLabel: function(labelName) {
for (var i = _scopeStack.length - 1; i >= 0; i--) {
var current = _scopeStack[i];
if (current["(labels)"][labelName]) {
return true;
}
if (current["(type)"] === "functionparams") {
return false;
}
}
return false;
},
/**
* Determine if a given name has been defined in the current function
* scope.
*
* @param {string} bindingName - the value of the identifier
* @param {object} options - options as supported by the
* `funct.bindingtype` method
*
* @return {boolean}
*/
has: function(bindingName, options) {
return Boolean(this.bindingtype(bindingName, options));
},
/**
* Create a new function-scoped binding and add it to the current scope.
* See the `block.add` method for coresponding logic to create
* block-scoped bindings.
*
* @param {string} bindingName - the value of the identifier
* @param {string} type - the type of the binding; either "function" or
* "var"
* @param {object} tok - the token that triggered the definition
* @param {boolean} unused - `true` if the binding has not been
* referenced
*/
add: function(bindingName, type, tok, unused) {
_current["(bindings)"][bindingName] = {
"(type)" : type,
"(token)": tok,
"(blockscoped)": false,
"(function)": _currentFunctBody,
"(unused)": unused };
}
},
block: {
/**
* Determine whether the current block scope is the global scope.
*
* @returns Boolean
*/
isGlobal: function() {
return _current["(type)"] === "global";
},
/**
* Resolve a reference to a binding and mark the corresponding binding as
* "used."
*
* @param {string} bindingName - the value of the identifier
* @param {object} token - the token value that triggered the reference
*/
use: function(bindingName, token) {
// If the name resolves to a parameter of the current function, then do
// not store usage. This is because in cases such as the following:
//
// function(a) {
// var a;
// a = a;
// }
//
// the usage of `a` will resolve to the parameter, not to the unset
// variable binding.
var paramScope = _currentFunctBody["(parent)"];
if (paramScope && paramScope["(bindings)"][bindingName] &&
paramScope["(bindings)"][bindingName]["(type)"] === "param") {
// then check its not declared by a block scope variable
if (!scopeManagerInst.funct.has(bindingName,
{ excludeParams: true, onlyBlockscoped: true })) {
paramScope["(bindings)"][bindingName]["(unused)"] = false;
}
}
if (token && (state.ignored.W117 || state.option.undef === false)) {
token.ignoreUndef = true;
}
_setupUsages(bindingName);
_current["(usages)"][bindingName]["(onlyUsedSubFunction)"] = false;
if (token) {
token["(function)"] = _currentFunctBody;
_current["(usages)"][bindingName]["(tokens)"].push(token);
}
// Block-scoped bindings can't be used within their initializer due to
// "temporal dead zone" (TDZ) restrictions.
var binding = _current["(bindings)"][bindingName];
if (binding && binding["(blockscoped)"] && !binding["(initialized)"]) {
error("E056", token, bindingName, binding["(type)"]);
}
},
reassign: function(bindingName, token) {
token.ignoreW020 = state.ignored.W020;
token.ignoreW021 = state.ignored.W021;
this.modify(bindingName, token);
_current["(usages)"][bindingName]["(reassigned)"].push(token);
},
modify: function(bindingName, token) {
_setupUsages(bindingName);
_current["(usages)"][bindingName]["(onlyUsedSubFunction)"] = false;
_current["(usages)"][bindingName]["(modified)"].push(token);
},
/**
* Create a new block-scoped binding and add it to the current scope. See
* the `funct.add` method for coresponding logic to create
* function-scoped bindings.
*
* @param {string} bindingName - the value of the identifier
* @param {string} type - the type of the binding; one of "class",
* "const", "function", "import", or "let"
* @param {object} tok - the token that triggered the definition
* @param {boolean} unused - `true` if the binding has not been
* referenced
* @param {boolean} initialized - `true` if the binding has been
* initialized (as is the case with
* bindings created via `import`
* declarations)
*/
add: function(bindingName, type, tok, unused, initialized) {
_current["(bindings)"][bindingName] = {
"(type)" : type,
"(token)": tok,
"(initialized)": !!initialized,
"(blockscoped)": true,
"(unused)": unused };
},
addLabel: function(labelName, opts) {
var token = opts.token;
if (scopeManagerInst.funct.hasLabel(labelName)) {
warning("E011", token, labelName);
}
else if (state.option.shadow === "outer") {
if (scopeManagerInst.funct.has(labelName)) {
warning("W004", token, labelName);
} else {
_checkOuterShadow(labelName, token);
}
}
_current["(labels)"][labelName] = token;
}
}
};
return scopeManagerInst;
};
module.exports = scopeManager;
},{"events":9,"lodash":16}],24:[function(require,module,exports){
"use strict";
var NameStack = require("./name-stack.js");
var state = {
syntax: {},
/**
* Determine if the code currently being linted is strict mode code.
*
* @returns {boolean}
*/
isStrict: function() {
return this.directive["use strict"] || this.inClassBody ||
this.option.module || this.option.strict === "implied";
},
/**
* Determine if the current state warrants a warning for statements outside
* of strict mode code.
*
* While emitting warnings based on function scope would be more intuitive
* (and less noisy), JSHint observes statement-based semantics in order to
* preserve legacy behavior.
*
* This method does not take the state of the parser into account, making no
* distinction between global code and function code. Because the "missing
* 'use strict'" warning is *also* reported at function boundaries, this
* function interprets `strict` option values `true` and `undefined` as
* equivalent.
*/
stmtMissingStrict: function() {
if (this.option.strict === "global") {
return true;
}
if (this.option.strict === false) {
return false;
}
if (this.option.globalstrict) {
return true;
}
return false;
},
allowsGlobalUsd: function() {
return this.option.strict === "global" || this.option.globalstrict ||
this.option.module || this.impliedClosure();
},
/**
* Determine if the current configuration describes an environment that is
* wrapped in an immediately-invoked function expression prior to evaluation.
*
* @returns {boolean}
*/
impliedClosure: function() {
return this.option.node || this.option.phantom || this.option.browserify;
},
// Assumption: chronologically ES3 < ES5 < ES6 < Moz
inMoz: function() {
return this.option.moz;
},
/**
* Determine if constructs introduced in ECMAScript 10 should be accepted.
*
* @returns {boolean}
*/
inES10: function() {
return this.esVersion >= 10;
},
/**
* Determine if constructs introduced in ECMAScript 9 should be accepted.
*
* @returns {boolean}
*/
inES9: function() {
return this.esVersion >= 9;
},
/**
* Determine if constructs introduced in ECMAScript 8 should be accepted.
*
* @returns {boolean}
*/
inES8: function() {
return this.esVersion >= 8;
},
/**
* Determine if constructs introduced in ECMAScript 7 should be accepted.
*
* @returns {boolean}
*/
inES7: function() {
return this.esVersion >= 7;
},
/**
* Determine if constructs introduced in ECMAScript 6 should be accepted.
*
* @param {boolean} strict - When `true`, do not interpret the `moz` option
* as ECMAScript 6
*
* @returns {boolean}
*/
inES6: function(strict) {
if (!strict && this.option.moz) {
return true;
}
return this.esVersion >= 6;
},
/**
* Determine if constructs introduced in ECMAScript 5 should be accepted.
*
* @returns {boolean}
*/
inES5: function() {
return !this.esVersion || this.esVersion >= 5 || this.option.moz;
},
/**
* Determine the current version of the input language by inspecting the
* value of all ECMAScript-version-related options. This logic is necessary
* to ensure compatibility with deprecated options `es3`, `es5`, and
* `esnext`, and it may be drastically simplified when those options are
* removed.
*
* @returns {string|null} - the name of any incompatible option detected,
* `null` otherwise
*/
inferEsVersion: function() {
var badOpt = null;
if (this.option.esversion) {
if (this.option.es3) {
badOpt = "es3";
} else if (this.option.es5) {
badOpt = "es5";
} else if (this.option.esnext) {
badOpt = "esnext";
}
if (badOpt) {
return badOpt;
}
if (this.option.esversion === 2015) {
this.esVersion = 6;
} else {
this.esVersion = this.option.esversion;
}
} else if (this.option.es3) {
this.esVersion = 3;
} else if (this.option.esnext) {
this.esVersion = 6;
}
return null;
},
reset: function() {
this.tokens = {
prev: null,
next: null,
curr: null
};
this.option = { unstable: {} };
this.esVersion = 5;
this.funct = null;
this.ignored = {};
this.directive = Object.create(null);
this.jsonMode = false;
this.lines = [];
this.tab = "";
this.cache = {}; // Node.JS doesn't have Map. Sniff.
this.ignoredLines = {};
this.forinifcheckneeded = false;
this.nameStack = new NameStack();
this.inClassBody = false;
}
};
exports.state = state;
},{"./name-stack.js":19}],25:[function(require,module,exports){
"use strict";
exports.register = function(linter) {
// Check for properties named __proto__. This special property was
// deprecated and then re-introduced for ES6.
linter.on("Identifier", function style_scanProto(data) {
if (linter.getOption("proto")) {
return;
}
if (data.name === "__proto__") {
linter.warn("W103", {
line: data.line,
char: data.char,
data: [ data.name, "6" ]
});
}
});
// Check for properties named __iterator__. This is a special property
// available only in browsers with JavaScript 1.7 implementation, but
// it is deprecated for ES6
linter.on("Identifier", function style_scanIterator(data) {
if (linter.getOption("iterator")) {
return;
}
if (data.name === "__iterator__") {
linter.warn("W103", {
line: data.line,
char: data.char,
data: [ data.name ]
});
}
});
// Check that all identifiers are using camelCase notation.
// Exceptions: names like MY_VAR and _myVar.
linter.on("Identifier", function style_scanCamelCase(data) {
if (!linter.getOption("camelcase")) {
return;
}
if (data.name.replace(/^_+|_+$/g, "").indexOf("_") > -1 && !data.name.match(/^[A-Z0-9_]*$/)) {
linter.warn("W106", {
line: data.line,
char: data.char,
data: [ data.name ]
});
}
});
// Enforce consistency in style of quoting.
linter.on("String", function style_scanQuotes(data) {
var quotmark = linter.getOption("quotmark");
var code;
if (!quotmark) {
return;
}
// If quotmark is set to 'single' warn about all double-quotes.
if (quotmark === "single" && data.quote !== "'") {
code = "W109";
}
// If quotmark is set to 'double' warn about all single-quotes.
if (quotmark === "double" && data.quote !== "\"") {
code = "W108";
}
// If quotmark is set to true, remember the first quotation style
// and then warn about all others.
if (quotmark === true) {
if (!linter.getCache("quotmark")) {
linter.setCache("quotmark", data.quote);
}
if (linter.getCache("quotmark") !== data.quote) {
code = "W110";
}
}
if (code) {
linter.warn(code, {
line: data.line,
char: data.char,
});
}
});
linter.on("Number", function style_scanNumbers(data) {
if (data.value.charAt(0) === ".") {
// Warn about a leading decimal point.
linter.warn("W008", {
line: data.line,
char: data.char,
data: [ data.value ]
});
}
if (data.value.substr(data.value.length - 1) === ".") {
// Warn about a trailing decimal point.
linter.warn("W047", {
line: data.line,
char: data.char,
data: [ data.value ]
});
}
if (/^00+/.test(data.value)) {
// Multiple leading zeroes.
linter.warn("W046", {
line: data.line,
char: data.char,
data: [ data.value ]
});
}
});
// Warn about script URLs.
linter.on("String", function style_scanJavaScriptURLs(data) {
var re = /^(?:javascript|jscript|ecmascript|vbscript|livescript)\s*:/i;
if (linter.getOption("scripturl")) {
return;
}
if (re.test(data.value)) {
linter.warn("W107", {
line: data.line,
char: data.char
});
}
});
};
},{}],26:[function(require,module,exports){
// jshint -W001
"use strict";
// Identifiers provided by the ECMAScript standard.
exports.reservedVars = {
NaN : false,
undefined : false
};
exports.ecmaIdentifiers = {
3: {
Array : false,
Boolean : false,
Date : false,
decodeURI : false,
decodeURIComponent : false,
encodeURI : false,
encodeURIComponent : false,
Error : false,
"eval" : false,
EvalError : false,
Function : false,
hasOwnProperty : false,
Infinity : false,
isFinite : false,
isNaN : false,
Math : false,
Number : false,
Object : false,
parseInt : false,
parseFloat : false,
RangeError : false,
ReferenceError : false,
RegExp : false,
String : false,
SyntaxError : false,
TypeError : false,
URIError : false
},
5: {
JSON : false
},
6: {
ArrayBuffer : false,
DataView : false,
Float32Array : false,
Float64Array : false,
Int8Array : false,
Int16Array : false,
Int32Array : false,
Map : false,
Promise : false,
Proxy : false,
Reflect : false,
Set : false,
Symbol : false,
Uint8Array : false,
Uint16Array : false,
Uint32Array : false,
Uint8ClampedArray : false,
WeakMap : false,
WeakSet : false
},
8: {
Atomics : false,
SharedArrayBuffer : false
}
};
// Global variables commonly provided by a web browser environment.
exports.browser = {
Audio : false,
Blob : false,
addEventListener : false, // EventTarget
applicationCache : false,
atob : false, // WindowOrWorkerGlobalScope
blur : false,
btoa : false, // WindowOrWorkerGlobalScope
cancelAnimationFrame : false,
CanvasGradient : false,
CanvasPattern : false,
CanvasRenderingContext2D: false,
CSS : false,
CSSImportRule : false,
CSSGroupingRule : false,
CSSMarginRule : false,
CSSMediaRule : false,
CSSNamespaceRule : false,
CSSPageRule : false,
CSSRule : false,
CSSRuleList : false,
CSSStyleDeclaration : false,
CSSStyleRule : false,
CSSStyleSheet : false,
clearInterval : false, // WindowOrWorkerGlobalScope
clearTimeout : false, // WindowOrWorkerGlobalScope
close : false,
closed : false,
Comment : false,
CompositionEvent : false,
createImageBitmap : false, // WindowOrWorkerGlobalScope
CustomEvent : false,
DOMParser : false,
defaultStatus : false,
dispatchEvent : false, // EventTarget
Document : false,
document : false,
DocumentFragment : false,
Element : false,
ElementTimeControl : false,
Event : false,
event : false,
fetch : false,
File : false,
FileList : false,
FileReader : false,
FormData : false,
focus : false,
frames : false,
getComputedStyle : false,
Headers : false,
HTMLAnchorElement : false,
HTMLAreaElement : false,
HTMLAudioElement : false,
HTMLBaseElement : false,
HTMLBlockquoteElement: false,
HTMLBodyElement : false,
HTMLBRElement : false,
HTMLButtonElement : false,
HTMLCanvasElement : false,
HTMLCollection : false,
HTMLDataElement : false,
HTMLDataListElement : false,
HTMLDetailsElement : false,
HTMLDialogElement : false,
HTMLDirectoryElement : false,
HTMLDivElement : false,
HTMLDListElement : false,
HTMLElement : false,
HTMLEmbedElement : false,
HTMLFieldSetElement : false,
HTMLFontElement : false,
HTMLFormElement : false,
HTMLFrameElement : false,
HTMLFrameSetElement : false,
HTMLHeadElement : false,
HTMLHeadingElement : false,
HTMLHRElement : false,
HTMLHtmlElement : false,
HTMLIFrameElement : false,
HTMLImageElement : false,
HTMLInputElement : false,
/* HTMLIsIndexElement was removed from the WHATWG HTML spec;
see https://github.com/whatwg/html/pull/1095.
HTMLIsIndexElement has been removed from browsers; see:
Chromium Removal: https://codereview.chromium.org/96653004/
Gecko Removal: https://bugzilla.mozilla.org/show_bug.cgi?id=1266495
WebKit Removal: https://bugs.webkit.org/show_bug.cgi?id=7139.
See also the discussion at https://github.com/jshint/jshint/pull/3222. */
HTMLIsIndexElement : false,
HTMLLabelElement : false,
HTMLLayerElement : false,
HTMLLegendElement : false,
HTMLLIElement : false,
HTMLLinkElement : false,
HTMLMapElement : false,
HTMLMarqueeElement : false,
HTMLMediaElement : false,
HTMLMenuElement : false,
HTMLMetaElement : false,
HTMLMeterElement : false,
HTMLModElement : false,
HTMLObjectElement : false,
HTMLOListElement : false,
HTMLOptGroupElement : false,
HTMLOptionElement : false,
HTMLParagraphElement : false,
HTMLParamElement : false,
HTMLPictureElement : false,
HTMLPreElement : false,
HTMLProgressElement : false,
HTMLQuoteElement : false,
HTMLScriptElement : false,
HTMLSelectElement : false,
HTMLSlotElement : false,
HTMLSourceElement : false,
HTMLStyleElement : false,
HTMLTableCaptionElement: false,
HTMLTableCellElement : false,
HTMLTableColElement : false,
HTMLTableElement : false,
HTMLTableRowElement : false,
HTMLTableSectionElement: false,
HTMLTemplateElement : false,
HTMLTextAreaElement : false,
HTMLTimeElement : false,
HTMLTitleElement : false,
HTMLTrackElement : false,
HTMLUListElement : false,
HTMLVideoElement : false,
history : false,
Image : false,
IntersectionObserver : false,
Intl : false,
length : false,
localStorage : false,
location : false,
matchMedia : false,
MediaList : false,
MediaRecorder : false,
MessageChannel : false,
MessageEvent : false,
MessagePort : false,
MouseEvent : false,
moveBy : false,
moveTo : false,
MutationObserver : false,
name : false,
Node : false,
NodeFilter : false,
NodeList : false,
Notification : false,
navigator : false,
onbeforeunload : true,
onblur : true,
onerror : true,
onfocus : true,
onload : true,
onresize : true,
onunload : true,
open : false,
openDatabase : false,
opener : false,
Option : false,
origin : false, // WindowOrWorkerGlobalScope
parent : false,
performance : false,
print : false,
queueMicrotask : false, // WindowOrWorkerGlobalScope
Range : false,
requestAnimationFrame : false,
removeEventListener : false, // EventTarget
Request : false,
resizeBy : false,
resizeTo : false,
Response : false,
screen : false,
scroll : false,
scrollBy : false,
scrollTo : false,
sessionStorage : false,
setInterval : false, // WindowOrWorkerGlobalScope
setTimeout : false, // WindowOrWorkerGlobalScope
SharedWorker : false,
status : false,
Storage : false,
StyleSheet : false,
SVGAElement : false,
SVGAltGlyphDefElement: false,
SVGAltGlyphElement : false,
SVGAltGlyphItemElement: false,
SVGAngle : false,
SVGAnimateColorElement: false,
SVGAnimateElement : false,
SVGAnimateMotionElement: false,
SVGAnimateTransformElement: false,
SVGAnimatedAngle : false,
SVGAnimatedBoolean : false,
SVGAnimatedEnumeration: false,
SVGAnimatedInteger : false,
SVGAnimatedLength : false,
SVGAnimatedLengthList: false,
SVGAnimatedNumber : false,
SVGAnimatedNumberList: false,
SVGAnimatedPathData : false,
SVGAnimatedPoints : false,
SVGAnimatedPreserveAspectRatio: false,
SVGAnimatedRect : false,
SVGAnimatedString : false,
SVGAnimatedTransformList: false,
SVGAnimationElement : false,
SVGCSSRule : false,
SVGCircleElement : false,
SVGClipPathElement : false,
SVGColor : false,
SVGColorProfileElement: false,
SVGColorProfileRule : false,
SVGComponentTransferFunctionElement: false,
SVGCursorElement : false,
SVGDefsElement : false,
SVGDescElement : false,
SVGDocument : false,
SVGElement : false,
SVGElementInstance : false,
SVGElementInstanceList: false,
SVGEllipseElement : false,
SVGExternalResourcesRequired: false,
SVGFEBlendElement : false,
SVGFEColorMatrixElement: false,
SVGFEComponentTransferElement: false,
SVGFECompositeElement: false,
SVGFEConvolveMatrixElement: false,
SVGFEDiffuseLightingElement: false,
SVGFEDisplacementMapElement: false,
SVGFEDistantLightElement: false,
SVGFEFloodElement : false,
SVGFEFuncAElement : false,
SVGFEFuncBElement : false,
SVGFEFuncGElement : false,
SVGFEFuncRElement : false,
SVGFEGaussianBlurElement: false,
SVGFEImageElement : false,
SVGFEMergeElement : false,
SVGFEMergeNodeElement: false,
SVGFEMorphologyElement: false,
SVGFEOffsetElement : false,
SVGFEPointLightElement: false,
SVGFESpecularLightingElement: false,
SVGFESpotLightElement: false,
SVGFETileElement : false,
SVGFETurbulenceElement: false,
SVGFilterElement : false,
SVGFilterPrimitiveStandardAttributes: false,
SVGFitToViewBox : false,
SVGFontElement : false,
SVGFontFaceElement : false,
SVGFontFaceFormatElement: false,
SVGFontFaceNameElement: false,
SVGFontFaceSrcElement: false,
SVGFontFaceUriElement: false,
SVGForeignObjectElement: false,
SVGGElement : false,
SVGGlyphElement : false,
SVGGlyphRefElement : false,
SVGGradientElement : false,
SVGHKernElement : false,
SVGICCColor : false,
SVGImageElement : false,
SVGLangSpace : false,
SVGLength : false,
SVGLengthList : false,
SVGLineElement : false,
SVGLinearGradientElement: false,
SVGLocatable : false,
SVGMPathElement : false,
SVGMarkerElement : false,
SVGMaskElement : false,
SVGMatrix : false,
SVGMetadataElement : false,
SVGMissingGlyphElement: false,
SVGNumber : false,
SVGNumberList : false,
SVGPaint : false,
SVGPathElement : false,
SVGPathSeg : false,
SVGPathSegArcAbs : false,
SVGPathSegArcRel : false,
SVGPathSegClosePath : false,
SVGPathSegCurvetoCubicAbs: false,
SVGPathSegCurvetoCubicRel: false,
SVGPathSegCurvetoCubicSmoothAbs: false,
SVGPathSegCurvetoCubicSmoothRel: false,
SVGPathSegCurvetoQuadraticAbs: false,
SVGPathSegCurvetoQuadraticRel: false,
SVGPathSegCurvetoQuadraticSmoothAbs: false,
SVGPathSegCurvetoQuadraticSmoothRel: false,
SVGPathSegLinetoAbs : false,
SVGPathSegLinetoHorizontalAbs: false,
SVGPathSegLinetoHorizontalRel: false,
SVGPathSegLinetoRel : false,
SVGPathSegLinetoVerticalAbs: false,
SVGPathSegLinetoVerticalRel: false,
SVGPathSegList : false,
SVGPathSegMovetoAbs : false,
SVGPathSegMovetoRel : false,
SVGPatternElement : false,
SVGPoint : false,
SVGPointList : false,
SVGPolygonElement : false,
SVGPolylineElement : false,
SVGPreserveAspectRatio: false,
SVGRadialGradientElement: false,
SVGRect : false,
SVGRectElement : false,
SVGRenderingIntent : false,
SVGSVGElement : false,
SVGScriptElement : false,
SVGSetElement : false,
SVGStopElement : false,
SVGStringList : false,
SVGStylable : false,
SVGStyleElement : false,
SVGSwitchElement : false,
SVGSymbolElement : false,
SVGTRefElement : false,
SVGTSpanElement : false,
SVGTests : false,
SVGTextContentElement: false,
SVGTextElement : false,
SVGTextPathElement : false,
SVGTextPositioningElement: false,
SVGTitleElement : false,
SVGTransform : false,
SVGTransformList : false,
SVGTransformable : false,
SVGURIReference : false,
SVGUnitTypes : false,
SVGUseElement : false,
SVGVKernElement : false,
SVGViewElement : false,
SVGViewSpec : false,
SVGZoomAndPan : false,
Text : false,
TextDecoder : false,
TextEncoder : false,
TimeEvent : false,
top : false,
URL : false,
WebGLActiveInfo : false,
WebGLBuffer : false,
WebGLContextEvent : false,
WebGLFramebuffer : false,
WebGLProgram : false,
WebGLRenderbuffer : false,
WebGLRenderingContext: false,
WebGLShader : false,
WebGLShaderPrecisionFormat: false,
WebGLTexture : false,
WebGLUniformLocation : false,
WebSocket : false,
window : false,
Window : false,
Worker : false,
XDomainRequest : false,
XMLDocument : false,
XMLHttpRequest : false,
XMLSerializer : false,
XPathEvaluator : false,
XPathException : false,
XPathExpression : false,
XPathNamespace : false,
XPathNSResolver : false,
XPathResult : false
};
exports.devel = {
alert : false,
confirm: false,
console: false,
Debug : false,
opera : false,
prompt : false
};
exports.worker = {
addEventListener : true, // EventTarget
atob : true, // WindowOrWorkerGlobalScope
btoa : true, // WindowOrWorkerGlobalScope
clearInterval : true, // WindowOrWorkerGlobalScope
clearTimeout : true, // WindowOrWorkerGlobalScope
createImageBitmap : true, // WindowOrWorkerGlobalScope
dispatchEvent : true, // EventTarget
importScripts : true,
onmessage : true,
origin : true, // WindowOrWorkerGlobalScope
postMessage : true,
queueMicrotask : true, // WindowOrWorkerGlobalScope
removeEventListener : true, // EventTarget
self : true,
setInterval : true, // WindowOrWorkerGlobalScope
setTimeout : true, // WindowOrWorkerGlobalScope
FileReaderSync : true
};
// Widely adopted global names that are not part of ECMAScript standard
exports.nonstandard = {
escape : false,
unescape: false
};
// Globals provided by popular JavaScript environments.
exports.couch = {
"require" : false,
respond : false,
getRow : false,
emit : false,
send : false,
start : false,
sum : false,
log : false,
exports : false,
module : false,
provides : false
};
exports.node = {
__filename : false,
__dirname : false,
arguments : false,
GLOBAL : false,
global : false,
module : false,
require : false,
// These globals are writeable because Node allows the following
// usage pattern: var Buffer = require("buffer").Buffer;
Buffer : true,
console : true,
exports : true,
process : true,
setTimeout : true,
clearTimeout : true,
setInterval : true,
clearInterval : true,
setImmediate : true, // v0.9.1+
clearImmediate: true // v0.9.1+
};
exports.browserify = {
__filename : false,
__dirname : false,
global : false,
module : false,
require : false,
Buffer : true,
exports : true,
process : true
};
exports.phantom = {
phantom : true,
require : true,
WebPage : true,
console : true, // in examples, but undocumented
exports : true // v1.7+
};
exports.qunit = {
asyncTest : false,
deepEqual : false,
equal : false,
expect : false,
module : false,
notDeepEqual : false,
notEqual : false,
notOk : false,
notPropEqual : false,
notStrictEqual : false,
ok : false,
propEqual : false,
QUnit : false,
raises : false,
start : false,
stop : false,
strictEqual : false,
test : false,
"throws" : false
};
exports.rhino = {
arguments : false,
defineClass : false,
deserialize : false,
gc : false,
help : false,
importClass : false,
importPackage: false,
"java" : false,
load : false,
loadClass : false,
Packages : false,
print : false,
quit : false,
readFile : false,
readUrl : false,
runCommand : false,
seal : false,
serialize : false,
spawn : false,
sync : false,
toint32 : false,
version : false
};
exports.shelljs = {
target : false,
echo : false,
exit : false,
cd : false,
pwd : false,
ls : false,
find : false,
cp : false,
rm : false,
mv : false,
mkdir : false,
test : false,
cat : false,
sed : false,
grep : false,
which : false,
dirs : false,
pushd : false,
popd : false,
env : false,
exec : false,
chmod : false,
config : false,
error : false,
tempdir : false
};
exports.typed = {
ArrayBuffer : false,
ArrayBufferView : false,
DataView : false,
Float32Array : false,
Float64Array : false,
Int16Array : false,
Int32Array : false,
Int8Array : false,
Uint16Array : false,
Uint32Array : false,
Uint8Array : false,
Uint8ClampedArray : false
};
exports.wsh = {
ActiveXObject : true,
Enumerator : true,
GetObject : true,
ScriptEngine : true,
ScriptEngineBuildVersion : true,
ScriptEngineMajorVersion : true,
ScriptEngineMinorVersion : true,
VBArray : true,
WSH : true,
WScript : true,
XDomainRequest : true
};
// Globals provided by popular JavaScript libraries.
exports.dojo = {
dojo : false,
dijit : false,
dojox : false,
define : false,
"require": false
};
exports.jquery = {
"$" : false,
jQuery : false
};
exports.mootools = {
"$" : false,
"$$" : false,
Asset : false,
Browser : false,
Chain : false,
Class : false,
Color : false,
Cookie : false,
Core : false,
Document : false,
DomReady : false,
DOMEvent : false,
DOMReady : false,
Drag : false,
Element : false,
Elements : false,
Event : false,
Events : false,
Fx : false,
Group : false,
Hash : false,
HtmlTable : false,
IFrame : false,
IframeShim : false,
InputValidator: false,
instanceOf : false,
Keyboard : false,
Locale : false,
Mask : false,
MooTools : false,
Native : false,
Options : false,
OverText : false,
Request : false,
Scroller : false,
Slick : false,
Slider : false,
Sortables : false,
Spinner : false,
Swiff : false,
Tips : false,
Type : false,
typeOf : false,
URI : false,
Window : false
};
exports.prototypejs = {
"$" : false,
"$$" : false,
"$A" : false,
"$F" : false,
"$H" : false,
"$R" : false,
"$break" : false,
"$continue" : false,
"$w" : false,
Abstract : false,
Ajax : false,
Class : false,
Enumerable : false,
Element : false,
Event : false,
Field : false,
Form : false,
Hash : false,
Insertion : false,
ObjectRange : false,
PeriodicalExecuter: false,
Position : false,
Prototype : false,
Selector : false,
Template : false,
Toggle : false,
Try : false,
Autocompleter : false,
Builder : false,
Control : false,
Draggable : false,
Draggables : false,
Droppables : false,
Effect : false,
Sortable : false,
SortableObserver : false,
Sound : false,
Scriptaculous : false
};
exports.yui = {
YUI : false,
Y : false,
YUI_config: false
};
exports.mocha = {
// Global (for config etc.)
mocha : false,
// BDD
describe : false,
xdescribe : false,
it : false,
xit : false,
context : false,
xcontext : false,
before : false,
after : false,
beforeEach : false,
afterEach : false,
// TDD
suite : false,
test : false,
setup : false,
teardown : false,
suiteSetup : false,
suiteTeardown : false
};
exports.jasmine = {
jasmine : false,
describe : false,
xdescribe : false,
it : false,
xit : false,
beforeEach : false,
afterEach : false,
setFixtures : false,
loadFixtures: false,
spyOn : false,
expect : false,
// Jasmine 1.3
runs : false,
waitsFor : false,
waits : false,
// Jasmine 2.1
beforeAll : false,
afterAll : false,
fail : false,
fdescribe : false,
fit : false,
pending : false,
// Jasmine 2.6
spyOnProperty: false
};
},{}],"jshint":[function(require,module,exports){
/*!
* JSHint, by JSHint Community.
*
* This file (and this file only) is licensed under the same slightly modified
* MIT license that JSLint is. It stops evil-doers everywhere:
*
* Copyright (c) 2002 Douglas Crockford (www.JSLint.com)
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* The Software shall be used for Good, not Evil.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
/*jshint quotmark:double */
/*exported console */
var _ = require("lodash");
var events = require("events");
var vars = require("./vars.js");
var messages = require("./messages.js");
var Lexer = require("./lex.js").Lexer;
var reg = require("./reg.js");
var state = require("./state.js").state;
var style = require("./style.js");
var options = require("./options.js");
var scopeManager = require("./scope-manager.js");
var prodParams = require("./prod-params.js");
// We need this module here because environments such as IE and Rhino
// don't necessarilly expose the 'console' API and browserify uses
// it to log things. It's a sad state of affair, really.
var console = require("console-browserify");
// We build the application inside a function so that we produce only a singleton
// variable. That function will be invoked immediately, and its return value is
// the JSHINT function itself.
var JSHINT = (function() {
"use strict";
var api, // Extension API
// These are operators that should not be used with the ! operator.
bang = {
"<" : true,
"<=" : true,
"==" : true,
"===": true,
"!==": true,
"!=" : true,
">" : true,
">=" : true,
"+" : true,
"-" : true,
"*" : true,
"/" : true,
"%" : true
},
declared, // Globals that were declared using /*global ... */ syntax.
functions, // All of the functions
inblock,
indent,
lookahead,
lex,
member,
membersOnly,
predefined, // Global variables defined by option
extraModules = [],
emitter = new events.EventEmitter();
function checkOption(name, isStable, t) {
var type, validNames;
if (isStable) {
type = "";
validNames = options.validNames;
} else {
type = "unstable ";
validNames = options.unstableNames;
}
name = name.trim();
if (/^[+-]W\d{3}$/g.test(name)) {
return true;
}
if (validNames.indexOf(name) === -1) {
if (t.type !== "jslint" && !_.has(options.removed, name)) {
error("E001", t, type, name);
return false;
}
}
return true;
}
function isString(obj) {
return Object.prototype.toString.call(obj) === "[object String]";
}
function isIdentifier(tkn, value) {
if (!tkn)
return false;
if (!tkn.identifier || tkn.value !== value)
return false;
return true;
}
/**
* ES3 defined a set of "FutureReservedWords" in order "to allow for the
* possibility of future adoption of [proposed] extensions."
*
* ES5 reduced the set of FutureReservedWords, in some cases by using them to
* define new syntactic forms (e.g. `class` and `const`) and in other cases
* by simply allowing their use as Identifiers (e.g. `int` and `goto`).
* Separately, ES5 introduced new restrictions on certain tokens, but limited
* the restriction to strict mode code (e.g. `let` and `yield`).
*
* This function determines if a given token describes a reserved word
* according to the current state of the parser.
*
* @param {number} context - the parsing context; see `prod-params.js` for
* more information
* @param {Token} token
*/
function isReserved(context, token) {
if (!token.reserved) {
return false;
}
var meta = token.meta;
if (meta && meta.isFutureReservedWord) {
if (state.inES5()) {
// ES3 FutureReservedWord in an ES5 environment.
if (!meta.es5) {
return false;
}
if (token.isProperty) {
return false;
}
}
} else if (meta && meta.es5 && !state.inES5()) {
return false;
}
// Some identifiers are reserved only within a strict mode environment.
if (meta && meta.strictOnly && state.inES5()) {
if (!state.option.strict && !state.isStrict()) {
return false;
}
}
if (token.id === "await" && (!(context & prodParams.async) && !state.option.module)) {
return false;
}
if (token.id === "yield" && (!(context & prodParams.yield))) {
return state.isStrict();
}
return true;
}
function supplant(str, data) {
return str.replace(/\{([^{}]*)\}/g, function(a, b) {
var r = data[b];
return typeof r === "string" || typeof r === "number" ? r : a;
});
}
function combine(dest, src) {
Object.keys(src).forEach(function(name) {
if (_.has(JSHINT.blacklist, name)) return;
dest[name] = src[name];
});
}
function processenforceall() {
if (state.option.enforceall) {
for (var enforceopt in options.bool.enforcing) {
if (state.option[enforceopt] === undefined &&
!options.noenforceall[enforceopt]) {
state.option[enforceopt] = true;
}
}
for (var relaxopt in options.bool.relaxing) {
if (state.option[relaxopt] === undefined) {
state.option[relaxopt] = false;
}
}
}
}
/**
* Apply all linting options according to the status of the `state` object.
*/
function applyOptions() {
var badESOpt = null;
processenforceall();
/**
* TODO: Remove in JSHint 3
*/
badESOpt = state.inferEsVersion();
if (badESOpt) {
quit("E059", state.tokens.next, "esversion", badESOpt);
}
if (state.inES5()) {
combine(predefined, vars.ecmaIdentifiers[5]);
}
if (state.inES6()) {
combine(predefined, vars.ecmaIdentifiers[6]);
}
if (state.inES8()) {
combine(predefined, vars.ecmaIdentifiers[8]);
}
/**
* Use `in` to check for the presence of any explicitly-specified value for
* `globalstrict` because both `true` and `false` should trigger an error.
*/
if (state.option.strict === "global" && "globalstrict" in state.option) {
quit("E059", state.tokens.next, "strict", "globalstrict");
}
if (state.option.module) {
/**
* TODO: Extend this restriction to *all* ES6-specific options.
*/
if (!state.inES6()) {
warning("W134", state.tokens.next, "module", 6);
}
}
if (state.option.regexpu) {
/**
* TODO: Extend this restriction to *all* ES6-specific options.
*/
if (!state.inES6()) {
warning("W134", state.tokens.next, "regexpu", 6);
}
}
if (state.option.couch) {
combine(predefined, vars.couch);
}
if (state.option.qunit) {
combine(predefined, vars.qunit);
}
if (state.option.rhino) {
combine(predefined, vars.rhino);
}
if (state.option.shelljs) {
combine(predefined, vars.shelljs);
combine(predefined, vars.node);
}
if (state.option.typed) {
combine(predefined, vars.typed);
}
if (state.option.phantom) {
combine(predefined, vars.phantom);
}
if (state.option.prototypejs) {
combine(predefined, vars.prototypejs);
}
if (state.option.node) {
combine(predefined, vars.node);
combine(predefined, vars.typed);
}
if (state.option.devel) {
combine(predefined, vars.devel);
}
if (state.option.dojo) {
combine(predefined, vars.dojo);
}
if (state.option.browser) {
combine(predefined, vars.browser);
combine(predefined, vars.typed);
}
if (state.option.browserify) {
combine(predefined, vars.browser);
combine(predefined, vars.typed);
combine(predefined, vars.browserify);
}
if (state.option.nonstandard) {
combine(predefined, vars.nonstandard);
}
if (state.option.jasmine) {
combine(predefined, vars.jasmine);
}
if (state.option.jquery) {
combine(predefined, vars.jquery);
}
if (state.option.mootools) {
combine(predefined, vars.mootools);
}
if (state.option.worker) {
combine(predefined, vars.worker);
}
if (state.option.wsh) {
combine(predefined, vars.wsh);
}
if (state.option.yui) {
combine(predefined, vars.yui);
}
if (state.option.mocha) {
combine(predefined, vars.mocha);
}
}
// Produce an error warning.
function quit(code, token, a, b) {
var percentage = Math.floor((token.line / state.lines.length) * 100);
var message = messages.errors[code].desc;
var exception = {
name: "JSHintError",
line: token.line,
character: token.from,
message: message + " (" + percentage + "% scanned).",
raw: message,
code: code,
a: a,
b: b
};
exception.reason = supplant(message, exception) + " (" + percentage +
"% scanned).";
throw exception;
}
function removeIgnoredMessages() {
var ignored = state.ignoredLines;
if (_.isEmpty(ignored)) return;
JSHINT.errors = _.reject(JSHINT.errors, function(err) { return ignored[err.line] });
}
function warning(code, t, a, b, c, d) {
var ch, l, w, msg;
if (/^W\d{3}$/.test(code)) {
if (state.ignored[code])
return;
msg = messages.warnings[code];
} else if (/E\d{3}/.test(code)) {
msg = messages.errors[code];
} else if (/I\d{3}/.test(code)) {
msg = messages.info[code];
}
t = t || state.tokens.next || {};
if (t.id === "(end)") { // `~
t = state.tokens.curr;
}
l = t.line;
ch = t.from;
w = {
id: "(error)",
raw: msg.desc,
code: msg.code,
evidence: state.lines[l - 1] || "",
line: l,
character: ch,
scope: JSHINT.scope,
a: a,
b: b,
c: c,
d: d
};
w.reason = supplant(msg.desc, w);
JSHINT.errors.push(w);
removeIgnoredMessages();
if (JSHINT.errors.length >= state.option.maxerr)
quit("E043", t);
return w;
}
function warningAt(m, l, ch, a, b, c, d) {
return warning(m, {
line: l,
from: ch
}, a, b, c, d);
}
function error(m, t, a, b, c, d) {
warning(m, t, a, b, c, d);
}
function errorAt(m, l, ch, a, b, c, d) {
return error(m, {
line: l,
from: ch
}, a, b, c, d);
}
// Tracking of "internal" scripts, like eval containing a static string
function addEvalCode(elem, token) {
JSHINT.internals.push({
id: "(internal)",
elem: elem,
token: token,
code: token.value.replace(/([^\\])(\\*)\2\\n/g, "$1\n")
});
}
/**
* Process an inline linting directive
*
* @param {Token} directiveToken - the directive-bearing comment token
* @param {Token} previous - the token that preceeds the directive
*/
function lintingDirective(directiveToken, previous) {
var body = directiveToken.body.split(",")
.map(function(s) { return s.trim(); });
var predef = {};
if (directiveToken.type === "falls through") {
previous.caseFallsThrough = true;
return;
}
if (directiveToken.type === "globals") {
body.forEach(function(item, idx) {
var parts = item.split(":");
var key = parts[0].trim();
if (key === "-" || !key.length) {
// Ignore trailing comma
if (idx > 0 && idx === body.length - 1) {
return;
}
error("E002", directiveToken);
return;
}
if (key.charAt(0) === "-") {
key = key.slice(1);
JSHINT.blacklist[key] = key;
delete predefined[key];
} else {
predef[key] = parts.length > 1 && parts[1].trim() === "true";
}
});
combine(predefined, predef);
for (var key in predef) {
if (_.has(predef, key)) {
declared[key] = directiveToken;
}
}
}
if (directiveToken.type === "exported") {
body.forEach(function(e, idx) {
if (!e.length) {
// Ignore trailing comma
if (idx > 0 && idx === body.length - 1) {
return;
}
error("E002", directiveToken);
return;
}
state.funct["(scope)"].addExported(e);
});
}
if (directiveToken.type === "members") {
membersOnly = membersOnly || {};
body.forEach(function(m) {
var ch1 = m.charAt(0);
var ch2 = m.charAt(m.length - 1);
if (ch1 === ch2 && (ch1 === "\"" || ch1 === "'")) {
m = m
.substr(1, m.length - 2)
.replace("\\\"", "\"");
}
membersOnly[m] = false;
});
}
var numvals = [
"maxstatements",
"maxparams",
"maxdepth",
"maxcomplexity",
"maxerr",
"maxlen",
"indent"
];
if (directiveToken.type === "jshint" || directiveToken.type === "jslint" ||
directiveToken.type === "jshint.unstable") {
body.forEach(function(item) {
var parts = item.split(":");
var key = parts[0].trim();
var val = parts.length > 1 ? parts[1].trim() : "";
var numberVal;
if (!checkOption(key, directiveToken.type !== "jshint.unstable", directiveToken)) {
return;
}
if (numvals.indexOf(key) >= 0) {
// GH988 - numeric options can be disabled by setting them to `false`
if (val !== "false") {
numberVal = +val;
if (typeof numberVal !== "number" || !isFinite(numberVal) ||
numberVal <= 0 || Math.floor(numberVal) !== numberVal) {
error("E032", directiveToken, val);
return;
}
state.option[key] = numberVal;
} else {
state.option[key] = key === "indent" ? 4 : false;
}
return;
}
if (key === "validthis") {
// `validthis` is valid only within a function scope.
if (state.funct["(global)"])
return void error("E009");
if (val !== "true" && val !== "false")
return void error("E002", directiveToken);
state.option.validthis = (val === "true");
return;
}
if (key === "quotmark") {
switch (val) {
case "true":
case "false":
state.option.quotmark = (val === "true");
break;
case "double":
case "single":
state.option.quotmark = val;
break;
default:
error("E002", directiveToken);
}
return;
}
if (key === "shadow") {
switch (val) {
case "true":
state.option.shadow = true;
break;
case "outer":
state.option.shadow = "outer";
break;
case "false":
case "inner":
state.option.shadow = "inner";
break;
default:
error("E002", directiveToken);
}
return;
}
if (key === "unused") {
switch (val) {
case "true":
state.option.unused = true;
break;
case "false":
state.option.unused = false;
break;
case "vars":
case "strict":
state.option.unused = val;
break;
default:
error("E002", directiveToken);
}
return;
}
if (key === "latedef") {
switch (val) {
case "true":
state.option.latedef = true;
break;
case "false":
state.option.latedef = false;
break;
case "nofunc":
state.option.latedef = "nofunc";
break;
default:
error("E002", directiveToken);
}
return;
}
if (key === "ignore") {
switch (val) {
case "line":
state.ignoredLines[directiveToken.line] = true;
removeIgnoredMessages();
break;
default:
error("E002", directiveToken);
}
return;
}
if (key === "strict") {
switch (val) {
case "true":
state.option.strict = true;
break;
case "false":
state.option.strict = false;
break;
case "global":
case "implied":
state.option.strict = val;
break;
default:
error("E002", directiveToken);
}
return;
}
if (key === "module") {
/**
* TODO: Extend this restriction to *all* "environmental" options.
*/
if (!hasParsedCode(state.funct)) {
error("E055", directiveToken, "module");
}
}
if (key === "esversion") {
switch (val) {
case "3":
case "5":
case "6":
case "7":
case "8":
case "9":
case "10":
state.option.moz = false;
state.option.esversion = +val;
break;
case "2015":
case "2016":
case "2017":
case "2018":
case "2019":
state.option.moz = false;
// Translate specification publication year to version number.
state.option.esversion = +val - 2009;
break;
default:
error("E002", directiveToken);
}
if (!hasParsedCode(state.funct)) {
error("E055", directiveToken, "esversion");
}
return;
}
var match = /^([+-])(W\d{3})$/g.exec(key);
if (match) {
// ignore for -W..., unignore for +W...
state.ignored[match[2]] = (match[1] === "-");
return;
}
var tn;
if (val === "true" || val === "false") {
if (directiveToken.type === "jslint") {
tn = options.renamed[key] || key;
state.option[tn] = (val === "true");
if (options.inverted[tn] !== undefined) {
state.option[tn] = !state.option[tn];
}
} else if (directiveToken.type === "jshint.unstable") {
state.option.unstable[key] = (val === "true");
} else {
state.option[key] = (val === "true");
}
return;
}
error("E002", directiveToken);
});
applyOptions();
}
}
/**
* Return a token beyond the token available in `state.tokens.next`. If no
* such token exists, return the "(end)" token. This function is used to
* determine parsing strategies in cases where the value of the next token
* does not provide sufficient information, as is the case with `for` loops,
* e.g.:
*
* for ( var i in ...
*
* versus:
*
* for ( var i = ...
*
* @param {number} [p] - offset of desired token; defaults to 0
*
* @returns {token}
*/
function peek(p) {
var i = p || 0, j = lookahead.length, t;
if (i < j) {
return lookahead[i];
}
while (j <= i) {
t = lex.token();
// When the lexer is exhausted, this function should produce the "(end)"
// token, even in cases where the requested token is beyond the end of
// the input stream.
if (!t) {
// If the lookahead buffer is empty, the expected "(end)" token was
// already emitted by the most recent invocation of `advance` and is
// available as the next token.
if (!lookahead.length) {
return state.tokens.next;
}
return lookahead[j - 1];
}
lookahead[j] = t;
j += 1;
}
return t;
}
function peekIgnoreEOL() {
var i = 0;
var t;
do {
t = peek(i++);
} while (t.id === "(endline)");
return t;
}
/**
* Consume the next token.
*
* @param {string} [expected] - the expected value of the next token's `id`
* property (in the case of punctuators) or
* `value` property (in the case of identifiers
* and literals); if unspecified, any token will
* be accepted
* @param {object} [relatedToken] - the token that informed the expected
* value, if any (for example: the opening
* brace when a closing brace is expected);
* used to produce more meaningful errors
*/
function advance(expected, relatedToken) {
var nextToken = state.tokens.next;
if (expected && nextToken.id !== expected) {
if (relatedToken) {
if (nextToken.id === "(end)") {
error("E019", relatedToken, relatedToken.id);
} else {
error("E020", nextToken, expected, relatedToken.id,
relatedToken.line, nextToken.value);
}
} else if (nextToken.type !== "(identifier)" || nextToken.value !== expected) {
error("E021", nextToken, expected, nextToken.value);
}
}
state.tokens.prev = state.tokens.curr;
state.tokens.curr = state.tokens.next;
for (;;) {
state.tokens.next = lookahead.shift() || lex.token();
if (!state.tokens.next) { // No more tokens left, give up
quit("E041", state.tokens.curr);
}
if (state.tokens.next.id === "(end)" || state.tokens.next.id === "(error)") {
return;
}
if (state.tokens.next.check) {
state.tokens.next.check();
}
if (state.tokens.next.isSpecial) {
lintingDirective(state.tokens.next, state.tokens.curr);
} else {
if (state.tokens.next.id !== "(endline)") {
break;
}
}
}
}
/**
* Determine whether a given token is an operator.
*
* @param {token} token
*
* @returns {boolean}
*/
function isOperator(token) {
return token.first || token.right || token.left || token.id === "yield" || token.id === "await";
}
function isEndOfExpr(context, curr, next) {
if (arguments.length <= 1) {
curr = state.tokens.curr;
next = state.tokens.next;
}
if (next.id === "in" && context & prodParams.noin) {
return true;
}
if (next.id === ";" || next.id === "}" || next.id === ":") {
return true;
}
if (next.infix === curr.infix ||
// Infix operators which follow `yield` should only be consumed as part
// of the current expression if allowed by the syntactic grammar. In
// effect, this prevents automatic semicolon insertion when `yield` is
// followed by a newline and a comma operator (without enabling it when
// `yield` is followed by a newline and a `[` token).
(curr.id === "yield" && curr.rbp < next.rbp)) {
return !sameLine(curr, next);
}
return false;
}
/**
* The `expression` function is the heart of JSHint's parsing behaior. It is
* based on the Pratt parser, but it extends that model with a `fud` method.
* Short for "first null denotation," it it similar to the `nud` ("null
* denotation") function, but it is only used on the first token of a
* statement. This simplifies usage in statement-oriented languages like
* JavaScript.
*
* .nud Null denotation
* .fud First null denotation
* .led Left denotation
* lbp Left binding power
* rbp Right binding power
*
* They are elements of the parsing method called Top Down Operator Precedence.
*
* In addition to parsing, this function applies a number of linting patterns.
*
* @param {number} context - the parsing context (a bitfield describing
* conditions of the current parsing operation
* which can influence how the next tokens are
* interpreted); see `prod-params.js` for more
* detail)
* @param {number} rbp - the right-binding power of the token to be consumed
*/
function expression(context, rbp) {
var left, isArray = false, isObject = false;
var initial = context & prodParams.initial;
var curr;
context &= ~prodParams.initial;
state.nameStack.push();
if (state.tokens.next.id === "(end)")
error("E006", state.tokens.curr);
advance();
if (initial) {
state.funct["(verb)"] = state.tokens.curr.value;
state.tokens.curr.beginsStmt = true;
}
curr = state.tokens.curr;
if (initial && curr.fud && (!curr.useFud || curr.useFud(context))) {
left = state.tokens.curr.fud(context);
} else {
if (state.tokens.curr.nud) {
left = state.tokens.curr.nud(context, rbp);
} else {
error("E030", state.tokens.curr, state.tokens.curr.id);
}
while (rbp < state.tokens.next.lbp && !isEndOfExpr(context)) {
isArray = state.tokens.curr.value === "Array";
isObject = state.tokens.curr.value === "Object";
// #527, new Foo.Array(), Foo.Array(), new Foo.Object(), Foo.Object()
// Line breaks in IfStatement heads exist to satisfy the checkJSHint
// "Line too long." error.
if (left && (left.value || (left.first && left.first.value))) {
// If the left.value is not "new", or the left.first.value is a "."
// then safely assume that this is not "new Array()" and possibly
// not "new Object()"...
if (left.value !== "new" ||
(left.first && left.first.value && left.first.value === ".")) {
isArray = false;
// ...In the case of Object, if the left.value and state.tokens.curr.value
// are not equal, then safely assume that this not "new Object()"
if (left.value !== state.tokens.curr.value) {
isObject = false;
}
}
}
advance();
if (isArray && state.tokens.curr.id === "(" && state.tokens.next.id === ")") {
warning("W009", state.tokens.curr);
}
if (isObject && state.tokens.curr.id === "(" && state.tokens.next.id === ")") {
warning("W010", state.tokens.curr);
}
if (left && state.tokens.curr.led) {
left = state.tokens.curr.led(context, left);
} else {
error("E033", state.tokens.curr, state.tokens.curr.id);
}
}
}
state.nameStack.pop();
return left;
}
// Functions for conformance of style.
function sameLine(first, second) {
return first.line === (second.startLine || second.line);
}
function nobreaknonadjacent(left, right) {
if (!state.option.laxbreak && !sameLine(left, right)) {
warning("W014", right, right.value);
}
}
function nolinebreak(t) {
t = t;
if (!sameLine(t, state.tokens.next)) {
warning("E022", t, t.value);
}
}
/**
* Validate the comma token in the "current" position of the token stream.
*
* @param {object} [opts]
* @param {boolean} [opts.property] - flag indicating whether the current
* comma token is situated directly within
* an object initializer
* @param {boolean} [opts.allowTrailing] - flag indicating whether the
* current comma token may appear
* directly before a delimiter
*
* @returns {boolean} flag indicating the validity of the current comma
* token; `false` if the token directly causes a syntax
* error, `true` otherwise
*/
function checkComma(opts) {
var prev = state.tokens.prev;
var curr = state.tokens.curr;
opts = opts || {};
if (!sameLine(prev, curr)) {
if (!state.option.laxcomma) {
if (checkComma.first) {
warning("I001", curr);
checkComma.first = false;
}
warning("W014", prev, curr.value);
}
}
if (state.tokens.next.identifier && !(opts.property && state.inES5())) {
// Keywords that cannot follow a comma operator.
switch (state.tokens.next.value) {
case "break":
case "case":
case "catch":
case "continue":
case "default":
case "do":
case "else":
case "finally":
case "for":
case "if":
case "in":
case "instanceof":
case "return":
case "switch":
case "throw":
case "try":
case "var":
case "let":
case "while":
case "with":
error("E024", state.tokens.next, state.tokens.next.value);
return false;
}
}
if (state.tokens.next.type === "(punctuator)") {
switch (state.tokens.next.value) {
case "}":
case "]":
case ",":
case ")":
if (opts.allowTrailing) {
return true;
}
error("E024", state.tokens.next, state.tokens.next.value);
return false;
}
}
return true;
}
/**
* Factory function for creating "symbols"--objects that will be inherited by
* tokens. The objects created by this function are stored in a symbol table
* and set as the prototype of the tokens generated by the lexer.
*
* Note that this definition of "symbol" describes an implementation detail
* of JSHint and is not related to the ECMAScript value type introduced in
* ES2015.
*
* @param {string} s - the name of the token; for keywords (e.g. `void`) and
* delimiters (e.g.. `[`), this is the token's text
* representation; for literals (e.g. numbers) and other
* "special" tokens (e.g. the end-of-file marker) this is
* a parenthetical value
* @param {number} p - the left-binding power of the token as used by the
* Pratt parsing semantics
*
* @returns {object} - the object describing the JSHint symbol (provided to
* support cases where further refinement is necessary)
*/
function symbol(s, p) {
var x = state.syntax[s];
if (!x || typeof x !== "object") {
state.syntax[s] = x = {
id: s,
lbp: p,
// Symbols that accept a right-hand side do so with a binding power
// that is commonly identical to their left-binding power. (This value
// is relevant when determining if the grouping operator is necessary
// to override the precedence of surrounding operators.) Because the
// exponentiation operator's left-binding power and right-binding power
// are distinct, the values must be encoded separately.
rbp: p,
value: s
};
}
return x;
}
/**
* Convenience function for defining delimiter symbols.
*
* @param {string} s - the name of the symbol
*
* @returns {object} - the object describing the JSHint symbol (provided to
* support cases where further refinement is necessary)
*/
function delim(s) {
var x = symbol(s, 0);
x.delim = true;
return x;
}
/**
* Convenience function for defining statement-denoting symbols.
*
* @param {string} s - the name of the symbol
* @param {function} f - the first null denotation function for the symbol;
* see the `expression` function for more detail
*
* @returns {object} - the object describing the JSHint symbol (provided to
* support cases where further refinement is necessary)
*/
function stmt(s, f) {
var x = delim(s);
x.identifier = x.reserved = true;
x.fud = f;
return x;
}
/**
* Convenience function for defining block-statement-denoting symbols.
*
* A block-statement-denoting symbol is one like 'if' or 'for', which will be
* followed by a block and will not have to end with a semicolon.
*
* @param {string} s - the name of the symbol
* @param {function} - the first null denotation function for the symbol; see
* the `expression` function for more detail
*
* @returns {object} - the object describing the JSHint symbol (provided to
* support cases where further refinement is necessary)
*/
function blockstmt(s, f) {
var x = stmt(s, f);
x.block = true;
return x;
}
/**
* Denote a given JSHint symbol as an identifier and a reserved keyword.
*
* @param {object} - a JSHint symbol value
*
* @returns {object} - the provided object
*/
function reserveName(x) {
var c = x.id.charAt(0);
if ((c >= "a" && c <= "z") || (c >= "A" && c <= "Z")) {
x.identifier = x.reserved = true;
}
return x;
}
/**
* Convenience function for defining "prefix" symbols--operators that accept
* expressions as a right-hand side.
*
* @param {string} s - the name of the symbol
* @param {function} [f] - the first null denotation function for the symbol;
* see the `expression` function for more detail
*
* @returns {object} - the object describing the JSHint symbol (provided to
* support cases where further refinement is necessary)
*/
function prefix(s, f) {
var x = symbol(s, 150);
reserveName(x);
x.nud = (typeof f === "function") ? f : function(context) {
this.arity = "unary";
this.right = expression(context, 150);
if (this.id === "++" || this.id === "--") {
if (state.option.plusplus) {
warning("W016", this, this.id);
}
if (this.right) {
checkLeftSideAssign(context, this.right, this);
}
}
return this;
};
return x;
}
/**
* Convenience function for defining "type" symbols--those that describe
* literal values.
*
* @param {string} s - the name of the symbol
* @param {function} f - the first null denotation function for the symbol;
* see the `expression` function for more detail
*
* @returns {object} - the object describing the JSHint symbol (provided to
* support cases where further refinement is necessary)
*/
function type(s, f) {
var x = symbol(s, 0);
x.type = s;
x.nud = f;
return x;
}
/**
* Convenience function for defining JSHint symbols for reserved
* keywords--those that are restricted from use as bindings (and as property
* names in ECMAScript 3 environments).
*
* @param {string} s - the name of the symbol
* @param {function} func - the first null denotation function for the
* symbol; see the `expression` function for more
* detail
*
* @returns {object} - the object describing the JSHint symbol (provided to
* support cases where further refinement is necessary)
*/
function reserve(name, func) {
var x = type(name, func);
x.identifier = true;
x.reserved = true;
return x;
}
/**
* Convenience function for defining JSHint symbols for keywords that are
* only reserved in some circumstances.
*
* @param {string} name - the name of the symbol
* @param {object} [meta] - a collection of optional arguments
* @param {function} [meta.nud] -the null denotation function for the symbol;
* see the `expression` function for more detail
* @param {boolean} [meta.es5] - `true` if the identifier is reserved
* in ECMAScript 5 or later
* @param {boolean} [meta.strictOnly] - `true` if the identifier is only
* reserved in strict mode code.
*
* @returns {object} - the object describing the JSHint symbol (provided to
* support cases where further refinement is necessary)
*/
function FutureReservedWord(name, meta) {
var x = type(name, state.syntax["(identifier)"].nud);
meta = meta || {};
meta.isFutureReservedWord = true;
x.value = name;
x.identifier = true;
x.reserved = true;
x.meta = meta;
return x;
}
/**
* Convenience function for defining "infix" symbols--operators that require
* operands as both "land-hand side" and "right-hand side".
*
* @param {string} s - the name of the symbol
* @param {function} [f] - a function to be invoked that consumes the
* right-hand side of the operator
* @param {number} p - the left-binding power of the token as used by the
* Pratt parsing semantics
* @param {boolean} [w] - if `true`
*
* @returns {object} - the object describing the JSHint symbol (provided to
* support cases where further refinement is necessary)
*/
function infix(s, f, p, w) {
var x = symbol(s, p);
reserveName(x);
x.infix = true;
x.led = function(context, left) {
if (!w) {
nobreaknonadjacent(state.tokens.prev, state.tokens.curr);
}
if ((s === "in" || s === "instanceof") && left.id === "!") {
warning("W018", left, "!");
}
if (typeof f === "function") {
return f(context, left, this);
} else {
this.left = left;
this.right = expression(context, p);
return this;
}
};
return x;
}
/**
* Convenience function for defining the `=>` token as used in arrow
* functions.
*
* @param {string} s - the name of the symbol
*
* @returns {object} - the object describing the JSHint symbol (provided to
* support cases where further refinement is necessary)
*/
function application(s) {
var x = symbol(s, 42);
x.infix = true;
x.led = function(context, left) {
nobreaknonadjacent(state.tokens.prev, state.tokens.curr);
this.left = left;
this.right = doFunction(context, { type: "arrow", loneArg: left });
return this;
};
return x;
}
/**
* Convenience function for defining JSHint symbols for relation operators.
*
* @param {string} s - the name of the symbol
* @param {function} [f] - a function to be invoked to enforce any additional
* linting rules.
*
* @returns {object} - the object describing the JSHint symbol (provided to
* support cases where further refinement is necessary)
*/
function relation(s, f) {
var x = symbol(s, 100);
x.infix = true;
x.led = function(context, left) {
nobreaknonadjacent(state.tokens.prev, state.tokens.curr);
this.left = left;
var right = this.right = expression(context, 100);
if (isIdentifier(left, "NaN") || isIdentifier(right, "NaN")) {
warning("W019", this);
} else if (f) {
f.apply(this, [context, left, right]);
}
if (!left || !right) {
quit("E041", state.tokens.curr);
}
if (left.id === "!") {
warning("W018", left, "!");
}
if (right.id === "!") {
warning("W018", right, "!");
}
return this;
};
return x;
}
/**
* Determine if a given token marks the beginning of a UnaryExpression.
*
* @param {object} token
*
* @returns {boolean}
*/
function beginsUnaryExpression(token) {
return token.arity === "unary" && token.id !== "++" && token.id !== "--";
}
var typeofValues = {};
typeofValues.legacy = [
// E4X extended the `typeof` operator to return "xml" for the XML and
// XMLList types it introduced.
// Ref: 11.3.2 The typeof Operator
// http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-357.pdf
"xml",
// IE<9 reports "unknown" when the `typeof` operator is applied to an
// object existing across a COM+ bridge. In lieu of official documentation
// (which does not exist), see:
// http://robertnyman.com/2005/12/21/what-is-typeof-unknown/
"unknown"
];
typeofValues.es3 = [
"undefined", "boolean", "number", "string", "function", "object",
];
typeofValues.es3 = typeofValues.es3.concat(typeofValues.legacy);
typeofValues.es6 = typeofValues.es3.concat("symbol", "bigint");
/**
* Validate comparisons between the result of a `typeof` expression and a
* string literal.
*
* @param {token} [left] - one of the values being compared
* @param {token} [right] - the other value being compared
* @param {object} state - the global state object (see `state.js`)
*
* @returns {boolean} - `false` if the second token describes a `typeof`
* expression and the first token is a string literal
* whose value is never returned by that operator;
* `true` otherwise
*/
function isTypoTypeof(left, right, state) {
var values;
if (state.option.notypeof)
return false;
if (!left || !right)
return false;
values = state.inES6() ? typeofValues.es6 : typeofValues.es3;
if (right.type === "(identifier)" && right.value === "typeof" && left.type === "(string)") {
if (left.value === "bigint") {
if (!state.option.unstable.bigint) {
warning("W144", left, "BigInt", "bigint");
}
return false;
}
return !_.includes(values, left.value);
}
return false;
}
/**
* Determine if a given token describes the built-in `eval` function.
*
* @param {token} left
* @param {object} state - the global state object (see `state.js`)
*
* @returns {boolean}
*/
function isGlobalEval(left, state) {
var isGlobal = false;
// permit methods to refer to an "eval" key in their own context
if (left.type === "this" && state.funct["(context)"] === null) {
isGlobal = true;
}
// permit use of "eval" members of objects
else if (left.type === "(identifier)") {
if (state.option.node && left.value === "global") {
isGlobal = true;
}
else if (state.option.browser && (left.value === "window" || left.value === "document")) {
isGlobal = true;
}
}
return isGlobal;
}
/**
* Determine if a given token describes a property of a built-in object.
*
* @param {token} left
*
* @returns {boolean}
*/
function findNativePrototype(left) {
var natives = [
"Array", "ArrayBuffer", "Boolean", "Collator", "DataView", "Date",
"DateTimeFormat", "Error", "EvalError", "Float32Array", "Float64Array",
"Function", "Infinity", "Intl", "Int16Array", "Int32Array", "Int8Array",
"Iterator", "Number", "NumberFormat", "Object", "RangeError",
"ReferenceError", "RegExp", "StopIteration", "String", "SyntaxError",
"TypeError", "Uint16Array", "Uint32Array", "Uint8Array", "Uint8ClampedArray",
"URIError"
];
function walkPrototype(obj) {
if (typeof obj !== "object") return;
return obj.right === "prototype" ? obj : walkPrototype(obj.left);
}
function walkNative(obj) {
while (!obj.identifier && typeof obj.left === "object")
obj = obj.left;
if (obj.identifier && natives.indexOf(obj.value) >= 0 &&
state.funct["(scope)"].isPredefined(obj.value)) {
return obj.value;
}
}
var prototype = walkPrototype(left);
if (prototype) return walkNative(prototype);
}
/**
* Determine if the given token is a valid assignment target; emit errors
* and/or warnings as appropriate
*
* @param {number} context - the parsing context; see `prod-params.js` for
* more information
* @param {token} left - the left hand side of the assignment
* @param {token=} assignToken - the token for the assignment, used for
* reporting
* @param {object=} options - optional object
* @param {boolean} options.allowDestructuring - whether to allow
* destructuring binding
*
* @returns {boolean} Whether the left hand side is OK
*/
function checkLeftSideAssign(context, left, assignToken, options) {
var allowDestructuring = options && options.allowDestructuring;
assignToken = assignToken || left;
if (state.option.freeze) {
var nativeObject = findNativePrototype(left);
if (nativeObject)
warning("W121", left, nativeObject);
}
if (left.identifier && !left.isMetaProperty) {
// The `reassign` method also calls `modify`, but we are specific in
// order to catch function re-assignment and globals re-assignment
state.funct["(scope)"].block.reassign(left.value, left);
}
if (left.id === ".") {
if (!left.left || left.left.value === "arguments" && !state.isStrict()) {
warning("W143", assignToken);
}
state.nameStack.set(state.tokens.prev);
return true;
} else if (left.id === "{" || left.id === "[") {
if (!allowDestructuring || !left.destructAssign) {
if (left.id === "{" || !left.left) {
warning("E031", assignToken);
} else if (left.left.value === "arguments" && !state.isStrict()) {
warning("W143", assignToken);
}
}
if (left.id === "[") {
state.nameStack.set(left.right);
}
return true;
} else if (left.identifier && !isReserved(context, left) && !left.isMetaProperty) {
if (state.funct["(scope)"].bindingtype(left.value) === "exception") {
warning("W022", left);
}
if (left.value === "eval" && state.isStrict()) {
error("E031", assignToken);
return false;
} else if (left.value === "arguments") {
if (!state.isStrict()) {
warning("W143", assignToken);
} else {
error("E031", assignToken);
return false;
}
}
state.nameStack.set(left);
return true;
}
error("E031", assignToken);
return false;
}
/**
* Convenience function for defining JSHint symbols for assignment operators.
*
* @param {string} s - the name of the symbol
* @param {function} [f] - a function to be invoked that consumes the
* right-hand side of the operator (see the `infix`
* function)
*
* @returns {object} - the object describing the JSHint symbol (provided to
* support cases where further refinement is necessary)
*/
function assignop(s, f) {
var x = infix(s, typeof f === "function" ? f : function(context, left, that) {
that.left = left;
checkLeftSideAssign(context, left, that, { allowDestructuring: true });
that.right = expression(context, 10);
return that;
}, 20);
x.exps = true;
x.assign = true;
return x;
}
/**
* Convenience function for defining JSHint symbols for bitwise operators.
*
* @param {string} s - the name of the symbol
* @param {function} [f] - the left denotation function for the symbol; see
* the `expression` function for more detail
* @param {number} p - the left-binding power of the token as used by the
* Pratt parsing semantics
*
* @returns {object} - the object describing the JSHint symbol (provided to
* support cases where further refinement is necessary)
*/
function bitwise(s, f, p) {
var x = symbol(s, p);
reserveName(x);
x.infix = true;
x.led = (typeof f === "function") ? f : function(context, left) {
if (state.option.bitwise) {
warning("W016", this, this.id);
}
this.left = left;
this.right = expression(context, p);
return this;
};
return x;
}
/**
* Convenience function for defining JSHint symbols for bitwise assignment
* operators. See the `assignop` function for more detail.
*
* @param {string} s - the name of the symbol
*
* @returns {object} - the object describing the JSHint symbol (provided to
* support cases where further refinement is necessary)
*/
function bitwiseassignop(s) {
symbol(s, 20).exps = true;
return infix(s, function(context, left, that) {
if (state.option.bitwise) {
warning("W016", that, that.id);
}
checkLeftSideAssign(context, left, that);
that.right = expression(context, 10);
return that;
}, 20);
}
/**
* Convenience function for defining JSHint symbols for those operators which
* have a single operand that appears before them in the source code.
*
* @param {string} s - the name of the symbol
*
* @returns {object} - the object describing the JSHint symbol (provided to
* support cases where further refinement is necessary)
*/
function suffix(s) {
var x = symbol(s, 150);
x.led = function(context, left) {
// this = suffix e.g. "++" punctuator
// left = symbol operated e.g. "a" identifier or "a.b" punctuator
if (state.option.plusplus) {
warning("W016", this, this.id);
}
checkLeftSideAssign(context, left, this);
this.left = left;
return this;
};
return x;
}
/**
* Retrieve the value of the current token if it is an identifier and
* optionally advance the parser.
*
* @param {number} context - the parsing context; see `prod-params.js` for
* more information
* @param {boolean} [prop] -`true` if this identifier is that of an object
* property
* @param {boolean} [preserve] - `true` if the token should not be consumed
*
* @returns {string|undefined} - the value of the identifier, if present
*/
function optionalidentifier(context, prop, preserve) {
if (!state.tokens.next.identifier) {
return;
}
if (!preserve) {
advance();
}
var curr = state.tokens.curr;
var val = state.tokens.curr.value;
if (!isReserved(context, curr)) {
return val;
}
if (prop) {
if (state.inES5()) {
return val;
}
}
warning("W024", state.tokens.curr, state.tokens.curr.id);
return val;
}
/**
* Consume the "..." token which designates "spread" and "rest" operations if
* it is present. If the operator is repeated, consume every repetition, and
* issue a single error describing the syntax error.
*
* @param {string} operation - either "spread" or "rest"
*
* @returns {boolean} a value describing whether or not any tokens were
* consumed in this way
*/
function spreadrest(operation) {
if (!checkPunctuator(state.tokens.next, "...")) {
return false;
}
if (!state.inES6(true)) {
warning("W119", state.tokens.next, operation + " operator", "6");
}
advance();
if (checkPunctuator(state.tokens.next, "...")) {
warning("E024", state.tokens.next, "...");
while (checkPunctuator(state.tokens.next, "...")) {
advance();
}
}
return true;
}
/**
* Ensure that the current token is an identifier and retrieve its value.
*
* @param {number} context - the parsing context; see `prod-params.js` for
* more information
* @param {boolean} [prop] -`true` if this identifier is that of an object
* property
*
* @returns {string|undefined} - the value of the identifier, if present
*/
function identifier(context, prop) {
var i = optionalidentifier(context, prop, false);
if (i) {
return i;
}
error("E030", state.tokens.next, state.tokens.next.value);
// The token should be consumed after a warning is issued so the parser
// can continue as though an identifier were found. The semicolon token
// should not be consumed in this way so that the parser interprets it as
// a statement delimiter;
if (state.tokens.next.id !== ";") {
advance();
}
}
/**
* Determine if the provided token may be evaluated and emit a linting
* warning if this is note the case.
*
* @param {token} controlToken
*/
function reachable(controlToken) {
var i = 0, t;
if (state.tokens.next.id !== ";" || controlToken.inBracelessBlock) {
return;
}
for (;;) {
do {
t = peek(i);
i += 1;
} while (t.id !== "(end)" && t.id === "(comment)");
if (t.reach) {
return;
}
if (t.id !== "(endline)") {
if (t.id === "function") {
if (state.option.latedef === true) {
warning("W026", t);
}
break;
}
warning("W027", t, t.value, controlToken.value);
break;
}
}
}
/**
* Consume the semicolon that delimits the statement currently being parsed,
* emitting relevant warnings/errors as appropriate.
*
* @param {token} stmt - token describing the statement under consideration
*/
function parseFinalSemicolon(stmt) {
if (state.tokens.next.id !== ";") {
// don't complain about unclosed templates / strings
if (state.tokens.next.isUnclosed) return advance();
var isSameLine = sameLine(state.tokens.curr, state.tokens.next) &&
state.tokens.next.id !== "(end)";
var blockEnd = checkPunctuator(state.tokens.next, "}");
if (isSameLine && !blockEnd && !(stmt.id === "do" && state.inES6(true))) {
errorAt("E058", state.tokens.curr.line, state.tokens.curr.character);
} else if (!state.option.asi) {
// If this is the last statement in a block that ends on the same line
// *and* option lastsemic is on, ignore the warning. Otherwise, issue
// a warning about missing semicolon.
if (!(blockEnd && isSameLine && state.option.lastsemic)) {
warningAt("W033", state.tokens.curr.line, state.tokens.curr.character);
}
}
} else {
advance(";");
}
}
/**
* Consume a statement.
*
* @param {number} context - the parsing context; see `prod-params.js` for
* more information
*
* @returns {token} - the token describing the statement
*/
function statement(context) {
var i = indent, r, t = state.tokens.next, hasOwnScope = false;
context |= prodParams.initial;
if (t.id === ";") {
advance(";");
return;
}
// Is this a labelled statement?
var res = isReserved(context, t);
// We're being more tolerant here: if someone uses
// a FutureReservedWord (that is not meant to start a statement)
// as a label, we warn but proceed anyway.
if (res && t.meta && t.meta.isFutureReservedWord && !t.fud) {
warning("W024", t, t.id);
res = false;
}
if (t.identifier && !res && peek().id === ":") {
advance();
advance(":");
hasOwnScope = true;
state.funct["(scope)"].stack();
state.funct["(scope)"].block.addLabel(t.value, { token: state.tokens.curr });
if (!state.tokens.next.labelled && state.tokens.next.value !== "{") {
warning("W028", state.tokens.next, t.value, state.tokens.next.value);
}
t = state.tokens.next;
}
// Is it a lonely block?
if (t.id === "{") {
// Is it a switch case block?
//
// switch (foo) {
// case bar: { <= here.
// ...
// }
// }
var iscase = (state.funct["(verb)"] === "case" && state.tokens.curr.value === ":");
block(context, true, true, false, false, iscase);
if (hasOwnScope) {
state.funct["(scope)"].unstack();
}
return;
}
// Parse the statement.
r = expression(context, 0);
if (r && !(r.identifier && r.value === "function") &&
!(r.type === "(punctuator)" && r.left &&
r.left.identifier && r.left.value === "function")) {
if (!state.isStrict() && state.stmtMissingStrict()) {
warning("E007");
}
}
// Look for the final semicolon.
if (!t.block) {
if (!state.option.expr && (!r || !r.exps)) {
warning("W030", state.tokens.curr);
} else if (state.option.nonew && r && r.left && r.id === "(" && r.left.id === "new") {
warning("W031", t);
}
parseFinalSemicolon(t);
}
// Restore the indentation.
indent = i;
if (hasOwnScope) {
state.funct["(scope)"].unstack();
}
return r;
}
/**
* Consume a series of statements until encountering either the end of the
* program or a token that interrupts control flow.
*
* @param {number} context - the parsing context; see `prod-params.js` for
* more information
*
* @returns {Array<token>} - the tokens consumed
*/
function statements(context) {
var a = [], p;
while (!state.tokens.next.reach && state.tokens.next.id !== "(end)") {
if (state.tokens.next.id === ";") {
p = peek();
if (!p || (p.id !== "(" && p.id !== "[")) {
warning("W032");
}
advance(";");
} else {
a.push(statement(context));
}
}
return a;
}
/**
* Parse any directives in a directive prologue.
*/
function directives() {
var current = state.tokens.next;
while (state.tokens.next.id === "(string)") {
var next = peekIgnoreEOL();
if (!isEndOfExpr(0, current, next)) {
break;
}
current = next;
advance();
var directive = state.tokens.curr.value;
if (state.directive[directive] ||
(directive === "use strict" && state.option.strict === "implied")) {
warning("W034", state.tokens.curr, directive);
}
// From ECMAScript 2016:
//
// > 14.1.2 Static Semantics: Early Errors
// >
// > [...]
// > - It is a Syntax Error if ContainsUseStrict of FunctionBody is true
// > and IsSimpleParameterList of FormalParameters is false.
if (directive === "use strict" && state.inES7() &&
!state.funct["(global)"] && state.funct["(hasSimpleParams)"] === false) {
error("E065", state.tokens.curr);
}
// there's no directive negation, so always set to true
state.directive[directive] = true;
parseFinalSemicolon(current);
}
if (state.isStrict()) {
state.option.undef = true;
}
}
/**
* Parses a single block. A block is a sequence of statements wrapped in
* braces.
*
* @param {number} context - parsing context
* @param {boolean} ordinary - `true` for everything but function bodies and
* try blocks
* @param {boolean} [stmt] - `true` if block can be a single statement (e.g.
* in if/for/while)
* @param {boolean} [isfunc] - `true` if block is a function body
* @param {boolean} [isfatarrow] - `true` if its a body of a fat arrow
* function
* @param {boolean} [iscase] - `true` if block is a switch case block
*
* @returns {token} - the token describing the block
*/
function block(context, ordinary, stmt, isfunc, isfatarrow, iscase) {
var a,
b = inblock,
old_indent = indent,
m,
t,
d;
inblock = ordinary;
t = state.tokens.next;
var metrics = state.funct["(metrics)"];
metrics.nestedBlockDepth += 1;
metrics.verifyMaxNestedBlockDepthPerFunction();
if (state.tokens.next.id === "{") {
advance("{");
// create a new block scope
state.funct["(scope)"].stack();
if (state.tokens.next.id !== "}") {
indent += state.option.indent;
while (!ordinary && state.tokens.next.from > indent) {
indent += state.option.indent;
}
if (isfunc) {
m = {};
for (d in state.directive) {
m[d] = state.directive[d];
}
directives();
state.funct["(isStrict)"] = state.isStrict();
if (state.option.strict && state.funct["(context)"]["(global)"]) {
if (!m["use strict"] && !state.isStrict()) {
warning("E007");
}
}
}
a = statements(context);
metrics.statementCount += a.length;
indent -= state.option.indent;
} else if (isfunc) {
// Ensure property is set for functions with empty bodies.
state.funct["(isStrict)"] = state.isStrict();
}
advance("}", t);
if (isfunc) {
state.funct["(scope)"].validateParams(isfatarrow);
if (m) {
state.directive = m;
}
}
state.funct["(scope)"].unstack();
indent = old_indent;
} else if (!ordinary) {
if (isfunc) {
state.funct["(scope)"].stack();
if (stmt && !isfatarrow && !state.inMoz()) {
error("W118", state.tokens.curr, "function closure expressions");
}
if (isfatarrow) {
state.funct["(scope)"].validateParams(true);
}
var expr = expression(context, 10);
if (state.option.noreturnawait && context & prodParams.async &&
expr.identifier && expr.value === "await") {
warning("W146", expr);
}
if (state.option.strict && state.funct["(context)"]["(global)"]) {
if (!state.isStrict()) {
warning("E007");
}
}
state.funct["(scope)"].unstack();
} else {
error("E021", state.tokens.next, "{", state.tokens.next.value);
}
} else {
state.funct["(scope)"].stack();
if (!stmt || state.option.curly) {
warning("W116", state.tokens.next, "{", state.tokens.next.value);
}
// JSHint observes Annex B of the ECMAScript specification by default,
// where function declarations are permitted in the statement positions
// of IfStatements.
var supportsFnDecl = state.funct["(verb)"] === "if" ||
state.tokens.curr.id === "else";
state.tokens.next.inBracelessBlock = true;
indent += state.option.indent;
// test indentation only if statement is in new line
a = [statement(context)];
indent -= state.option.indent;
if (a[0] && a[0].declaration &&
!(supportsFnDecl && a[0].id === "function")) {
error("E048", a[0], a[0].id[0].toUpperCase() + a[0].id.slice(1));
}
state.funct["(scope)"].unstack();
}
// Don't clear and let it propagate out if it is "break", "return" or
// similar in switch case
switch (state.funct["(verb)"]) {
case "break":
case "continue":
case "return":
case "throw":
if (iscase) {
break;
}
/* falls through */
default:
state.funct["(verb)"] = null;
}
inblock = b;
if (ordinary && state.option.noempty && (!a || a.length === 0)) {
warning("W035", state.tokens.prev);
}
metrics.nestedBlockDepth -= 1;
return a;
}
/**
* Update the global state which tracks all statically-identifiable property
* names, and emit a warning if the `members` linting directive is in use and
* does not include the given name.
*
* @param {string} m - the property name
*/
function countMember(m) {
if (membersOnly && typeof membersOnly[m] !== "boolean") {
warning("W036", state.tokens.curr, m);
}
if (typeof member[m] === "number") {
member[m] += 1;
} else {
member[m] = 1;
}
}
// Build the syntax table by declaring the syntactic elements of the language.
type("(number)", function() {
if (state.tokens.next.id === ".") {
warning("W005", this);
}
return this;
});
type("(string)", function() {
return this;
});
state.syntax["(identifier)"] = {
type: "(identifier)",
lbp: 0,
identifier: true,
nud: function(context) {
var v = this.value;
// If this identifier is the lone parameter to a shorthand "fat arrow"
// function definition, i.e.
//
// x => x;
//
// ...it should not be considered as a variable in the current scope. It
// will be added to the scope of the new function when the next token is
// parsed, so it can be safely ignored for now.
var isLoneArrowParam = state.tokens.next.id === "=>";
if (isReserved(context, this)) {
warning("W024", this, v);
} else if (!isLoneArrowParam && !state.funct["(comparray)"].check(v)) {
state.funct["(scope)"].block.use(v, state.tokens.curr);
}
return this;
},
led: function() {
/* istanbul ignore next */
error("E033", state.tokens.next, state.tokens.next.value);
}
};
var baseTemplateSyntax = {
identifier: false,
template: true,
};
state.syntax["(template)"] = _.extend({
lbp: 155,
type: "(template)",
nud: doTemplateLiteral,
led: doTemplateLiteral,
noSubst: false
}, baseTemplateSyntax);
state.syntax["(template middle)"] = _.extend({
lbp: 0,
type: "(template middle)",
noSubst: false
}, baseTemplateSyntax);
state.syntax["(template tail)"] = _.extend({
lbp: 0,
type: "(template tail)",
tail: true,
noSubst: false
}, baseTemplateSyntax);
state.syntax["(no subst template)"] = _.extend({
lbp: 155,
type: "(template)",
nud: doTemplateLiteral,
led: doTemplateLiteral,
noSubst: true,
tail: true // mark as tail, since it's always the last component
}, baseTemplateSyntax);
type("(regexp)", function() {
return this;
});
// ECMAScript parser
delim("(endline)");
(function(x) {
x.line = x.from = 0;
})(delim("(begin)"));
delim("(end)").reach = true;
delim("(error)").reach = true;
delim("}").reach = true;
delim(")");
delim("]");
delim("\"").reach = true;
delim("'").reach = true;
delim(";");
delim(":").reach = true;
delim("#");
reserve("else");
reserve("case").reach = true;
reserve("catch");
reserve("default").reach = true;
reserve("finally");
reserve("true", function() { return this; });
reserve("false", function() { return this; });
reserve("null", function() { return this; });
reserve("this", function() {
if (state.isStrict() && !isMethod() &&
!state.option.validthis && ((state.funct["(statement)"] &&
state.funct["(name)"].charAt(0) > "Z") || state.funct["(global)"])) {
warning("W040", this);
}
return this;
});
reserve("super", function() {
superNud.call(state.tokens.curr, this);
return this;
});
assignop("=", "assign");
assignop("+=", "assignadd");
assignop("-=", "assignsub");
assignop("*=", "assignmult");
assignop("/=", "assigndiv").nud = function() {
/* istanbul ignore next */
error("E014");
};
assignop("%=", "assignmod");
assignop("**=", function(context, left, that) {
if (!state.inES7()) {
warning("W119", that, "Exponentiation operator", "7");
}
that.left = left;
checkLeftSideAssign(context, left, that);
that.right = expression(context, 10);
return that;
});
bitwiseassignop("&=");
bitwiseassignop("|=");
bitwiseassignop("^=");
bitwiseassignop("<<=");
bitwiseassignop(">>=");
bitwiseassignop(">>>=");
infix(",", function(context, left, that) {
if (state.option.nocomma) {
warning("W127", that);
}
that.left = left;
if (checkComma()) {
that.right = expression(context, 10);
} else {
that.right = null;
}
return that;
}, 10, true);
infix("?", function(context, left, that) {
increaseComplexityCount();
that.left = left;
that.right = expression(context & ~prodParams.noin, 10);
advance(":");
expression(context, 10);
return that;
}, 30);
var orPrecendence = 40;
infix("||", function(context, left, that) {
increaseComplexityCount();
that.left = left;
that.right = expression(context, orPrecendence);
return that;
}, orPrecendence);
infix("&&", "and", 50);
// The Exponentiation operator, introduced in ECMAScript 2016
//
// ExponentiationExpression[Yield] :
// UnaryExpression[?Yield]
// UpdateExpression[?Yield] ** ExponentiationExpression[?Yield]
infix("**", function(context, left, that) {
if (!state.inES7()) {
warning("W119", that, "Exponentiation operator", "7");
}
// Disallow UnaryExpressions which are not wrapped in parenthesis
if (!left.paren && beginsUnaryExpression(left)) {
error("E024", that, "**");
}
that.left = left;
that.right = expression(context, that.rbp);
return that;
}, 150);
state.syntax["**"].rbp = 140;
bitwise("|", "bitor", 70);
bitwise("^", "bitxor", 80);
bitwise("&", "bitand", 90);
relation("==", function(context, left, right) {
var eqnull = state.option.eqnull &&
((left && left.value) === "null" || (right && right.value) === "null");
switch (true) {
case !eqnull && state.option.eqeqeq:
this.from = this.character;
warning("W116", this, "===", "==");
break;
/* istanbul ignore next */
case isTypoTypeof(right, left, state):
warning("W122", this, right.value);
break;
case isTypoTypeof(left, right, state):
warning("W122", this, left.value);
break;
}
return this;
});
relation("===", function(context, left, right) {
if (isTypoTypeof(right, left, state)) {
warning("W122", this, right.value);
} else if (isTypoTypeof(left, right, state)) {
/* istanbul ignore next */
warning("W122", this, left.value);
}
return this;
});
relation("!=", function(context, left, right) {
var eqnull = state.option.eqnull &&
((left && left.value) === "null" || (right && right.value) === "null");
if (!eqnull && state.option.eqeqeq) {
this.from = this.character;
warning("W116", this, "!==", "!=");
} else if (isTypoTypeof(right, left, state)) {
/* istanbul ignore next */
warning("W122", this, right.value);
} else if (isTypoTypeof(left, right, state)) {
warning("W122", this, left.value);
}
return this;
});
relation("!==", function(context, left, right) {
if (isTypoTypeof(right, left, state)) {
warning("W122", this, right.value);
} else if (isTypoTypeof(left, right, state)) {
/* istanbul ignore next */
warning("W122", this, left.value);
}
return this;
});
relation("<");
relation(">");
relation("<=");
relation(">=");
bitwise("<<", "shiftleft", 120);
bitwise(">>", "shiftright", 120);
bitwise(">>>", "shiftrightunsigned", 120);
infix("in", "in", 120);
infix("instanceof", function(context, left, token) {
var right;
var scope = state.funct["(scope)"];
token.left = left;
token.right = right = expression(context, 120);
// This condition reflects a syntax error which will be reported by the
// `expression` function.
if (!right) {
return token;
}
if (right.id === "(number)" ||
right.id === "(string)" ||
right.value === "null" ||
(right.value === "undefined" && !scope.has("undefined")) ||
right.arity === "unary" ||
right.id === "{" ||
(right.id === "[" && !right.right) ||
right.id === "(regexp)" ||
(right.id === "(template)" && !right.tag)) {
error("E060");
}
if (right.id === "function") {
warning("W139");
}
return token;
}, 120);
infix("+", function(context, left, that) {
var next = state.tokens.next;
var right;
that.left = left;
that.right = right = expression(context, 130);
if (left && right && left.id === "(string)" && right.id === "(string)") {
left.value += right.value;
left.character = right.character;
if (!state.option.scripturl && reg.javascriptURL.test(left.value)) {
warning("W050", left);
}
return left;
}
if (next.id === "+" || next.id === "++") {
warning("W007", that.right);
}
return that;
}, 130);
prefix("+", function(context) {
var next = state.tokens.next;
this.arity = "unary";
this.right = expression(context, 150);
if (next.id === "+" || next.id === "++") {
warning("W007", this.right);
}
return this;
});
infix("-", function(context, left, that) {
var next = state.tokens.next;
that.left = left;
that.right = expression(context, 130);
if (next.id === "-" || next.id === "--") {
warning("W006", that.right);
}
return that;
}, 130);
prefix("-", function(context) {
var next = state.tokens.next;
this.arity = "unary";
this.right = expression(context, 150);
if (next.id === "-" || next.id === "--") {
warning("W006", this.right);
}
return this;
});
infix("*", "mult", 140);
infix("/", "div", 140);
infix("%", "mod", 140);
suffix("++");
prefix("++", "preinc");
state.syntax["++"].exps = true;
suffix("--");
prefix("--", "predec");
state.syntax["--"].exps = true;
prefix("delete", function(context) {
this.arity = "unary";
var p = expression(context, 150);
if (!p) {
return this;
}
if (p.id !== "." && p.id !== "[") {
warning("W051");
}
this.first = p;
// The `delete` operator accepts unresolvable references when not in strict
// mode, so the operand may be undefined.
if (p.identifier && !state.isStrict()) {
p.forgiveUndef = true;
}
return this;
}).exps = true;
prefix("~", function(context) {
if (state.option.bitwise) {
warning("W016", this, "~");
}
this.arity = "unary";
this.right = expression(context, 150);
return this;
});
infix("...");
prefix("!", function(context) {
this.arity = "unary";
this.right = expression(context, 150);
if (!this.right) { // '!' followed by nothing? Give up.
quit("E041", this);
}
if (bang[this.right.id] === true) {
warning("W018", this, "!");
}
return this;
});
prefix("typeof", function(context) {
this.arity = "unary";
var p = expression(context, 150);
this.first = this.right = p;
if (!p) { // 'typeof' followed by nothing? Give up.
quit("E041", this);
}
// The `typeof` operator accepts unresolvable references, so the operand
// may be undefined.
if (p.identifier) {
p.forgiveUndef = true;
}
return this;
});
prefix("new", function(context) {
var mp = metaProperty(context, "target", function() {
if (!state.inES6(true)) {
warning("W119", state.tokens.prev, "new.target", "6");
}
var inFunction, c = state.funct;
while (c) {
inFunction = !c["(global)"];
if (!c["(arrow)"]) { break; }
c = c["(context)"];
}
if (!inFunction) {
warning("W136", state.tokens.prev, "new.target");
}
});
if (mp) { return mp; }
var c = expression(context, 155), i;
if (c && c.id !== "function") {
if (c.identifier) {
switch (c.value) {
case "Number":
case "String":
case "Boolean":
case "Math":
case "JSON":
warning("W053", state.tokens.prev, c.value);
break;
case "Symbol":
if (state.inES6()) {
warning("W053", state.tokens.prev, c.value);
}
break;
case "Function":
if (!state.option.evil) {
warning("W054");
}
break;
case "Date":
case "RegExp":
case "this":
break;
default:
i = c.value.substr(0, 1);
if (state.option.newcap && (i < "A" || i > "Z") &&
!state.funct["(scope)"].isPredefined(c.value)) {
warning("W055", state.tokens.curr);
}
}
} else {
if (c.id !== "." && c.id !== "[" && c.id !== "(") {
/* istanbul ignore next */
warning("W056", state.tokens.curr);
}
}
} else {
if (!state.option.supernew)
warning("W057", this);
}
if (state.tokens.next.id !== "(" && !state.option.supernew) {
warning("W058", state.tokens.curr, state.tokens.curr.value);
}
this.first = this.right = c;
return this;
});
state.syntax["new"].exps = true;
// Class statement
blockstmt("class", function(context) {
var className, classNameToken;
var inexport = context & prodParams.export;
if (!state.inES6()) {
warning("W104", state.tokens.curr, "class", "6");
}
state.inClassBody = true;
// Class Declaration: 'class <Classname>'
if (state.tokens.next.identifier && state.tokens.next.value !== "extends") {
classNameToken = state.tokens.next;
className = classNameToken.value;
identifier(context);
// unintialized, so that the 'extends' clause is parsed while the class is in TDZ
state.funct["(scope)"].addbinding(className, {
type: "class",
initialized: false,
token: classNameToken
});
}
// Class Declaration: 'class <Classname> extends <Superclass>'
if (state.tokens.next.value === "extends") {
advance("extends");
expression(context, 0);
}
if (classNameToken) {
this.name = className;
state.funct["(scope)"].initialize(className);
if (inexport) {
state.funct["(scope)"].setExported(className, classNameToken);
}
}
state.funct["(scope)"].stack();
classBody(this, context);
return this;
}).exps = true;
/*
Class expression
The Block- and Expression- handling for "class" are almost identical, except for the ordering of steps.
In an expression:, the name should not be saved into the calling scope, but is still accessible inside the definition, so we open a new scope first, then save the name. We also mark it as used.
*/
prefix("class", function(context) {
var className, classNameToken;
if (!state.inES6()) {
warning("W104", state.tokens.curr, "class", "6");
}
state.inClassBody = true;
// Class Declaration: 'class <Classname>'
if (state.tokens.next.identifier && state.tokens.next.value !== "extends") {
classNameToken = state.tokens.next;
className = classNameToken.value;
identifier(context);
}
// Class Declaration: 'class <Classname> extends <Superclass>'
if (state.tokens.next.value === "extends") {
advance("extends");
expression(context, 0);
}
state.funct["(scope)"].stack();
if (classNameToken) {
this.name = className;
state.funct["(scope)"].addbinding(className, {
type: "class",
initialized: true,
token: classNameToken
});
state.funct["(scope)"].block.use(className, classNameToken);
}
classBody(this, context);
return this;
});
function classBody(classToken, context) {
var props = Object.create(null);
var name, accessorType, token, isStatic, inGenerator, hasConstructor;
/* istanbul ignore else */
if (state.tokens.next.value === "{") {
advance("{");
} else {
warning("W116", state.tokens.curr, "identifier", state.tokens.next.type); //?
advance();
}
while (state.tokens.next.value !== "}") {
isStatic = false;
inGenerator = false;
context &= ~prodParams.preAsync;
if (state.tokens.next.value === "static" &&
!checkPunctuator(peek(), "(")) {
isStatic = true;
advance();
}
if (state.tokens.next.value === "async") {
if (!checkPunctuator(peek(), "(")) {
context |= prodParams.preAsync;
advance();
nolinebreak(state.tokens.curr);
if (checkPunctuator(state.tokens.next, "*")) {
inGenerator = true;
advance("*");
if (!state.inES9()) {
warning("W119", state.tokens.next, "async generators", "9");
}
}
if (!state.inES8()) {
warning("W119", state.tokens.curr, "async functions", "8");
}
}
}
if (state.tokens.next.value === "*") {
inGenerator = true;
advance();
}
token = state.tokens.next;
if ((token.value === "set" || token.value === "get") && !checkPunctuator(peek(), "(")) {
if (inGenerator) {
/* istanbul ignore next */
error("E024", token, token.value);
}
accessorType = token.value;
advance();
token = state.tokens.next;
if (!isStatic && token.value === "constructor") {
error("E049", token, "class " + accessorType + "ter method", token.value);
} else if (isStatic && token.value === "prototype") {
error("E049", token, "static class " + accessorType + "ter method", token.value);
}
} else {
accessorType = null;
}
switch (token.value) {
case ";":
warning("W032", token);
advance();
break;
case "constructor":
if (isStatic) {
// treat like a regular method -- static methods can be called 'constructor'
name = propertyName(context);
saveProperty(props, name, token, true, isStatic);
doMethod(classToken, context, name, inGenerator);
} else {
if (inGenerator || context & prodParams.preAsync) {
error("E024", token, token.value);
} else if (hasConstructor) {
/* istanbul ignore next */
error("E024", token, token.value);
} else {
hasConstructor = !accessorType && !isStatic;
}
advance();
doMethod(classToken, context, state.nameStack.infer());
}
break;
case "[":
name = computedPropertyName(context);
doMethod(classToken, context, name, inGenerator);
// We don't check names (via calling saveProperty()) of computed expressions like ["Symbol.iterator"]()
break;
default:
name = propertyName(context);
if (name === undefined) {
error("E024", token, token.value);
advance();
break;
}
if (accessorType) {
saveAccessor(accessorType, props, name, token, true, isStatic);
name = state.nameStack.infer();
} else {
if (isStatic && name === "prototype") {
error("E049", token, "static class method", name);
}
saveProperty(props, name, token, true, isStatic);
}
doMethod(classToken, context, name, inGenerator);
break;
}
}
advance("}");
checkProperties(props);
state.inClassBody = false;
state.funct["(scope)"].unstack();
}
function doMethod(classToken, context, name, generator) {
if (generator) {
if (!state.inES6()) {
warning("W119", state.tokens.curr, "function*", "6");
}
}
if (state.tokens.next.value !== "(") {
error("E054", state.tokens.next, state.tokens.next.value);
advance();
if (state.tokens.next.value === "{") {
// manually cheating the test "invalidClasses", which asserts this particular behavior when a class is misdefined.
advance();
if (state.tokens.next.value === "}") {
warning("W116", state.tokens.next, "(", state.tokens.next.value);
advance();
identifier(context);
advance();
}
/* istanbul ignore next */
return;
} else {
while (state.tokens.next.value !== "(") {
advance();
}
}
}
doFunction(context, { name: name,
type: generator ? "generator" : null,
isMethod: true,
statement: classToken });
}
prefix("void").exps = true;
infix(".", function(context, left, that) {
var m = identifier(context, true);
if (typeof m === "string") {
countMember(m);
}
that.left = left;
that.right = m;
if (m && m === "hasOwnProperty" && state.tokens.next.value === "=") {
warning("W001");
}
if (left && left.value === "arguments" && (m === "callee" || m === "caller")) {
if (state.option.noarg)
warning("W059", left, m);
else if (state.isStrict())
error("E008");
} else if (!state.option.evil && left && left.value === "document" &&
(m === "write" || m === "writeln")) {
warning("W060", left);
}
if (!state.option.evil && (m === "eval" || m === "execScript")) {
if (isGlobalEval(left, state)) {
warning("W061");
}
}
return that;
}, 160, true);
infix("(", function(context, left, that) {
if (state.option.immed && left && !left.immed && left.id === "function") {
warning("W062");
}
if (state.option.asi && checkPunctuators(state.tokens.prev, [")", "]"]) &&
!sameLine(state.tokens.prev, state.tokens.curr)) {
warning("W014", state.tokens.curr, state.tokens.curr.id);
}
var n = 0;
var p = [];
if (left) {
if (left.type === "(identifier)") {
if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) {
if ("Array Number String Boolean Date Object Error Symbol".indexOf(left.value) === -1) {
if (left.value === "Math") {
/* istanbul ignore next */
warning("W063", left);
} else if (state.option.newcap) {
warning("W064", left);
}
}
}
}
}
if (state.tokens.next.id !== ")") {
for (;;) {
spreadrest("spread");
p[p.length] = expression(context, 10);
n += 1;
if (state.tokens.next.id !== ",") {
break;
}
advance(",");
checkComma({ allowTrailing: true });
if (state.tokens.next.id === ")") {
if (!state.inES8()) {
warning("W119", state.tokens.curr, "Trailing comma in arguments lists", "8");
}
break;
}
}
}
advance(")");
if (typeof left === "object") {
if (!state.inES5() && left.value === "parseInt" && n === 1) {
warning("W065", state.tokens.curr);
}
if (!state.option.evil) {
if (left.value === "eval" || left.value === "Function" ||
left.value === "execScript") {
warning("W061", left);
// This conditional expression was initially implemented with a typo
// which prevented the branch's execution in all cases. While
// enabling the code will produce behavior that is consistent with
// the other forms of code evaluation that follow, such a change is
// also technically incompatable with prior versions of JSHint (due
// to the fact that the behavior was never formally documented). This
// branch should be enabled as part of a major release.
//if (p[0] && p[0].id === "(string)") {
// addEvalCode(left, p[0]);
//}
} else if (p[0] && p[0].id === "(string)" &&
(left.value === "setTimeout" ||
left.value === "setInterval")) {
warning("W066", left);
addEvalCode(left, p[0]);
// window.setTimeout/setInterval
} else if (p[0] && p[0].id === "(string)" &&
left.value === "." &&
left.left.value === "window" &&
(left.right === "setTimeout" ||
left.right === "setInterval")) {
warning("W066", left);
addEvalCode(left, p[0]);
}
}
if (!left.identifier && left.id !== "." && left.id !== "[" && left.id !== "=>" &&
left.id !== "(" && left.id !== "&&" && left.id !== "||" && left.id !== "?" &&
left.id !== "async" && !(state.inES6() && left["(name)"])) {
warning("W067", that);
}
}
that.left = left;
return that;
}, 155, true).exps = true;
function peekThroughParens(parens) {
var pn = state.tokens.next;
var i = -1;
var pn1;
do {
if (pn.value === "(") {
parens += 1;
} else if (pn.value === ")") {
parens -= 1;
}
i += 1;
pn1 = pn;
pn = peek(i);
} while (!(parens === 0 && pn1.value === ")") && pn.type !== "(end)");
return pn;
}
prefix("(", function(context, rbp) {
var ret, triggerFnExpr, first, last;
var opening = state.tokens.curr;
var preceeding = state.tokens.prev;
var isNecessary = !state.option.singleGroups;
var pn = peekThroughParens(1);
if (state.tokens.next.id === "function") {
triggerFnExpr = state.tokens.next.immed = true;
}
// If the balanced grouping operator is followed by a "fat arrow", the
// current token marks the beginning of a "fat arrow" function and parsing
// should proceed accordingly.
if (pn.value === "=>") {
pn.funct = doFunction(context, { type: "arrow", parsedOpening: true });
return pn;
}
// The ECMA262 grammar requires an expression between the "opening
// parenthesis" and "close parenthesis" tokens of the grouping operator.
// However, the "ignore" directive is commonly used to inject values that
// are not included in the token stream. For example:
//
// return (
// /*jshint ignore:start */
// <div></div>
// /*jshint ignore:end */
// );
//
// The "empty" grouping operator is permitted in order to tolerate this
// pattern.
if (state.tokens.next.id === ")") {
advance(")");
return;
}
ret = expression(context, 0);
advance(")", this);
if (!ret) {
return;
}
ret.paren = true;
if (state.option.immed && ret && ret.id === "function") {
if (state.tokens.next.id !== "(" &&
state.tokens.next.id !== "." && state.tokens.next.id !== "[") {
warning("W068", this);
}
}
if (ret.id === ",") {
first = ret.left;
while (first.id === ",") {
first = first.left;
}
last = ret.right;
} else {
first = last = ret;
if (!isNecessary) {
// async functions are identified after parsing due to the complexity
// of disambiguating the `async` keyword.
if (!triggerFnExpr) {
triggerFnExpr = ret.id === "async";
}
isNecessary =
// Used to distinguish from an ExpressionStatement which may not
// begin with the `{` and `function` tokens
(opening.beginsStmt && (ret.id === "{" || triggerFnExpr)) ||
// Used to signal that a function expression is being supplied to
// some other operator.
(triggerFnExpr &&
// For parenthesis wrapping a function expression to be considered
// necessary, the grouping operator should be the left-hand-side of
// some other operator--either within the parenthesis or directly
// following them.
(!isEndOfExpr() || state.tokens.prev.id !== "}")) ||
// Used to demarcate an arrow function as the left-hand side of some
// operator.
(ret.id === "=>" && !isEndOfExpr()) ||
// Used as the return value of a single-statement arrow function
(ret.id === "{" && preceeding.id === "=>") ||
// Used to cover a unary expression as the left-hand side of the
// exponentiation operator
(beginsUnaryExpression(ret) && state.tokens.next.id === "**") ||
// Used to delineate an integer number literal from a dereferencing
// punctuator (otherwise interpreted as a decimal point)
(ret.type === "(number)" &&
checkPunctuator(pn, ".") && /^\d+$/.test(ret.value)) ||
// Used to wrap object destructuring assignment
(opening.beginsStmt && ret.id === "=" && ret.left.id === "{");
}
}
// The operator may be necessary to override the default binding power of
// neighboring operators (whenever there is an operator in use within the
// first expression *or* the current group contains multiple expressions)
if (!isNecessary && (isOperator(first) || first !== last)) {
isNecessary =
(rbp > first.lbp) ||
(rbp > 0 && rbp === first.lbp) ||
(!isEndOfExpr() && last.rbp < state.tokens.next.lbp);
}
if (!isNecessary) {
warning("W126", opening);
}
return ret;
});
application("=>");
infix("[", function(context, left, that) {
var e, s, canUseDot;
if (state.option.asi && checkPunctuators(state.tokens.prev, [")", "]"]) &&
!sameLine(state.tokens.prev, state.tokens.curr)) {
warning("W014", state.tokens.curr, state.tokens.curr.id);
}
e = expression(context & ~prodParams.noin, 10);
if (e && e.type === "(string)") {
if (!state.option.evil && (e.value === "eval" || e.value === "execScript")) {
if (isGlobalEval(left, state)) {
warning("W061");
}
}
countMember(e.value);
if (!state.option.sub && reg.identifier.test(e.value)) {
s = state.syntax[e.value];
if (s) {
canUseDot = !isReserved(context, s);
} else {
// This branch exists to preserve legacy behavior with version 2.9.5
// and earlier. In those releases, `eval` and `arguments` were
// incorrectly interpreted as reserved keywords, so Member
// Expressions such as `object["eval"]` did not trigger warning W069.
//
// TODO: Remove in JSHint 3
canUseDot = e.value !== "eval" && e.value !== "arguments";
}
if (canUseDot) {
warning("W069", state.tokens.prev, e.value);
}
}
}
advance("]", that);
if (e && e.value === "hasOwnProperty" && state.tokens.next.value === "=") {
warning("W001");
}
that.left = left;
that.right = e;
return that;
}, 160, true);
function comprehensiveArrayExpression(context) {
var res = {};
res.exps = true;
state.funct["(comparray)"].stack();
// Handle reversed for expressions, used in spidermonkey
var reversed = false;
if (state.tokens.next.value !== "for") {
reversed = true;
if (!state.inMoz()) {
warning("W116", state.tokens.next, "for", state.tokens.next.value);
}
state.funct["(comparray)"].setState("use");
res.right = expression(context, 10);
}
advance("for");
if (state.tokens.next.value === "each") {
advance("each");
if (!state.inMoz()) {
warning("W118", state.tokens.curr, "for each");
}
}
advance("(");
state.funct["(comparray)"].setState("define");
res.left = expression(context, 130);
if (_.includes(["in", "of"], state.tokens.next.value)) {
advance();
} else {
/* istanbul ignore next */
error("E045", state.tokens.curr);
}
state.funct["(comparray)"].setState("generate");
expression(context, 10);
advance(")");
if (state.tokens.next.value === "if") {
advance("if");
advance("(");
state.funct["(comparray)"].setState("filter");
expression(context, 10);
advance(")");
}
if (!reversed) {
state.funct["(comparray)"].setState("use");
res.right = expression(context, 10);
}
advance("]");
state.funct["(comparray)"].unstack();
return res;
}
prefix("[", function(context) {
var blocktype = lookupBlockType();
if (blocktype.isCompArray) {
if (!state.option.esnext && !state.inMoz()) {
warning("W118", state.tokens.curr, "array comprehension");
}
return comprehensiveArrayExpression(context);
} else if (blocktype.isDestAssign) {
this.destructAssign = destructuringPattern(context, {
openingParsed: true,
assignment: true
});
return this;
}
var b = !sameLine(state.tokens.curr, state.tokens.next);
this.first = [];
if (b) {
indent += state.option.indent;
if (state.tokens.next.from === indent + state.option.indent) {
/* istanbul ignore next */
indent += state.option.indent;
}
}
while (state.tokens.next.id !== "(end)") {
while (state.tokens.next.id === ",") {
if (!state.option.elision) {
if (!state.inES5()) {
// Maintain compat with old options --- ES5 mode without
// elision=true will warn once per comma
warning("W070");
} else {
warning("W128");
do {
advance(",");
} while (state.tokens.next.id === ",");
continue;
}
}
advance(",");
}
if (state.tokens.next.id === "]") {
break;
}
spreadrest("spread");
this.first.push(expression(context, 10));
if (state.tokens.next.id === ",") {
advance(",");
checkComma({ allowTrailing: true });
if (state.tokens.next.id === "]" && !state.inES5()) {
warning("W070", state.tokens.curr);
break;
}
} else {
if (state.option.trailingcomma && state.inES5()) {
warningAt("W140", state.tokens.curr.line, state.tokens.curr.character);
}
break;
}
}
if (b) {
indent -= state.option.indent;
}
advance("]", this);
return this;
});
function isMethod() {
return !!state.funct["(method)"];
}
function propertyName(context, preserveOrToken) {
var id;
var preserve = true;
if (typeof preserveOrToken === "object") {
/* istanbul ignore next */
id = preserveOrToken;
} else {
preserve = preserveOrToken;
id = optionalidentifier(context, true, preserve);
}
if (!id) {
if (state.tokens.next.id === "(string)") {
id = state.tokens.next.value;
if (!preserve) {
advance();
}
} else if (state.tokens.next.id === "(number)") {
id = state.tokens.next.value.toString();
if (!preserve) {
advance();
}
}
/* istanbul ignore next */
} else if (typeof id === "object") {
if (id.id === "(string)" || id.id === "(identifier)") id = id.value;
else if (id.id === "(number)") id = id.value.toString();
}
if (id === "hasOwnProperty") {
warning("W001");
}
return id;
}
/**
* @param {Number} context The parsing context
* @param {Object} [options]
* @param {token} [options.loneArg] The argument to the function in cases
* where it was defined using the
* single-argument shorthand.
* @param {bool} [options.parsedOpening] Whether the opening parenthesis has
* already been parsed.
*
* @returns {{ arity: number, params: Array.<string>, isSimple: boolean }}
*/
function functionparams(context, options) {
var next;
var paramsIds = [];
var ident;
var tokens = [];
var t;
var pastDefault = false;
var pastRest = false;
var arity = 0;
var loneArg = options && options.loneArg;
var hasDestructuring = false;
if (loneArg && loneArg.identifier === true) {
state.funct["(scope)"].addParam(loneArg.value, loneArg);
return { arity: 1, params: [ loneArg.value ], isSimple: true };
}
next = state.tokens.next;
if (!options || !options.parsedOpening) {
advance("(");
}
if (state.tokens.next.id === ")") {
advance(")");
return;
}
function addParam(addParamArgs) {
state.funct["(scope)"].addParam.apply(state.funct["(scope)"], addParamArgs);
}
for (;;) {
arity++;
// are added to the param scope
var currentParams = [];
if (_.includes(["{", "["], state.tokens.next.id)) {
hasDestructuring = true;
tokens = destructuringPattern(context);
for (t in tokens) {
t = tokens[t];
if (t.id) {
paramsIds.push(t.id);
currentParams.push([t.id, t.token]);
}
}
} else {
pastRest = spreadrest("rest");
ident = identifier(context);
if (ident) {
paramsIds.push(ident);
currentParams.push([ident, state.tokens.curr]);
} else {
// Skip invalid parameter.
while (!checkPunctuators(state.tokens.next, [",", ")"])) advance();
}
}
// It is valid to have a regular argument after a default argument
// since undefined can be used for missing parameters. Still warn as it is
// a possible code smell.
if (pastDefault) {
if (state.tokens.next.id !== "=") {
error("W138", state.tokens.curr);
}
}
if (state.tokens.next.id === "=") {
if (!state.inES6()) {
warning("W119", state.tokens.next, "default parameters", "6");
}
if (pastRest) {
error("E062", state.tokens.next);
}
advance("=");
pastDefault = true;
expression(context, 10);
}
// now we have evaluated the default expression, add the variable to the param scope
currentParams.forEach(addParam);
if (state.tokens.next.id === ",") {
if (pastRest) {
warning("W131", state.tokens.next);
}
advance(",");
checkComma({ allowTrailing: true });
}
if (state.tokens.next.id === ")") {
if (state.tokens.curr.id === "," && !state.inES8()) {
warning("W119", state.tokens.curr, "Trailing comma in function parameters", "8");
}
advance(")", next);
return {
arity: arity,
params: paramsIds,
isSimple: !hasDestructuring && !pastRest && !pastDefault
};
}
}
}
/**
* Factory function for creating objects used to track statistics of function
* literals.
*
* @param {string} name - the identifier name to associate with the function
* @param {object} [token] - token responsible for creating the function
* object
* @param {object} [overwrites] - a collection of properties that should
* override the corresponding default value of
* the new "functor" object
*/
function functor(name, token, overwrites) {
var funct = {
"(name)" : name,
"(breakage)" : 0,
"(loopage)" : 0,
// The strictness of the function body is tracked via a dedicated
// property (as opposed to via the global `state` object) so that the
// value can be referenced after the body has been fully parsed (i.e.
// when validating the identifier used in function declarations and
// function expressions).
"(isStrict)" : "unknown",
"(global)" : false,
"(line)" : null,
"(character)" : null,
"(metrics)" : null,
"(statement)" : null,
"(context)" : null,
"(scope)" : null,
"(comparray)" : null,
"(yielded)" : null,
"(arrow)" : null,
"(async)" : null,
"(params)" : null
};
if (token) {
_.extend(funct, {
"(line)" : token.line,
"(character)": token.character,
"(metrics)" : createMetrics(token)
});
}
_.extend(funct, overwrites);
if (funct["(context)"]) {
funct["(scope)"] = funct["(context)"]["(scope)"];
funct["(comparray)"] = funct["(context)"]["(comparray)"];
}
return funct;
}
/**
* Determine if the parser has begun parsing executable code.
*
* @param {Token} funct - The current "functor" token
*
* @returns {boolean}
*/
function hasParsedCode(funct) {
return funct["(global)"] && !funct["(verb)"];
}
/**
* This function is used as both a null-denotation method *and* a
* left-denotation method, meaning the first parameter is overloaded.
*/
function doTemplateLiteral(context, leftOrRbp) {
// ASSERT: this.type === "(template)"
// jshint validthis: true
var ctx = this.context;
var noSubst = this.noSubst;
var depth = this.depth;
var left = typeof leftOrRbp === "number" ? null : leftOrRbp;
if (!noSubst) {
while (!end()) {
if (!state.tokens.next.template || state.tokens.next.depth > depth) {
expression(context, 0); // should probably have different rbp?
} else {
// skip template start / middle
advance();
}
}
}
return {
id: "(template)",
type: "(template)",
tag: left
};
function end() {
if (state.tokens.curr.template && state.tokens.curr.tail &&
state.tokens.curr.context === ctx) {
/* istanbul ignore next */
return true;
}
var complete = (state.tokens.next.template && state.tokens.next.tail &&
state.tokens.next.context === ctx);
if (complete) advance();
return complete || state.tokens.next.isUnclosed;
}
}
/**
* Parse a function literal.
*
* @param {Number} context The parsing context
* @param {Object} [options]
* @param {string} [options.name] The identifier belonging to the function (if
* any)
* @param {token} [options.statement] The statement that triggered creation
* of the current function.
* @param {string} [options.type] If specified, either "generator" or "arrow"
* @param {token} [options.loneArg] The argument to the function in cases
* where it was defined using the
* single-argument shorthand
* @param {bool} [options.parsedOpening] Whether the opening parenthesis has
* already been parsed
* @param {string} [options.classExprBinding] Define a function with this
* identifier in the new function's
* scope, mimicking the bahavior of
* class expression names within
* the body of member functions.
*/
function doFunction(context, options) {
var f, token, name, statement, classExprBinding, isGenerator, isArrow,
isMethod, ignoreLoopFunc;
var oldOption = state.option;
var oldIgnored = state.ignored;
var isAsync = context & prodParams.preAsync;
if (options) {
name = options.name;
statement = options.statement;
classExprBinding = options.classExprBinding;
isGenerator = options.type === "generator";
isArrow = options.type === "arrow";
isMethod = options.isMethod;
ignoreLoopFunc = options.ignoreLoopFunc;
}
context &= ~prodParams.noin;
context &= ~prodParams.tryClause;
if (isAsync) {
context |= prodParams.async;
} else {
context &= ~prodParams.async;
}
if (isGenerator) {
context |= prodParams.yield;
} else if (!isArrow) {
context &= ~prodParams.yield;
}
context &= ~prodParams.preAsync;
state.option = Object.create(state.option);
state.ignored = Object.create(state.ignored);
state.funct = functor(name || state.nameStack.infer(), state.tokens.next, {
"(statement)": statement,
"(context)": state.funct,
"(arrow)": isArrow,
"(method)": isMethod,
"(async)": isAsync
});
f = state.funct;
token = state.tokens.curr;
functions.push(state.funct);
// So that the function is available to itself and referencing itself is not
// seen as a closure, add the function name to a new scope, but do not
// test for unused (unused: false)
// it is a new block scope so that params can override it, it can be block scoped
// but declarations inside the function don't cause already declared error
state.funct["(scope)"].stack("functionouter");
var internallyAccessibleName = !isMethod && (name || classExprBinding);
if (internallyAccessibleName) {
state.funct["(scope)"].block.add(internallyAccessibleName,
classExprBinding ? "class" : "function", state.tokens.curr, false);
}
if (!isArrow) {
state.funct["(scope)"].funct.add("arguments", "var", token, false);
}
// create the param scope (params added in functionparams)
state.funct["(scope)"].stack("functionparams");
var paramsInfo = functionparams(context, options);
if (paramsInfo) {
state.funct["(params)"] = paramsInfo.params;
state.funct["(hasSimpleParams)"] = paramsInfo.isSimple;
state.funct["(metrics)"].arity = paramsInfo.arity;
state.funct["(metrics)"].verifyMaxParametersPerFunction();
} else {
state.funct["(params)"] = [];
state.funct["(metrics)"].arity = 0;
state.funct["(hasSimpleParams)"] = true;
}
if (isArrow) {
context &= ~prodParams.yield;
if (!state.inES6(true)) {
warning("W119", state.tokens.curr, "arrow function syntax (=>)", "6");
}
if (!options.loneArg) {
advance("=>");
}
}
block(context, false, true, true, isArrow);
if (!state.option.noyield && isGenerator && !state.funct["(yielded)"]) {
warning("W124", state.tokens.curr);
}
state.funct["(metrics)"].verifyMaxStatementsPerFunction();
state.funct["(metrics)"].verifyMaxComplexityPerFunction();
state.funct["(unusedOption)"] = state.option.unused;
state.option = oldOption;
state.ignored = oldIgnored;
state.funct["(last)"] = state.tokens.curr.line;
state.funct["(lastcharacter)"] = state.tokens.curr.character;
// unstack the params scope
state.funct["(scope)"].unstack(); // also does usage and label checks
// unstack the function outer stack
state.funct["(scope)"].unstack();
state.funct = state.funct["(context)"];
if (!ignoreLoopFunc && !state.option.loopfunc && state.funct["(loopage)"]) {
// If the function we just parsed accesses any non-local variables
// trigger a warning. Otherwise, the function is safe even within
// a loop.
if (f["(outerMutables)"]) {
warning("W083", token, f["(outerMutables)"].join(", "));
}
}
return f;
}
function createMetrics(functionStartToken) {
return {
statementCount: 0,
nestedBlockDepth: -1,
ComplexityCount: 1,
arity: 0,
verifyMaxStatementsPerFunction: function() {
if (state.option.maxstatements &&
this.statementCount > state.option.maxstatements) {
warning("W071", functionStartToken, this.statementCount);
}
},
verifyMaxParametersPerFunction: function() {
if (_.isNumber(state.option.maxparams) &&
this.arity > state.option.maxparams) {
warning("W072", functionStartToken, this.arity);
}
},
verifyMaxNestedBlockDepthPerFunction: function() {
if (state.option.maxdepth &&
this.nestedBlockDepth > 0 &&
this.nestedBlockDepth === state.option.maxdepth + 1) {
warning("W073", null, this.nestedBlockDepth);
}
},
verifyMaxComplexityPerFunction: function() {
var max = state.option.maxcomplexity;
var cc = this.ComplexityCount;
if (max && cc > max) {
warning("W074", functionStartToken, cc);
}
}
};
}
function increaseComplexityCount() {
state.funct["(metrics)"].ComplexityCount += 1;
}
// Parse assignments that were found instead of conditionals.
// For example: if (a = 1) { ... }
function checkCondAssignment(token) {
if (!token || token.paren) {
return;
}
if (token.id === ",") {
checkCondAssignment(token.right);
return;
}
switch (token.id) {
case "=":
case "+=":
case "-=":
case "*=":
case "%=":
case "&=":
case "|=":
case "^=":
case "/=":
if (!state.option.boss) {
warning("W084", token);
}
}
}
/**
* Validate the properties defined within an object literal or class body.
* See the `saveAccessor` and `saveProperty` functions for more detail.
*
* @param {object} props - Collection of objects describing the properties
* encountered
*/
function checkProperties(props) {
// Check for lonely setters if in the ES5 mode.
if (state.inES5()) {
for (var name in props) {
if (props[name] && props[name].setterToken && !props[name].getterToken &&
!props[name].static) {
warning("W078", props[name].setterToken);
}
}
}
}
function metaProperty(context, name, c) {
if (checkPunctuator(state.tokens.next, ".")) {
var left = state.tokens.curr.id;
advance(".");
var id = identifier(context);
state.tokens.curr.isMetaProperty = true;
if (name !== id) {
error("E057", state.tokens.prev, left, id);
} else {
c();
}
return state.tokens.curr;
}
}
//object literals
(function(x) {
x.nud = function(context) {
var b, f, i, params, t, isGeneratorMethod = false, nextVal;
var props = Object.create(null); // All properties, including accessors
var isAsyncMethod = false;
b = !sameLine(state.tokens.curr, state.tokens.next);
if (b) {
indent += state.option.indent;
if (state.tokens.next.from === indent + state.option.indent) {
/* istanbul ignore next */
indent += state.option.indent;
}
}
var blocktype = lookupBlockType();
if (blocktype.isDestAssign) {
this.destructAssign = destructuringPattern(context, {
openingParsed: true,
assignment: true
});
return this;
}
state.inObjectBody = true;
for (;;) {
if (state.tokens.next.id === "}") {
break;
}
nextVal = state.tokens.next.value;
if (state.tokens.next.identifier &&
(peekIgnoreEOL().id === "," || peekIgnoreEOL().id === "}")) {
if (!state.inES6()) {
warning("W104", state.tokens.next, "object short notation", "6");
}
i = propertyName(context, true);
saveProperty(props, i, state.tokens.next);
expression(context, 10);
} else if (peek().id !== ":" && (nextVal === "get" || nextVal === "set")) {
advance(nextVal);
if (!state.inES5()) {
error("E034");
}
if (state.tokens.next.id === "[") {
i = computedPropertyName(context);
} else {
i = propertyName(context);
// ES6 allows for get() {...} and set() {...} method
// definition shorthand syntax, so we don't produce an error
// if linting ECMAScript 6 code.
if (!i && !state.inES6()) {
error("E035");
}
}
// We don't want to save this getter unless it's an actual getter
// and not an ES6 concise method
if (i) {
saveAccessor(nextVal, props, i, state.tokens.curr);
}
t = state.tokens.next;
f = doFunction(context, { isMethod: true });
params = f["(params)"];
// Don't warn about getter/setter pairs if this is an ES6 concise method
if (nextVal === "get" && i && params.length) {
warning("W076", t, params[0], i);
} else if (nextVal === "set" && i && f["(metrics)"].arity !== 1) {
warning("W077", t, i);
}
} else if (spreadrest("spread")) {
if (!state.inES9()) {
warning("W119", state.tokens.next, "object spread property", "9");
}
expression(context, 10);
} else {
if (state.tokens.next.id === "async" && !checkPunctuators(peek(), ["(", ":"])) {
if (!state.inES8()) {
warning("W119", state.tokens.next, "async functions", "8");
}
isAsyncMethod = true;
advance();
nolinebreak(state.tokens.curr);
} else {
isAsyncMethod = false;
}
if (state.tokens.next.value === "*" && state.tokens.next.type === "(punctuator)") {
if (isAsyncMethod && !state.inES9()) {
warning("W119", state.tokens.next, "async generators", "9");
} else if (!state.inES6()) {
warning("W104", state.tokens.next, "generator functions", "6");
}
advance("*");
isGeneratorMethod = true;
} else {
isGeneratorMethod = false;
}
if (state.tokens.next.id === "[") {
i = computedPropertyName(context);
state.nameStack.set(i);
} else {
state.nameStack.set(state.tokens.next);
i = propertyName(context);
saveProperty(props, i, state.tokens.next);
if (typeof i !== "string") {
break;
}
}
if (state.tokens.next.value === "(") {
if (!state.inES6()) {
warning("W104", state.tokens.curr, "concise methods", "6");
}
doFunction(isAsyncMethod ? context | prodParams.preAsync : context, {
isMethod: true,
type: isGeneratorMethod ? "generator" : null
});
} else {
advance(":");
expression(context, 10);
}
}
countMember(i);
if (state.tokens.next.id === ",") {
advance(",");
checkComma({ allowTrailing: true, property: true });
if (state.tokens.next.id === ",") {
/* istanbul ignore next */
warning("W070", state.tokens.curr);
} else if (state.tokens.next.id === "}" && !state.inES5()) {
warning("W070", state.tokens.curr);
}
} else {
if (state.option.trailingcomma && state.inES5()) {
warningAt("W140", state.tokens.curr.line, state.tokens.curr.character);
}
break;
}
}
if (b) {
indent -= state.option.indent;
}
advance("}", this);
checkProperties(props);
state.inObjectBody = false;
return this;
};
x.fud = function() {
/* istanbul ignore next */
error("E036", state.tokens.curr);
};
}(delim("{")));
function destructuringPattern(context, options) {
var isAssignment = options && options.assignment;
context &= ~prodParams.noin;
if (!state.inES6()) {
warning("W104", state.tokens.curr,
isAssignment ? "destructuring assignment" : "destructuring binding", "6");
}
return destructuringPatternRecursive(context, options);
}
function destructuringPatternRecursive(context, options) {
var ids, idx;
var identifiers = [];
var openingParsed = options && options.openingParsed;
var isAssignment = options && options.assignment;
var recursiveOptions = isAssignment ? { assignment: isAssignment } : null;
var firstToken = openingParsed ? state.tokens.curr : state.tokens.next;
var nextInnerDE = function() {
var ident;
if (checkPunctuators(state.tokens.next, ["[", "{"])) {
ids = destructuringPatternRecursive(context, recursiveOptions);
for (idx = 0; idx < ids.length; idx++) {
identifiers.push({ id: ids[idx].id, token: ids[idx].token });
}
} else if (checkPunctuator(state.tokens.next, ",")) {
identifiers.push({ id: null, token: state.tokens.curr });
} else if (checkPunctuator(state.tokens.next, "(")) {
advance("(");
nextInnerDE();
advance(")");
} else {
if (isAssignment) {
var assignTarget = expression(context, 20);
if (assignTarget) {
checkLeftSideAssign(context, assignTarget);
// if the target was a simple identifier, add it to the list to return
if (assignTarget.identifier) {
ident = assignTarget.value;
}
}
} else {
ident = identifier(context);
}
if (ident) {
identifiers.push({ id: ident, token: state.tokens.curr });
}
}
};
var assignmentProperty = function(context) {
var id, expr;
if (checkPunctuator(state.tokens.next, "[")) {
advance("[");
expression(context, 10);
advance("]");
advance(":");
nextInnerDE();
} else if (state.tokens.next.id === "(string)" ||
state.tokens.next.id === "(number)") {
advance();
advance(":");
nextInnerDE();
} else {
// this id will either be the property name or the property name and the assigning identifier
var isRest = spreadrest("rest");
if (isRest) {
if (!state.inES9()) {
warning("W119", state.tokens.next, "object rest property", "9");
}
// Due to visual symmetry with the array rest property (and the early
// design of the language feature), developers may mistakenly assume
// any expression is valid in this position. If the next token is not
// an identifier, attempt to parse an expression and issue an error.
// order to recover more gracefully from this condition.
if (state.tokens.next.type === "(identifier)") {
id = identifier(context);
} else {
expr = expression(context, 10);
error("E030", expr, expr.value);
}
} else {
id = identifier(context);
}
if (!isRest && checkPunctuator(state.tokens.next, ":")) {
advance(":");
nextInnerDE();
} else if (id) {
// in this case we are assigning (not declaring), so check assignment
if (isAssignment) {
checkLeftSideAssign(context, state.tokens.curr);
}
identifiers.push({ id: id, token: state.tokens.curr });
}
if (isRest && checkPunctuator(state.tokens.next, ",")) {
warning("W130", state.tokens.next);
}
}
};
var id, value;
if (checkPunctuator(firstToken, "[")) {
if (!openingParsed) {
advance("[");
}
if (checkPunctuator(state.tokens.next, "]")) {
warning("W137", state.tokens.curr);
}
var element_after_rest = false;
while (!checkPunctuator(state.tokens.next, "]")) {
var isRest = spreadrest("rest");
nextInnerDE();
if (isRest && !element_after_rest &&
checkPunctuator(state.tokens.next, ",")) {
warning("W130", state.tokens.next);
element_after_rest = true;
}
if (!isRest && checkPunctuator(state.tokens.next, "=")) {
if (checkPunctuator(state.tokens.prev, "...")) {
/* istanbul ignore next */
advance("]");
} else {
advance("=");
}
id = state.tokens.prev;
value = expression(context, 10);
if (value && value.identifier && value.value === "undefined") {
warning("W080", id, id.value);
}
}
if (!checkPunctuator(state.tokens.next, "]")) {
advance(",");
}
}
advance("]");
} else if (checkPunctuator(firstToken, "{")) {
if (!openingParsed) {
advance("{");
}
if (checkPunctuator(state.tokens.next, "}")) {
warning("W137", state.tokens.curr);
}
while (!checkPunctuator(state.tokens.next, "}")) {
assignmentProperty(context);
if (checkPunctuator(state.tokens.next, "=")) {
advance("=");
id = state.tokens.prev;
value = expression(context, 10);
if (value && value.identifier && value.value === "undefined") {
warning("W080", id, id.value);
}
}
if (!checkPunctuator(state.tokens.next, "}")) {
advance(",");
if (checkPunctuator(state.tokens.next, "}")) {
// Trailing comma
// ObjectBindingPattern: { BindingPropertyList , }
break;
}
}
}
advance("}");
}
return identifiers;
}
function destructuringPatternMatch(tokens, value) {
var first = value.first;
if (!first)
return;
_.zip(tokens, Array.isArray(first) ? first : [ first ]).forEach(function(val) {
var token = val[0];
var value = val[1];
if (token && value)
token.first = value;
else if (token && token.first && !value)
/* istanbul ignore next */
warning("W080", token.first, token.first.value);
});
}
function blockVariableStatement(type, statement, context) {
// used for both let and const statements
var noin = context & prodParams.noin;
var inexport = context & prodParams.export;
var isLet = type === "let";
var isConst = type === "const";
var tokens, lone, value, letblock;
if (!state.inES6()) {
warning("W104", state.tokens.curr, type, "6");
}
if (isLet && isMozillaLet()) {
advance("(");
state.funct["(scope)"].stack();
letblock = true;
statement.declaration = false;
}
statement.first = [];
for (;;) {
var names = [];
if (_.includes(["{", "["], state.tokens.next.value)) {
tokens = destructuringPattern(context);
lone = false;
} else {
tokens = [ { id: identifier(context), token: state.tokens.curr } ];
lone = true;
}
// A `const` declaration without an initializer is permissible within the
// head of for-in and for-of statements. If this binding list is being
// parsed as part of a `for` statement of any kind, allow the initializer
// to be omitted. Although this may erroneously allow such forms from
// "C-style" `for` statements (i.e. `for (const x;;) {}`, the `for`
// statement logic includes dedicated logic to issue the error for such
// cases.
if (!noin && isConst && state.tokens.next.id !== "=") {
warning("E012", state.tokens.curr, state.tokens.curr.value);
}
for (var t in tokens) {
if (tokens.hasOwnProperty(t)) {
t = tokens[t];
// It is a Syntax Error if the BoundNames of BindingList contains
// "let".
if (t.id === "let") {
/* istanbul ignore next */
warning("W024", t.token, t.id);
}
if (state.funct["(scope)"].block.isGlobal()) {
if (predefined[t.id] === false) {
warning("W079", t.token, t.id);
}
}
if (t.id) {
state.funct["(scope)"].addbinding(t.id, {
type: type,
token: t.token });
names.push(t.token);
}
}
}
if (state.tokens.next.id === "=") {
statement.hasInitializer = true;
advance("=");
if (!noin && peek(0).id === "=" && state.tokens.next.identifier) {
warning("W120", state.tokens.next, state.tokens.next.value);
}
var id = state.tokens.prev;
value = expression(context, 10);
if (value) {
if (value.identifier && value.value === "undefined") {
warning("W080", id, id.value);
}
if (!lone) {
destructuringPatternMatch(names, value);
}
}
}
// Bindings are not immediately initialized in for-in and for-of
// statements. As with `const` initializers (described above), the `for`
// statement parsing logic includes
if (state.tokens.next.value !== "in" && state.tokens.next.value !== "of") {
for (t in tokens) {
if (tokens.hasOwnProperty(t)) {
t = tokens[t];
state.funct["(scope)"].initialize(t.id);
if (lone && inexport) {
state.funct["(scope)"].setExported(t.token.value, t.token);
}
}
}
}
statement.first = statement.first.concat(names);
if (state.tokens.next.id !== ",") {
break;
}
statement.hasComma = true;
advance(",");
checkComma();
}
if (letblock) {
advance(")");
block(context, true, true);
statement.block = true;
state.funct["(scope)"].unstack();
}
return statement;
}
var conststatement = stmt("const", function(context) {
return blockVariableStatement("const", this, context);
});
conststatement.exps = true;
conststatement.declaration = true;
/**
* Determine if the current `let` token designates the beginning of a "let
* block" or "let expression" as implemented in the Mozilla SpiderMonkey
* engine.
*
* This function will only return `true` if Mozilla extensions have been
* enabled. It would be preferable to detect the language feature regardless
* of the parser's state because this would allow JSHint to instruct users to
* enable the `moz` option where necessary. This is not possible because the
* language extension is not compatible with standard JavaScript. For
* example, the following program code may describe a "let block" or a
* function invocation:
*
* let(x)
* {
* typeof x;
* }
*
* @returns {boolean}
*/
function isMozillaLet() {
return state.tokens.next.id === "(" && state.inMoz();
}
var letstatement = stmt("let", function(context) {
return blockVariableStatement("let", this, context);
});
letstatement.nud = function(context, rbp) {
if (isMozillaLet()) {
// create a new block scope we use only for the current expression
state.funct["(scope)"].stack();
advance("(");
state.tokens.prev.fud(context);
advance(")");
expression(context, rbp);
state.funct["(scope)"].unstack();
} else {
this.exps = false;
return state.syntax["(identifier)"].nud.apply(this, arguments);
}
};
letstatement.meta = { es5: true, isFutureReservedWord: false, strictOnly: true };
letstatement.exps = true;
letstatement.declaration = true;
letstatement.useFud = function(context) {
var next = state.tokens.next;
var nextIsBindingName;
if (this.line !== next.line && !state.inES6()) {
return false;
}
// JSHint generally interprets `let` as a reserved word even though it is
// not considered as such by the ECMAScript specification because doing so
// simplifies parsing logic. It is special-cased here so that code such as
//
// let
// let
//
// is correctly interpreted as an invalid LexicalBinding. (Without this
// consideration, the code above would be parsed as two
// IdentifierReferences.)
nextIsBindingName = next.identifier && (!isReserved(context, next) ||
next.id === "let");
return nextIsBindingName || checkPunctuators(next, ["{", "["]) ||
isMozillaLet();
};
var varstatement = stmt("var", function(context) {
var noin = context & prodParams.noin;
var inexport = context & prodParams.export;
var tokens, lone, value, id;
this.first = [];
for (;;) {
var names = [];
if (_.includes(["{", "["], state.tokens.next.value)) {
tokens = destructuringPattern(context);
lone = false;
} else {
tokens = [];
id = identifier(context);
if (id) {
tokens.push({ id: id, token: state.tokens.curr });
}
lone = true;
}
if (state.option.varstmt) {
warning("W132", this);
}
for (var t in tokens) {
if (tokens.hasOwnProperty(t)) {
t = tokens[t];
if (state.funct["(global)"] && !state.impliedClosure()) {
if (predefined[t.id] === false) {
warning("W079", t.token, t.id);
} else if (state.option.futurehostile === false) {
if ((!state.inES5() && vars.ecmaIdentifiers[5][t.id] === false) ||
(!state.inES6() && vars.ecmaIdentifiers[6][t.id] === false)) {
warning("W129", t.token, t.id);
}
}
}
if (t.id) {
state.funct["(scope)"].addbinding(t.id, {
type: "var",
token: t.token });
if (lone && inexport) {
state.funct["(scope)"].setExported(t.id, t.token);
}
names.push(t.token);
}
}
}
if (state.tokens.next.id === "=") {
this.hasInitializer = true;
state.nameStack.set(state.tokens.curr);
advance("=");
if (peek(0).id === "=" && state.tokens.next.identifier) {
if (!noin &&
!state.funct["(params)"] ||
state.funct["(params)"].indexOf(state.tokens.next.value) === -1) {
warning("W120", state.tokens.next, state.tokens.next.value);
}
}
id = state.tokens.prev;
value = expression(context, 10);
if (value) {
if (!state.funct["(loopage)"] && value.identifier &&
value.value === "undefined") {
warning("W080", id, id.value);
}
if (!lone) {
destructuringPatternMatch(names, value);
}
}
}
this.first = this.first.concat(names);
if (state.tokens.next.id !== ",") {
break;
}
this.hasComma = true;
advance(",");
checkComma();
}
return this;
});
varstatement.exps = true;
blockstmt("function", function(context) {
var inexport = context & prodParams.export;
var generator = false;
var isAsync = context & prodParams.preAsync;
var labelType = "";
if (isAsync) {
labelType = "async ";
}
if (state.tokens.next.value === "*") {
if (isAsync && !state.inES9()) {
warning("W119", state.tokens.prev, "async generators", "9");
} else if (!isAsync && !state.inES6(true)) {
warning("W119", state.tokens.next, "function*", "6");
}
advance("*");
labelType += "generator ";
generator = true;
}
labelType += "function";
if (inblock) {
warning("W082", state.tokens.curr);
}
var nameToken = optionalidentifier(context) ? state.tokens.curr : null;
if (!nameToken) {
if (!inexport) {
warning("W025");
}
} else {
state.funct["(scope)"].addbinding(nameToken.value, {
type: labelType,
token: state.tokens.curr,
initialized: true });
if (inexport) {
state.funct["(scope)"].setExported(nameToken.value, state.tokens.prev);
}
}
var f = doFunction(context, {
name: nameToken && nameToken.value,
statement: this,
type: generator ? "generator" : null,
ignoreLoopFunc: inblock // a declaration may already have warned
});
// If the function declaration is strict because the surrounding code is
// strict, the invalid name will trigger E008 when the scope manager
// attempts to create a binding in the strict environment record. An error
// should only be signaled here when the function itself enables strict
// mode (the scope manager will not report an error because a declaration
// does not introduce a binding into the function's environment record).
var enablesStrictMode = f["(isStrict)"] && !state.isStrict();
if (nameToken && (f["(name)"] === "arguments" || f["(name)"] === "eval") &&
enablesStrictMode) {
error("E008", nameToken);
}
if (state.tokens.next.id === "(" && state.tokens.next.line === state.tokens.curr.line) {
/* istanbul ignore next */
error("E039");
}
return this;
}).declaration = true;
prefix("function", function(context) {
var generator = false;
var isAsync = context & prodParams.preAsync;
if (state.tokens.next.value === "*") {
if (isAsync && !state.inES9()) {
warning("W119", state.tokens.prev, "async generators", "9");
} else if (!isAsync && !state.inES6(true)) {
warning("W119", state.tokens.curr, "function*", "6");
}
advance("*");
generator = true;
}
// This context modification restricts the use of `await` as the optional
// BindingIdentifier in async function expressions.
var nameToken = optionalidentifier(isAsync ? context | prodParams.async : context) ?
state.tokens.curr : null;
var f = doFunction(context, {
name: nameToken && nameToken.value,
type: generator ? "generator" : null
});
if (generator && nameToken && nameToken.value === "yield") {
error("E024", nameToken, "yield");
}
if (nameToken && (f["(name)"] === "arguments" || f["(name)"] === "eval") &&
f["(isStrict)"]) {
error("E008", nameToken);
}
return this;
});
blockstmt("if", function(context) {
var t = state.tokens.next;
increaseComplexityCount();
advance("(");
var expr = expression(context, 0);
if (!expr) {
quit("E041", this);
}
checkCondAssignment(expr);
// When the if is within a for-in loop, check if the condition
// starts with a negation operator
var forinifcheck = null;
if (state.option.forin && state.forinifcheckneeded) {
state.forinifcheckneeded = false; // We only need to analyze the first if inside the loop
forinifcheck = state.forinifchecks[state.forinifchecks.length - 1];
if (expr.type === "(punctuator)" && expr.value === "!") {
forinifcheck.type = "(negative)";
} else {
forinifcheck.type = "(positive)";
}
}
advance(")", t);
var s = block(context, true, true);
// When the if is within a for-in loop and the condition has a negative form,
// check if the body contains nothing but a continue statement
if (forinifcheck && forinifcheck.type === "(negative)") {
if (s && s[0] && s[0].type === "(identifier)" && s[0].value === "continue") {
forinifcheck.type = "(negative-with-continue)";
}
}
if (state.tokens.next.id === "else") {
advance("else");
if (state.tokens.next.id === "if" || state.tokens.next.id === "switch") {
statement(context);
} else {
block(context, true, true);
}
}
return this;
});
blockstmt("try", function(context) {
var b;
var hasParameter = false;
function catchParameter() {
advance("(");
if (checkPunctuators(state.tokens.next, ["[", "{"])) {
var tokens = destructuringPattern(context);
_.each(tokens, function(token) {
if (token.id) {
state.funct["(scope)"].addParam(token.id, token, "exception");
}
});
} else if (state.tokens.next.type !== "(identifier)") {
warning("E030", state.tokens.next, state.tokens.next.value);
} else {
// only advance if an identifier is present. This allows JSHint to
// recover from the case where no value is specified.
state.funct["(scope)"].addParam(identifier(context), state.tokens.curr, "exception");
}
if (state.tokens.next.value === "if") {
if (!state.inMoz()) {
warning("W118", state.tokens.curr, "catch filter");
}
advance("if");
expression(context, 0);
}
advance(")");
}
block(context | prodParams.tryClause, true);
while (state.tokens.next.id === "catch") {
increaseComplexityCount();
if (b && (!state.inMoz())) {
warning("W118", state.tokens.next, "multiple catch blocks");
}
advance("catch");
if (state.tokens.next.id !== "{") {
state.funct["(scope)"].stack("catchparams");
hasParameter = true;
catchParameter();
} else if (!state.inES10()) {
warning("W119", state.tokens.curr, "optional catch binding", "10");
}
block(context, false);
if (hasParameter) {
state.funct["(scope)"].unstack();
hasParameter = false;
}
b = true;
}
if (state.tokens.next.id === "finally") {
advance("finally");
block(context, true);
return;
}
if (!b) {
error("E021", state.tokens.next, "catch", state.tokens.next.value);
}
return this;
});
blockstmt("while", function(context) {
var t = state.tokens.next;
state.funct["(breakage)"] += 1;
state.funct["(loopage)"] += 1;
increaseComplexityCount();
advance("(");
checkCondAssignment(expression(context, 0));
advance(")", t);
block(context, true, true);
state.funct["(breakage)"] -= 1;
state.funct["(loopage)"] -= 1;
return this;
}).labelled = true;
blockstmt("with", function(context) {
var t = state.tokens.next;
if (state.isStrict()) {
error("E010", state.tokens.curr);
} else if (!state.option.withstmt) {
warning("W085", state.tokens.curr);
}
advance("(");
expression(context, 0);
advance(")", t);
block(context, true, true);
return this;
});
blockstmt("switch", function(context) {
var t = state.tokens.next;
var g = false;
var noindent = false;
var seenCase = false;
state.funct["(breakage)"] += 1;
advance("(");
checkCondAssignment(expression(context, 0));
advance(")", t);
t = state.tokens.next;
advance("{");
state.funct["(scope)"].stack();
if (state.tokens.next.from === indent)
noindent = true;
if (!noindent)
indent += state.option.indent;
for (;;) {
switch (state.tokens.next.id) {
case "case":
switch (state.funct["(verb)"]) {
case "yield":
case "break":
case "case":
case "continue":
case "return":
case "switch":
case "throw":
break;
case "default":
if (state.option.leanswitch) {
warning("W145", state.tokens.next);
}
break;
default:
// You can tell JSHint that you don't use break intentionally by
// adding a comment /* falls through */ on a line just before
// the next `case`.
if (!state.tokens.curr.caseFallsThrough) {
warning("W086", state.tokens.curr, "case");
}
}
advance("case");
expression(context, 0);
seenCase = true;
increaseComplexityCount();
g = true;
advance(":");
state.funct["(verb)"] = "case";
break;
case "default":
switch (state.funct["(verb)"]) {
case "yield":
case "break":
case "continue":
case "return":
case "throw":
break;
case "case":
if (state.option.leanswitch) {
warning("W145", state.tokens.curr);
}
break;
default:
// Do not display a warning if 'default' is the first statement or if
// there is a special /* falls through */ comment.
if (seenCase && !state.tokens.curr.caseFallsThrough) {
warning("W086", state.tokens.curr, "default");
}
}
advance("default");
g = true;
advance(":");
state.funct["(verb)"] = "default";
break;
case "}":
if (!noindent)
indent -= state.option.indent;
advance("}", t);
state.funct["(scope)"].unstack();
state.funct["(breakage)"] -= 1;
state.funct["(verb)"] = undefined;
return;
/* istanbul ignore next */
case "(end)":
error("E023", state.tokens.next, "}");
return;
default:
indent += state.option.indent;
if (g) {
switch (state.tokens.curr.id) {
/* istanbul ignore next */
case ",":
error("E040");
return;
case ":":
g = false;
statements(context);
break;
/* istanbul ignore next */
default:
error("E025", state.tokens.curr);
return;
}
} else {
/* istanbul ignore else */
if (state.tokens.curr.id === ":") {
advance(":");
error("E024", state.tokens.curr, ":");
statements(context);
} else {
error("E021", state.tokens.next, "case", state.tokens.next.value);
return;
}
}
indent -= state.option.indent;
}
}
}).labelled = true;
stmt("debugger", function() {
if (!state.option.debug) {
warning("W087", this);
}
return this;
}).exps = true;
(function() {
var x = stmt("do", function(context) {
state.funct["(breakage)"] += 1;
state.funct["(loopage)"] += 1;
increaseComplexityCount();
this.first = block(context, true, true);
advance("while");
var t = state.tokens.next;
advance("(");
checkCondAssignment(expression(context, 0));
advance(")", t);
state.funct["(breakage)"] -= 1;
state.funct["(loopage)"] -= 1;
return this;
});
x.labelled = true;
x.exps = true;
}());
blockstmt("for", function(context) {
var s, t = state.tokens.next;
var letscope = false;
var isAsync = false;
var foreachtok = null;
if (t.value === "each") {
foreachtok = t;
advance("each");
if (!state.inMoz()) {
warning("W118", state.tokens.curr, "for each");
}
}
if (state.tokens.next.identifier && state.tokens.next.value === "await") {
advance("await");
isAsync = true;
if (!(context & prodParams.async)) {
error("E024", state.tokens.curr, "await");
} else if (!state.inES9()) {
warning("W119", state.tokens.curr, "asynchronous iteration", "9");
}
}
increaseComplexityCount();
advance("(");
// what kind of for(…) statement it is? for(…of…)? for(…in…)? for(…;…;…)?
var nextop; // contains the token of the "in" or "of" operator
var comma; // First comma punctuator at level 0
var initializer; // First initializer at level 0
var bindingPower;
var targets;
var target;
var decl;
var afterNext = peek();
var headContext = context | prodParams.noin;
if (state.tokens.next.id === "var") {
advance("var");
decl = state.tokens.curr.fud(headContext);
comma = decl.hasComma ? decl : null;
initializer = decl.hasInitializer ? decl : null;
} else if (state.tokens.next.id === "const" ||
// The "let" keyword only signals a lexical binding if it is followed by
// an identifier, `{`, or `[`. Otherwise, it should be parsed as an
// IdentifierReference (i.e. in a subsquent branch).
(state.tokens.next.id === "let" &&
((afterNext.identifier && afterNext.id !== "in") ||
checkPunctuators(afterNext, ["{", "["])))) {
advance(state.tokens.next.id);
// create a new block scope
letscope = true;
state.funct["(scope)"].stack();
decl = state.tokens.curr.fud(headContext);
comma = decl.hasComma ? decl : null;
initializer = decl.hasInitializer ? decl : null;
} else if (!checkPunctuator(state.tokens.next, ";")) {
targets = [];
while (state.tokens.next.value !== "in" &&
state.tokens.next.value !== "of" &&
!checkPunctuator(state.tokens.next, ";")) {
if (checkPunctuators(state.tokens.next, ["{", "["])) {
destructuringPattern(headContext, { assignment: true })
.forEach(function(elem) {
this.push(elem.token);
}, targets);
if (checkPunctuator(state.tokens.next, "=")) {
advance("=");
initializer = state.tokens.curr;
expression(headContext, 10);
}
} else {
target = expression(headContext, 10);
if (target) {
if (target.type === "(identifier)") {
targets.push(target);
} else if (checkPunctuator(target, "=")) {
initializer = target;
targets.push(target);
}
}
}
if (checkPunctuator(state.tokens.next, ",")) {
advance(",");
if (!comma) {
comma = state.tokens.curr;
}
}
}
//checkLeftSideAssign(target, nextop);
// In the event of a syntax error, do not issue warnings regarding the
// implicit creation of bindings.
if (!initializer && !comma) {
targets.forEach(function(token) {
if (!state.funct["(scope)"].has(token.value)) {
warning("W088", token, token.value);
}
});
}
}
nextop = state.tokens.next;
if (isAsync && nextop.value !== "of") {
error("E066", nextop);
}
// if we're in a for (… in|of …) statement
if (_.includes(["in", "of"], nextop.value)) {
if (nextop.value === "of") {
bindingPower = 20;
if (!state.inES6()) {
warning("W104", nextop, "for of", "6");
}
} else {
bindingPower = 0;
}
if (comma) {
error("W133", comma, nextop.value, "more than one ForBinding");
}
if (initializer) {
error("W133", initializer, nextop.value, "initializer is forbidden");
}
if (target && !comma && !initializer) {
checkLeftSideAssign(context, target, nextop);
}
advance(nextop.value);
// The binding power is variable because for-in statements accept any
// Expression in this position, while for-of statements are limited to
// AssignmentExpressions. For example:
//
// for ( LeftHandSideExpression in Expression ) Statement
// for ( LeftHandSideExpression of AssignmentExpression ) Statement
expression(context, bindingPower);
advance(")", t);
if (nextop.value === "in" && state.option.forin) {
state.forinifcheckneeded = true;
if (state.forinifchecks === undefined) {
state.forinifchecks = [];
}
// Push a new for-in-if check onto the stack. The type will be modified
// when the loop's body is parsed and a suitable if statement exists.
state.forinifchecks.push({
type: "(none)"
});
}
state.funct["(breakage)"] += 1;
state.funct["(loopage)"] += 1;
s = block(context, true, true);
if (nextop.value === "in" && state.option.forin) {
if (state.forinifchecks && state.forinifchecks.length > 0) {
var check = state.forinifchecks.pop();
if (// No if statement or not the first statement in loop body
s && s.length > 0 && (typeof s[0] !== "object" || s[0].value !== "if") ||
// Positive if statement is not the only one in loop body
check.type === "(positive)" && s.length > 1 ||
// Negative if statement but no continue
check.type === "(negative)") {
warning("W089", this);
}
}
// Reset the flag in case no if statement was contained in the loop body
state.forinifcheckneeded = false;
}
state.funct["(breakage)"] -= 1;
state.funct["(loopage)"] -= 1;
} else {
if (foreachtok) {
error("E045", foreachtok);
}
nolinebreak(state.tokens.curr);
advance(";");
if (decl) {
if (decl.value === "const" && !decl.hasInitializer) {
warning("E012", decl, decl.first[0].value);
}
decl.first.forEach(function(token) {
state.funct["(scope)"].initialize(token.value);
});
}
// start loopage after the first ; as the next two expressions are executed
// on every loop
state.funct["(loopage)"] += 1;
if (state.tokens.next.id !== ";") {
checkCondAssignment(expression(context, 0));
}
nolinebreak(state.tokens.curr);
advance(";");
if (state.tokens.next.id === ";") {
error("E021", state.tokens.next, ")", ";");
}
if (state.tokens.next.id !== ")") {
for (;;) {
expression(context, 0);
if (state.tokens.next.id !== ",") {
break;
}
advance(",");
checkComma();
}
}
advance(")", t);
state.funct["(breakage)"] += 1;
block(context, true, true);
state.funct["(breakage)"] -= 1;
state.funct["(loopage)"] -= 1;
}
// unstack loop blockscope
if (letscope) {
state.funct["(scope)"].unstack();
}
return this;
}).labelled = true;
stmt("break", function() {
var v = state.tokens.next.value;
if (!state.option.asi)
nolinebreak(this);
if (state.tokens.next.identifier &&
sameLine(state.tokens.curr, state.tokens.next)) {
if (!state.funct["(scope)"].funct.hasLabel(v)) {
warning("W090", state.tokens.next, v);
}
this.first = state.tokens.next;
advance();
} else {
if (state.funct["(breakage)"] === 0)
warning("W052", state.tokens.next, this.value);
}
reachable(this);
return this;
}).exps = true;
stmt("continue", function() {
var v = state.tokens.next.value;
if (state.funct["(breakage)"] === 0 || !state.funct["(loopage)"]) {
warning("W052", state.tokens.next, this.value);
}
if (!state.option.asi)
nolinebreak(this);
if (state.tokens.next.identifier) {
if (sameLine(state.tokens.curr, state.tokens.next)) {
if (!state.funct["(scope)"].funct.hasLabel(v)) {
warning("W090", state.tokens.next, v);
}
this.first = state.tokens.next;
advance();
}
}
reachable(this);
return this;
}).exps = true;
stmt("return", function(context) {
if (sameLine(this, state.tokens.next)) {
if (state.tokens.next.id !== ";" && !state.tokens.next.reach) {
this.first = expression(context, 0);
if (this.first &&
this.first.type === "(punctuator)" && this.first.value === "=" &&
!this.first.paren && !state.option.boss) {
warning("W093", this.first);
}
if (state.option.noreturnawait && context & prodParams.async &&
!(context & prodParams.tryClause) &&
this.first.identifier && this.first.value === "await") {
warning("W146", this.first);
}
}
} else {
if (state.tokens.next.type === "(punctuator)" &&
["[", "{", "+", "-"].indexOf(state.tokens.next.value) > -1) {
nolinebreak(this); // always warn (Line breaking error)
}
}
reachable(this);
return this;
}).exps = true;
prefix("await", function(context) {
if (context & prodParams.async) {
// If the parameters of the current function scope have not been defined,
// it is because the current expression is contained within the parameter
// list.
if (!state.funct["(params)"]) {
error("E024", this, "await");
}
expression(context, 10);
return this;
} else {
this.exps = false;
return state.syntax["(identifier)"].nud.apply(this, arguments);
}
}).exps = true;
(function(asyncSymbol) {
asyncSymbol.meta = { es5: true, isFutureReservedWord: true, strictOnly: true };
asyncSymbol.isFunc = function() {
var next = state.tokens.next;
var afterParens;
if (this.line !== next.line) {
return false;
}
if (next.id === "function") {
return true;
}
if (next.id === "(") {
afterParens = peekThroughParens(0);
return afterParens.id === "=>";
}
if (next.identifier) {
return peek().id === "=>";
}
return false;
};
asyncSymbol.useFud = asyncSymbol.isFunc;
// async function declaration
asyncSymbol.fud = function(context) {
if (!state.inES8()) {
warning("W119", this, "async functions", "8");
}
context |= prodParams.preAsync;
context |= prodParams.initial;
this.func = expression(context, 0);
this.block = this.func.block;
this.exps = this.func.exps;
return this;
};
asyncSymbol.exps = true;
delete asyncSymbol.reserved;
}(prefix("async", function(context, rbp) {
if (this.isFunc(context)) {
if (!state.inES8()) {
warning("W119", this, "async functions", "8");
}
context |= prodParams.preAsync;
this.func = expression(context, rbp);
this.identifier = false;
return this;
}
this.exps = false;
return state.syntax["(identifier)"].nud.apply(this, arguments);
})));
(function(yieldSymbol) {
yieldSymbol.rbp = yieldSymbol.lbp = 25;
yieldSymbol.exps = true;
})(prefix("yield", function(context) {
if (state.inMoz()) {
return mozYield.call(this, context);
}
if (!(context & prodParams.yield)) {
this.exps = false;
return state.syntax["(identifier)"].nud.apply(this, arguments);
}
var prev = state.tokens.prev;
// If the parameters of the current function scope have not been defined,
// it is because the current expression is contained within the parameter
// list.
if (!state.funct["(params)"]) {
error("E024", this, "yield");
}
if (!this.beginsStmt && prev.lbp > 30 && !checkPunctuators(prev, ["("])) {
error("E061", this);
}
if (!state.inES6()) {
warning("W104", state.tokens.curr, "yield", "6");
}
state.funct["(yielded)"] = true;
if (state.tokens.next.value === "*") {
advance("*");
}
// Parse operand
if (state.tokens.curr.value === "*" || sameLine(state.tokens.curr, state.tokens.next)) {
if (state.tokens.next.nud) {
nobreaknonadjacent(state.tokens.curr, state.tokens.next);
this.first = expression(context, 10);
if (this.first.type === "(punctuator)" && this.first.value === "=" &&
!this.first.paren && !state.option.boss) {
warning("W093", this.first);
}
} else if (state.tokens.next.led) {
if (state.tokens.next.id !== ",") {
error("W017", state.tokens.next);
}
}
}
return this;
}));
/**
* Parsing logic for non-standard Mozilla implementation of `yield`
* expressions.
*/
var mozYield = function(context) {
var prev = state.tokens.prev;
if (state.inES6(true) && !(context & prodParams.yield)) {
error("E046", state.tokens.curr, "yield");
}
state.funct["(yielded)"] = true;
var delegatingYield = false;
if (state.tokens.next.value === "*") {
delegatingYield = true;
advance("*");
}
if (sameLine(this, state.tokens.next)) {
if (delegatingYield ||
(state.tokens.next.id !== ";" && !state.option.asi &&
!state.tokens.next.reach && state.tokens.next.nud)) {
nobreaknonadjacent(state.tokens.curr, state.tokens.next);
this.first = expression(context, 10);
if (this.first.type === "(punctuator)" && this.first.value === "=" &&
!this.first.paren && !state.option.boss) {
warning("W093", this.first);
}
}
if (state.tokens.next.id !== ")" &&
(prev.lbp > 30 || (!prev.assign && !isEndOfExpr()))) {
error("E050", this);
}
} else if (!state.option.asi) {
nolinebreak(this); // always warn (Line breaking error)
}
return this;
};
stmt("throw", function(context) {
nolinebreak(this);
this.first = expression(context, 20);
reachable(this);
return this;
}).exps = true;
stmt("import", function(context) {
if (!state.funct["(scope)"].block.isGlobal()) {
error("E053", state.tokens.curr, "Import");
}
if (!state.inES6()) {
warning("W119", state.tokens.curr, "import", "6");
}
if (state.tokens.next.type === "(string)") {
// ModuleSpecifier :: StringLiteral
advance("(string)");
return this;
}
if (state.tokens.next.identifier) {
// ImportClause :: ImportedDefaultBinding
this.name = identifier(context);
// Import bindings are immutable (see ES6 8.1.1.5.5)
state.funct["(scope)"].addbinding(this.name, {
type: "import",
initialized: true,
token: state.tokens.curr });
if (state.tokens.next.value === ",") {
// ImportClause :: ImportedDefaultBinding , NameSpaceImport
// ImportClause :: ImportedDefaultBinding , NamedImports
advance(",");
// At this point, we intentionally fall through to continue matching
// either NameSpaceImport or NamedImports.
// Discussion:
// https://github.com/jshint/jshint/pull/2144#discussion_r23978406
} else {
advance("from");
advance("(string)");
return this;
}
}
if (state.tokens.next.id === "*") {
// ImportClause :: NameSpaceImport
advance("*");
advance("as");
if (state.tokens.next.identifier) {
this.name = identifier(context);
// Import bindings are immutable (see ES6 8.1.1.5.5)
state.funct["(scope)"].addbinding(this.name, {
type: "import",
initialized: true,
token: state.tokens.curr });
}
} else {
// ImportClause :: NamedImports
advance("{");
for (;;) {
if (state.tokens.next.value === "}") {
advance("}");
break;
}
var importName;
if (state.tokens.next.type === "default") {
importName = "default";
advance("default");
} else {
importName = identifier(context);
}
if (state.tokens.next.value === "as") {
advance("as");
importName = identifier(context);
}
// Import bindings are immutable (see ES6 8.1.1.5.5)
state.funct["(scope)"].addbinding(importName, {
type: "import",
initialized: true,
token: state.tokens.curr });
if (state.tokens.next.value === ",") {
advance(",");
} else if (state.tokens.next.value === "}") {
advance("}");
break;
} else {
error("E024", state.tokens.next, state.tokens.next.value);
break;
}
}
}
// FromClause
advance("from");
advance("(string)");
// Support for ES2015 modules was released without warning for `import`
// declarations that lack bindings. Issuing a warning would therefor
// constitute a breaking change.
// TODO: enable this warning in JSHint 3
// if (hasBindings) {
// warning("W142", this, "import", moduleSpecifier);
// }
return this;
}).exps = true;
stmt("export", function(context) {
var ok = true;
var token;
var identifier;
var moduleSpecifier;
context = context | prodParams.export;
if (!state.inES6()) {
warning("W119", state.tokens.curr, "export", "6");
ok = false;
}
if (!state.funct["(scope)"].block.isGlobal()) {
error("E053", state.tokens.curr, "Export");
ok = false;
}
if (state.tokens.next.value === "*") {
// ExportDeclaration :: export * FromClause
advance("*");
advance("from");
advance("(string)");
return this;
}
if (state.tokens.next.type === "default") {
// ExportDeclaration ::
// export default [lookahead ∉ { function, class }] AssignmentExpression[In] ;
// export default HoistableDeclaration
// export default ClassDeclaration
// because the 'name' of a default-exported function is, confusingly, 'default'
// see https://bocoup.com/blog/whats-in-a-function-name
state.nameStack.set(state.tokens.next);
advance("default");
var exportType = state.tokens.next.id;
if (exportType === "function") {
this.block = true;
advance("function");
state.syntax["function"].fud(context);
} else if (exportType === "async" && peek().id === "function") {
this.block = true;
advance("async");
advance("function");
state.syntax["function"].fud(context | prodParams.preAsync);
} else if (exportType === "class") {
this.block = true;
advance("class");
state.syntax["class"].fud(context);
} else {
token = expression(context, 10);
if (token.identifier) {
identifier = token.value;
state.funct["(scope)"].setExported(identifier, token);
}
}
return this;
}
if (state.tokens.next.value === "{") {
// ExportDeclaration :: export ExportClause
advance("{");
var exportedTokens = [];
while (!checkPunctuator(state.tokens.next, "}")) {
if (!state.tokens.next.identifier) {
/* istanbul ignore next */
error("E030", state.tokens.next, state.tokens.next.value);
}
advance();
exportedTokens.push(state.tokens.curr);
if (state.tokens.next.value === "as") {
advance("as");
if (!state.tokens.next.identifier) {
/* istanbul ignore next */
error("E030", state.tokens.next, state.tokens.next.value);
}
advance();
}
if (!checkPunctuator(state.tokens.next, "}")) {
advance(",");
}
}
advance("}");
if (state.tokens.next.value === "from") {
// ExportDeclaration :: export ExportClause FromClause
advance("from");
moduleSpecifier = state.tokens.next;
advance("(string)");
} else if (ok) {
exportedTokens.forEach(function(token) {
state.funct["(scope)"].setExported(token.value, token);
});
}
if (exportedTokens.length === 0) {
if (moduleSpecifier) {
warning("W142", this, "export", moduleSpecifier.value);
} else {
warning("W141", this, "export");
}
}
return this;
} else if (state.tokens.next.id === "var") {
// ExportDeclaration :: export VariableStatement
advance("var");
state.tokens.curr.fud(context);
} else if (state.tokens.next.id === "let") {
// ExportDeclaration :: export VariableStatement
advance("let");
state.tokens.curr.fud(context);
} else if (state.tokens.next.id === "const") {
// ExportDeclaration :: export VariableStatement
advance("const");
state.tokens.curr.fud(context);
} else if (state.tokens.next.id === "function") {
// ExportDeclaration :: export Declaration
this.block = true;
advance("function");
state.syntax["function"].fud(context);
} else if (state.tokens.next.id === "async" && peek().id === "function") {
// ExportDeclaration :: export Declaration
this.block = true;
advance("async");
advance("function");
state.syntax["function"].fud(context | prodParams.preAsync);
} else if (state.tokens.next.id === "class") {
// ExportDeclaration :: export Declaration
this.block = true;
advance("class");
state.syntax["class"].fud(context);
} else {
/* istanbul ignore next */
error("E024", state.tokens.next, state.tokens.next.value);
}
return this;
}).exps = true;
/**
* Determine if SuperCall or SuperProperty may be used in the current context
* (as described by the provided "functor" object).
*
* @param {string} type - one of "property" or "call"
* @param {object} funct - a "functor" object describing the current function
* context
*
* @returns {boolean}
*/
function supportsSuper(type, funct) {
if (type === "call" && funct["(async)"]) {
return false;
}
if (type === "property" && funct["(method)"]) {
return true;
}
if (type === "call" && funct["(statement)"] &&
funct["(statement)"].id === "class") {
return true;
}
if (funct["(arrow)"]) {
return supportsSuper(type, funct["(context)"]);
}
return false;
}
var superNud = function() {
var next = state.tokens.next;
if (checkPunctuators(next, ["[", "."])) {
if (!supportsSuper("property", state.funct)) {
error("E063", this);
}
} else if (checkPunctuator(next, "(")) {
if (!supportsSuper("call", state.funct)) {
error("E064", this);
}
} else {
error("E024", next, next.value || next.id);
}
return this;
};
// Future Reserved Words
FutureReservedWord("abstract");
FutureReservedWord("boolean");
FutureReservedWord("byte");
FutureReservedWord("char");
FutureReservedWord("double");
FutureReservedWord("enum", { es5: true });
FutureReservedWord("export", { es5: true });
FutureReservedWord("extends", { es5: true });
FutureReservedWord("final");
FutureReservedWord("float");
FutureReservedWord("goto");
FutureReservedWord("implements", { es5: true, strictOnly: true });
FutureReservedWord("import", { es5: true });
FutureReservedWord("int");
FutureReservedWord("interface", { es5: true, strictOnly: true });
FutureReservedWord("long");
FutureReservedWord("native");
FutureReservedWord("package", { es5: true, strictOnly: true });
FutureReservedWord("private", { es5: true, strictOnly: true });
FutureReservedWord("protected", { es5: true, strictOnly: true });
FutureReservedWord("public", { es5: true, strictOnly: true });
FutureReservedWord("short");
FutureReservedWord("static", { es5: true, strictOnly: true });
FutureReservedWord("synchronized");
FutureReservedWord("transient");
FutureReservedWord("volatile");
// this function is used to determine whether a squarebracket or a curlybracket
// expression is a comprehension array, destructuring assignment or a json value.
var lookupBlockType = function() {
var pn, pn1, prev;
var i = -1;
var bracketStack = 0;
var ret = {};
if (checkPunctuators(state.tokens.curr, ["[", "{"])) {
bracketStack += 1;
}
do {
prev = i === -1 ? state.tokens.curr : pn;
pn = i === -1 ? state.tokens.next : peek(i);
pn1 = peek(i + 1);
i = i + 1;
if (checkPunctuators(pn, ["[", "{"])) {
bracketStack += 1;
} else if (checkPunctuators(pn, ["]", "}"])) {
bracketStack -= 1;
}
if (bracketStack === 1 && pn.identifier && pn.value === "for" &&
!checkPunctuator(prev, ".")) {
ret.isCompArray = true;
ret.notJson = true;
break;
}
if (bracketStack === 0 && checkPunctuators(pn, ["}", "]"])) {
if (pn1.value === "=") {
ret.isDestAssign = true;
ret.notJson = true;
break;
} else if (pn1.value === ".") {
ret.notJson = true;
break;
}
}
if (checkPunctuator(pn, ";")) {
ret.notJson = true;
}
} while (bracketStack > 0 && pn.id !== "(end)");
return ret;
};
/**
* Update an object used to track property names within object initializers
* and class bodies. Produce warnings in response to duplicated names.
*
* @param {object} props - a collection of all properties of the object or
* class to which the current property is being
* assigned
* @param {string} name - the property name
* @param {object} tkn - the token defining the property
* @param {boolean} [isClass] - whether the accessor is part of an ES6 Class
* definition
* @param {boolean} [isStatic] - whether the accessor is a static method
* @param {boolean} [isComputed] - whether the property is a computed expression like [Symbol.iterator]
*/
function saveProperty(props, name, tkn, isClass, isStatic, isComputed) {
if (tkn.identifier) {
name = tkn.value;
}
var key = name;
if (isClass && isStatic) {
key = "static " + name;
}
if (props[key] && name !== "__proto__" && !isComputed) {
var msg = ["key", "class method", "static class method"];
msg = msg[(isClass || false) + (isStatic || false)];
warning("W075", state.tokens.next, msg, name);
} else {
props[key] = Object.create(null);
}
props[key].basic = true;
props[key].basictkn = tkn;
}
/**
* Update an object used to track property names within object initializers
* and class bodies. Produce warnings in response to duplicated names.
*
* @param {string} accessorType - Either "get" or "set"
* @param {object} props - a collection of all properties of the object or
* class to which the current accessor is being
* assigned
* @param {object} tkn - the identifier token representing the accessor name
* @param {boolean} [isClass] - whether the accessor is part of an ES6 Class
* definition
* @param {boolean} [isStatic] - whether the accessor is a static method
*/
function saveAccessor(accessorType, props, name, tkn, isClass, isStatic) {
var flagName = accessorType === "get" ? "getterToken" : "setterToken";
var key = name;
state.tokens.curr.accessorType = accessorType;
state.nameStack.set(tkn);
if (isClass && isStatic) {
key = "static " + name;
}
if (props[key]) {
if ((props[key].basic || props[key][flagName]) && name !== "__proto__") {
var msg = "";
if (isClass) {
if (isStatic) {
msg += "static ";
}
msg += accessorType + "ter method";
} else {
msg = "key";
}
warning("W075", state.tokens.next, msg, name);
}
} else {
props[key] = Object.create(null);
}
props[key][flagName] = tkn;
if (isStatic) {
props[key].static = true;
}
}
/**
* Parse a computed property name within object initializers and class bodies
* as introduced by ES2015. For example:
*
* void {
* [object.method()]: null
* };
*
* @param {number} context - the parsing context
*
* @returns {object} - the token value that describes the expression which
* defines the property name
*/
function computedPropertyName(context) {
advance("[");
// Explicitly reclassify token as a delimeter to prevent its later
// interpretation as an "infix" operator.
state.tokens.curr.delim = true;
state.tokens.curr.lbp = 0;
if (!state.inES6()) {
warning("W119", state.tokens.curr, "computed property names", "6");
}
var value = expression(context & ~prodParams.noin, 10);
advance("]");
return value;
}
/**
* Test whether a given token is a punctuator whose `value` property matches
* one of the specified values. This function explicitly verifies the token's
* `type` property so that like-valued string literals (e.g. `";"`) do not
* produce false positives.
*
* @param {Token} token
* @param {Array.<string>} values
*
* @returns {boolean}
*/
function checkPunctuators(token, values) {
if (token.type === "(punctuator)") {
return _.includes(values, token.value);
}
return false;
}
/**
* Test whether a given token is a punctuator whose `value` property matches
* the specified value. This function explicitly verifies the token's `type`
* property so that like-valued string literals (e.g. `";"`) do not produce
* false positives.
*
* @param {Token} token
* @param {string} value
*
* @returns {boolean}
*/
function checkPunctuator(token, value) {
return token.type === "(punctuator)" && token.value === value;
}
// Check whether this function has been reached for a destructuring assign with undeclared values
function destructuringAssignOrJsonValue(context) {
// lookup for the assignment (ECMAScript 6 only)
// if it has semicolons, it is a block, so go parse it as a block
// or it's not a block, but there are assignments, check for undeclared variables
var block = lookupBlockType();
if (block.notJson) {
if (!state.inES6() && block.isDestAssign) {
/* istanbul ignore next */
warning("W104", state.tokens.curr, "destructuring assignment", "6");
}
statements(context);
// otherwise parse json value
} else {
state.option.laxbreak = true;
state.jsonMode = true;
jsonValue();
}
}
/**
* Parse and define the three states of a list comprehension in order to
* avoid defining global variables, but keeping them to the list
* comprehension scope only. The order of the states are as follows:
*
* - "use" - which will be the returned iterative part of the list
* comprehension
* - "define" - which will define the variables local to the list
* comprehension
* - "filter" - which will help filter out values
*/
var arrayComprehension = function() {
var CompArray = function() {
this.mode = "use";
this.variables = [];
};
var _carrays = [];
var _current;
function declare(v) {
var l = _current.variables.filter(function(elt) {
// if it has, change its undef state
if (elt.value === v) {
elt.undef = false;
return v;
}
}).length;
return l !== 0;
}
function use(v) {
var l = _current.variables.filter(function(elt) {
// and if it has been defined
if (elt.value === v && !elt.undef) {
if (elt.unused === true) {
elt.unused = false;
}
return v;
}
}).length;
// otherwise we warn about it
return (l === 0);
}
return { stack: function() {
_current = new CompArray();
_carrays.push(_current);
},
unstack: function() {
_current.variables.filter(function(v) {
if (v.unused)
warning("W098", v.token, v.token.raw_text || v.value);
if (v.undef)
state.funct["(scope)"].block.use(v.value, v.token);
});
_carrays.splice(-1, 1);
_current = _carrays[_carrays.length - 1];
},
setState: function(s) {
if (_.includes(["use", "define", "generate", "filter"], s))
_current.mode = s;
},
check: function(v) {
if (!_current) {
return;
}
// When we are in "use" state of the list comp, we enqueue that var
if (_current && _current.mode === "use") {
if (use(v)) {
_current.variables.push({
token: state.tokens.curr,
value: v,
undef: true,
unused: false
});
}
return true;
// When we are in "define" state of the list comp,
} else if (_current && _current.mode === "define") {
// check if the variable has been used previously
if (!declare(v)) {
_current.variables.push({
token: state.tokens.curr,
value: v,
undef: false,
unused: true
});
}
return true;
// When we are in the "generate" state of the list comp,
} else if (_current && _current.mode === "generate") {
state.funct["(scope)"].block.use(v, state.tokens.curr);
return true;
// When we are in "filter" state,
} else if (_current && _current.mode === "filter") {
// we check whether current variable has been declared
if (use(v)) {
// if not we warn about it
/* istanbul ignore next */
state.funct["(scope)"].block.use(v, state.tokens.curr);
}
return true;
}
/* istanbul ignore next */
return false;
}
};
};
/**
* Parse input according to the JSON format.
*
* http://json.org/
*/
function jsonValue() {
function jsonObject() {
var o = {}, t = state.tokens.next;
advance("{");
if (state.tokens.next.id !== "}") {
for (;;) {
if (state.tokens.next.id === "(end)") {
error("E026", state.tokens.next, t.line);
} else if (state.tokens.next.id === "}") {
warning("W094", state.tokens.curr);
break;
} else if (state.tokens.next.id === ",") {
error("E028", state.tokens.next);
} else if (state.tokens.next.id !== "(string)") {
warning("W095", state.tokens.next, state.tokens.next.value);
}
if (o[state.tokens.next.value] === true) {
warning("W075", state.tokens.next, "key", state.tokens.next.value);
} else if ((state.tokens.next.value === "__proto__" &&
!state.option.proto) || (state.tokens.next.value === "__iterator__" &&
!state.option.iterator)) {
warning("W096", state.tokens.next, state.tokens.next.value);
} else {
o[state.tokens.next.value] = true;
}
advance();
advance(":");
jsonValue();
if (state.tokens.next.id !== ",") {
break;
}
advance(",");
}
}
advance("}");
}
function jsonArray() {
var t = state.tokens.next;
advance("[");
if (state.tokens.next.id !== "]") {
for (;;) {
if (state.tokens.next.id === "(end)") {
error("E027", state.tokens.next, t.line);
} else if (state.tokens.next.id === "]") {
warning("W094", state.tokens.curr);
break;
} else if (state.tokens.next.id === ",") {
error("E028", state.tokens.next);
}
jsonValue();
if (state.tokens.next.id !== ",") {
break;
}
advance(",");
}
}
advance("]");
}
switch (state.tokens.next.id) {
case "{":
jsonObject();
break;
case "[":
jsonArray();
break;
case "true":
case "false":
case "null":
case "(number)":
case "(string)":
advance();
break;
case "-":
advance("-");
advance("(number)");
break;
default:
error("E003", state.tokens.next);
}
}
/**
* Lint dynamically-evaluated code, appending any resulting errors/warnings
* into the global `errors` array.
*
* @param {array} internals - collection of "internals" objects describing
* string tokens that contain evaluated code
* @param {object} options - linting options to apply
* @param {object} globals - globally-defined bindings for the evaluated code
*/
function lintEvalCode(internals, options, globals) {
var priorErrorCount, idx, jdx, internal;
for (idx = 0; idx < internals.length; idx += 1) {
internal = internals[idx];
options.scope = internal.elem;
priorErrorCount = JSHINT.errors.length;
itself(internal.code, options, globals);
for (jdx = priorErrorCount; jdx < JSHINT.errors.length; jdx += 1) {
JSHINT.errors[jdx].line += internal.token.line - 1;
}
}
}
var escapeRegex = function(str) {
return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
};
// The actual JSHINT function itself.
var itself = function(s, o, g) {
var x, reIgnoreStr, reIgnore;
var optionKeys, newOptionObj, newIgnoredObj;
o = _.clone(o);
state.reset();
newOptionObj = state.option;
newIgnoredObj = state.ignored;
if (o && o.scope) {
JSHINT.scope = o.scope;
} else {
JSHINT.errors = [];
JSHINT.internals = [];
JSHINT.blacklist = {};
JSHINT.scope = "(main)";
}
predefined = Object.create(null);
combine(predefined, vars.ecmaIdentifiers[3]);
combine(predefined, vars.reservedVars);
declared = Object.create(null);
var exported = Object.create(null); // Variables that live outside the current file
function each(obj, cb) {
if (!obj)
return;
if (!Array.isArray(obj) && typeof obj === "object")
obj = Object.keys(obj);
obj.forEach(cb);
}
if (o) {
each([o.predef, o.globals], function(dict) {
each(dict, function(item) {
var slice, prop;
if (item[0] === "-") {
slice = item.slice(1);
JSHINT.blacklist[slice] = slice;
// remove from predefined if there
delete predefined[slice];
} else {
prop = Object.getOwnPropertyDescriptor(dict, item);
predefined[item] = prop ? prop.value : false;
}
});
});
each(o.exported || null, function(item) {
exported[item] = true;
});
delete o.predef;
delete o.exported;
optionKeys = Object.keys(o);
for (x = 0; x < optionKeys.length; x++) {
if (/^-W\d{3}$/g.test(optionKeys[x])) {
newIgnoredObj[optionKeys[x].slice(1)] = true;
} else {
var optionKey = optionKeys[x];
newOptionObj[optionKey] = o[optionKey];
}
}
}
state.option = newOptionObj;
state.ignored = newIgnoredObj;
state.option.indent = state.option.indent || 4;
state.option.maxerr = state.option.maxerr || 50;
indent = 1;
var scopeManagerInst = scopeManager(state, predefined, exported, declared);
scopeManagerInst.on("warning", function(ev) {
warning.apply(null, [ ev.code, ev.token].concat(ev.data));
});
scopeManagerInst.on("error", function(ev) {
/* istanbul ignore next */
error.apply(null, [ ev.code, ev.token ].concat(ev.data));
});
state.funct = functor("(global)", null, {
"(global)" : true,
"(scope)" : scopeManagerInst,
"(comparray)" : arrayComprehension(),
"(metrics)" : createMetrics(state.tokens.next)
});
functions = [state.funct];
member = {};
membersOnly = null;
inblock = false;
lookahead = [];
if (!isString(s) && !Array.isArray(s)) {
errorAt("E004", 0);
return false;
}
api = {
get isJSON() {
/* istanbul ignore next */
return state.jsonMode;
},
getOption: function(name) {
return state.option[name] || null;
},
getCache: function(name) {
return state.cache[name];
},
setCache: function(name, value) {
state.cache[name] = value;
},
warn: function(code, data) {
warningAt.apply(null, [ code, data.line, data.char ].concat(data.data));
},
on: function(names, listener) {
names.split(" ").forEach(function(name) {
emitter.on(name, listener);
}.bind(this));
}
};
emitter.removeAllListeners();
(extraModules || []).forEach(function(func) {
func(api);
});
state.tokens.prev = state.tokens.curr = state.tokens.next = state.syntax["(begin)"];
if (o && o.ignoreDelimiters) {
if (!Array.isArray(o.ignoreDelimiters)) {
/* istanbul ignore next */
o.ignoreDelimiters = [o.ignoreDelimiters];
}
o.ignoreDelimiters.forEach(function(delimiterPair) {
if (!delimiterPair.start || !delimiterPair.end)
return;
reIgnoreStr = escapeRegex(delimiterPair.start) +
"[\\s\\S]*?" +
escapeRegex(delimiterPair.end);
reIgnore = new RegExp(reIgnoreStr, "ig");
s = s.replace(reIgnore, function(match) {
return match.replace(/./g, " ");
});
});
}
lex = new Lexer(s);
lex.on("warning", function(ev) {
warningAt.apply(null, [ ev.code, ev.line, ev.character].concat(ev.data));
});
lex.on("error", function(ev) {
errorAt.apply(null, [ ev.code, ev.line, ev.character ].concat(ev.data));
});
lex.on("fatal", function(ev) {
quit("E041", ev);
});
lex.on("Identifier", function(ev) {
emitter.emit("Identifier", ev);
});
lex.on("String", function(ev) {
emitter.emit("String", ev);
});
lex.on("Number", function(ev) {
emitter.emit("Number", ev);
});
// Check options
var name;
for (name in o) {
if (_.has(o, name)) {
checkOption(name, true, state.tokens.curr);
}
}
if (o) {
for (name in o.unstable) {
if (_.has(o.unstable, name)) {
checkOption(name, false, state.tokens.curr);
}
}
}
try {
applyOptions();
// combine the passed globals after we've assumed all our options
combine(predefined, g || {});
//reset values
checkComma.first = true;
advance();
switch (state.tokens.next.id) {
case "{":
case "[":
destructuringAssignOrJsonValue(0);
break;
default:
directives();
if (state.directive["use strict"]) {
if (!state.allowsGlobalUsd()) {
warning("W097", state.tokens.prev);
}
}
statements(0);
}
if (state.tokens.next.id !== "(end)") {
quit("E041", state.tokens.curr);
}
state.funct["(scope)"].unstack();
} catch (err) {
if (err && err.name === "JSHintError") {
var nt = state.tokens.next || {};
JSHINT.errors.push({
scope : "(main)",
raw : err.raw,
code : err.code,
reason : err.reason,
line : err.line || nt.line,
character : err.character || nt.from
});
} else {
/* istanbul ignore next */
throw err;
}
}
// Loop over the listed "internals", and check them as well.
if (JSHINT.scope === "(main)") {
lintEvalCode(JSHINT.internals, o || {}, g);
}
return JSHINT.errors.length === 0;
};
// Modules.
itself.addModule = function(func) {
extraModules.push(func);
};
itself.addModule(style.register);
// Data summary.
itself.data = function() {
var data = {
functions: [],
options: state.option
};
var fu, f, i, n, globals;
if (itself.errors.length) {
data.errors = itself.errors;
}
if (state.jsonMode) {
/* istanbul ignore next */
data.json = true;
}
var impliedGlobals = state.funct["(scope)"].getImpliedGlobals();
if (impliedGlobals.length > 0) {
data.implieds = impliedGlobals;
}
globals = state.funct["(scope)"].getUsedOrDefinedGlobals();
if (globals.length > 0) {
data.globals = globals;
}
for (i = 1; i < functions.length; i += 1) {
f = functions[i];
fu = {};
fu.name = f["(name)"];
fu.param = f["(params)"];
fu.line = f["(line)"];
fu.character = f["(character)"];
fu.last = f["(last)"];
fu.lastcharacter = f["(lastcharacter)"];
fu.metrics = {
complexity: f["(metrics)"].ComplexityCount,
parameters: f["(metrics)"].arity,
statements: f["(metrics)"].statementCount
};
data.functions.push(fu);
}
var unuseds = state.funct["(scope)"].getUnuseds();
if (unuseds.length > 0) {
data.unused = unuseds;
}
for (n in member) {
if (typeof member[n] === "number") {
data.member = member;
break;
}
}
return data;
};
itself.jshint = itself;
return itself;
}());
// Make JSHINT a Node module, if possible.
if (typeof exports === "object" && exports) {
exports.JSHINT = JSHINT;
}
},{"./lex.js":17,"./messages.js":18,"./options.js":20,"./prod-params.js":21,"./reg.js":22,"./scope-manager.js":23,"./state.js":24,"./style.js":25,"./vars.js":26,"console-browserify":14,"events":9,"lodash":16}]},{},[]);
JSHINT = require('jshint').JSHINT;
if (typeof exports === 'object' && exports) exports.JSHINT = JSHINT;
}());