The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / lib / path.js @ 20229d68

History | View | Annotate | Download (14.7 KB)

1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21

    
22

    
23
var isWindows = process.platform === 'win32';
24
var util = require('util');
25

    
26

    
27
// resolves . and .. elements in a path array with directory names there
28
// must be no slashes, empty elements, or device names (c:\) in the array
29
// (so also no leading and trailing slashes - it does not distinguish
30
// relative and absolute paths)
31
function normalizeArray(parts, allowAboveRoot) {
32
  // if the path tries to go above the root, `up` ends up > 0
33
  var up = 0;
34
  for (var i = parts.length - 1; i >= 0; i--) {
35
    var last = parts[i];
36
    if (last === '.') {
37
      parts.splice(i, 1);
38
    } else if (last === '..') {
39
      parts.splice(i, 1);
40
      up++;
41
    } else if (up) {
42
      parts.splice(i, 1);
43
      up--;
44
    }
45
  }
46

    
47
  // if the path is allowed to go above the root, restore leading ..s
48
  if (allowAboveRoot) {
49
    for (; up--; up) {
50
      parts.unshift('..');
51
    }
52
  }
53

    
54
  return parts;
55
}
56

    
57

    
58
if (isWindows) {
59
  // Regex to split a windows path into three parts: [*, device, slash,
60
  // tail] windows-only
61
  var splitDeviceRe =
62
      /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/;
63

    
64
  // Regex to split the tail part of the above into [*, dir, basename, ext]
65
  var splitTailRe =
66
      /^([\s\S]*?)((?:\.{1,2}|[^\\\/]+?|)(\.[^.\/\\]*|))(?:[\\\/]*)$/;
67

    
68
  // Function to split a filename into [root, dir, basename, ext]
69
  // windows version
70
  var splitPath = function(filename) {
71
    // Separate device+slash from tail
72
    var result = splitDeviceRe.exec(filename),
73
        device = (result[1] || '') + (result[2] || ''),
74
        tail = result[3] || '';
75
    // Split the tail into dir, basename and extension
76
    var result2 = splitTailRe.exec(tail),
77
        dir = result2[1],
78
        basename = result2[2],
79
        ext = result2[3];
80
    return [device, dir, basename, ext];
81
  };
82

    
83
  var normalizeUNCRoot = function(device) {
84
    return '\\\\' + device.replace(/^[\\\/]+/, '').replace(/[\\\/]+/g, '\\');
85
  };
86

    
87
  // path.resolve([from ...], to)
88
  // windows version
89
  exports.resolve = function() {
90
    var resolvedDevice = '',
91
        resolvedTail = '',
92
        resolvedAbsolute = false;
93

    
94
    for (var i = arguments.length - 1; i >= -1; i--) {
95
      var path;
96
      if (i >= 0) {
97
        path = arguments[i];
98
      } else if (!resolvedDevice) {
99
        path = process.cwd();
100
      } else {
101
        // Windows has the concept of drive-specific current working
102
        // directories. If we've resolved a drive letter but not yet an
103
        // absolute path, get cwd for that drive. We're sure the device is not
104
        // an unc path at this points, because unc paths are always absolute.
105
        path = process.env['=' + resolvedDevice];
106
        // Verify that a drive-local cwd was found and that it actually points
107
        // to our drive. If not, default to the drive's root.
108
        if (!path || path.substr(0, 3).toLowerCase() !==
109
            resolvedDevice.toLowerCase() + '\\') {
110
          path = resolvedDevice + '\\';
111
        }
112
      }
113

    
114
      // Skip empty and invalid entries
115
      if (!util.isString(path)) {
116
        throw new TypeError('Arguments to path.resolve must be strings');
117
      } else if (!path) {
118
        continue;
119
      }
120

    
121
      var result = splitDeviceRe.exec(path),
122
          device = result[1] || '',
123
          isUnc = device && device.charAt(1) !== ':',
124
          isAbsolute = exports.isAbsolute(path),
125
          tail = result[3];
126

    
127
      if (device &&
128
          resolvedDevice &&
129
          device.toLowerCase() !== resolvedDevice.toLowerCase()) {
130
        // This path points to another device so it is not applicable
131
        continue;
132
      }
133

    
134
      if (!resolvedDevice) {
135
        resolvedDevice = device;
136
      }
137
      if (!resolvedAbsolute) {
138
        resolvedTail = tail + '\\' + resolvedTail;
139
        resolvedAbsolute = isAbsolute;
140
      }
141

    
142
      if (resolvedDevice && resolvedAbsolute) {
143
        break;
144
      }
145
    }
146

    
147
    // Convert slashes to backslashes when `resolvedDevice` points to an UNC
148
    // root. Also squash multiple slashes into a single one where appropriate.
149
    if (isUnc) {
150
      resolvedDevice = normalizeUNCRoot(resolvedDevice);
151
    }
152

    
153
    // At this point the path should be resolved to a full absolute path,
154
    // but handle relative paths to be safe (might happen when process.cwd()
155
    // fails)
156

    
157
    // Normalize the tail path
158

    
159
    function f(p) {
160
      return !!p;
161
    }
162

    
163
    resolvedTail = normalizeArray(resolvedTail.split(/[\\\/]+/).filter(f),
164
                                  !resolvedAbsolute).join('\\');
165

    
166
    return (resolvedDevice + (resolvedAbsolute ? '\\' : '') + resolvedTail) ||
167
           '.';
168
  };
169

    
170
  // windows version
171
  exports.normalize = function(path) {
172
    var result = splitDeviceRe.exec(path),
173
        device = result[1] || '',
174
        isUnc = device && device.charAt(1) !== ':',
175
        isAbsolute = exports.isAbsolute(path),
176
        tail = result[3],
177
        trailingSlash = /[\\\/]$/.test(tail);
178

    
179
    // If device is a drive letter, we'll normalize to lower case.
180
    if (device && device.charAt(1) === ':') {
181
      device = device[0].toLowerCase() + device.substr(1);
182
    }
183

    
184
    // Normalize the tail path
185
    tail = normalizeArray(tail.split(/[\\\/]+/).filter(function(p) {
186
      return !!p;
187
    }), !isAbsolute).join('\\');
188

    
189
    if (!tail && !isAbsolute) {
190
      tail = '.';
191
    }
192
    if (tail && trailingSlash) {
193
      tail += '\\';
194
    }
195

    
196
    // Convert slashes to backslashes when `device` points to an UNC root.
197
    // Also squash multiple slashes into a single one where appropriate.
198
    if (isUnc) {
199
      device = normalizeUNCRoot(device);
200
    }
201

    
202
    return device + (isAbsolute ? '\\' : '') + tail;
203
  };
204

    
205
  // windows version
206
  exports.isAbsolute = function(path) {
207
    var result = splitDeviceRe.exec(path),
208
        device = result[1] || '',
209
        isUnc = !!device && device.charAt(1) !== ':';
210
    // UNC paths are always absolute
211
    return !!result[2] || isUnc;
212
  };
213

    
214
  // windows version
215
  exports.join = function() {
216
    function f(p) {
217
      if (!util.isString(p)) {
218
        throw new TypeError('Arguments to path.join must be strings');
219
      }
220
      return p;
221
    }
222

    
223
    var paths = Array.prototype.filter.call(arguments, f);
224
    var joined = paths.join('\\');
225

    
226
    // Make sure that the joined path doesn't start with two slashes, because
227
    // normalize() will mistake it for an UNC path then.
228
    //
229
    // This step is skipped when it is very clear that the user actually
230
    // intended to point at an UNC path. This is assumed when the first
231
    // non-empty string arguments starts with exactly two slashes followed by
232
    // at least one more non-slash character.
233
    //
234
    // Note that for normalize() to treat a path as an UNC path it needs to
235
    // have at least 2 components, so we don't filter for that here.
236
    // This means that the user can use join to construct UNC paths from
237
    // a server name and a share name; for example:
238
    //   path.join('//server', 'share') -> '\\\\server\\share\')
239
    if (!/^[\\\/]{2}[^\\\/]/.test(paths[0])) {
240
      joined = joined.replace(/^[\\\/]{2,}/, '\\');
241
    }
242

    
243
    return exports.normalize(joined);
244
  };
245

    
246
  // path.relative(from, to)
247
  // it will solve the relative path from 'from' to 'to', for instance:
248
  // from = 'C:\\orandea\\test\\aaa'
249
  // to = 'C:\\orandea\\impl\\bbb'
250
  // The output of the function should be: '..\\..\\impl\\bbb'
251
  // windows version
252
  exports.relative = function(from, to) {
253
    from = exports.resolve(from);
254
    to = exports.resolve(to);
255

    
256
    // windows is not case sensitive
257
    var lowerFrom = from.toLowerCase();
258
    var lowerTo = to.toLowerCase();
259

    
260
    function trim(arr) {
261
      var start = 0;
262
      for (; start < arr.length; start++) {
263
        if (arr[start] !== '') break;
264
      }
265

    
266
      var end = arr.length - 1;
267
      for (; end >= 0; end--) {
268
        if (arr[end] !== '') break;
269
      }
270

    
271
      if (start > end) return [];
272
      return arr.slice(start, end + 1);
273
    }
274

    
275
    var toParts = trim(to.split('\\'));
276

    
277
    var lowerFromParts = trim(lowerFrom.split('\\'));
278
    var lowerToParts = trim(lowerTo.split('\\'));
279

    
280
    var length = Math.min(lowerFromParts.length, lowerToParts.length);
281
    var samePartsLength = length;
282
    for (var i = 0; i < length; i++) {
283
      if (lowerFromParts[i] !== lowerToParts[i]) {
284
        samePartsLength = i;
285
        break;
286
      }
287
    }
288

    
289
    if (samePartsLength == 0) {
290
      return to;
291
    }
292

    
293
    var outputParts = [];
294
    for (var i = samePartsLength; i < lowerFromParts.length; i++) {
295
      outputParts.push('..');
296
    }
297

    
298
    outputParts = outputParts.concat(toParts.slice(samePartsLength));
299

    
300
    return outputParts.join('\\');
301
  };
302

    
303
  exports.sep = '\\';
304
  exports.delimiter = ';';
305

    
306
} else /* posix */ {
307

    
308
  // Split a filename into [root, dir, basename, ext], unix version
309
  // 'root' is just a slash, or nothing.
310
  var splitPathRe =
311
      /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
312
  var splitPath = function(filename) {
313
    return splitPathRe.exec(filename).slice(1);
314
  };
315

    
316
  // path.resolve([from ...], to)
317
  // posix version
318
  exports.resolve = function() {
319
    var resolvedPath = '',
320
        resolvedAbsolute = false;
321

    
322
    for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
323
      var path = (i >= 0) ? arguments[i] : process.cwd();
324

    
325
      // Skip empty and invalid entries
326
      if (!util.isString(path)) {
327
        throw new TypeError('Arguments to path.resolve must be strings');
328
      } else if (!path) {
329
        continue;
330
      }
331

    
332
      resolvedPath = path + '/' + resolvedPath;
333
      resolvedAbsolute = path.charAt(0) === '/';
334
    }
335

    
336
    // At this point the path should be resolved to a full absolute path, but
337
    // handle relative paths to be safe (might happen when process.cwd() fails)
338

    
339
    // Normalize the path
340
    resolvedPath = normalizeArray(resolvedPath.split('/').filter(function(p) {
341
      return !!p;
342
    }), !resolvedAbsolute).join('/');
343

    
344
    return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
345
  };
