343 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			343 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
# upath v1.2.0
 | 
						|
 | 
						|
[](https://travis-ci.org/anodynos/upath)
 | 
						|
[](https://david-dm.org/anodynos/upath)
 | 
						|
 | 
						|
A drop-in replacement / proxy to nodejs's `path` that:
 | 
						|
 | 
						|
  * Replaces the windows `\` with the unix `/` in all string params & results. This has significant positives - see below.
 | 
						|
 | 
						|
  * Adds **filename extensions** functions `addExt`, `trimExt`, `removeExt`, `changeExt`, and `defaultExt`.
 | 
						|
 | 
						|
  * Add a `normalizeSafe` function to preserve any meaningful leading `./` & a `normalizeTrim` which additionally trims any useless ending `/`.
 | 
						|
 | 
						|
  * Plus a helper `toUnix` that simply converts `\` to `/` and consolidates duplicates.
 | 
						|
 | 
						|
**Useful note: these docs are actually auto generated from [specs](https://github.com/anodynos/upath/blob/master/source/spec/upath-spec.coffee), running on Linux.**
 | 
						|
 | 
						|
Notes:
 | 
						|
 | 
						|
 * `upath.sep` is set to `'/'` for seamless replacement (as of 1.0.3).
 | 
						|
 | 
						|
 * upath has no runtime dependencies, except built-in `path` (as of 1.0.4)
 | 
						|
 | 
						|
 * travis-ci tested in node versions 4 to 12
 | 
						|
      
 | 
						|
 | 
						|
## Why ?
 | 
						|
 | 
						|
Normal `path` doesn't convert paths to a unified format (ie `/`) before calculating paths (`normalize`, `join`), which can lead to numerous problems.
 | 
						|
Also path joining, normalization etc on the two formats is not consistent, depending on where it runs. Running `path` on Windows yields different results than when it runs on Linux / Mac.
 | 
						|
 | 
						|
In general, if you code your paths logic while developing on Unix/Mac and it runs on Windows, you may run into problems when using `path`.
 | 
						|
 | 
						|
Note that using **Unix `/` on Windows** works perfectly inside nodejs (and other languages), so there's no reason to stick to the Windows legacy at all.
 | 
						|
 | 
						|
##### Examples / specs
 | 
						|
        
 | 
						|
 | 
						|
Check out the different (improved) behavior to vanilla `path`:
 | 
						|
 | 
						|
    `upath.normalize(path)`        --returns-->
 | 
						|
 | 
						|
          ✓ `'c:/windows/nodejs/path'`           --->      `'c:/windows/nodejs/path'`  // equal to `path.normalize()`
 | 
						|
          ✓ `'c:/windows/../nodejs/path'`        --->              `'c:/nodejs/path'`  // equal to `path.normalize()`
 | 
						|
          ✓ `'c:\\windows\\nodejs\\path'`        --->      `'c:/windows/nodejs/path'`  // `path.normalize()` gives `'c:\windows\nodejs\path'`
 | 
						|
          ✓ `'c:\\windows\\..\\nodejs\\path'`    --->              `'c:/nodejs/path'`  // `path.normalize()` gives `'c:\windows\..\nodejs\path'`
 | 
						|
          ✓ `'//windows\\unix/mixed'`            --->         `'/windows/unix/mixed'`  // `path.normalize()` gives `'/windows\unix/mixed'`
 | 
						|
          ✓ `'\\windows//unix/mixed'`            --->         `'/windows/unix/mixed'`  // `path.normalize()` gives `'\windows/unix/mixed'`
 | 
						|
          ✓ `'////\\windows\\..\\unix/mixed/'`   --->                `'/unix/mixed/'`  // `path.normalize()` gives `'/\windows\..\unix/mixed/'`
 | 
						|
        
 | 
						|
 | 
						|
Joining paths can also be a problem:
 | 
						|
 | 
						|
    `upath.join(paths...)`        --returns-->
 | 
						|
 | 
						|
          ✓ `'some/nodejs/deep', '../path'`       --->       `'some/nodejs/path'`  // equal to `path.join()`
 | 
						|
          ✓ `'some/nodejs\\windows', '../path'`   --->       `'some/nodejs/path'`  // `path.join()` gives `'some/path'`
 | 
						|
          ✓ `'some\\windows\\only', '..\\path'`   --->      `'some/windows/path'`  // `path.join()` gives `'some\windows\only/..\path'`
 | 
						|
        
 | 
						|
 | 
						|
Parsing with `path.parse()` should also be consistent across OSes:
 | 
						|
 | 
						|
  `upath.parse(path)`        --returns-->
 | 
						|
 | 
						|
          ✓ `'c:\Windows\Directory\somefile.ext'`      ---> `{ root: '', dir: 'c:/Windows/Directory', base: 'somefile.ext', ext: '.ext', name: 'somefile' }`
 | 
						|
                                    // `path.parse()` gives `'{ root: '', dir: '', base: 'c:\\Windows\\Directory\\somefile.ext', ext: '.ext', name: 'c:\\Windows\\Directory\\somefile' }'`
 | 
						|
          ✓ `'/root/of/unix/somefile.ext'`             ---> `{ root: '/', dir: '/root/of/unix', base: 'somefile.ext', ext: '.ext', name: 'somefile' }`  // equal to `path.parse()`
 | 
						|
    
 | 
						|
 | 
						|
## Added functions
 | 
						|
      
 | 
						|
 | 
						|
#### `upath.toUnix(path)`
 | 
						|
 | 
						|
Just converts all `` to `/` and consolidates duplicates, without performing any normalization.
 | 
						|
 | 
						|
##### Examples / specs
 | 
						|
 | 
						|
    `upath.toUnix(path)`        --returns-->
 | 
						|
 | 
						|
        ✓ `'.//windows\//unix//mixed////'`      --->         `'./windows/unix/mixed/'`
 | 
						|
        ✓ `'..///windows\..\\unix/mixed'`       --->      `'../windows/../unix/mixed'`
 | 
						|
      
 | 
						|
 | 
						|
#### `upath.normalizeSafe(path)`
 | 
						|
 | 
						|
Exactly like `path.normalize(path)`, but it keeps the first meaningful `./`.
 | 
						|
 | 
						|
Note that the unix `/` is returned everywhere, so windows `\` is always converted to unix `/`.
 | 
						|
 | 
						|
##### Examples / specs & how it differs from vanilla `path`
 | 
						|
 | 
						|
    `upath.normalizeSafe(path)`        --returns-->
 | 
						|
 | 
						|
        ✓ `''`                               --->                          `'.'`  // equal to `path.normalize()`
 | 
						|
        ✓ `'.'`                              --->                          `'.'`  // equal to `path.normalize()`
 | 
						|
        ✓ `'./'`                             --->                         `'./'`  // equal to `path.normalize()`
 | 
						|
        ✓ `'.//'`                            --->                         `'./'`  // equal to `path.normalize()`
 | 
						|
        ✓ `'.\\'`                            --->                         `'./'`  // `path.normalize()` gives `'.\'`
 | 
						|
        ✓ `'.\\//'`                          --->                         `'./'`  // `path.normalize()` gives `'.\/'`
 | 
						|
        ✓ `'./..'`                           --->                         `'..'`  // equal to `path.normalize()`
 | 
						|
        ✓ `'.//..'`                          --->                         `'..'`  // equal to `path.normalize()`
 | 
						|
        ✓ `'./../'`                          --->                        `'../'`  // equal to `path.normalize()`
 | 
						|
        ✓ `'.\\..\\'`                        --->                        `'../'`  // `path.normalize()` gives `'.\..\'`
 | 
						|
        ✓ `'./../dep'`                       --->                     `'../dep'`  // equal to `path.normalize()`
 | 
						|
        ✓ `'../dep'`                         --->                     `'../dep'`  // equal to `path.normalize()`
 | 
						|
        ✓ `'../path/dep'`                    --->                `'../path/dep'`  // equal to `path.normalize()`
 | 
						|
        ✓ `'../path/../dep'`                 --->                     `'../dep'`  // equal to `path.normalize()`
 | 
						|
        ✓ `'dep'`                            --->                        `'dep'`  // equal to `path.normalize()`
 | 
						|
        ✓ `'path//dep'`                      --->                   `'path/dep'`  // equal to `path.normalize()`
 | 
						|
        ✓ `'./dep'`                          --->                      `'./dep'`  // `path.normalize()` gives `'dep'`
 | 
						|
        ✓ `'./path/dep'`                     --->                 `'./path/dep'`  // `path.normalize()` gives `'path/dep'`
 | 
						|
        ✓ `'./path/../dep'`                  --->                      `'./dep'`  // `path.normalize()` gives `'dep'`
 | 
						|
        ✓ `'.//windows\\unix/mixed/'`        --->      `'./windows/unix/mixed/'`  // `path.normalize()` gives `'windows\unix/mixed/'`
 | 
						|
        ✓ `'..//windows\\unix/mixed'`        --->      `'../windows/unix/mixed'`  // `path.normalize()` gives `'../windows\unix/mixed'`
 | 
						|
        ✓ `'windows\\unix/mixed/'`           --->        `'windows/unix/mixed/'`  // `path.normalize()` gives `'windows\unix/mixed/'`
 | 
						|
        ✓ `'..//windows\\..\\unix/mixed'`    --->              `'../unix/mixed'`  // `path.normalize()` gives `'../windows\..\unix/mixed'`
 | 
						|
      
 | 
						|
 | 
						|
#### `upath.normalizeTrim(path)`
 | 
						|
 | 
						|
Exactly like `path.normalizeSafe(path)`, but it trims any useless ending `/`.
 | 
						|
 | 
						|
##### Examples / specs
 | 
						|
 | 
						|
    `upath.normalizeTrim(path)`        --returns-->
 | 
						|
 | 
						|
        ✓ `'./'`                          --->                         `'.'`  // `upath.normalizeSafe()` gives `'./'`
 | 
						|
        ✓ `'./../'`                       --->                        `'..'`  // `upath.normalizeSafe()` gives `'../'`
 | 
						|
        ✓ `'./../dep/'`                   --->                    `'../dep'`  // `upath.normalizeSafe()` gives `'../dep/'`
 | 
						|
        ✓ `'path//dep\\'`                 --->                  `'path/dep'`  // `upath.normalizeSafe()` gives `'path/dep/'`
 | 
						|
        ✓ `'.//windows\\unix/mixed/'`     --->      `'./windows/unix/mixed'`  // `upath.normalizeSafe()` gives `'./windows/unix/mixed/'`
 | 
						|
      
 | 
						|
 | 
						|
#### `upath.joinSafe([path1][, path2][, ...])`
 | 
						|
 | 
						|
Exactly like `path.join()`, but it keeps the first meaningful `./`.
 | 
						|
 | 
						|
Note that the unix `/` is returned everywhere, so windows `\` is always converted to unix `/`.
 | 
						|
 | 
						|
##### Examples / specs & how it differs from vanilla `path`
 | 
						|
 | 
						|
    `upath.joinSafe(path)`        --returns-->
 | 
						|
 | 
						|
        ✓ `'some/nodejs/deep', '../path'`                --->           `'some/nodejs/path'`  // equal to `path.join()`
 | 
						|
        ✓ `'./some/local/unix/', '../path'`              --->          `'./some/local/path'`  // `path.join()` gives `'some/local/path'`
 | 
						|
        ✓ `'./some\\current\\mixed', '..\\path'`         --->        `'./some/current/path'`  // `path.join()` gives `'some\current\mixed/..\path'`
 | 
						|
        ✓ `'../some/relative/destination', '..\\path'`   --->      `'../some/relative/path'`  // `path.join()` gives `'../some/relative/destination/..\path'`
 | 
						|
    
 | 
						|
 | 
						|
## Added functions for *filename extension* manipulation.
 | 
						|
 | 
						|
**Happy notes:**
 | 
						|
 | 
						|
  In all functions you can:
 | 
						|
 | 
						|
  * use both `.ext` & `ext` - the dot `.` on the extension is always adjusted correctly.
 | 
						|
 | 
						|
  * omit the `ext` param (pass null/undefined/empty string) and the common sense thing will happen.
 | 
						|
 | 
						|
  * ignore specific extensions from being considered as valid ones (eg `.min`, `.dev` `.aLongExtIsNotAnExt` etc), hence no trimming or replacement takes place on them.
 | 
						|
 | 
						|
       
 | 
						|
 | 
						|
#### `upath.addExt(filename, [ext])`
 | 
						|
 | 
						|
Adds `.ext` to `filename`, but only if it doesn't already have the exact extension.
 | 
						|
 | 
						|
##### Examples / specs
 | 
						|
 | 
						|
    `upath.addExt(filename, 'js')`     --returns-->
 | 
						|
 | 
						|
        ✓ `'myfile/addExt'`           --->           `'myfile/addExt.js'`
 | 
						|
        ✓ `'myfile/addExt.txt'`       --->       `'myfile/addExt.txt.js'`
 | 
						|
        ✓ `'myfile/addExt.js'`        --->           `'myfile/addExt.js'`
 | 
						|
        ✓ `'myfile/addExt.min.'`      --->      `'myfile/addExt.min..js'`
 | 
						|
        
 | 
						|
 | 
						|
It adds nothing if no `ext` param is passed.
 | 
						|
 | 
						|
    `upath.addExt(filename)`           --returns-->
 | 
						|
 | 
						|
          ✓ `'myfile/addExt'`           --->              `'myfile/addExt'`
 | 
						|
          ✓ `'myfile/addExt.txt'`       --->          `'myfile/addExt.txt'`
 | 
						|
          ✓ `'myfile/addExt.js'`        --->           `'myfile/addExt.js'`
 | 
						|
          ✓ `'myfile/addExt.min.'`      --->         `'myfile/addExt.min.'`
 | 
						|
      
 | 
						|
 | 
						|
#### `upath.trimExt(filename, [ignoreExts], [maxSize=7])`
 | 
						|
 | 
						|
Trims a filename's extension.
 | 
						|
 | 
						|
  * Extensions are considered to be up to `maxSize` chars long, counting the dot (defaults to 7).
 | 
						|
 | 
						|
  * An `Array` of `ignoreExts` (eg `['.min']`) prevents these from being considered as extension, thus are not trimmed.
 | 
						|
 | 
						|
##### Examples / specs
 | 
						|
 | 
						|
    `upath.trimExt(filename)`          --returns-->
 | 
						|
 | 
						|
        ✓ `'my/trimedExt.txt'`             --->                 `'my/trimedExt'`
 | 
						|
        ✓ `'my/trimedExt'`                 --->                 `'my/trimedExt'`
 | 
						|
        ✓ `'my/trimedExt.min'`             --->                 `'my/trimedExt'`
 | 
						|
        ✓ `'my/trimedExt.min.js'`          --->             `'my/trimedExt.min'`
 | 
						|
        ✓ `'../my/trimedExt.longExt'`      --->      `'../my/trimedExt.longExt'`
 | 
						|
        
 | 
						|
 | 
						|
It is ignoring `.min` & `.dev` as extensions, and considers exts with up to 8 chars.
 | 
						|
 | 
						|
    `upath.trimExt(filename, ['min', '.dev'], 8)`          --returns-->
 | 
						|
 | 
						|
          ✓ `'my/trimedExt.txt'`              --->                  `'my/trimedExt'`
 | 
						|
          ✓ `'my/trimedExt.min'`              --->              `'my/trimedExt.min'`
 | 
						|
          ✓ `'my/trimedExt.dev'`              --->              `'my/trimedExt.dev'`
 | 
						|
          ✓ `'../my/trimedExt.longExt'`       --->               `'../my/trimedExt'`
 | 
						|
          ✓ `'../my/trimedExt.longRExt'`      --->      `'../my/trimedExt.longRExt'`
 | 
						|
      
 | 
						|
 | 
						|
#### `upath.removeExt(filename, ext)`
 | 
						|
 | 
						|
Removes the specific `ext` extension from filename, if it has it. Otherwise it leaves it as is.
 | 
						|
As in all upath functions, it be `.ext` or `ext`.
 | 
						|
 | 
						|
##### Examples / specs
 | 
						|
 | 
						|
    `upath.removeExt(filename, '.js')`          --returns-->
 | 
						|
 | 
						|
        ✓ `'removedExt.js'`          --->          `'removedExt'`
 | 
						|
        ✓ `'removedExt.txt.js'`      --->      `'removedExt.txt'`
 | 
						|
        ✓ `'notRemoved.txt'`         --->      `'notRemoved.txt'`
 | 
						|
 | 
						|
It does not care about the length of exts.
 | 
						|
 | 
						|
    `upath.removeExt(filename, '.longExt')`          --returns-->
 | 
						|
 | 
						|
        ✓ `'removedExt.longExt'`          --->          `'removedExt'`
 | 
						|
        ✓ `'removedExt.txt.longExt'`      --->      `'removedExt.txt'`
 | 
						|
        ✓ `'notRemoved.txt'`              --->      `'notRemoved.txt'`
 | 
						|
 | 
						|
 | 
						|
#### `upath.changeExt(filename, [ext], [ignoreExts], [maxSize=7])`
 | 
						|
 | 
						|
Changes a filename's extension to `ext`. If it has no (valid) extension, it adds it.
 | 
						|
 | 
						|
  * Valid extensions are considered to be up to `maxSize` chars long, counting the dot (defaults to 7).
 | 
						|
 | 
						|
  * An `Array` of `ignoreExts` (eg `['.min']`) prevents these from being considered as extension, thus are not changed - the new extension is added instead.
 | 
						|
 | 
						|
##### Examples / specs
 | 
						|
 | 
						|
    `upath.changeExt(filename, '.js')`  --returns-->
 | 
						|
 | 
						|
        ✓ `'my/module.min'`            --->                `'my/module.js'`
 | 
						|
        ✓ `'my/module.coffee'`         --->                `'my/module.js'`
 | 
						|
        ✓ `'my/module'`                --->                `'my/module.js'`
 | 
						|
        ✓ `'file/withDot.'`            --->             `'file/withDot.js'`
 | 
						|
        ✓ `'file/change.longExt'`      --->      `'file/change.longExt.js'`
 | 
						|
        
 | 
						|
 | 
						|
If no `ext` param is given, it trims the current extension (if any).
 | 
						|
 | 
						|
    `upath.changeExt(filename)`        --returns-->
 | 
						|
 | 
						|
          ✓ `'my/module.min'`            --->                   `'my/module'`
 | 
						|
          ✓ `'my/module.coffee'`         --->                   `'my/module'`
 | 
						|
          ✓ `'my/module'`                --->                   `'my/module'`
 | 
						|
          ✓ `'file/withDot.'`            --->                `'file/withDot'`
 | 
						|
          ✓ `'file/change.longExt'`      --->         `'file/change.longExt'`
 | 
						|
        
 | 
						|
 | 
						|
It is ignoring `.min` & `.dev` as extensions, and considers exts with up to 8 chars.
 | 
						|
 | 
						|
    `upath.changeExt(filename, 'js', ['min', '.dev'], 8)`        --returns-->
 | 
						|
 | 
						|
          ✓ `'my/module.coffee'`          --->                 `'my/module.js'`
 | 
						|
          ✓ `'file/notValidExt.min'`      --->      `'file/notValidExt.min.js'`
 | 
						|
          ✓ `'file/notValidExt.dev'`      --->      `'file/notValidExt.dev.js'`
 | 
						|
          ✓ `'file/change.longExt'`       --->               `'file/change.js'`
 | 
						|
          ✓ `'file/change.longRExt'`      --->      `'file/change.longRExt.js'`
 | 
						|
      
 | 
						|
 | 
						|
#### `upath.defaultExt(filename, [ext], [ignoreExts], [maxSize=7])`
 | 
						|
 | 
						|
Adds `.ext` to `filename`, only if it doesn't already have _any_ *old* extension.
 | 
						|
 | 
						|
  * (Old) extensions are considered to be up to `maxSize` chars long, counting the dot (defaults to 7).
 | 
						|
 | 
						|
  * An `Array` of `ignoreExts` (eg `['.min']`) will force adding default `.ext` even if one of these is present.
 | 
						|
 | 
						|
##### Examples / specs
 | 
						|
 | 
						|
    `upath.defaultExt(filename, 'js')`   --returns-->
 | 
						|
 | 
						|
        ✓ `'fileWith/defaultExt'`              --->              `'fileWith/defaultExt.js'`
 | 
						|
        ✓ `'fileWith/defaultExt.js'`           --->              `'fileWith/defaultExt.js'`
 | 
						|
        ✓ `'fileWith/defaultExt.min'`          --->             `'fileWith/defaultExt.min'`
 | 
						|
        ✓ `'fileWith/defaultExt.longExt'`      --->      `'fileWith/defaultExt.longExt.js'`
 | 
						|
        
 | 
						|
 | 
						|
If no `ext` param is passed, it leaves filename intact.
 | 
						|
 | 
						|
    `upath.defaultExt(filename)`       --returns-->
 | 
						|
 | 
						|
          ✓ `'fileWith/defaultExt'`              --->                 `'fileWith/defaultExt'`
 | 
						|
          ✓ `'fileWith/defaultExt.js'`           --->              `'fileWith/defaultExt.js'`
 | 
						|
          ✓ `'fileWith/defaultExt.min'`          --->             `'fileWith/defaultExt.min'`
 | 
						|
          ✓ `'fileWith/defaultExt.longExt'`      --->         `'fileWith/defaultExt.longExt'`
 | 
						|
        
 | 
						|
 | 
						|
It is ignoring `.min` & `.dev` as extensions, and considers exts with up to 8 chars.
 | 
						|
 | 
						|
    `upath.defaultExt(filename, 'js', ['min', '.dev'], 8)` --returns-->
 | 
						|
 | 
						|
          ✓ `'fileWith/defaultExt'`               --->               `'fileWith/defaultExt.js'`
 | 
						|
          ✓ `'fileWith/defaultExt.min'`           --->           `'fileWith/defaultExt.min.js'`
 | 
						|
          ✓ `'fileWith/defaultExt.dev'`           --->           `'fileWith/defaultExt.dev.js'`
 | 
						|
          ✓ `'fileWith/defaultExt.longExt'`       --->          `'fileWith/defaultExt.longExt'`
 | 
						|
          ✓ `'fileWith/defaultExt.longRext'`      --->      `'fileWith/defaultExt.longRext.js'`
 | 
						|
 | 
						|
 | 
						|
Copyright(c) 2014-2019 Angelos Pikoulas (agelos.pikoulas@gmail.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 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.
 |