├── .travis.yml ├── appveyor.yml ├── index.js ├── license ├── package.json ├── readme.md └── test.js /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '6' 4 | - '5' 5 | - '4' 6 | - '0.12' 7 | - '0.10' 8 | - '0.8' 9 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | 2 | # Test against this version of Node.js 3 | environment: 4 | matrix: 5 | - nodejs_version: "6" 6 | - nodejs_version: "5" 7 | - nodejs_version: "4" 8 | - nodejs_version: "0.12" 9 | - nodejs_version: "0.10" 10 | - nodejs_version: "0.8" 11 | 12 | # Install scripts. (runs after repo cloning) 13 | install: 14 | # Get the latest stable version of Node.js or io.js 15 | - ps: Install-Product node $env:nodejs_version 16 | # install modules 17 | - npm install 18 | 19 | # Post-install test scripts. 20 | test_script: 21 | # Output useful info for debugging. 22 | - node --version 23 | - npm --version 24 | # run tests 25 | - npm test 26 | 27 | # Don't actually build. 28 | build: off 29 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var inspect = require('util').inspect; 5 | 6 | function assertPath(path) { 7 | if (typeof path !== 'string') { 8 | throw new TypeError('Path must be a string. Received ' + inspect(path)); 9 | } 10 | } 11 | 12 | function posix(path) { 13 | assertPath(path); 14 | if (path.length === 0) 15 | return '.'; 16 | var code = path.charCodeAt(0); 17 | var hasRoot = (code === 47/*/*/); 18 | var end = -1; 19 | var matchedSlash = true; 20 | for (var i = path.length - 1; i >= 1; --i) { 21 | code = path.charCodeAt(i); 22 | if (code === 47/*/*/) { 23 | if (!matchedSlash) { 24 | end = i; 25 | break; 26 | } 27 | } else { 28 | // We saw the first non-path separator 29 | matchedSlash = false; 30 | } 31 | } 32 | 33 | if (end === -1) 34 | return hasRoot ? '/' : '.'; 35 | if (hasRoot && end === 1) 36 | return '//'; 37 | return path.slice(0, end); 38 | } 39 | 40 | function win32(path) { 41 | assertPath(path); 42 | var len = path.length; 43 | if (len === 0) 44 | return '.'; 45 | var rootEnd = -1; 46 | var end = -1; 47 | var matchedSlash = true; 48 | var offset = 0; 49 | var code = path.charCodeAt(0); 50 | 51 | // Try to match a root 52 | if (len > 1) { 53 | if (code === 47/*/*/ || code === 92/*\*/) { 54 | // Possible UNC root 55 | 56 | rootEnd = offset = 1; 57 | 58 | code = path.charCodeAt(1); 59 | if (code === 47/*/*/ || code === 92/*\*/) { 60 | // Matched double path separator at beginning 61 | var j = 2; 62 | var last = j; 63 | // Match 1 or more non-path separators 64 | for (; j < len; ++j) { 65 | code = path.charCodeAt(j); 66 | if (code === 47/*/*/ || code === 92/*\*/) 67 | break; 68 | } 69 | if (j < len && j !== last) { 70 | // Matched! 71 | last = j; 72 | // Match 1 or more path separators 73 | for (; j < len; ++j) { 74 | code = path.charCodeAt(j); 75 | if (code !== 47/*/*/ && code !== 92/*\*/) 76 | break; 77 | } 78 | if (j < len && j !== last) { 79 | // Matched! 80 | last = j; 81 | // Match 1 or more non-path separators 82 | for (; j < len; ++j) { 83 | code = path.charCodeAt(j); 84 | if (code === 47/*/*/ || code === 92/*\*/) 85 | break; 86 | } 87 | if (j === len) { 88 | // We matched a UNC root only 89 | return path; 90 | } 91 | if (j !== last) { 92 | // We matched a UNC root with leftovers 93 | 94 | // Offset by 1 to include the separator after the UNC root to 95 | // treat it as a "normal root" on top of a (UNC) root 96 | rootEnd = offset = j + 1; 97 | } 98 | } 99 | } 100 | } 101 | } else if ((code >= 65/*A*/ && code <= 90/*Z*/) || 102 | (code >= 97/*a*/ && code <= 122/*z*/)) { 103 | // Possible device root 104 | 105 | code = path.charCodeAt(1); 106 | if (path.charCodeAt(1) === 58/*:*/) { 107 | rootEnd = offset = 2; 108 | if (len > 2) { 109 | code = path.charCodeAt(2); 110 | if (code === 47/*/*/ || code === 92/*\*/) 111 | rootEnd = offset = 3; 112 | } 113 | } 114 | } 115 | } else if (code === 47/*/*/ || code === 92/*\*/) { 116 | return path[0]; 117 | } 118 | 119 | for (var i = len - 1; i >= offset; --i) { 120 | code = path.charCodeAt(i); 121 | if (code === 47/*/*/ || code === 92/*\*/) { 122 | if (!matchedSlash) { 123 | end = i; 124 | break; 125 | } 126 | } else { 127 | // We saw the first non-path separator 128 | matchedSlash = false; 129 | } 130 | } 131 | 132 | if (end === -1) { 133 | if (rootEnd === -1) 134 | return '.'; 135 | else 136 | end = rootEnd; 137 | } 138 | return path.slice(0, end); 139 | } 140 | 141 | module.exports = process.platform === 'win32' ? win32 : posix; 142 | module.exports.posix = posix; 143 | module.exports.win32 = win32; 144 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) Elan Shanker and Node.js contributors. All rights reserved. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to 8 | deal in the Software without restriction, including without limitation the 9 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | sell copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 | IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "path-dirname", 3 | "version": "1.0.2", 4 | "description": "Node.js path.dirname() ponyfill", 5 | "license": "MIT", 6 | "repository": "es128/path-dirname", 7 | "author": "Elan Shanker", 8 | "scripts": { 9 | "test": "node test.js" 10 | }, 11 | "files": [ 12 | "index.js" 13 | ], 14 | "keywords": [ 15 | "dirname", 16 | "dir", 17 | "path", 18 | "paths", 19 | "file", 20 | "built-in", 21 | "util", 22 | "utils", 23 | "core", 24 | "stdlib", 25 | "ponyfill", 26 | "polyfill", 27 | "shim" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # path-dirname [![Build Status](https://travis-ci.org/es128/path-dirname.svg?branch=master)](https://travis-ci.org/es128/path-dirname) 2 | 3 | > Node.js [`path.dirname()`](https://nodejs.org/api/path.html#path_path_dirname_path) [ponyfill](https://ponyfill.com) 4 | 5 | This was needed in order to expose `path.posix.dirname()` on Node.js v0.10 6 | 7 | ## Install 8 | 9 | ``` 10 | $ npm install --save path-dirname 11 | ``` 12 | 13 | 14 | ## Usage 15 | 16 | ```js 17 | const pathDirname = require('path-dirname'); 18 | 19 | pathDirname('/home/foo'); 20 | //=> '/home' 21 | pathDirname('C:\\Users\\foo'); 22 | //=> 'C:\\Users' 23 | pathDirname('foo'); 24 | //=> '.' 25 | pathDirname('foo/bar'); 26 | //=> 'foo' 27 | 28 | //Using posix version for consistent output when dealing with glob escape chars 29 | pathDirname.win32('C:\\Users\\foo/\\*bar'); 30 | //=> 'C:\\Users\\foo/' 31 | pathDirname.posix('C:\\Users\\foo/\\*bar'); 32 | //=> 'C:\\Users\\foo' 33 | ``` 34 | 35 | 36 | ## API 37 | 38 | See the [`path.dirname()` docs](https://nodejs.org/api/path.html#path_path_dirname_path). 39 | 40 | ### pathDirname(path) 41 | 42 | ### pathDirname.posix(path) 43 | 44 | POSIX specific version. 45 | 46 | ### pathDirname.win32(path) 47 | 48 | Windows specific version. 49 | 50 | 51 | ## License 52 | 53 | MIT 54 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var pathDirname = require('./'); 3 | 4 | var path = { 5 | posix: { 6 | dirname: pathDirname.posix 7 | }, 8 | win32: { 9 | dirname: pathDirname.win32 10 | } 11 | }; 12 | 13 | var f = __filename; 14 | 15 | // https://github.com/nodejs/node/blob/0f2f8e/test/parallel/test-path.js#L67-L115 16 | 17 | // path.dirname tests 18 | assert.strictEqual(pathDirname(f).substr(-13), 19 | process.platform === 'win32' ? '\\path-dirname' : '/path-dirname'); 20 | 21 | assert.strictEqual(path.posix.dirname('/a/b/'), '/a'); 22 | assert.strictEqual(path.posix.dirname('/a/b'), '/a'); 23 | assert.strictEqual(path.posix.dirname('/a'), '/'); 24 | assert.strictEqual(path.posix.dirname(''), '.'); 25 | assert.strictEqual(path.posix.dirname('/'), '/'); 26 | assert.strictEqual(path.posix.dirname('////'), '/'); 27 | assert.strictEqual(path.posix.dirname('foo'), '.'); 28 | 29 | assert.strictEqual(path.win32.dirname('c:\\'), 'c:\\'); 30 | assert.strictEqual(path.win32.dirname('c:\\foo'), 'c:\\'); 31 | assert.strictEqual(path.win32.dirname('c:\\foo\\'), 'c:\\'); 32 | assert.strictEqual(path.win32.dirname('c:\\foo\\bar'), 'c:\\foo'); 33 | assert.strictEqual(path.win32.dirname('c:\\foo\\bar\\'), 'c:\\foo'); 34 | assert.strictEqual(path.win32.dirname('c:\\foo\\bar\\baz'), 'c:\\foo\\bar'); 35 | assert.strictEqual(path.win32.dirname('\\'), '\\'); 36 | assert.strictEqual(path.win32.dirname('\\foo'), '\\'); 37 | assert.strictEqual(path.win32.dirname('\\foo\\'), '\\'); 38 | assert.strictEqual(path.win32.dirname('\\foo\\bar'), '\\foo'); 39 | assert.strictEqual(path.win32.dirname('\\foo\\bar\\'), '\\foo'); 40 | assert.strictEqual(path.win32.dirname('\\foo\\bar\\baz'), '\\foo\\bar'); 41 | assert.strictEqual(path.win32.dirname('c:'), 'c:'); 42 | assert.strictEqual(path.win32.dirname('c:foo'), 'c:'); 43 | assert.strictEqual(path.win32.dirname('c:foo\\'), 'c:'); 44 | assert.strictEqual(path.win32.dirname('c:foo\\bar'), 'c:foo'); 45 | assert.strictEqual(path.win32.dirname('c:foo\\bar\\'), 'c:foo'); 46 | assert.strictEqual(path.win32.dirname('c:foo\\bar\\baz'), 'c:foo\\bar'); 47 | assert.strictEqual(path.win32.dirname('\\\\unc\\share'), 48 | '\\\\unc\\share'); 49 | assert.strictEqual(path.win32.dirname('\\\\unc\\share\\foo'), 50 | '\\\\unc\\share\\'); 51 | assert.strictEqual(path.win32.dirname('\\\\unc\\share\\foo\\'), 52 | '\\\\unc\\share\\'); 53 | assert.strictEqual(path.win32.dirname('\\\\unc\\share\\foo\\bar'), 54 | '\\\\unc\\share\\foo'); 55 | assert.strictEqual(path.win32.dirname('\\\\unc\\share\\foo\\bar\\'), 56 | '\\\\unc\\share\\foo'); 57 | assert.strictEqual(path.win32.dirname('\\\\unc\\share\\foo\\bar\\baz'), 58 | '\\\\unc\\share\\foo\\bar'); 59 | assert.strictEqual(path.win32.dirname('/a/b/'), '/a'); 60 | assert.strictEqual(path.win32.dirname('/a/b'), '/a'); 61 | assert.strictEqual(path.win32.dirname('/a'), '/'); 62 | assert.strictEqual(path.win32.dirname(''), '.'); 63 | assert.strictEqual(path.win32.dirname('/'), '/'); 64 | assert.strictEqual(path.win32.dirname('////'), '/'); 65 | assert.strictEqual(path.win32.dirname('foo'), '.'); 66 | --------------------------------------------------------------------------------