346

    
347
  // path.normalize(path)
348
  // posix version
349
  exports.normalize = function(path) {
350
    var isAbsolute = exports.isAbsolute(path),
351
        trailingSlash = path[path.length - 1] === '/',
352
        segments = path.split('/'),
353
        nonEmptySegments = [];
354

    
355
    // Normalize the path
356
    for (var i = 0; i < segments.length; i++) {
357
      if (segments[i]) {
358
        nonEmptySegments.push(segments[i]);
359
      }
360
    }
361
    path = normalizeArray(nonEmptySegments, !isAbsolute).join('/');
362

    
363
    if (!path && !isAbsolute) {
364
      path = '.';
365
    }
366
    if (path && trailingSlash) {
367
      path += '/';
368
    }
369

    
370
    return (isAbsolute ? '/' : '') + path;
371
  };
372

    
373
  // posix version
374
  exports.isAbsolute = function(path) {
375
    return path.charAt(0) === '/';
376
  };
377

    
378
  // posix version
379
  exports.join = function() {
380
    var path = '';
381
    for (var i = 0; i < arguments.length; i++) {
382
      var segment = arguments[i];
383
      if (!util.isString(segment)) {
384
        throw new TypeError('Arguments to path.join must be strings');
385
      }
386
      if (segment) {
387
        if (!path) {
388
          path += segment;
389
        } else {
390
          path += '/' + segment;
391
        }
392
      }
393
    }
394
    return exports.normalize(path);
395
  };
