index.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993
  1. // Load modules
  2. var Crypto = require('crypto');
  3. var Path = require('path');
  4. var Util = require('util');
  5. var Escape = require('./escape');
  6. // Declare internals
  7. var internals = {};
  8. // Clone object or array
  9. exports.clone = function (obj, seen) {
  10. if (typeof obj !== 'object' ||
  11. obj === null) {
  12. return obj;
  13. }
  14. seen = seen || { orig: [], copy: [] };
  15. var lookup = seen.orig.indexOf(obj);
  16. if (lookup !== -1) {
  17. return seen.copy[lookup];
  18. }
  19. var newObj;
  20. var cloneDeep = false;
  21. if (!Array.isArray(obj)) {
  22. if (Buffer.isBuffer(obj)) {
  23. newObj = new Buffer(obj);
  24. }
  25. else if (obj instanceof Date) {
  26. newObj = new Date(obj.getTime());
  27. }
  28. else if (obj instanceof RegExp) {
  29. newObj = new RegExp(obj);
  30. }
  31. else {
  32. var proto = Object.getPrototypeOf(obj);
  33. if (proto &&
  34. proto.isImmutable) {
  35. newObj = obj;
  36. }
  37. else {
  38. newObj = Object.create(proto);
  39. cloneDeep = true;
  40. }
  41. }
  42. }
  43. else {
  44. newObj = [];
  45. cloneDeep = true;
  46. }
  47. seen.orig.push(obj);
  48. seen.copy.push(newObj);
  49. if (cloneDeep) {
  50. var keys = Object.getOwnPropertyNames(obj);
  51. for (var i = 0, il = keys.length; i < il; ++i) {
  52. var key = keys[i];
  53. var descriptor = Object.getOwnPropertyDescriptor(obj, key);
  54. if (descriptor &&
  55. (descriptor.get ||
  56. descriptor.set)) {
  57. Object.defineProperty(newObj, key, descriptor);
  58. }
  59. else {
  60. newObj[key] = exports.clone(obj[key], seen);
  61. }
  62. }
  63. }
  64. return newObj;
  65. };
  66. // Merge all the properties of source into target, source wins in conflict, and by default null and undefined from source are applied
  67. /*eslint-disable */
  68. exports.merge = function (target, source, isNullOverride /* = true */, isMergeArrays /* = true */) {
  69. /*eslint-enable */
  70. exports.assert(target && typeof target === 'object', 'Invalid target value: must be an object');
  71. exports.assert(source === null || source === undefined || typeof source === 'object', 'Invalid source value: must be null, undefined, or an object');
  72. if (!source) {
  73. return target;
  74. }
  75. if (Array.isArray(source)) {
  76. exports.assert(Array.isArray(target), 'Cannot merge array onto an object');
  77. if (isMergeArrays === false) { // isMergeArrays defaults to true
  78. target.length = 0; // Must not change target assignment
  79. }
  80. for (var i = 0, il = source.length; i < il; ++i) {
  81. target.push(exports.clone(source[i]));
  82. }
  83. return target;
  84. }
  85. var keys = Object.keys(source);
  86. for (var k = 0, kl = keys.length; k < kl; ++k) {
  87. var key = keys[k];
  88. var value = source[key];
  89. if (value &&
  90. typeof value === 'object') {
  91. if (!target[key] ||
  92. typeof target[key] !== 'object' ||
  93. (Array.isArray(target[key]) ^ Array.isArray(value)) ||
  94. value instanceof Date ||
  95. Buffer.isBuffer(value) ||
  96. value instanceof RegExp) {
  97. target[key] = exports.clone(value);
  98. }
  99. else {
  100. exports.merge(target[key], value, isNullOverride, isMergeArrays);
  101. }
  102. }
  103. else {
  104. if (value !== null &&
  105. value !== undefined) { // Explicit to preserve empty strings
  106. target[key] = value;
  107. }
  108. else if (isNullOverride !== false) { // Defaults to true
  109. target[key] = value;
  110. }
  111. }
  112. }
  113. return target;
  114. };
  115. // Apply options to a copy of the defaults
  116. exports.applyToDefaults = function (defaults, options, isNullOverride) {
  117. exports.assert(defaults && typeof defaults === 'object', 'Invalid defaults value: must be an object');
  118. exports.assert(!options || options === true || typeof options === 'object', 'Invalid options value: must be true, falsy or an object');
  119. if (!options) { // If no options, return null
  120. return null;
  121. }
  122. var copy = exports.clone(defaults);
  123. if (options === true) { // If options is set to true, use defaults
  124. return copy;
  125. }
  126. return exports.merge(copy, options, isNullOverride === true, false);
  127. };
  128. // Clone an object except for the listed keys which are shallow copied
  129. exports.cloneWithShallow = function (source, keys) {
  130. if (!source ||
  131. typeof source !== 'object') {
  132. return source;
  133. }
  134. var storage = internals.store(source, keys); // Move shallow copy items to storage
  135. var copy = exports.clone(source); // Deep copy the rest
  136. internals.restore(copy, source, storage); // Shallow copy the stored items and restore
  137. return copy;
  138. };
  139. internals.store = function (source, keys) {
  140. var storage = {};
  141. for (var i = 0, il = keys.length; i < il; ++i) {
  142. var key = keys[i];
  143. var value = exports.reach(source, key);
  144. if (value !== undefined) {
  145. storage[key] = value;
  146. internals.reachSet(source, key, undefined);
  147. }
  148. }
  149. return storage;
  150. };
  151. internals.restore = function (copy, source, storage) {
  152. var keys = Object.keys(storage);
  153. for (var i = 0, il = keys.length; i < il; ++i) {
  154. var key = keys[i];
  155. internals.reachSet(copy, key, storage[key]);
  156. internals.reachSet(source, key, storage[key]);
  157. }
  158. };
  159. internals.reachSet = function (obj, key, value) {
  160. var path = key.split('.');
  161. var ref = obj;
  162. for (var i = 0, il = path.length; i < il; ++i) {
  163. var segment = path[i];
  164. if (i + 1 === il) {
  165. ref[segment] = value;
  166. }
  167. ref = ref[segment];
  168. }
  169. };
  170. // Apply options to defaults except for the listed keys which are shallow copied from option without merging
  171. exports.applyToDefaultsWithShallow = function (defaults, options, keys) {
  172. exports.assert(defaults && typeof defaults === 'object', 'Invalid defaults value: must be an object');
  173. exports.assert(!options || options === true || typeof options === 'object', 'Invalid options value: must be true, falsy or an object');
  174. exports.assert(keys && Array.isArray(keys), 'Invalid keys');
  175. if (!options) { // If no options, return null
  176. return null;
  177. }
  178. var copy = exports.cloneWithShallow(defaults, keys);
  179. if (options === true) { // If options is set to true, use defaults
  180. return copy;
  181. }
  182. var storage = internals.store(options, keys); // Move shallow copy items to storage
  183. exports.merge(copy, options, false, false); // Deep copy the rest
  184. internals.restore(copy, options, storage); // Shallow copy the stored items and restore
  185. return copy;
  186. };
  187. // Deep object or array comparison
  188. exports.deepEqual = function (obj, ref, options, seen) {
  189. options = options || { prototype: true };
  190. var type = typeof obj;
  191. if (type !== typeof ref) {
  192. return false;
  193. }
  194. if (type !== 'object' ||
  195. obj === null ||
  196. ref === null) {
  197. if (obj === ref) { // Copied from Deep-eql, copyright(c) 2013 Jake Luer, jake@alogicalparadox.com, MIT Licensed, https://github.com/chaijs/deep-eql
  198. return obj !== 0 || 1 / obj === 1 / ref; // -0 / +0
  199. }
  200. return obj !== obj && ref !== ref; // NaN
  201. }
  202. seen = seen || [];
  203. if (seen.indexOf(obj) !== -1) {
  204. return true; // If previous comparison failed, it would have stopped execution
  205. }
  206. seen.push(obj);
  207. if (Array.isArray(obj)) {
  208. if (!Array.isArray(ref)) {
  209. return false;
  210. }
  211. if (!options.part && obj.length !== ref.length) {
  212. return false;
  213. }
  214. for (var i = 0, il = obj.length; i < il; ++i) {
  215. if (options.part) {
  216. var found = false;
  217. for (var r = 0, rl = ref.length; r < rl; ++r) {
  218. if (exports.deepEqual(obj[i], ref[r], options, seen)) {
  219. found = true;
  220. break;
  221. }
  222. }
  223. return found;
  224. }
  225. if (!exports.deepEqual(obj[i], ref[i], options, seen)) {
  226. return false;
  227. }
  228. }
  229. return true;
  230. }
  231. if (Buffer.isBuffer(obj)) {
  232. if (!Buffer.isBuffer(ref)) {
  233. return false;
  234. }
  235. if (obj.length !== ref.length) {
  236. return false;
  237. }
  238. for (var j = 0, jl = obj.length; j < jl; ++j) {
  239. if (obj[j] !== ref[j]) {
  240. return false;
  241. }
  242. }
  243. return true;
  244. }
  245. if (obj instanceof Date) {
  246. return (ref instanceof Date && obj.getTime() === ref.getTime());
  247. }
  248. if (obj instanceof RegExp) {
  249. return (ref instanceof RegExp && obj.toString() === ref.toString());
  250. }
  251. if (options.prototype) {
  252. if (Object.getPrototypeOf(obj) !== Object.getPrototypeOf(ref)) {
  253. return false;
  254. }
  255. }
  256. var keys = Object.getOwnPropertyNames(obj);
  257. if (!options.part && keys.length !== Object.getOwnPropertyNames(ref).length) {
  258. return false;
  259. }
  260. for (var k = 0, kl = keys.length; k < kl; ++k) {
  261. var key = keys[k];
  262. var descriptor = Object.getOwnPropertyDescriptor(obj, key);
  263. if (descriptor.get) {
  264. if (!exports.deepEqual(descriptor, Object.getOwnPropertyDescriptor(ref, key), options, seen)) {
  265. return false;
  266. }
  267. }
  268. else if (!exports.deepEqual(obj[key], ref[key], options, seen)) {
  269. return false;
  270. }
  271. }
  272. return true;
  273. };
  274. // Remove duplicate items from array
  275. exports.unique = function (array, key) {
  276. var index = {};
  277. var result = [];
  278. for (var i = 0, il = array.length; i < il; ++i) {
  279. var id = (key ? array[i][key] : array[i]);
  280. if (index[id] !== true) {
  281. result.push(array[i]);
  282. index[id] = true;
  283. }
  284. }
  285. return result;
  286. };
  287. // Convert array into object
  288. exports.mapToObject = function (array, key) {
  289. if (!array) {
  290. return null;
  291. }
  292. var obj = {};
  293. for (var i = 0, il = array.length; i < il; ++i) {
  294. if (key) {
  295. if (array[i][key]) {
  296. obj[array[i][key]] = true;
  297. }
  298. }
  299. else {
  300. obj[array[i]] = true;
  301. }
  302. }
  303. return obj;
  304. };
  305. // Find the common unique items in two arrays
  306. exports.intersect = function (array1, array2, justFirst) {
  307. if (!array1 || !array2) {
  308. return [];
  309. }
  310. var common = [];
  311. var hash = (Array.isArray(array1) ? exports.mapToObject(array1) : array1);
  312. var found = {};
  313. for (var i = 0, il = array2.length; i < il; ++i) {
  314. if (hash[array2[i]] && !found[array2[i]]) {
  315. if (justFirst) {
  316. return array2[i];
  317. }
  318. common.push(array2[i]);
  319. found[array2[i]] = true;
  320. }
  321. }
  322. return (justFirst ? null : common);
  323. };
  324. // Test if the reference contains the values
  325. exports.contain = function (ref, values, options) {
  326. /*
  327. string -> string(s)
  328. array -> item(s)
  329. object -> key(s)
  330. object -> object (key:value)
  331. */
  332. var valuePairs = null;
  333. if (typeof ref === 'object' &&
  334. typeof values === 'object' &&
  335. !Array.isArray(ref) &&
  336. !Array.isArray(values)) {
  337. valuePairs = values;
  338. values = Object.keys(values);
  339. }
  340. else {
  341. values = [].concat(values);
  342. }
  343. options = options || {}; // deep, once, only, part
  344. exports.assert(arguments.length >= 2, 'Insufficient arguments');
  345. exports.assert(typeof ref === 'string' || typeof ref === 'object', 'Reference must be string or an object');
  346. exports.assert(values.length, 'Values array cannot be empty');
  347. var compare, compareFlags;
  348. if (options.deep) {
  349. compare = exports.deepEqual;
  350. var hasOnly = options.hasOwnProperty('only'), hasPart = options.hasOwnProperty('part');
  351. compareFlags = {
  352. prototype: hasOnly ? options.only : hasPart ? !options.part : false,
  353. part: hasOnly ? !options.only : hasPart ? options.part : true
  354. };
  355. }
  356. else {
  357. compare = function (a, b) {
  358. return a === b;
  359. };
  360. }
  361. var misses = false;
  362. var matches = new Array(values.length);
  363. for (var i = 0, il = matches.length; i < il; ++i) {
  364. matches[i] = 0;
  365. }
  366. if (typeof ref === 'string') {
  367. var pattern = '(';
  368. for (i = 0, il = values.length; i < il; ++i) {
  369. var value = values[i];
  370. exports.assert(typeof value === 'string', 'Cannot compare string reference to non-string value');
  371. pattern += (i ? '|' : '') + exports.escapeRegex(value);
  372. }
  373. var regex = new RegExp(pattern + ')', 'g');
  374. var leftovers = ref.replace(regex, function ($0, $1) {
  375. var index = values.indexOf($1);
  376. ++matches[index];
  377. return ''; // Remove from string
  378. });
  379. misses = !!leftovers;
  380. }
  381. else if (Array.isArray(ref)) {
  382. for (i = 0, il = ref.length; i < il; ++i) {
  383. for (var j = 0, jl = values.length, matched = false; j < jl && matched === false; ++j) {
  384. matched = compare(values[j], ref[i], compareFlags) && j;
  385. }
  386. if (matched !== false) {
  387. ++matches[matched];
  388. }
  389. else {
  390. misses = true;
  391. }
  392. }
  393. }
  394. else {
  395. var keys = Object.keys(ref);
  396. for (i = 0, il = keys.length; i < il; ++i) {
  397. var key = keys[i];
  398. var pos = values.indexOf(key);
  399. if (pos !== -1) {
  400. if (valuePairs &&
  401. !compare(valuePairs[key], ref[key], compareFlags)) {
  402. return false;
  403. }
  404. ++matches[pos];
  405. }
  406. else {
  407. misses = true;
  408. }
  409. }
  410. }
  411. var result = false;
  412. for (i = 0, il = matches.length; i < il; ++i) {
  413. result = result || !!matches[i];
  414. if ((options.once && matches[i] > 1) ||
  415. (!options.part && !matches[i])) {
  416. return false;
  417. }
  418. }
  419. if (options.only &&
  420. misses) {
  421. return false;
  422. }
  423. return result;
  424. };
  425. // Flatten array
  426. exports.flatten = function (array, target) {
  427. var result = target || [];
  428. for (var i = 0, il = array.length; i < il; ++i) {
  429. if (Array.isArray(array[i])) {
  430. exports.flatten(array[i], result);
  431. }
  432. else {
  433. result.push(array[i]);
  434. }
  435. }
  436. return result;
  437. };
  438. // Convert an object key chain string ('a.b.c') to reference (object[a][b][c])
  439. exports.reach = function (obj, chain, options) {
  440. if (chain === false ||
  441. chain === null ||
  442. typeof chain === 'undefined') {
  443. return obj;
  444. }
  445. options = options || {};
  446. if (typeof options === 'string') {
  447. options = { separator: options };
  448. }
  449. var path = chain.split(options.separator || '.');
  450. var ref = obj;
  451. for (var i = 0, il = path.length; i < il; ++i) {
  452. var key = path[i];
  453. if (key[0] === '-' && Array.isArray(ref)) {
  454. key = key.slice(1, key.length);
  455. key = ref.length - key;
  456. }
  457. if (!ref ||
  458. !ref.hasOwnProperty(key) ||
  459. (typeof ref !== 'object' && options.functions === false)) { // Only object and function can have properties
  460. exports.assert(!options.strict || i + 1 === il, 'Missing segment', key, 'in reach path ', chain);
  461. exports.assert(typeof ref === 'object' || options.functions === true || typeof ref !== 'function', 'Invalid segment', key, 'in reach path ', chain);
  462. ref = options.default;
  463. break;
  464. }
  465. ref = ref[key];
  466. }
  467. return ref;
  468. };
  469. exports.reachTemplate = function (obj, template, options) {
  470. return template.replace(/{([^}]+)}/g, function ($0, chain) {
  471. var value = exports.reach(obj, chain, options);
  472. return (value === undefined || value === null ? '' : value);
  473. });
  474. };
  475. exports.formatStack = function (stack) {
  476. var trace = [];
  477. for (var i = 0, il = stack.length; i < il; ++i) {
  478. var item = stack[i];
  479. trace.push([item.getFileName(), item.getLineNumber(), item.getColumnNumber(), item.getFunctionName(), item.isConstructor()]);
  480. }
  481. return trace;
  482. };
  483. exports.formatTrace = function (trace) {
  484. var display = [];
  485. for (var i = 0, il = trace.length; i < il; ++i) {
  486. var row = trace[i];
  487. display.push((row[4] ? 'new ' : '') + row[3] + ' (' + row[0] + ':' + row[1] + ':' + row[2] + ')');
  488. }
  489. return display;
  490. };
  491. exports.callStack = function (slice) {
  492. // http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
  493. var v8 = Error.prepareStackTrace;
  494. Error.prepareStackTrace = function (err, stack) {
  495. return stack;
  496. };
  497. var capture = {};
  498. Error.captureStackTrace(capture, arguments.callee); /*eslint no-caller:0 */
  499. var stack = capture.stack;
  500. Error.prepareStackTrace = v8;
  501. var trace = exports.formatStack(stack);
  502. if (slice) {
  503. return trace.slice(slice);
  504. }
  505. return trace;
  506. };
  507. exports.displayStack = function (slice) {
  508. var trace = exports.callStack(slice === undefined ? 1 : slice + 1);
  509. return exports.formatTrace(trace);
  510. };
  511. exports.abortThrow = false;
  512. exports.abort = function (message, hideStack) {
  513. if (process.env.NODE_ENV === 'test' || exports.abortThrow === true) {
  514. throw new Error(message || 'Unknown error');
  515. }
  516. var stack = '';
  517. if (!hideStack) {
  518. stack = exports.displayStack(1).join('\n\t');
  519. }
  520. console.log('ABORT: ' + message + '\n\t' + stack);
  521. process.exit(1);
  522. };
  523. exports.assert = function (condition /*, msg1, msg2, msg3 */) {
  524. if (condition) {
  525. return;
  526. }
  527. if (arguments.length === 2 && arguments[1] instanceof Error) {
  528. throw arguments[1];
  529. }
  530. var msgs = [];
  531. for (var i = 1, il = arguments.length; i < il; ++i) {
  532. if (arguments[i] !== '') {
  533. msgs.push(arguments[i]); // Avoids Array.slice arguments leak, allowing for V8 optimizations
  534. }
  535. }
  536. msgs = msgs.map(function (msg) {
  537. return typeof msg === 'string' ? msg : msg instanceof Error ? msg.message : exports.stringify(msg);
  538. });
  539. throw new Error(msgs.join(' ') || 'Unknown error');
  540. };
  541. exports.Timer = function () {
  542. this.ts = 0;
  543. this.reset();
  544. };
  545. exports.Timer.prototype.reset = function () {
  546. this.ts = Date.now();
  547. };
  548. exports.Timer.prototype.elapsed = function () {
  549. return Date.now() - this.ts;
  550. };
  551. exports.Bench = function () {
  552. this.ts = 0;
  553. this.reset();
  554. };
  555. exports.Bench.prototype.reset = function () {
  556. this.ts = exports.Bench.now();
  557. };
  558. exports.Bench.prototype.elapsed = function () {
  559. return exports.Bench.now() - this.ts;
  560. };
  561. exports.Bench.now = function () {
  562. var ts = process.hrtime();
  563. return (ts[0] * 1e3) + (ts[1] / 1e6);
  564. };
  565. // Escape string for Regex construction
  566. exports.escapeRegex = function (string) {
  567. // Escape ^$.*+-?=!:|\/()[]{},
  568. return string.replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g, '\\$&');
  569. };
  570. // Base64url (RFC 4648) encode
  571. exports.base64urlEncode = function (value, encoding) {
  572. var buf = (Buffer.isBuffer(value) ? value : new Buffer(value, encoding || 'binary'));
  573. return buf.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '');
  574. };
  575. // Base64url (RFC 4648) decode
  576. exports.base64urlDecode = function (value, encoding) {
  577. if (value &&
  578. !/^[\w\-]*$/.test(value)) {
  579. return new Error('Invalid character');
  580. }
  581. try {
  582. var buf = new Buffer(value, 'base64');
  583. return (encoding === 'buffer' ? buf : buf.toString(encoding || 'binary'));
  584. }
  585. catch (err) {
  586. return err;
  587. }
  588. };
  589. // Escape attribute value for use in HTTP header
  590. exports.escapeHeaderAttribute = function (attribute) {
  591. // Allowed value characters: !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9, \, "
  592. exports.assert(/^[ \w\!#\$%&'\(\)\*\+,\-\.\/\:;<\=>\?@\[\]\^`\{\|\}~\"\\]*$/.test(attribute), 'Bad attribute value (' + attribute + ')');
  593. return attribute.replace(/\\/g, '\\\\').replace(/\"/g, '\\"'); // Escape quotes and slash
  594. };
  595. exports.escapeHtml = function (string) {
  596. return Escape.escapeHtml(string);
  597. };
  598. exports.escapeJavaScript = function (string) {
  599. return Escape.escapeJavaScript(string);
  600. };
  601. exports.nextTick = function (callback) {
  602. return function () {
  603. var args = arguments;
  604. process.nextTick(function () {
  605. callback.apply(null, args);
  606. });
  607. };
  608. };
  609. exports.once = function (method) {
  610. if (method._hoekOnce) {
  611. return method;
  612. }
  613. var once = false;
  614. var wrapped = function () {
  615. if (!once) {
  616. once = true;
  617. method.apply(null, arguments);
  618. }
  619. };
  620. wrapped._hoekOnce = true;
  621. return wrapped;
  622. };
  623. exports.isAbsolutePath = function (path, platform) {
  624. if (!path) {
  625. return false;
  626. }
  627. if (Path.isAbsolute) { // node >= 0.11
  628. return Path.isAbsolute(path);
  629. }
  630. platform = platform || process.platform;
  631. // Unix
  632. if (platform !== 'win32') {
  633. return path[0] === '/';
  634. }
  635. // Windows
  636. return !!/^(?:[a-zA-Z]:[\\\/])|(?:[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/])/.test(path); // C:\ or \\something\something
  637. };
  638. exports.isInteger = function (value) {
  639. return (typeof value === 'number' &&
  640. parseFloat(value) === parseInt(value, 10) &&
  641. !isNaN(value));
  642. };
  643. exports.ignore = function () { };
  644. exports.inherits = Util.inherits;
  645. exports.format = Util.format;
  646. exports.transform = function (source, transform, options) {
  647. exports.assert(source === null || source === undefined || typeof source === 'object' || Array.isArray(source), 'Invalid source object: must be null, undefined, an object, or an array');
  648. if (Array.isArray(source)) {
  649. var results = [];
  650. for (var i = 0, il = source.length; i < il; ++i) {
  651. results.push(exports.transform(source[i], transform, options));
  652. }
  653. return results;
  654. }
  655. var result = {};
  656. var keys = Object.keys(transform);
  657. for (var k = 0, kl = keys.length; k < kl; ++k) {
  658. var key = keys[k];
  659. var path = key.split('.');
  660. var sourcePath = transform[key];
  661. exports.assert(typeof sourcePath === 'string', 'All mappings must be "." delineated strings');
  662. var segment;
  663. var res = result;
  664. while (path.length > 1) {
  665. segment = path.shift();
  666. if (!res[segment]) {
  667. res[segment] = {};
  668. }
  669. res = res[segment];
  670. }
  671. segment = path.shift();
  672. res[segment] = exports.reach(source, sourcePath, options);
  673. }
  674. return result;
  675. };
  676. exports.uniqueFilename = function (path, extension) {
  677. if (extension) {
  678. extension = extension[0] !== '.' ? '.' + extension : extension;
  679. }
  680. else {
  681. extension = '';
  682. }
  683. path = Path.resolve(path);
  684. var name = [Date.now(), process.pid, Crypto.randomBytes(8).toString('hex')].join('-') + extension;
  685. return Path.join(path, name);
  686. };
  687. exports.stringify = function () {
  688. try {
  689. return JSON.stringify.apply(null, arguments);
  690. }
  691. catch (err) {
  692. return '[Cannot display object: ' + err.message + ']';
  693. }
  694. };
  695. exports.shallow = function (source) {
  696. var target = {};
  697. var keys = Object.keys(source);
  698. for (var i = 0, il = keys.length; i < il; ++i) {
  699. var key = keys[i];
  700. target[key] = source[key];
  701. }
  702. return target;
  703. };