diff --git a/lib/coffee-script/helpers.js b/lib/coffee-script/helpers.js index c7c04813..8f97efff 100644 --- a/lib/coffee-script/helpers.js +++ b/lib/coffee-script/helpers.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 1.6.1 (function() { - var buildLocationData, extend, flatten, normalizePath, _ref; + var buildLocationData, extend, flatten, last, normalizePath, repeat, _ref; exports.starts = function(string, literal, start) { return literal === string.substr(start, literal.length); @@ -12,6 +12,19 @@ return literal === string.substr(string.length - len - (back || 0), len); }; + exports.repeat = repeat = function(str, n) { + var res; + res = ''; + while (n > 0) { + if (n & 1) { + res += str; + } + n >>>= 1; + str += str; + } + return res; + }; + exports.compact = function(array) { var item, _i, _len, _results; _results = []; @@ -70,7 +83,7 @@ return val; }; - exports.last = function(array, back) { + exports.last = last = function(array, back) { return array[array.length - (back || 0) - 1]; }; @@ -167,50 +180,48 @@ }; exports.normalizePath = normalizePath = function(path, removeTrailingSlash) { - var i, parts, root, _ref1; + var i, newParts, part, parts, root, _i, _len; if (removeTrailingSlash == null) { removeTrailingSlash = false; } root = false; parts = path.split('/'); + newParts = []; i = 0; - if (parts.length > 1 && parts[i] === '') { - parts.splice(i, 1); + if (parts.length > 1 && parts[0] === '') { + parts.shift(); root = true; } - while (i < parts.length) { - if ((_ref1 = parts[i]) === '.' || _ref1 === '') { + for (i = _i = 0, _len = parts.length; _i < _len; i = ++_i) { + part = parts[i]; + if (part === '.' || part === '') { if ((i === parts.length - 1) && !removeTrailingSlash) { - parts[i] = ''; - i++; - } else { - parts.splice(i, 1); + newParts.push(''); } - } else if (parts[i] === '..') { - if (i === 0 || (i && parts[i - 1] === '..')) { - i++; + } else if (part === '..') { + if (newParts.length === 0 || (newParts.length && last(newParts === '..'))) { + newParts.push('..'); } else { - parts.splice(i - 1, 2); - i--; + newParts.pop(); } } else { - i++; + newParts.push(part); } } if (root) { - if (parts.length === 0) { + if (newParts.length === 0) { return '/'; } - if (parts.length[0] === '..') { + if (newParts.length[0] === '..') { throw new Error("Invalid path: " + path); } - parts.unshift(''); + newParts.unshift(''); } - return parts.join('/'); + return newParts.join('/'); }; exports.relativePath = function(from, to, cwd) { - var answer, _i, _ref1; + var answer; if (cwd == null) { cwd = null; } @@ -227,12 +238,7 @@ if (from.length && from[0] === "..") { throw new Error("'cwd' must be specified if 'from' references parent directory: " + (from.join('/')) + " -> " + (to.join('/'))); } - answer = ""; - if (from.length > 1) { - for (_i = 0, _ref1 = from.length - 1; 0 <= _ref1 ? _i < _ref1 : _i > _ref1; 0 <= _ref1 ? _i++ : _i--) { - answer += "../"; - } - } + answer = repeat("../", from.length - 1); return answer + ("" + (to.join('/'))); }; diff --git a/src/helpers.coffee b/src/helpers.coffee index 10d38903..91b096de 100644 --- a/src/helpers.coffee +++ b/src/helpers.coffee @@ -11,6 +11,16 @@ exports.ends = (string, literal, back) -> len = literal.length literal is string.substr string.length - len - (back or 0), len +# Repeat a string `n` times. +exports.repeat = repeat = (str, n) -> + # Use clever algorithm to have O(log(n)) string concatenation operations. + res = '' + while n > 0 + res += str if n & 1 + n >>>= 1 + str += str + res + # Trim out all falsy values from an array. exports.compact = (array) -> item for item in array when item @@ -53,7 +63,7 @@ exports.del = (obj, key) -> val # Gets the last item of an array(-like) object. -exports.last = (array, back) -> array[array.length - (back or 0) - 1] +exports.last = last = (array, back) -> array[array.length - (back or 0) - 1] # Typical Array::some exports.some = Array::some ? (fn) -> @@ -125,37 +135,34 @@ exports.isLiterate = (file) -> /\.(litcoffee|coffee\.md)$/.test file exports.normalizePath = normalizePath = (path, removeTrailingSlash=no) -> root = no # Does this path start with the root? parts = path.split '/' + newParts = [] i = 0 # If the path started with a '/', set the root flag. - if parts.length > 1 and parts[i] == '' - parts.splice i, 1 + if parts.length > 1 and parts[0] == '' + parts.shift() root = yes - while i < parts.length - if parts[i] in ['.', ''] + for part, i in parts + if part in ['.', ''] if (i is parts.length - 1) and not removeTrailingSlash - # Leave the trailing '/'' - parts[i] = '' - i++ - else - # Remove the empty element - parts.splice i, 1 - else if parts[i] is '..' - if i is 0 or (i and parts[i-1] is '..') + # Leave the trailing '/'. Note that we're pushing a '', but because we join with '/'s + # later, this will become a '/'. + newParts.push '' + else if part is '..' + if newParts.length is 0 or (newParts.length and last newParts is '..') # Leave the ".." - i++ + newParts.push '..' else - # Remove the '..' and the previous element - parts.splice i-1, 2 - i-- + # Drop the '..' and remote the previous element + newParts.pop() else - i++ + newParts.push part if root - if parts.length == 0 then return '/' - if parts.length[0] is '..' + if newParts.length is 0 then return '/' + if newParts.length[0] is '..' # Uhh... This doesn't make any sense. throw new Error "Invalid path: #{path}" - parts.unshift '' # Add back the leading "/" - parts.join '/' + newParts.unshift '' # Add back the leading "/" + newParts.join '/' # Solve the relative path from `from` to `to`. # @@ -169,13 +176,11 @@ exports.relativePath = (from, to, cwd=null) -> if cwd from = cwd + "/" + from to = cwd + "/" + to - from = (normalizePath from).split '/' - to = (normalizePath to).split '/' + from = normalizePath(from).split '/' + to = normalizePath(to).split '/' while from.length > 0 and to.length > 0 and from[0] == to[0] from.shift() to.shift() if from.length and from[0] is ".." then throw new Error "'cwd' must be specified if 'from' references parent directory: #{from.join '/'} -> #{to.join '/'}" - answer = "" - if from.length > 1 then for [0...(from.length - 1)] - answer += "../" + answer = repeat "../", from.length - 1 answer + "#{to.join '/'}"