396

    
397

    
398
  // path.relative(from, to)
399
  // posix version
400
  exports.relative = function(from, to) {
401
    from = exports.resolve(from).substr(1);
402
    to = exports.resolve(to).substr(1);
403

    
404
    function trim(arr) {
405
      var start = 0;
406
      for (; start < arr.length; start++) {
407
        if (arr[start] !== '') break;
408
      }
409

    
410
      var end = arr.length - 1;
411
      for (; end >= 0; end--) {
412
        if (arr[end] !== '') break;
413
      }
414

    
415
      if (start > end) return [];
416
      return arr.slice(start, end + 1);
417
    }
418

    
419
    var fromParts = trim(from.split('/'));
420
    var toParts = trim(to.split('/'));
421

    
422
    var length = Math.min(fromParts.length, toParts.length);
423
    var samePartsLength = length;
424
    for (var i = 0; i < length; i++) {
425
      if (fromParts[i] !== toParts[i]) {
426
        samePartsLength = i;
427
        break;
428
      }
429
    }
430

    
431
    var outputParts = [];
432
    for (var i = samePartsLength; i < fromParts.length; i++) {
433
      outputParts.push('..');
434
    }
435

    
436
    outputParts = outputParts.concat(toParts.slice(samePartsLength));
437

    
438
    return outputParts.join('/');
439
  };
