* Resolve a relative path. * * @param {String} base * @param {String} relative * @param {Boolean} append * @return {String}
(base, relative, append)
| 756 | */ |
| 757 | |
| 758 | function resolvePath(base, relative, append) { |
| 759 | var query = base.match(/(\?.*)$/); |
| 760 | if (query) { |
| 761 | query = query[1]; |
| 762 | base = base.slice(0, -query.length); |
| 763 | } |
| 764 | // a query! |
| 765 | if (relative.charAt(0) === '?') { |
| 766 | return base + relative; |
| 767 | } |
| 768 | var stack = base.split('/'); |
| 769 | // remove trailing segment if: |
| 770 | // - not appending |
| 771 | // - appending to trailing slash (last segment is empty) |
| 772 | if (!append || !stack[stack.length - 1]) { |
| 773 | stack.pop(); |
| 774 | } |
| 775 | // resolve relative path |
| 776 | var segments = relative.replace(/^\//, '').split('/'); |
| 777 | for (var i = 0; i < segments.length; i++) { |
| 778 | var segment = segments[i]; |
| 779 | if (segment === '.') { |
| 780 | continue; |
| 781 | } else if (segment === '..') { |
| 782 | stack.pop(); |
| 783 | } else { |
| 784 | stack.push(segment); |
| 785 | } |
| 786 | } |
| 787 | // ensure leading slash |
| 788 | if (stack[0] !== '') { |
| 789 | stack.unshift(''); |
| 790 | } |
| 791 | return stack.join('/'); |
| 792 | } |
| 793 | |
| 794 | /** |
| 795 | * Forgiving check for a promise |