Skip to content

optimizationLevel 2 lets .. erase the Windows drive root and UNC share from patterns #318

Description

@chuanghiduoc

name: optimizationLevel 2 lets .. erase the Windows drive root and UNC share from patterns
about: L2 pattern optimizer collapses C:/foo/../.. to a pattern that matches / instead of C:/, and //srv/share/../x to a pattern that no longer matches the original target
title: optimizationLevel 2 lets .. erase the Windows drive root and UNC share from patterns
labels: bug
assignees: ''


Follow-up to 7953af1 ("do not allow .. to consume drive letter on Windows"), tested on master (10.2.6, ded1bbd).

That commit guards a single .. from consuming a drive-letter part. But the guard only inspects the part immediately preceding each individual ... With two consecutive .., the first one eats the literal segment, so by the time the loop reaches the second .. the preceding part is an ordinary string and the drive gets eaten too — the whole pattern collapses to a single empty part:

import { minimatch, Minimatch } from 'minimatch'

minimatch('C:/', 'C:/foo/../..', { platform: 'win32', optimizationLevel: 2 }) // false — should be true
minimatch('/',  'C:/foo/../..', { platform: 'win32', optimizationLevel: 2 }) // true  — should be false

// L1 is correct on both:
minimatch('C:/', 'C:/foo/../..', { platform: 'win32', optimizationLevel: 1 }) // true
minimatch('/',  'C:/foo/../..', { platform: 'win32', optimizationLevel: 1 }) // false

const m = new Minimatch('C:/foo/../..', { platform: 'win32', optimizationLevel: 2 })
// m.set === [['']]  — drive letter fully erased

UNC shares are eaten as well. The L2 docs say empty/. parts near a possible UNC prefix are preserved, but .. still consumes the share component (and can then consume the server name):

minimatch('//srv/share/x', '//srv/share/../x', { platform: 'win32', optimizationLevel: 2 }) // false — should be true
minimatch('//srv/x',       '//srv/share/../x', { platform: 'win32', optimizationLevel: 2 }) // true  — should be false

const m2 = new Minimatch('//srv/share/../x', { platform: 'win32', optimizationLevel: 2 })
// m2.set === [['', '', 'srv', 'x']]  — 'share' was consumed

Impact: for a file-walker (the documented use case for optimizationLevel: 2) a pattern like C:/build/../** or a UNC ignore rule silently stops matching paths it was written for, or starts matching unrelated ones (/). All results above verified against master with npx tsx.

Failing tests: test/optimizer-drive-root.ts (tap; all 4 assertions fail on master).

Suggested fix direction: after each splice in the ..-elimination loop, re-evaluate the new preceding part under the same guard (drive letter), and skip splices where the removed pair would expose/consume a //-prefixed server+share root.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions