// -> /+ if (!this.preserveMultipleSlashes) { + for (let i = 1; i < parts.length - 1; i++) { + const p = parts[i]; + // don't squeeze out UNC patterns + if (i === 1 && p === '' && parts[0] === '') + continue; + if (p === '.' || p === '') { + didSomething = true; + parts.splice(i, 1); + i--; + } + } + if (parts[0] === '.' && + parts.length === 2 && + (parts[1] === '.' || parts[1] === '')) { + didSomething = true; + parts.pop(); + } + } + // //../
-> /+ let dd = 0; + while (-1 !== (dd = parts.indexOf('..', dd + 1))) { + const p = parts[dd - 1]; + if (p && p !== '.' && p !== '..' && p !== '**') { + didSomething = true; + parts.splice(dd - 1, 2); + dd -= 2; + } + } + } while (didSomething); + return parts.length === 0 ? [''] : parts; + } + // First phase: single-pattern processing + // is 1 or more portions + //is 1 or more portions + // is any portion other than ., .., '', or ** + //
is . or '' + // + // **/.. is *brutal* for filesystem walking performance, because + // it effectively resets the recursive walk each time it occurs, + // and ** cannot be reduced out by a .. pattern part like a regexp + // or most strings (other than .., ., and '') can be. + // + // /**/..//
/
-> { /..//
/
, /**//
/
} + // // -> /+ // //../
-> /+ // **/**/ -> **/ + // + // **/*/ -> */**/ <== not valid because ** doesn't follow + // this WOULD be allowed if ** did follow symlinks, or * didn't + firstPhasePreProcess(globParts) { + let didSomething = false; + do { + didSomething = false; + // /**/..//
/
-> { /..//
/
, /**//
/
} + for (let parts of globParts) { + let gs = -1; + while (-1 !== (gs = parts.indexOf('**', gs + 1))) { + let gss = gs; + while (parts[gss + 1] === '**') { + // /**/**/-> /**/+ gss++; + } + // eg, if gs is 2 and gss is 4, that means we have 3 ** + // parts, and can remove 2 of them. + if (gss > gs) { + parts.splice(gs + 1, gss - gs); + } + let next = parts[gs + 1]; + const p = parts[gs + 2]; + const p2 = parts[gs + 3]; + if (next !== '..') + continue; + if (!p || + p === '.' || + p === '..' || + !p2 || + p2 === '.' || + p2 === '..') { + continue; + } + didSomething = true; + // edit parts in place, and push the new one + parts.splice(gs, 1); + const other = parts.slice(0); + other[gs] = '**'; + globParts.push(other); + gs--; + } + // // -> /+ if (!this.preserveMultipleSlashes) { + for (let i = 1; i < parts.length - 1; i++) { + const p = parts[i]; + // don't squeeze out UNC patterns + if (i === 1 && p === '' && parts[0] === '') + continue; + if (p === '.' || p === '') { + didSomething = true; + parts.splice(i, 1); + i--; + } + } + if (parts[0] === '.' && + parts.length === 2 && + (parts[1] === '.' || parts[1] === '')) { + didSomething = true; + parts.pop(); + } + } + // //../
-> /+ let dd = 0; + while (-1 !== (dd = parts.indexOf('..', dd + 1))) { + const p = parts[dd - 1]; + if (p && p !== '.' && p !== '..' && p !== '**') { + didSomething = true; + const needDot = dd === 1 && parts[dd + 1] === '**'; + const splin = needDot ? ['.'] : []; + parts.splice(dd - 1, 2, ...splin); + if (parts.length === 0) + parts.push(''); + dd -= 2; + } + } + } + } while (didSomething); + return globParts; + } + // second phase: multi-pattern dedupes + // { /*/, //
} -> /*/+ // { /, /} -> /