1// this is just a very light wrapper around 2 arrays with an offset index
2import { GLOBSTAR } from 'minimatch';
3const isPatternList = (pl) => pl.length >= 1;
4const isGlobList = (gl) => gl.length >= 1;
5/**
6 * An immutable-ish view on an array of glob parts and their parsed
7 * results
8 */
9export class Pattern {
10    #patternList;
11    #globList;
12    #index;
13    length;
14    #platform;
15    #rest;
16    #globString;
17    #isDrive;
18    #isUNC;
19    #isAbsolute;
20    #followGlobstar = true;
21    constructor(patternList, globList, index, platform) {
22        if (!isPatternList(patternList)) {
23            throw new TypeError('empty pattern list');
24        }
25        if (!isGlobList(globList)) {
26            throw new TypeError('empty glob list');
27        }
28        if (globList.length !== patternList.length) {
29            throw new TypeError('mismatched pattern list and glob list lengths');
30        }
31        this.length = patternList.length;
32        if (index < 0 || index >= this.length) {
33            throw new TypeError('index out of range');
34        }
35        this.#patternList = patternList;
36        this.#globList = globList;
37        this.#index = index;
38        this.#platform = platform;
39        // normalize root entries of absolute patterns on initial creation.
40        if (this.#index === 0) {
41            // c: => ['c:/']
42            // C:/ => ['C:/']
43            // C:/x => ['C:/', 'x']
44            // //host/share => ['//host/share/']
45            // //host/share/ => ['//host/share/']
46            // //host/share/x => ['//host/share/', 'x']
47            // /etc => ['/', 'etc']
48            // / => ['/']
49            if (this.isUNC()) {
50                // '' / '' / 'host' / 'share'
51                const [p0, p1, p2, p3, ...prest] = this.#patternList;
52                const [g0, g1, g2, g3, ...grest] = this.#globList;
53                if (prest[0] === '') {
54                    // ends in /
55                    prest.shift();
56                    grest.shift();
57                }
58                const p = [p0, p1, p2, p3, ''].join('/');
59                const g = [g0, g1, g2, g3, ''].join('/');
60                this.#patternList = [p, ...prest];
61                this.#globList = [g, ...grest];
62                this.length = this.#patternList.length;
63            }
64            else if (this.isDrive() || this.isAbsolute()) {
65                const [p1, ...prest] = this.#patternList;
66                const [g1, ...grest] = this.#globList;
67                if (prest[0] === '') {
68                    // ends in /
69                    prest.shift();
70                    grest.shift();
71                }
72                const p = p1 + '/';
73                const g = g1 + '/';
74                this.#patternList = [p, ...prest];
75                this.#globList = [g, ...grest];
76                this.length = this.#patternList.length;
77            }
78        }
79    }
80    /**
81     * The first entry in the parsed list of patterns
82     */
83    pattern() {
84        return this.#patternList[this.#index];
85    }
86    /**
87     * true of if pattern() returns a string
88     */
89    isString() {
90        return typeof this.#patternList[this.#index] === 'string';
91    }
92    /**
93     * true of if pattern() returns GLOBSTAR
94     */
95    isGlobstar() {
96        return this.#patternList[this.#index] === GLOBSTAR;
97    }
98    /**
99     * true if pattern() returns a regexp
100     */
101    isRegExp() {
102        return this.#patternList[this.#index] instanceof RegExp;
103    }
104    /**
105     * The /-joined set of glob parts that make up this pattern
106     */
107    globString() {
108        return (this.#globString =
109            this.#globString ||
110                (this.#index === 0
111                    ? this.isAbsolute()
112                        ? this.#globList[0] + this.#globList.slice(1).join('/')
113                        : this.#globList.join('/')
114                    : this.#globList.slice(this.#index).join('/')));
115    }
116    /**
117     * true if there are more pattern parts after this one
118     */
119    hasMore() {
120        return this.length > this.#index + 1;
121    }
122    /**
123     * The rest of the pattern after this part, or null if this is the end
124     */
125    rest() {
126        if (this.#rest !== undefined)
127            return this.#rest;
128        if (!this.hasMore())
129            return (this.#rest = null);
130        this.#rest = new Pattern(this.#patternList, this.#globList, this.#index + 1, this.#platform);
131        this.#rest.#isAbsolute = this.#isAbsolute;
132        this.#rest.#isUNC = this.#isUNC;
133        this.#rest.#isDrive = this.#isDrive;
134        return this.#rest;
135    }
136    /**
137     * true if the pattern represents a //unc/path/ on windows
138     */
139    isUNC() {
140        const pl = this.#patternList;
141        return this.#isUNC !== undefined
142            ? this.#isUNC
143            : (this.#isUNC =
144                this.#platform === 'win32' &&
145                    this.#index === 0 &&
146                    pl[0] === '' &&
147                    pl[1] === '' &&
148                    typeof pl[2] === 'string' &&
149                    !!pl[2] &&
150                    typeof pl[3] === 'string' &&
151                    !!pl[3]);
152    }
153    // pattern like C:/...
154    // split = ['C:', ...]
155    // XXX: would be nice to handle patterns like `c:*` to test the cwd
156    // in c: for *, but I don't know of a way to even figure out what that
157    // cwd is without actually chdir'ing into it?
158    /**
159     * True if the pattern starts with a drive letter on Windows
160     */
161    isDrive() {
162        const pl = this.#patternList;
163        return this.#isDrive !== undefined
164            ? this.#isDrive
165            : (this.#isDrive =
166                this.#platform === 'win32' &&
167                    this.#index === 0 &&
168                    this.length > 1 &&
169                    typeof pl[0] === 'string' &&
170                    /^[a-z]:$/i.test(pl[0]));
171    }
172    // pattern = '/' or '/...' or '/x/...'
173    // split = ['', ''] or ['', ...] or ['', 'x', ...]
174    // Drive and UNC both considered absolute on windows
175    /**
176     * True if the pattern is rooted on an absolute path
177     */
178    isAbsolute() {
179        const pl = this.#patternList;
180        return this.#isAbsolute !== undefined
181            ? this.#isAbsolute
182            : (this.#isAbsolute =
183                (pl[0] === '' && pl.length > 1) ||
184                    this.isDrive() ||
185                    this.isUNC());
186    }
187    /**
188     * consume the root of the pattern, and return it
189     */
190    root() {
191        const p = this.#patternList[0];
192        return typeof p === 'string' && this.isAbsolute() && this.#index === 0
193            ? p
194            : '';
195    }
196    /**
197     * Check to see if the current globstar pattern is allowed to follow
198     * a symbolic link.
199     */
200    checkFollowGlobstar() {
201        return !(this.#index === 0 ||
202            !this.isGlobstar() ||
203            !this.#followGlobstar);
204    }
205    /**
206     * Mark that the current globstar pattern is following a symbolic link
207     */
208    markFollowGlobstar() {
209        if (this.#index === 0 || !this.isGlobstar() || !this.#followGlobstar)
210            return false;
211        this.#followGlobstar = false;
212        return true;
213    }
214}
215//# sourceMappingURL=pattern.js.map