440

    
441
  exports.sep = '/';
442
  exports.delimiter = ':';
443
}
444

    
445
exports.dirname = function(path) {
446
  var result = splitPath(path),
447
      root = result[0],
448
      dir = result[1];
449

    
450
  if (!root && !dir) {
451
    // No dirname whatsoever
452
    return '.';
453
  }
454

    
455
  if (dir) {
456
    // It has a dirname, strip trailing slash
457
    dir = dir.substr(0, dir.length - 1);
458
  }
459

    
460
  return root + dir;
461
};
462

    
463

    
464
exports.basename = function(path, ext) {
465
  var f = splitPath(path)[2];
466
  // TODO: make this comparison case-insensitive on windows?
467
  if (ext && f.substr(-1 * ext.length) === ext) {
468
    f = f.substr(0, f.length - ext.length);
469
  }
470
  return f;
471
};
472

    
473

    
474
exports.extname = function(path) {
475
  return splitPath(path)[3];
476
};
477

    
478

    
479
exports.exists = util.deprecate(function(path, callback) {
480
  require('fs').exists(path, callback);
481
}, 'path.exists is now called `fs.exists`.');
482

    
483

    
484
exports.existsSync = util.deprecate(function(path) {
485
  return require('fs').existsSync(path);
486
}, 'path.existsSync is now called `fs.existsSync`.');
487

    
488

    
489
if (isWindows) {
490
  exports._makeLong = function(path) {
491
    // Note: this will *probably* throw somewhere.
492
    if (!util.isString(path))
493
      return path;
494

    
495
    if (!path) {
496
      return '';
497
    }
498

    
499
    var resolvedPath = exports.resolve(path);
500

    
501
    if (/^[a-zA-Z]\:\\/.test(resolvedPath)) {
502
      // path is local filesystem path, which needs to be converted
503
      // to long UNC path.
504
      return '\\\\?\\' + resolvedPath;
505
    } else if (/^\\\\[^?.]/.test(resolvedPath)) {
506
      // path is network UNC path, which needs to be converted
507
      // to long UNC path.
508
      return '\\\\?\\UNC\\' + resolvedPath.substring(2);
509
    }
510

    
511
    return path;
512
  };
513
} else {
514
  exports._makeLong = function(path) {
515
    return path;
516
  };
517
}