Legend:
- Unmodified
- Added
- Removed
-
imaps-frontend/node_modules/rollup/dist/shared/index.js
rd565449 r0c6b92a 1 1 /* 2 2 @license 3 Rollup.js v4.2 0.04 Sat, 03 Aug 2024 04:48:21 GMT - commit df12edfea6e9c1a71bda1a01bed1ab787b7514d53 Rollup.js v4.27.4 4 Sat, 23 Nov 2024 06:59:50 GMT - commit e805b546405a4e6cfccd3fe73e9f4df770023824 5 5 6 6 https://github.com/rollup/rollup … … 11 11 12 12 const rollup = require('./rollup.js'); 13 const require$$0$1 = require('fs'); 13 const require$$0$1 = require('path'); 14 const require$$0$2 = require('fs'); 14 15 const require$$2 = require('util'); 15 16 const require$$1 = require('stream'); 16 const require$$0$2 = require('path');17 17 const require$$2$1 = require('os'); 18 18 const fseventsImporter = require('./fsevents-importer.js'); 19 19 const require$$0$3 = require('events'); 20 20 21 var chokidar = {}; 22 23 const fs$3 = require$$0$1; 24 const { Readable } = require$$1; 25 const sysPath$3 = require$$0$2; 26 const { promisify: promisify$3 } = require$$2; 27 const picomatch$1 = rollup.picomatch; 28 29 const readdir$1 = promisify$3(fs$3.readdir); 30 const stat$3 = promisify$3(fs$3.stat); 31 const lstat$2 = promisify$3(fs$3.lstat); 32 const realpath$1 = promisify$3(fs$3.realpath); 33 34 /** 35 * @typedef {Object} EntryInfo 36 * @property {String} path 37 * @property {String} fullPath 38 * @property {fs.Stats=} stats 39 * @property {fs.Dirent=} dirent 40 * @property {String} basename 41 */ 42 43 const BANG$2 = '!'; 44 const RECURSIVE_ERROR_CODE = 'READDIRP_RECURSIVE_ERROR'; 45 const NORMAL_FLOW_ERRORS = new Set(['ENOENT', 'EPERM', 'EACCES', 'ELOOP', RECURSIVE_ERROR_CODE]); 46 const FILE_TYPE = 'files'; 47 const DIR_TYPE = 'directories'; 48 const FILE_DIR_TYPE = 'files_directories'; 49 const EVERYTHING_TYPE = 'all'; 50 const ALL_TYPES = [FILE_TYPE, DIR_TYPE, FILE_DIR_TYPE, EVERYTHING_TYPE]; 51 52 const isNormalFlowError = error => NORMAL_FLOW_ERRORS.has(error.code); 53 const [maj, min] = process.versions.node.split('.').slice(0, 2).map(n => Number.parseInt(n, 10)); 54 const wantBigintFsStats = process.platform === 'win32' && (maj > 10 || (maj === 10 && min >= 5)); 55 56 const normalizeFilter = filter => { 57 if (filter === undefined) return; 58 if (typeof filter === 'function') return filter; 59 60 if (typeof filter === 'string') { 61 const glob = picomatch$1(filter.trim()); 62 return entry => glob(entry.basename); 63 } 64 65 if (Array.isArray(filter)) { 66 const positive = []; 67 const negative = []; 68 for (const item of filter) { 69 const trimmed = item.trim(); 70 if (trimmed.charAt(0) === BANG$2) { 71 negative.push(picomatch$1(trimmed.slice(1))); 72 } else { 73 positive.push(picomatch$1(trimmed)); 74 } 75 } 76 77 if (negative.length > 0) { 78 if (positive.length > 0) { 79 return entry => 80 positive.some(f => f(entry.basename)) && !negative.some(f => f(entry.basename)); 81 } 82 return entry => !negative.some(f => f(entry.basename)); 83 } 84 return entry => positive.some(f => f(entry.basename)); 85 } 86 }; 87 88 class ReaddirpStream extends Readable { 89 static get defaultOptions() { 90 return { 91 root: '.', 92 /* eslint-disable no-unused-vars */ 93 fileFilter: (path) => true, 94 directoryFilter: (path) => true, 95 /* eslint-enable no-unused-vars */ 96 type: FILE_TYPE, 97 lstat: false, 98 depth: 2147483648, 99 alwaysStat: false 100 }; 101 } 102 103 constructor(options = {}) { 104 super({ 105 objectMode: true, 106 autoDestroy: true, 107 highWaterMark: options.highWaterMark || 4096 108 }); 109 const opts = { ...ReaddirpStream.defaultOptions, ...options }; 110 const { root, type } = opts; 111 112 this._fileFilter = normalizeFilter(opts.fileFilter); 113 this._directoryFilter = normalizeFilter(opts.directoryFilter); 114 115 const statMethod = opts.lstat ? lstat$2 : stat$3; 116 // Use bigint stats if it's windows and stat() supports options (node 10+). 117 if (wantBigintFsStats) { 118 this._stat = path => statMethod(path, { bigint: true }); 119 } else { 120 this._stat = statMethod; 121 } 122 123 this._maxDepth = opts.depth; 124 this._wantsDir = [DIR_TYPE, FILE_DIR_TYPE, EVERYTHING_TYPE].includes(type); 125 this._wantsFile = [FILE_TYPE, FILE_DIR_TYPE, EVERYTHING_TYPE].includes(type); 126 this._wantsEverything = type === EVERYTHING_TYPE; 127 this._root = sysPath$3.resolve(root); 128 this._isDirent = ('Dirent' in fs$3) && !opts.alwaysStat; 129 this._statsProp = this._isDirent ? 'dirent' : 'stats'; 130 this._rdOptions = { encoding: 'utf8', withFileTypes: this._isDirent }; 131 132 // Launch stream with one parent, the root dir. 133 this.parents = [this._exploreDir(root, 1)]; 134 this.reading = false; 135 this.parent = undefined; 136 } 137 138 async _read(batch) { 139 if (this.reading) return; 140 this.reading = true; 141 142 try { 143 while (!this.destroyed && batch > 0) { 144 const { path, depth, files = [] } = this.parent || {}; 145 146 if (files.length > 0) { 147 const slice = files.splice(0, batch).map(dirent => this._formatEntry(dirent, path)); 148 for (const entry of await Promise.all(slice)) { 149 if (this.destroyed) return; 150 151 const entryType = await this._getEntryType(entry); 152 if (entryType === 'directory' && this._directoryFilter(entry)) { 153 if (depth <= this._maxDepth) { 154 this.parents.push(this._exploreDir(entry.fullPath, depth + 1)); 155 } 156 157 if (this._wantsDir) { 158 this.push(entry); 159 batch--; 160 } 161 } else if ((entryType === 'file' || this._includeAsFile(entry)) && this._fileFilter(entry)) { 162 if (this._wantsFile) { 163 this.push(entry); 164 batch--; 165 } 166 } 167 } 168 } else { 169 const parent = this.parents.pop(); 170 if (!parent) { 171 this.push(null); 172 break; 173 } 174 this.parent = await parent; 175 if (this.destroyed) return; 176 } 177 } 178 } catch (error) { 179 this.destroy(error); 180 } finally { 181 this.reading = false; 182 } 183 } 184 185 async _exploreDir(path, depth) { 186 let files; 187 try { 188 files = await readdir$1(path, this._rdOptions); 189 } catch (error) { 190 this._onError(error); 191 } 192 return { files, depth, path }; 193 } 194 195 async _formatEntry(dirent, path) { 196 let entry; 197 try { 198 const basename = this._isDirent ? dirent.name : dirent; 199 const fullPath = sysPath$3.resolve(sysPath$3.join(path, basename)); 200 entry = { path: sysPath$3.relative(this._root, fullPath), fullPath, basename }; 201 entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath); 202 } catch (err) { 203 this._onError(err); 204 } 205 return entry; 206 } 207 208 _onError(err) { 209 if (isNormalFlowError(err) && !this.destroyed) { 210 this.emit('warn', err); 211 } else { 212 this.destroy(err); 213 } 214 } 215 216 async _getEntryType(entry) { 217 // entry may be undefined, because a warning or an error were emitted 218 // and the statsProp is undefined 219 const stats = entry && entry[this._statsProp]; 220 if (!stats) { 221 return; 222 } 223 if (stats.isFile()) { 224 return 'file'; 225 } 226 if (stats.isDirectory()) { 227 return 'directory'; 228 } 229 if (stats && stats.isSymbolicLink()) { 230 const full = entry.fullPath; 231 try { 232 const entryRealPath = await realpath$1(full); 233 const entryRealPathStats = await lstat$2(entryRealPath); 234 if (entryRealPathStats.isFile()) { 235 return 'file'; 236 } 237 if (entryRealPathStats.isDirectory()) { 238 const len = entryRealPath.length; 239 if (full.startsWith(entryRealPath) && full.substr(len, 1) === sysPath$3.sep) { 240 const recursiveError = new Error( 241 `Circular symlink detected: "${full}" points to "${entryRealPath}"` 242 ); 243 recursiveError.code = RECURSIVE_ERROR_CODE; 244 return this._onError(recursiveError); 245 } 246 return 'directory'; 247 } 248 } catch (error) { 249 this._onError(error); 250 } 251 } 252 } 253 254 _includeAsFile(entry) { 255 const stats = entry && entry[this._statsProp]; 256 257 return stats && this._wantsEverything && !stats.isDirectory(); 258 } 21 var chokidar$1 = {}; 22 23 var utils$2 = {}; 24 25 var constants$3; 26 var hasRequiredConstants$3; 27 28 function requireConstants$3 () { 29 if (hasRequiredConstants$3) return constants$3; 30 hasRequiredConstants$3 = 1; 31 32 const path = require$$0$1; 33 const WIN_SLASH = '\\\\/'; 34 const WIN_NO_SLASH = `[^${WIN_SLASH}]`; 35 36 /** 37 * Posix glob regex 38 */ 39 40 const DOT_LITERAL = '\\.'; 41 const PLUS_LITERAL = '\\+'; 42 const QMARK_LITERAL = '\\?'; 43 const SLASH_LITERAL = '\\/'; 44 const ONE_CHAR = '(?=.)'; 45 const QMARK = '[^/]'; 46 const END_ANCHOR = `(?:${SLASH_LITERAL}|$)`; 47 const START_ANCHOR = `(?:^|${SLASH_LITERAL})`; 48 const DOTS_SLASH = `${DOT_LITERAL}{1,2}${END_ANCHOR}`; 49 const NO_DOT = `(?!${DOT_LITERAL})`; 50 const NO_DOTS = `(?!${START_ANCHOR}${DOTS_SLASH})`; 51 const NO_DOT_SLASH = `(?!${DOT_LITERAL}{0,1}${END_ANCHOR})`; 52 const NO_DOTS_SLASH = `(?!${DOTS_SLASH})`; 53 const QMARK_NO_DOT = `[^.${SLASH_LITERAL}]`; 54 const STAR = `${QMARK}*?`; 55 56 const POSIX_CHARS = { 57 DOT_LITERAL, 58 PLUS_LITERAL, 59 QMARK_LITERAL, 60 SLASH_LITERAL, 61 ONE_CHAR, 62 QMARK, 63 END_ANCHOR, 64 DOTS_SLASH, 65 NO_DOT, 66 NO_DOTS, 67 NO_DOT_SLASH, 68 NO_DOTS_SLASH, 69 QMARK_NO_DOT, 70 STAR, 71 START_ANCHOR 72 }; 73 74 /** 75 * Windows glob regex 76 */ 77 78 const WINDOWS_CHARS = { 79 ...POSIX_CHARS, 80 81 SLASH_LITERAL: `[${WIN_SLASH}]`, 82 QMARK: WIN_NO_SLASH, 83 STAR: `${WIN_NO_SLASH}*?`, 84 DOTS_SLASH: `${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$)`, 85 NO_DOT: `(?!${DOT_LITERAL})`, 86 NO_DOTS: `(?!(?:^|[${WIN_SLASH}])${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`, 87 NO_DOT_SLASH: `(?!${DOT_LITERAL}{0,1}(?:[${WIN_SLASH}]|$))`, 88 NO_DOTS_SLASH: `(?!${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`, 89 QMARK_NO_DOT: `[^.${WIN_SLASH}]`, 90 START_ANCHOR: `(?:^|[${WIN_SLASH}])`, 91 END_ANCHOR: `(?:[${WIN_SLASH}]|$)` 92 }; 93 94 /** 95 * POSIX Bracket Regex 96 */ 97 98 const POSIX_REGEX_SOURCE = { 99 alnum: 'a-zA-Z0-9', 100 alpha: 'a-zA-Z', 101 ascii: '\\x00-\\x7F', 102 blank: ' \\t', 103 cntrl: '\\x00-\\x1F\\x7F', 104 digit: '0-9', 105 graph: '\\x21-\\x7E', 106 lower: 'a-z', 107 print: '\\x20-\\x7E ', 108 punct: '\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~', 109 space: ' \\t\\r\\n\\v\\f', 110 upper: 'A-Z', 111 word: 'A-Za-z0-9_', 112 xdigit: 'A-Fa-f0-9' 113 }; 114 115 constants$3 = { 116 MAX_LENGTH: 1024 * 64, 117 POSIX_REGEX_SOURCE, 118 119 // regular expressions 120 REGEX_BACKSLASH: /\\(?![*+?^${}(|)[\]])/g, 121 REGEX_NON_SPECIAL_CHARS: /^[^@![\].,$*+?^{}()|\\/]+/, 122 REGEX_SPECIAL_CHARS: /[-*+?.^${}(|)[\]]/, 123 REGEX_SPECIAL_CHARS_BACKREF: /(\\?)((\W)(\3*))/g, 124 REGEX_SPECIAL_CHARS_GLOBAL: /([-*+?.^${}(|)[\]])/g, 125 REGEX_REMOVE_BACKSLASH: /(?:\[.*?[^\\]\]|\\(?=.))/g, 126 127 // Replace globs with equivalent patterns to reduce parsing time. 128 REPLACEMENTS: { 129 '***': '*', 130 '**/**': '**', 131 '**/**/**': '**' 132 }, 133 134 // Digits 135 CHAR_0: 48, /* 0 */ 136 CHAR_9: 57, /* 9 */ 137 138 // Alphabet chars. 139 CHAR_UPPERCASE_A: 65, /* A */ 140 CHAR_LOWERCASE_A: 97, /* a */ 141 CHAR_UPPERCASE_Z: 90, /* Z */ 142 CHAR_LOWERCASE_Z: 122, /* z */ 143 144 CHAR_LEFT_PARENTHESES: 40, /* ( */ 145 CHAR_RIGHT_PARENTHESES: 41, /* ) */ 146 147 CHAR_ASTERISK: 42, /* * */ 148 149 // Non-alphabetic chars. 150 CHAR_AMPERSAND: 38, /* & */ 151 CHAR_AT: 64, /* @ */ 152 CHAR_BACKWARD_SLASH: 92, /* \ */ 153 CHAR_CARRIAGE_RETURN: 13, /* \r */ 154 CHAR_CIRCUMFLEX_ACCENT: 94, /* ^ */ 155 CHAR_COLON: 58, /* : */ 156 CHAR_COMMA: 44, /* , */ 157 CHAR_DOT: 46, /* . */ 158 CHAR_DOUBLE_QUOTE: 34, /* " */ 159 CHAR_EQUAL: 61, /* = */ 160 CHAR_EXCLAMATION_MARK: 33, /* ! */ 161 CHAR_FORM_FEED: 12, /* \f */ 162 CHAR_FORWARD_SLASH: 47, /* / */ 163 CHAR_GRAVE_ACCENT: 96, /* ` */ 164 CHAR_HASH: 35, /* # */ 165 CHAR_HYPHEN_MINUS: 45, /* - */ 166 CHAR_LEFT_ANGLE_BRACKET: 60, /* < */ 167 CHAR_LEFT_CURLY_BRACE: 123, /* { */ 168 CHAR_LEFT_SQUARE_BRACKET: 91, /* [ */ 169 CHAR_LINE_FEED: 10, /* \n */ 170 CHAR_NO_BREAK_SPACE: 160, /* \u00A0 */ 171 CHAR_PERCENT: 37, /* % */ 172 CHAR_PLUS: 43, /* + */ 173 CHAR_QUESTION_MARK: 63, /* ? */ 174 CHAR_RIGHT_ANGLE_BRACKET: 62, /* > */ 175 CHAR_RIGHT_CURLY_BRACE: 125, /* } */ 176 CHAR_RIGHT_SQUARE_BRACKET: 93, /* ] */ 177 CHAR_SEMICOLON: 59, /* ; */ 178 CHAR_SINGLE_QUOTE: 39, /* ' */ 179 CHAR_SPACE: 32, /* */ 180 CHAR_TAB: 9, /* \t */ 181 CHAR_UNDERSCORE: 95, /* _ */ 182 CHAR_VERTICAL_LINE: 124, /* | */ 183 CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279, /* \uFEFF */ 184 185 SEP: path.sep, 186 187 /** 188 * Create EXTGLOB_CHARS 189 */ 190 191 extglobChars(chars) { 192 return { 193 '!': { type: 'negate', open: '(?:(?!(?:', close: `))${chars.STAR})` }, 194 '?': { type: 'qmark', open: '(?:', close: ')?' }, 195 '+': { type: 'plus', open: '(?:', close: ')+' }, 196 '*': { type: 'star', open: '(?:', close: ')*' }, 197 '@': { type: 'at', open: '(?:', close: ')' } 198 }; 199 }, 200 201 /** 202 * Create GLOB_CHARS 203 */ 204 205 globChars(win32) { 206 return win32 === true ? WINDOWS_CHARS : POSIX_CHARS; 207 } 208 }; 209 return constants$3; 259 210 } 260 211 261 /** 262 * @typedef {Object} ReaddirpArguments 263 * @property {Function=} fileFilter 264 * @property {Function=} directoryFilter 265 * @property {String=} type 266 * @property {Number=} depth 267 * @property {String=} root 268 * @property {Boolean=} lstat 269 * @property {Boolean=} bigint 270 */ 271 272 /** 273 * Main function which ends up calling readdirRec and reads all files and directories in given root recursively. 274 * @param {String} root Root directory 275 * @param {ReaddirpArguments=} options Options to specify root (start directory), filters and recursion depth 276 */ 277 const readdirp$1 = (root, options = {}) => { 278 let type = options.entryType || options.type; 279 if (type === 'both') type = FILE_DIR_TYPE; // backwards-compatibility 280 if (type) options.type = type; 281 if (!root) { 282 throw new Error('readdirp: root argument is required. Usage: readdirp(root, options)'); 283 } else if (typeof root !== 'string') { 284 throw new TypeError('readdirp: root argument must be a string. Usage: readdirp(root, options)'); 285 } else if (type && !ALL_TYPES.includes(type)) { 286 throw new Error(`readdirp: Invalid type passed. Use one of ${ALL_TYPES.join(', ')}`); 287 } 288 289 options.root = root; 290 return new ReaddirpStream(options); 291 }; 292 293 const readdirpPromise = (root, options = {}) => { 294 return new Promise((resolve, reject) => { 295 const files = []; 296 readdirp$1(root, options) 297 .on('data', entry => files.push(entry)) 298 .on('end', () => resolve(files)) 299 .on('error', error => reject(error)); 300 }); 301 }; 302 303 readdirp$1.promise = readdirpPromise; 304 readdirp$1.ReaddirpStream = ReaddirpStream; 305 readdirp$1.default = readdirp$1; 306 307 var readdirp_1 = readdirp$1; 308 309 var anymatch$2 = {exports: {}}; 212 var hasRequiredUtils$2; 213 214 function requireUtils$2 () { 215 if (hasRequiredUtils$2) return utils$2; 216 hasRequiredUtils$2 = 1; 217 (function (exports) { 218 219 const path = require$$0$1; 220 const win32 = process.platform === 'win32'; 221 const { 222 REGEX_BACKSLASH, 223 REGEX_REMOVE_BACKSLASH, 224 REGEX_SPECIAL_CHARS, 225 REGEX_SPECIAL_CHARS_GLOBAL 226 } = /*@__PURE__*/ requireConstants$3(); 227 228 exports.isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); 229 exports.hasRegexChars = str => REGEX_SPECIAL_CHARS.test(str); 230 exports.isRegexChar = str => str.length === 1 && exports.hasRegexChars(str); 231 exports.escapeRegex = str => str.replace(REGEX_SPECIAL_CHARS_GLOBAL, '\\$1'); 232 exports.toPosixSlashes = str => str.replace(REGEX_BACKSLASH, '/'); 233 234 exports.removeBackslashes = str => { 235 return str.replace(REGEX_REMOVE_BACKSLASH, match => { 236 return match === '\\' ? '' : match; 237 }); 238 }; 239 240 exports.supportsLookbehinds = () => { 241 const segs = process.version.slice(1).split('.').map(Number); 242 if (segs.length === 3 && segs[0] >= 9 || (segs[0] === 8 && segs[1] >= 10)) { 243 return true; 244 } 245 return false; 246 }; 247 248 exports.isWindows = options => { 249 if (options && typeof options.windows === 'boolean') { 250 return options.windows; 251 } 252 return win32 === true || path.sep === '\\'; 253 }; 254 255 exports.escapeLast = (input, char, lastIdx) => { 256 const idx = input.lastIndexOf(char, lastIdx); 257 if (idx === -1) return input; 258 if (input[idx - 1] === '\\') return exports.escapeLast(input, char, idx - 1); 259 return `${input.slice(0, idx)}\\${input.slice(idx)}`; 260 }; 261 262 exports.removePrefix = (input, state = {}) => { 263 let output = input; 264 if (output.startsWith('./')) { 265 output = output.slice(2); 266 state.prefix = './'; 267 } 268 return output; 269 }; 270 271 exports.wrapOutput = (input, state = {}, options = {}) => { 272 const prepend = options.contains ? '' : '^'; 273 const append = options.contains ? '' : '$'; 274 275 let output = `${prepend}(?:${input})${append}`; 276 if (state.negated === true) { 277 output = `(?:^(?!${output}).*$)`; 278 } 279 return output; 280 }; 281 } (utils$2)); 282 return utils$2; 283 } 284 285 var scan_1$1; 286 var hasRequiredScan$1; 287 288 function requireScan$1 () { 289 if (hasRequiredScan$1) return scan_1$1; 290 hasRequiredScan$1 = 1; 291 292 const utils = /*@__PURE__*/ requireUtils$2(); 293 const { 294 CHAR_ASTERISK, /* * */ 295 CHAR_AT, /* @ */ 296 CHAR_BACKWARD_SLASH, /* \ */ 297 CHAR_COMMA, /* , */ 298 CHAR_DOT, /* . */ 299 CHAR_EXCLAMATION_MARK, /* ! */ 300 CHAR_FORWARD_SLASH, /* / */ 301 CHAR_LEFT_CURLY_BRACE, /* { */ 302 CHAR_LEFT_PARENTHESES, /* ( */ 303 CHAR_LEFT_SQUARE_BRACKET, /* [ */ 304 CHAR_PLUS, /* + */ 305 CHAR_QUESTION_MARK, /* ? */ 306 CHAR_RIGHT_CURLY_BRACE, /* } */ 307 CHAR_RIGHT_PARENTHESES, /* ) */ 308 CHAR_RIGHT_SQUARE_BRACKET /* ] */ 309 } = /*@__PURE__*/ requireConstants$3(); 310 311 const isPathSeparator = code => { 312 return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; 313 }; 314 315 const depth = token => { 316 if (token.isPrefix !== true) { 317 token.depth = token.isGlobstar ? Infinity : 1; 318 } 319 }; 320 321 /** 322 * Quickly scans a glob pattern and returns an object with a handful of 323 * useful properties, like `isGlob`, `path` (the leading non-glob, if it exists), 324 * `glob` (the actual pattern), `negated` (true if the path starts with `!` but not 325 * with `!(`) and `negatedExtglob` (true if the path starts with `!(`). 326 * 327 * ```js 328 * const pm = require('picomatch'); 329 * console.log(pm.scan('foo/bar/*.js')); 330 * { isGlob: true, input: 'foo/bar/*.js', base: 'foo/bar', glob: '*.js' } 331 * ``` 332 * @param {String} `str` 333 * @param {Object} `options` 334 * @return {Object} Returns an object with tokens and regex source string. 335 * @api public 336 */ 337 338 const scan = (input, options) => { 339 const opts = options || {}; 340 341 const length = input.length - 1; 342 const scanToEnd = opts.parts === true || opts.scanToEnd === true; 343 const slashes = []; 344 const tokens = []; 345 const parts = []; 346 347 let str = input; 348 let index = -1; 349 let start = 0; 350 let lastIndex = 0; 351 let isBrace = false; 352 let isBracket = false; 353 let isGlob = false; 354 let isExtglob = false; 355 let isGlobstar = false; 356 let braceEscaped = false; 357 let backslashes = false; 358 let negated = false; 359 let negatedExtglob = false; 360 let finished = false; 361 let braces = 0; 362 let prev; 363 let code; 364 let token = { value: '', depth: 0, isGlob: false }; 365 366 const eos = () => index >= length; 367 const peek = () => str.charCodeAt(index + 1); 368 const advance = () => { 369 prev = code; 370 return str.charCodeAt(++index); 371 }; 372 373 while (index < length) { 374 code = advance(); 375 let next; 376 377 if (code === CHAR_BACKWARD_SLASH) { 378 backslashes = token.backslashes = true; 379 code = advance(); 380 381 if (code === CHAR_LEFT_CURLY_BRACE) { 382 braceEscaped = true; 383 } 384 continue; 385 } 386 387 if (braceEscaped === true || code === CHAR_LEFT_CURLY_BRACE) { 388 braces++; 389 390 while (eos() !== true && (code = advance())) { 391 if (code === CHAR_BACKWARD_SLASH) { 392 backslashes = token.backslashes = true; 393 advance(); 394 continue; 395 } 396 397 if (code === CHAR_LEFT_CURLY_BRACE) { 398 braces++; 399 continue; 400 } 401 402 if (braceEscaped !== true && code === CHAR_DOT && (code = advance()) === CHAR_DOT) { 403 isBrace = token.isBrace = true; 404 isGlob = token.isGlob = true; 405 finished = true; 406 407 if (scanToEnd === true) { 408 continue; 409 } 410 411 break; 412 } 413 414 if (braceEscaped !== true && code === CHAR_COMMA) { 415 isBrace = token.isBrace = true; 416 isGlob = token.isGlob = true; 417 finished = true; 418 419 if (scanToEnd === true) { 420 continue; 421 } 422 423 break; 424 } 425 426 if (code === CHAR_RIGHT_CURLY_BRACE) { 427 braces--; 428 429 if (braces === 0) { 430 braceEscaped = false; 431 isBrace = token.isBrace = true; 432 finished = true; 433 break; 434 } 435 } 436 } 437 438 if (scanToEnd === true) { 439 continue; 440 } 441 442 break; 443 } 444 445 if (code === CHAR_FORWARD_SLASH) { 446 slashes.push(index); 447 tokens.push(token); 448 token = { value: '', depth: 0, isGlob: false }; 449 450 if (finished === true) continue; 451 if (prev === CHAR_DOT && index === (start + 1)) { 452 start += 2; 453 continue; 454 } 455 456 lastIndex = index + 1; 457 continue; 458 } 459 460 if (opts.noext !== true) { 461 const isExtglobChar = code === CHAR_PLUS 462 || code === CHAR_AT 463 || code === CHAR_ASTERISK 464 || code === CHAR_QUESTION_MARK 465 || code === CHAR_EXCLAMATION_MARK; 466 467 if (isExtglobChar === true && peek() === CHAR_LEFT_PARENTHESES) { 468 isGlob = token.isGlob = true; 469 isExtglob = token.isExtglob = true; 470 finished = true; 471 if (code === CHAR_EXCLAMATION_MARK && index === start) { 472 negatedExtglob = true; 473 } 474 475 if (scanToEnd === true) { 476 while (eos() !== true && (code = advance())) { 477 if (code === CHAR_BACKWARD_SLASH) { 478 backslashes = token.backslashes = true; 479 code = advance(); 480 continue; 481 } 482 483 if (code === CHAR_RIGHT_PARENTHESES) { 484 isGlob = token.isGlob = true; 485 finished = true; 486 break; 487 } 488 } 489 continue; 490 } 491 break; 492 } 493 } 494 495 if (code === CHAR_ASTERISK) { 496 if (prev === CHAR_ASTERISK) isGlobstar = token.isGlobstar = true; 497 isGlob = token.isGlob = true; 498 finished = true; 499 500 if (scanToEnd === true) { 501 continue; 502 } 503 break; 504 } 505 506 if (code === CHAR_QUESTION_MARK) { 507 isGlob = token.isGlob = true; 508 finished = true; 509 510 if (scanToEnd === true) { 511 continue; 512 } 513 break; 514 } 515 516 if (code === CHAR_LEFT_SQUARE_BRACKET) { 517 while (eos() !== true && (next = advance())) { 518 if (next === CHAR_BACKWARD_SLASH) { 519 backslashes = token.backslashes = true; 520 advance(); 521 continue; 522 } 523 524 if (next === CHAR_RIGHT_SQUARE_BRACKET) { 525 isBracket = token.isBracket = true; 526 isGlob = token.isGlob = true; 527 finished = true; 528 break; 529 } 530 } 531 532 if (scanToEnd === true) { 533 continue; 534 } 535 536 break; 537 } 538 539 if (opts.nonegate !== true && code === CHAR_EXCLAMATION_MARK && index === start) { 540 negated = token.negated = true; 541 start++; 542 continue; 543 } 544 545 if (opts.noparen !== true && code === CHAR_LEFT_PARENTHESES) { 546 isGlob = token.isGlob = true; 547 548 if (scanToEnd === true) { 549 while (eos() !== true && (code = advance())) { 550 if (code === CHAR_LEFT_PARENTHESES) { 551 backslashes = token.backslashes = true; 552 code = advance(); 553 continue; 554 } 555 556 if (code === CHAR_RIGHT_PARENTHESES) { 557 finished = true; 558 break; 559 } 560 } 561 continue; 562 } 563 break; 564 } 565 566 if (isGlob === true) { 567 finished = true; 568 569 if (scanToEnd === true) { 570 continue; 571 } 572 573 break; 574 } 575 } 576 577 if (opts.noext === true) { 578 isExtglob = false; 579 isGlob = false; 580 } 581 582 let base = str; 583 let prefix = ''; 584 let glob = ''; 585 586 if (start > 0) { 587 prefix = str.slice(0, start); 588 str = str.slice(start); 589 lastIndex -= start; 590 } 591 592 if (base && isGlob === true && lastIndex > 0) { 593 base = str.slice(0, lastIndex); 594 glob = str.slice(lastIndex); 595 } else if (isGlob === true) { 596 base = ''; 597 glob = str; 598 } else { 599 base = str; 600 } 601 602 if (base && base !== '' && base !== '/' && base !== str) { 603 if (isPathSeparator(base.charCodeAt(base.length - 1))) { 604 base = base.slice(0, -1); 605 } 606 } 607 608 if (opts.unescape === true) { 609 if (glob) glob = utils.removeBackslashes(glob); 610 611 if (base && backslashes === true) { 612 base = utils.removeBackslashes(base); 613 } 614 } 615 616 const state = { 617 prefix, 618 input, 619 start, 620 base, 621 glob, 622 isBrace, 623 isBracket, 624 isGlob, 625 isExtglob, 626 isGlobstar, 627 negated, 628 negatedExtglob 629 }; 630 631 if (opts.tokens === true) { 632 state.maxDepth = 0; 633 if (!isPathSeparator(code)) { 634 tokens.push(token); 635 } 636 state.tokens = tokens; 637 } 638 639 if (opts.parts === true || opts.tokens === true) { 640 let prevIndex; 641 642 for (let idx = 0; idx < slashes.length; idx++) { 643 const n = prevIndex ? prevIndex + 1 : start; 644 const i = slashes[idx]; 645 const value = input.slice(n, i); 646 if (opts.tokens) { 647 if (idx === 0 && start !== 0) { 648 tokens[idx].isPrefix = true; 649 tokens[idx].value = prefix; 650 } else { 651 tokens[idx].value = value; 652 } 653 depth(tokens[idx]); 654 state.maxDepth += tokens[idx].depth; 655 } 656 if (idx !== 0 || value !== '') { 657 parts.push(value); 658 } 659 prevIndex = i; 660 } 661 662 if (prevIndex && prevIndex + 1 < input.length) { 663 const value = input.slice(prevIndex + 1); 664 parts.push(value); 665 666 if (opts.tokens) { 667 tokens[tokens.length - 1].value = value; 668 depth(tokens[tokens.length - 1]); 669 state.maxDepth += tokens[tokens.length - 1].depth; 670 } 671 } 672 673 state.slashes = slashes; 674 state.parts = parts; 675 } 676 677 return state; 678 }; 679 680 scan_1$1 = scan; 681 return scan_1$1; 682 } 683 684 var parse_1$2; 685 var hasRequiredParse$2; 686 687 function requireParse$2 () { 688 if (hasRequiredParse$2) return parse_1$2; 689 hasRequiredParse$2 = 1; 690 691 const constants = /*@__PURE__*/ requireConstants$3(); 692 const utils = /*@__PURE__*/ requireUtils$2(); 693 694 /** 695 * Constants 696 */ 697 698 const { 699 MAX_LENGTH, 700 POSIX_REGEX_SOURCE, 701 REGEX_NON_SPECIAL_CHARS, 702 REGEX_SPECIAL_CHARS_BACKREF, 703 REPLACEMENTS 704 } = constants; 705 706 /** 707 * Helpers 708 */ 709 710 const expandRange = (args, options) => { 711 if (typeof options.expandRange === 'function') { 712 return options.expandRange(...args, options); 713 } 714 715 args.sort(); 716 const value = `[${args.join('-')}]`; 717 718 return value; 719 }; 720 721 /** 722 * Create the message for a syntax error 723 */ 724 725 const syntaxError = (type, char) => { 726 return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`; 727 }; 728 729 /** 730 * Parse the given input string. 731 * @param {String} input 732 * @param {Object} options 733 * @return {Object} 734 */ 735 736 const parse = (input, options) => { 737 if (typeof input !== 'string') { 738 throw new TypeError('Expected a string'); 739 } 740 741 input = REPLACEMENTS[input] || input; 742 743 const opts = { ...options }; 744 const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; 745 746 let len = input.length; 747 if (len > max) { 748 throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`); 749 } 750 751 const bos = { type: 'bos', value: '', output: opts.prepend || '' }; 752 const tokens = [bos]; 753 754 const capture = opts.capture ? '' : '?:'; 755 const win32 = utils.isWindows(options); 756 757 // create constants based on platform, for windows or posix 758 const PLATFORM_CHARS = constants.globChars(win32); 759 const EXTGLOB_CHARS = constants.extglobChars(PLATFORM_CHARS); 760 761 const { 762 DOT_LITERAL, 763 PLUS_LITERAL, 764 SLASH_LITERAL, 765 ONE_CHAR, 766 DOTS_SLASH, 767 NO_DOT, 768 NO_DOT_SLASH, 769 NO_DOTS_SLASH, 770 QMARK, 771 QMARK_NO_DOT, 772 STAR, 773 START_ANCHOR 774 } = PLATFORM_CHARS; 775 776 const globstar = opts => { 777 return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`; 778 }; 779 780 const nodot = opts.dot ? '' : NO_DOT; 781 const qmarkNoDot = opts.dot ? QMARK : QMARK_NO_DOT; 782 let star = opts.bash === true ? globstar(opts) : STAR; 783 784 if (opts.capture) { 785 star = `(${star})`; 786 } 787 788 // minimatch options support 789 if (typeof opts.noext === 'boolean') { 790 opts.noextglob = opts.noext; 791 } 792 793 const state = { 794 input, 795 index: -1, 796 start: 0, 797 dot: opts.dot === true, 798 consumed: '', 799 output: '', 800 prefix: '', 801 backtrack: false, 802 negated: false, 803 brackets: 0, 804 braces: 0, 805 parens: 0, 806 quotes: 0, 807 globstar: false, 808 tokens 809 }; 810 811 input = utils.removePrefix(input, state); 812 len = input.length; 813 814 const extglobs = []; 815 const braces = []; 816 const stack = []; 817 let prev = bos; 818 let value; 819 820 /** 821 * Tokenizing helpers 822 */ 823 824 const eos = () => state.index === len - 1; 825 const peek = state.peek = (n = 1) => input[state.index + n]; 826 const advance = state.advance = () => input[++state.index] || ''; 827 const remaining = () => input.slice(state.index + 1); 828 const consume = (value = '', num = 0) => { 829 state.consumed += value; 830 state.index += num; 831 }; 832 833 const append = token => { 834 state.output += token.output != null ? token.output : token.value; 835 consume(token.value); 836 }; 837 838 const negate = () => { 839 let count = 1; 840 841 while (peek() === '!' && (peek(2) !== '(' || peek(3) === '?')) { 842 advance(); 843 state.start++; 844 count++; 845 } 846 847 if (count % 2 === 0) { 848 return false; 849 } 850 851 state.negated = true; 852 state.start++; 853 return true; 854 }; 855 856 const increment = type => { 857 state[type]++; 858 stack.push(type); 859 }; 860 861 const decrement = type => { 862 state[type]--; 863 stack.pop(); 864 }; 865 866 /** 867 * Push tokens onto the tokens array. This helper speeds up 868 * tokenizing by 1) helping us avoid backtracking as much as possible, 869 * and 2) helping us avoid creating extra tokens when consecutive 870 * characters are plain text. This improves performance and simplifies 871 * lookbehinds. 872 */ 873 874 const push = tok => { 875 if (prev.type === 'globstar') { 876 const isBrace = state.braces > 0 && (tok.type === 'comma' || tok.type === 'brace'); 877 const isExtglob = tok.extglob === true || (extglobs.length && (tok.type === 'pipe' || tok.type === 'paren')); 878 879 if (tok.type !== 'slash' && tok.type !== 'paren' && !isBrace && !isExtglob) { 880 state.output = state.output.slice(0, -prev.output.length); 881 prev.type = 'star'; 882 prev.value = '*'; 883 prev.output = star; 884 state.output += prev.output; 885 } 886 } 887 888 if (extglobs.length && tok.type !== 'paren') { 889 extglobs[extglobs.length - 1].inner += tok.value; 890 } 891 892 if (tok.value || tok.output) append(tok); 893 if (prev && prev.type === 'text' && tok.type === 'text') { 894 prev.value += tok.value; 895 prev.output = (prev.output || '') + tok.value; 896 return; 897 } 898 899 tok.prev = prev; 900 tokens.push(tok); 901 prev = tok; 902 }; 903 904 const extglobOpen = (type, value) => { 905 const token = { ...EXTGLOB_CHARS[value], conditions: 1, inner: '' }; 906 907 token.prev = prev; 908 token.parens = state.parens; 909 token.output = state.output; 910 const output = (opts.capture ? '(' : '') + token.open; 911 912 increment('parens'); 913 push({ type, value, output: state.output ? '' : ONE_CHAR }); 914 push({ type: 'paren', extglob: true, value: advance(), output }); 915 extglobs.push(token); 916 }; 917 918 const extglobClose = token => { 919 let output = token.close + (opts.capture ? ')' : ''); 920 let rest; 921 922 if (token.type === 'negate') { 923 let extglobStar = star; 924 925 if (token.inner && token.inner.length > 1 && token.inner.includes('/')) { 926 extglobStar = globstar(opts); 927 } 928 929 if (extglobStar !== star || eos() || /^\)+$/.test(remaining())) { 930 output = token.close = `)$))${extglobStar}`; 931 } 932 933 if (token.inner.includes('*') && (rest = remaining()) && /^\.[^\\/.]+$/.test(rest)) { 934 // Any non-magical string (`.ts`) or even nested expression (`.{ts,tsx}`) can follow after the closing parenthesis. 935 // In this case, we need to parse the string and use it in the output of the original pattern. 936 // Suitable patterns: `/!(*.d).ts`, `/!(*.d).{ts,tsx}`, `**/!(*-dbg).@(js)`. 937 // 938 // Disabling the `fastpaths` option due to a problem with parsing strings as `.ts` in the pattern like `**/!(*.d).ts`. 939 const expression = parse(rest, { ...options, fastpaths: false }).output; 940 941 output = token.close = `)${expression})${extglobStar})`; 942 } 943 944 if (token.prev.type === 'bos') { 945 state.negatedExtglob = true; 946 } 947 } 948 949 push({ type: 'paren', extglob: true, value, output }); 950 decrement('parens'); 951 }; 952 953 /** 954 * Fast paths 955 */ 956 957 if (opts.fastpaths !== false && !/(^[*!]|[/()[\]{}"])/.test(input)) { 958 let backslashes = false; 959 960 let output = input.replace(REGEX_SPECIAL_CHARS_BACKREF, (m, esc, chars, first, rest, index) => { 961 if (first === '\\') { 962 backslashes = true; 963 return m; 964 } 965 966 if (first === '?') { 967 if (esc) { 968 return esc + first + (rest ? QMARK.repeat(rest.length) : ''); 969 } 970 if (index === 0) { 971 return qmarkNoDot + (rest ? QMARK.repeat(rest.length) : ''); 972 } 973 return QMARK.repeat(chars.length); 974 } 975 976 if (first === '.') { 977 return DOT_LITERAL.repeat(chars.length); 978 } 979 980 if (first === '*') { 981 if (esc) { 982 return esc + first + (rest ? star : ''); 983 } 984 return star; 985 } 986 return esc ? m : `\\${m}`; 987 }); 988 989 if (backslashes === true) { 990 if (opts.unescape === true) { 991 output = output.replace(/\\/g, ''); 992 } else { 993 output = output.replace(/\\+/g, m => { 994 return m.length % 2 === 0 ? '\\\\' : (m ? '\\' : ''); 995 }); 996 } 997 } 998 999 if (output === input && opts.contains === true) { 1000 state.output = input; 1001 return state; 1002 } 1003 1004 state.output = utils.wrapOutput(output, state, options); 1005 return state; 1006 } 1007 1008 /** 1009 * Tokenize input until we reach end-of-string 1010 */ 1011 1012 while (!eos()) { 1013 value = advance(); 1014 1015 if (value === '\u0000') { 1016 continue; 1017 } 1018 1019 /** 1020 * Escaped characters 1021 */ 1022 1023 if (value === '\\') { 1024 const next = peek(); 1025 1026 if (next === '/' && opts.bash !== true) { 1027 continue; 1028 } 1029 1030 if (next === '.' || next === ';') { 1031 continue; 1032 } 1033 1034 if (!next) { 1035 value += '\\'; 1036 push({ type: 'text', value }); 1037 continue; 1038 } 1039 1040 // collapse slashes to reduce potential for exploits 1041 const match = /^\\+/.exec(remaining()); 1042 let slashes = 0; 1043 1044 if (match && match[0].length > 2) { 1045 slashes = match[0].length; 1046 state.index += slashes; 1047 if (slashes % 2 !== 0) { 1048 value += '\\'; 1049 } 1050 } 1051 1052 if (opts.unescape === true) { 1053 value = advance(); 1054 } else { 1055 value += advance(); 1056 } 1057 1058 if (state.brackets === 0) { 1059 push({ type: 'text', value }); 1060 continue; 1061 } 1062 } 1063 1064 /** 1065 * If we're inside a regex character class, continue 1066 * until we reach the closing bracket. 1067 */ 1068 1069 if (state.brackets > 0 && (value !== ']' || prev.value === '[' || prev.value === '[^')) { 1070 if (opts.posix !== false && value === ':') { 1071 const inner = prev.value.slice(1); 1072 if (inner.includes('[')) { 1073 prev.posix = true; 1074 1075 if (inner.includes(':')) { 1076 const idx = prev.value.lastIndexOf('['); 1077 const pre = prev.value.slice(0, idx); 1078 const rest = prev.value.slice(idx + 2); 1079 const posix = POSIX_REGEX_SOURCE[rest]; 1080 if (posix) { 1081 prev.value = pre + posix; 1082 state.backtrack = true; 1083 advance(); 1084 1085 if (!bos.output && tokens.indexOf(prev) === 1) { 1086 bos.output = ONE_CHAR; 1087 } 1088 continue; 1089 } 1090 } 1091 } 1092 } 1093 1094 if ((value === '[' && peek() !== ':') || (value === '-' && peek() === ']')) { 1095 value = `\\${value}`; 1096 } 1097 1098 if (value === ']' && (prev.value === '[' || prev.value === '[^')) { 1099 value = `\\${value}`; 1100 } 1101 1102 if (opts.posix === true && value === '!' && prev.value === '[') { 1103 value = '^'; 1104 } 1105 1106 prev.value += value; 1107 append({ value }); 1108 continue; 1109 } 1110 1111 /** 1112 * If we're inside a quoted string, continue 1113 * until we reach the closing double quote. 1114 */ 1115 1116 if (state.quotes === 1 && value !== '"') { 1117 value = utils.escapeRegex(value); 1118 prev.value += value; 1119 append({ value }); 1120 continue; 1121 } 1122 1123 /** 1124 * Double quotes 1125 */ 1126 1127 if (value === '"') { 1128 state.quotes = state.quotes === 1 ? 0 : 1; 1129 if (opts.keepQuotes === true) { 1130 push({ type: 'text', value }); 1131 } 1132 continue; 1133 } 1134 1135 /** 1136 * Parentheses 1137 */ 1138 1139 if (value === '(') { 1140 increment('parens'); 1141 push({ type: 'paren', value }); 1142 continue; 1143 } 1144 1145 if (value === ')') { 1146 if (state.parens === 0 && opts.strictBrackets === true) { 1147 throw new SyntaxError(syntaxError('opening', '(')); 1148 } 1149 1150 const extglob = extglobs[extglobs.length - 1]; 1151 if (extglob && state.parens === extglob.parens + 1) { 1152 extglobClose(extglobs.pop()); 1153 continue; 1154 } 1155 1156 push({ type: 'paren', value, output: state.parens ? ')' : '\\)' }); 1157 decrement('parens'); 1158 continue; 1159 } 1160 1161 /** 1162 * Square brackets 1163 */ 1164 1165 if (value === '[') { 1166 if (opts.nobracket === true || !remaining().includes(']')) { 1167 if (opts.nobracket !== true && opts.strictBrackets === true) { 1168 throw new SyntaxError(syntaxError('closing', ']')); 1169 } 1170 1171 value = `\\${value}`; 1172 } else { 1173 increment('brackets'); 1174 } 1175 1176 push({ type: 'bracket', value }); 1177 continue; 1178 } 1179 1180 if (value === ']') { 1181 if (opts.nobracket === true || (prev && prev.type === 'bracket' && prev.value.length === 1)) { 1182 push({ type: 'text', value, output: `\\${value}` }); 1183 continue; 1184 } 1185 1186 if (state.brackets === 0) { 1187 if (opts.strictBrackets === true) { 1188 throw new SyntaxError(syntaxError('opening', '[')); 1189 } 1190 1191 push({ type: 'text', value, output: `\\${value}` }); 1192 continue; 1193 } 1194 1195 decrement('brackets'); 1196 1197 const prevValue = prev.value.slice(1); 1198 if (prev.posix !== true && prevValue[0] === '^' && !prevValue.includes('/')) { 1199 value = `/${value}`; 1200 } 1201 1202 prev.value += value; 1203 append({ value }); 1204 1205 // when literal brackets are explicitly disabled 1206 // assume we should match with a regex character class 1207 if (opts.literalBrackets === false || utils.hasRegexChars(prevValue)) { 1208 continue; 1209 } 1210 1211 const escaped = utils.escapeRegex(prev.value); 1212 state.output = state.output.slice(0, -prev.value.length); 1213 1214 // when literal brackets are explicitly enabled 1215 // assume we should escape the brackets to match literal characters 1216 if (opts.literalBrackets === true) { 1217 state.output += escaped; 1218 prev.value = escaped; 1219 continue; 1220 } 1221 1222 // when the user specifies nothing, try to match both 1223 prev.value = `(${capture}${escaped}|${prev.value})`; 1224 state.output += prev.value; 1225 continue; 1226 } 1227 1228 /** 1229 * Braces 1230 */ 1231 1232 if (value === '{' && opts.nobrace !== true) { 1233 increment('braces'); 1234 1235 const open = { 1236 type: 'brace', 1237 value, 1238 output: '(', 1239 outputIndex: state.output.length, 1240 tokensIndex: state.tokens.length 1241 }; 1242 1243 braces.push(open); 1244 push(open); 1245 continue; 1246 } 1247 1248 if (value === '}') { 1249 const brace = braces[braces.length - 1]; 1250 1251 if (opts.nobrace === true || !brace) { 1252 push({ type: 'text', value, output: value }); 1253 continue; 1254 } 1255 1256 let output = ')'; 1257 1258 if (brace.dots === true) { 1259 const arr = tokens.slice(); 1260 const range = []; 1261 1262 for (let i = arr.length - 1; i >= 0; i--) { 1263 tokens.pop(); 1264 if (arr[i].type === 'brace') { 1265 break; 1266 } 1267 if (arr[i].type !== 'dots') { 1268 range.unshift(arr[i].value); 1269 } 1270 } 1271 1272 output = expandRange(range, opts); 1273 state.backtrack = true; 1274 } 1275 1276 if (brace.comma !== true && brace.dots !== true) { 1277 const out = state.output.slice(0, brace.outputIndex); 1278 const toks = state.tokens.slice(brace.tokensIndex); 1279 brace.value = brace.output = '\\{'; 1280 value = output = '\\}'; 1281 state.output = out; 1282 for (const t of toks) { 1283 state.output += (t.output || t.value); 1284 } 1285 } 1286 1287 push({ type: 'brace', value, output }); 1288 decrement('braces'); 1289 braces.pop(); 1290 continue; 1291 } 1292 1293 /** 1294 * Pipes 1295 */ 1296 1297 if (value === '|') { 1298 if (extglobs.length > 0) { 1299 extglobs[extglobs.length - 1].conditions++; 1300 } 1301 push({ type: 'text', value }); 1302 continue; 1303 } 1304 1305 /** 1306 * Commas 1307 */ 1308 1309 if (value === ',') { 1310 let output = value; 1311 1312 const brace = braces[braces.length - 1]; 1313 if (brace && stack[stack.length - 1] === 'braces') { 1314 brace.comma = true; 1315 output = '|'; 1316 } 1317 1318 push({ type: 'comma', value, output }); 1319 continue; 1320 } 1321 1322 /** 1323 * Slashes 1324 */ 1325 1326 if (value === '/') { 1327 // if the beginning of the glob is "./", advance the start 1328 // to the current index, and don't add the "./" characters 1329 // to the state. This greatly simplifies lookbehinds when 1330 // checking for BOS characters like "!" and "." (not "./") 1331 if (prev.type === 'dot' && state.index === state.start + 1) { 1332 state.start = state.index + 1; 1333 state.consumed = ''; 1334 state.output = ''; 1335 tokens.pop(); 1336 prev = bos; // reset "prev" to the first token 1337 continue; 1338 } 1339 1340 push({ type: 'slash', value, output: SLASH_LITERAL }); 1341 continue; 1342 } 1343 1344 /** 1345 * Dots 1346 */ 1347 1348 if (value === '.') { 1349 if (state.braces > 0 && prev.type === 'dot') { 1350 if (prev.value === '.') prev.output = DOT_LITERAL; 1351 const brace = braces[braces.length - 1]; 1352 prev.type = 'dots'; 1353 prev.output += value; 1354 prev.value += value; 1355 brace.dots = true; 1356 continue; 1357 } 1358 1359 if ((state.braces + state.parens) === 0 && prev.type !== 'bos' && prev.type !== 'slash') { 1360 push({ type: 'text', value, output: DOT_LITERAL }); 1361 continue; 1362 } 1363 1364 push({ type: 'dot', value, output: DOT_LITERAL }); 1365 continue; 1366 } 1367 1368 /** 1369 * Question marks 1370 */ 1371 1372 if (value === '?') { 1373 const isGroup = prev && prev.value === '('; 1374 if (!isGroup && opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { 1375 extglobOpen('qmark', value); 1376 continue; 1377 } 1378 1379 if (prev && prev.type === 'paren') { 1380 const next = peek(); 1381 let output = value; 1382 1383 if (next === '<' && !utils.supportsLookbehinds()) { 1384 throw new Error('Node.js v10 or higher is required for regex lookbehinds'); 1385 } 1386 1387 if ((prev.value === '(' && !/[!=<:]/.test(next)) || (next === '<' && !/<([!=]|\w+>)/.test(remaining()))) { 1388 output = `\\${value}`; 1389 } 1390 1391 push({ type: 'text', value, output }); 1392 continue; 1393 } 1394 1395 if (opts.dot !== true && (prev.type === 'slash' || prev.type === 'bos')) { 1396 push({ type: 'qmark', value, output: QMARK_NO_DOT }); 1397 continue; 1398 } 1399 1400 push({ type: 'qmark', value, output: QMARK }); 1401 continue; 1402 } 1403 1404 /** 1405 * Exclamation 1406 */ 1407 1408 if (value === '!') { 1409 if (opts.noextglob !== true && peek() === '(') { 1410 if (peek(2) !== '?' || !/[!=<:]/.test(peek(3))) { 1411 extglobOpen('negate', value); 1412 continue; 1413 } 1414 } 1415 1416 if (opts.nonegate !== true && state.index === 0) { 1417 negate(); 1418 continue; 1419 } 1420 } 1421 1422 /** 1423 * Plus 1424 */ 1425 1426 if (value === '+') { 1427 if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { 1428 extglobOpen('plus', value); 1429 continue; 1430 } 1431 1432 if ((prev && prev.value === '(') || opts.regex === false) { 1433 push({ type: 'plus', value, output: PLUS_LITERAL }); 1434 continue; 1435 } 1436 1437 if ((prev && (prev.type === 'bracket' || prev.type === 'paren' || prev.type === 'brace')) || state.parens > 0) { 1438 push({ type: 'plus', value }); 1439 continue; 1440 } 1441 1442 push({ type: 'plus', value: PLUS_LITERAL }); 1443 continue; 1444 } 1445 1446 /** 1447 * Plain text 1448 */ 1449 1450 if (value === '@') { 1451 if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { 1452 push({ type: 'at', extglob: true, value, output: '' }); 1453 continue; 1454 } 1455 1456 push({ type: 'text', value }); 1457 continue; 1458 } 1459 1460 /** 1461 * Plain text 1462 */ 1463 1464 if (value !== '*') { 1465 if (value === '$' || value === '^') { 1466 value = `\\${value}`; 1467 } 1468 1469 const match = REGEX_NON_SPECIAL_CHARS.exec(remaining()); 1470 if (match) { 1471 value += match[0]; 1472 state.index += match[0].length; 1473 } 1474 1475 push({ type: 'text', value }); 1476 continue; 1477 } 1478 1479 /** 1480 * Stars 1481 */ 1482 1483 if (prev && (prev.type === 'globstar' || prev.star === true)) { 1484 prev.type = 'star'; 1485 prev.star = true; 1486 prev.value += value; 1487 prev.output = star; 1488 state.backtrack = true; 1489 state.globstar = true; 1490 consume(value); 1491 continue; 1492 } 1493 1494 let rest = remaining(); 1495 if (opts.noextglob !== true && /^\([^?]/.test(rest)) { 1496 extglobOpen('star', value); 1497 continue; 1498 } 1499 1500 if (prev.type === 'star') { 1501 if (opts.noglobstar === true) { 1502 consume(value); 1503 continue; 1504 } 1505 1506 const prior = prev.prev; 1507 const before = prior.prev; 1508 const isStart = prior.type === 'slash' || prior.type === 'bos'; 1509 const afterStar = before && (before.type === 'star' || before.type === 'globstar'); 1510 1511 if (opts.bash === true && (!isStart || (rest[0] && rest[0] !== '/'))) { 1512 push({ type: 'star', value, output: '' }); 1513 continue; 1514 } 1515 1516 const isBrace = state.braces > 0 && (prior.type === 'comma' || prior.type === 'brace'); 1517 const isExtglob = extglobs.length && (prior.type === 'pipe' || prior.type === 'paren'); 1518 if (!isStart && prior.type !== 'paren' && !isBrace && !isExtglob) { 1519 push({ type: 'star', value, output: '' }); 1520 continue; 1521 } 1522 1523 // strip consecutive `/**/` 1524 while (rest.slice(0, 3) === '/**') { 1525 const after = input[state.index + 4]; 1526 if (after && after !== '/') { 1527 break; 1528 } 1529 rest = rest.slice(3); 1530 consume('/**', 3); 1531 } 1532 1533 if (prior.type === 'bos' && eos()) { 1534 prev.type = 'globstar'; 1535 prev.value += value; 1536 prev.output = globstar(opts); 1537 state.output = prev.output; 1538 state.globstar = true; 1539 consume(value); 1540 continue; 1541 } 1542 1543 if (prior.type === 'slash' && prior.prev.type !== 'bos' && !afterStar && eos()) { 1544 state.output = state.output.slice(0, -(prior.output + prev.output).length); 1545 prior.output = `(?:${prior.output}`; 1546 1547 prev.type = 'globstar'; 1548 prev.output = globstar(opts) + (opts.strictSlashes ? ')' : '|$)'); 1549 prev.value += value; 1550 state.globstar = true; 1551 state.output += prior.output + prev.output; 1552 consume(value); 1553 continue; 1554 } 1555 1556 if (prior.type === 'slash' && prior.prev.type !== 'bos' && rest[0] === '/') { 1557 const end = rest[1] !== void 0 ? '|$' : ''; 1558 1559 state.output = state.output.slice(0, -(prior.output + prev.output).length); 1560 prior.output = `(?:${prior.output}`; 1561 1562 prev.type = 'globstar'; 1563 prev.output = `${globstar(opts)}${SLASH_LITERAL}|${SLASH_LITERAL}${end})`; 1564 prev.value += value; 1565 1566 state.output += prior.output + prev.output; 1567 state.globstar = true; 1568 1569 consume(value + advance()); 1570 1571 push({ type: 'slash', value: '/', output: '' }); 1572 continue; 1573 } 1574 1575 if (prior.type === 'bos' && rest[0] === '/') { 1576 prev.type = 'globstar'; 1577 prev.value += value; 1578 prev.output = `(?:^|${SLASH_LITERAL}|${globstar(opts)}${SLASH_LITERAL})`; 1579 state.output = prev.output; 1580 state.globstar = true; 1581 consume(value + advance()); 1582 push({ type: 'slash', value: '/', output: '' }); 1583 continue; 1584 } 1585 1586 // remove single star from output 1587 state.output = state.output.slice(0, -prev.output.length); 1588 1589 // reset previous token to globstar 1590 prev.type = 'globstar'; 1591 prev.output = globstar(opts); 1592 prev.value += value; 1593 1594 // reset output with globstar 1595 state.output += prev.output; 1596 state.globstar = true; 1597 consume(value); 1598 continue; 1599 } 1600 1601 const token = { type: 'star', value, output: star }; 1602 1603 if (opts.bash === true) { 1604 token.output = '.*?'; 1605 if (prev.type === 'bos' || prev.type === 'slash') { 1606 token.output = nodot + token.output; 1607 } 1608 push(token); 1609 continue; 1610 } 1611 1612 if (prev && (prev.type === 'bracket' || prev.type === 'paren') && opts.regex === true) { 1613 token.output = value; 1614 push(token); 1615 continue; 1616 } 1617 1618 if (state.index === state.start || prev.type === 'slash' || prev.type === 'dot') { 1619 if (prev.type === 'dot') { 1620 state.output += NO_DOT_SLASH; 1621 prev.output += NO_DOT_SLASH; 1622 1623 } else if (opts.dot === true) { 1624 state.output += NO_DOTS_SLASH; 1625 prev.output += NO_DOTS_SLASH; 1626 1627 } else { 1628 state.output += nodot; 1629 prev.output += nodot; 1630 } 1631 1632 if (peek() !== '*') { 1633 state.output += ONE_CHAR; 1634 prev.output += ONE_CHAR; 1635 } 1636 } 1637 1638 push(token); 1639 } 1640 1641 while (state.brackets > 0) { 1642 if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ']')); 1643 state.output = utils.escapeLast(state.output, '['); 1644 decrement('brackets'); 1645 } 1646 1647 while (state.parens > 0) { 1648 if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ')')); 1649 state.output = utils.escapeLast(state.output, '('); 1650 decrement('parens'); 1651 } 1652 1653 while (state.braces > 0) { 1654 if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', '}')); 1655 state.output = utils.escapeLast(state.output, '{'); 1656 decrement('braces'); 1657 } 1658 1659 if (opts.strictSlashes !== true && (prev.type === 'star' || prev.type === 'bracket')) { 1660 push({ type: 'maybe_slash', value: '', output: `${SLASH_LITERAL}?` }); 1661 } 1662 1663 // rebuild the output if we had to backtrack at any point 1664 if (state.backtrack === true) { 1665 state.output = ''; 1666 1667 for (const token of state.tokens) { 1668 state.output += token.output != null ? token.output : token.value; 1669 1670 if (token.suffix) { 1671 state.output += token.suffix; 1672 } 1673 } 1674 } 1675 1676 return state; 1677 }; 1678 1679 /** 1680 * Fast paths for creating regular expressions for common glob patterns. 1681 * This can significantly speed up processing and has very little downside 1682 * impact when none of the fast paths match. 1683 */ 1684 1685 parse.fastpaths = (input, options) => { 1686 const opts = { ...options }; 1687 const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; 1688 const len = input.length; 1689 if (len > max) { 1690 throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`); 1691 } 1692 1693 input = REPLACEMENTS[input] || input; 1694 const win32 = utils.isWindows(options); 1695 1696 // create constants based on platform, for windows or posix 1697 const { 1698 DOT_LITERAL, 1699 SLASH_LITERAL, 1700 ONE_CHAR, 1701 DOTS_SLASH, 1702 NO_DOT, 1703 NO_DOTS, 1704 NO_DOTS_SLASH, 1705 STAR, 1706 START_ANCHOR 1707 } = constants.globChars(win32); 1708 1709 const nodot = opts.dot ? NO_DOTS : NO_DOT; 1710 const slashDot = opts.dot ? NO_DOTS_SLASH : NO_DOT; 1711 const capture = opts.capture ? '' : '?:'; 1712 const state = { negated: false, prefix: '' }; 1713 let star = opts.bash === true ? '.*?' : STAR; 1714 1715 if (opts.capture) { 1716 star = `(${star})`; 1717 } 1718 1719 const globstar = opts => { 1720 if (opts.noglobstar === true) return star; 1721 return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`; 1722 }; 1723 1724 const create = str => { 1725 switch (str) { 1726 case '*': 1727 return `${nodot}${ONE_CHAR}${star}`; 1728 1729 case '.*': 1730 return `${DOT_LITERAL}${ONE_CHAR}${star}`; 1731 1732 case '*.*': 1733 return `${nodot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`; 1734 1735 case '*/*': 1736 return `${nodot}${star}${SLASH_LITERAL}${ONE_CHAR}${slashDot}${star}`; 1737 1738 case '**': 1739 return nodot + globstar(opts); 1740 1741 case '**/*': 1742 return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${ONE_CHAR}${star}`; 1743 1744 case '**/*.*': 1745 return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`; 1746 1747 case '**/.*': 1748 return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${DOT_LITERAL}${ONE_CHAR}${star}`; 1749 1750 default: { 1751 const match = /^(.*?)\.(\w+)$/.exec(str); 1752 if (!match) return; 1753 1754 const source = create(match[1]); 1755 if (!source) return; 1756 1757 return source + DOT_LITERAL + match[2]; 1758 } 1759 } 1760 }; 1761 1762 const output = utils.removePrefix(input, state); 1763 let source = create(output); 1764 1765 if (source && opts.strictSlashes !== true) { 1766 source += `${SLASH_LITERAL}?`; 1767 } 1768 1769 return source; 1770 }; 1771 1772 parse_1$2 = parse; 1773 return parse_1$2; 1774 } 1775 1776 var picomatch_1$1; 1777 var hasRequiredPicomatch$3; 1778 1779 function requirePicomatch$3 () { 1780 if (hasRequiredPicomatch$3) return picomatch_1$1; 1781 hasRequiredPicomatch$3 = 1; 1782 1783 const path = require$$0$1; 1784 const scan = /*@__PURE__*/ requireScan$1(); 1785 const parse = /*@__PURE__*/ requireParse$2(); 1786 const utils = /*@__PURE__*/ requireUtils$2(); 1787 const constants = /*@__PURE__*/ requireConstants$3(); 1788 const isObject = val => val && typeof val === 'object' && !Array.isArray(val); 1789 1790 /** 1791 * Creates a matcher function from one or more glob patterns. The 1792 * returned function takes a string to match as its first argument, 1793 * and returns true if the string is a match. The returned matcher 1794 * function also takes a boolean as the second argument that, when true, 1795 * returns an object with additional information. 1796 * 1797 * ```js 1798 * const picomatch = require('picomatch'); 1799 * // picomatch(glob[, options]); 1800 * 1801 * const isMatch = picomatch('*.!(*a)'); 1802 * console.log(isMatch('a.a')); //=> false 1803 * console.log(isMatch('a.b')); //=> true 1804 * ``` 1805 * @name picomatch 1806 * @param {String|Array} `globs` One or more glob patterns. 1807 * @param {Object=} `options` 1808 * @return {Function=} Returns a matcher function. 1809 * @api public 1810 */ 1811 1812 const picomatch = (glob, options, returnState = false) => { 1813 if (Array.isArray(glob)) { 1814 const fns = glob.map(input => picomatch(input, options, returnState)); 1815 const arrayMatcher = str => { 1816 for (const isMatch of fns) { 1817 const state = isMatch(str); 1818 if (state) return state; 1819 } 1820 return false; 1821 }; 1822 return arrayMatcher; 1823 } 1824 1825 const isState = isObject(glob) && glob.tokens && glob.input; 1826 1827 if (glob === '' || (typeof glob !== 'string' && !isState)) { 1828 throw new TypeError('Expected pattern to be a non-empty string'); 1829 } 1830 1831 const opts = options || {}; 1832 const posix = utils.isWindows(options); 1833 const regex = isState 1834 ? picomatch.compileRe(glob, options) 1835 : picomatch.makeRe(glob, options, false, true); 1836 1837 const state = regex.state; 1838 delete regex.state; 1839 1840 let isIgnored = () => false; 1841 if (opts.ignore) { 1842 const ignoreOpts = { ...options, ignore: null, onMatch: null, onResult: null }; 1843 isIgnored = picomatch(opts.ignore, ignoreOpts, returnState); 1844 } 1845 1846 const matcher = (input, returnObject = false) => { 1847 const { isMatch, match, output } = picomatch.test(input, regex, options, { glob, posix }); 1848 const result = { glob, state, regex, posix, input, output, match, isMatch }; 1849 1850 if (typeof opts.onResult === 'function') { 1851 opts.onResult(result); 1852 } 1853 1854 if (isMatch === false) { 1855 result.isMatch = false; 1856 return returnObject ? result : false; 1857 } 1858 1859 if (isIgnored(input)) { 1860 if (typeof opts.onIgnore === 'function') { 1861 opts.onIgnore(result); 1862 } 1863 result.isMatch = false; 1864 return returnObject ? result : false; 1865 } 1866 1867 if (typeof opts.onMatch === 'function') { 1868 opts.onMatch(result); 1869 } 1870 return returnObject ? result : true; 1871 }; 1872 1873 if (returnState) { 1874 matcher.state = state; 1875 } 1876 1877 return matcher; 1878 }; 1879 1880 /** 1881 * Test `input` with the given `regex`. This is used by the main 1882 * `picomatch()` function to test the input string. 1883 * 1884 * ```js 1885 * const picomatch = require('picomatch'); 1886 * // picomatch.test(input, regex[, options]); 1887 * 1888 * console.log(picomatch.test('foo/bar', /^(?:([^/]*?)\/([^/]*?))$/)); 1889 * // { isMatch: true, match: [ 'foo/', 'foo', 'bar' ], output: 'foo/bar' } 1890 * ``` 1891 * @param {String} `input` String to test. 1892 * @param {RegExp} `regex` 1893 * @return {Object} Returns an object with matching info. 1894 * @api public 1895 */ 1896 1897 picomatch.test = (input, regex, options, { glob, posix } = {}) => { 1898 if (typeof input !== 'string') { 1899 throw new TypeError('Expected input to be a string'); 1900 } 1901 1902 if (input === '') { 1903 return { isMatch: false, output: '' }; 1904 } 1905 1906 const opts = options || {}; 1907 const format = opts.format || (posix ? utils.toPosixSlashes : null); 1908 let match = input === glob; 1909 let output = (match && format) ? format(input) : input; 1910 1911 if (match === false) { 1912 output = format ? format(input) : input; 1913 match = output === glob; 1914 } 1915 1916 if (match === false || opts.capture === true) { 1917 if (opts.matchBase === true || opts.basename === true) { 1918 match = picomatch.matchBase(input, regex, options, posix); 1919 } else { 1920 match = regex.exec(output); 1921 } 1922 } 1923 1924 return { isMatch: Boolean(match), match, output }; 1925 }; 1926 1927 /** 1928 * Match the basename of a filepath. 1929 * 1930 * ```js 1931 * const picomatch = require('picomatch'); 1932 * // picomatch.matchBase(input, glob[, options]); 1933 * console.log(picomatch.matchBase('foo/bar.js', '*.js'); // true 1934 * ``` 1935 * @param {String} `input` String to test. 1936 * @param {RegExp|String} `glob` Glob pattern or regex created by [.makeRe](#makeRe). 1937 * @return {Boolean} 1938 * @api public 1939 */ 1940 1941 picomatch.matchBase = (input, glob, options, posix = utils.isWindows(options)) => { 1942 const regex = glob instanceof RegExp ? glob : picomatch.makeRe(glob, options); 1943 return regex.test(path.basename(input)); 1944 }; 1945 1946 /** 1947 * Returns true if **any** of the given glob `patterns` match the specified `string`. 1948 * 1949 * ```js 1950 * const picomatch = require('picomatch'); 1951 * // picomatch.isMatch(string, patterns[, options]); 1952 * 1953 * console.log(picomatch.isMatch('a.a', ['b.*', '*.a'])); //=> true 1954 * console.log(picomatch.isMatch('a.a', 'b.*')); //=> false 1955 * ``` 1956 * @param {String|Array} str The string to test. 1957 * @param {String|Array} patterns One or more glob patterns to use for matching. 1958 * @param {Object} [options] See available [options](#options). 1959 * @return {Boolean} Returns true if any patterns match `str` 1960 * @api public 1961 */ 1962 1963 picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str); 1964 1965 /** 1966 * Parse a glob pattern to create the source string for a regular 1967 * expression. 1968 * 1969 * ```js 1970 * const picomatch = require('picomatch'); 1971 * const result = picomatch.parse(pattern[, options]); 1972 * ``` 1973 * @param {String} `pattern` 1974 * @param {Object} `options` 1975 * @return {Object} Returns an object with useful properties and output to be used as a regex source string. 1976 * @api public 1977 */ 1978 1979 picomatch.parse = (pattern, options) => { 1980 if (Array.isArray(pattern)) return pattern.map(p => picomatch.parse(p, options)); 1981 return parse(pattern, { ...options, fastpaths: false }); 1982 }; 1983 1984 /** 1985 * Scan a glob pattern to separate the pattern into segments. 1986 * 1987 * ```js 1988 * const picomatch = require('picomatch'); 1989 * // picomatch.scan(input[, options]); 1990 * 1991 * const result = picomatch.scan('!./foo/*.js'); 1992 * console.log(result); 1993 * { prefix: '!./', 1994 * input: '!./foo/*.js', 1995 * start: 3, 1996 * base: 'foo', 1997 * glob: '*.js', 1998 * isBrace: false, 1999 * isBracket: false, 2000 * isGlob: true, 2001 * isExtglob: false, 2002 * isGlobstar: false, 2003 * negated: true } 2004 * ``` 2005 * @param {String} `input` Glob pattern to scan. 2006 * @param {Object} `options` 2007 * @return {Object} Returns an object with 2008 * @api public 2009 */ 2010 2011 picomatch.scan = (input, options) => scan(input, options); 2012 2013 /** 2014 * Compile a regular expression from the `state` object returned by the 2015 * [parse()](#parse) method. 2016 * 2017 * @param {Object} `state` 2018 * @param {Object} `options` 2019 * @param {Boolean} `returnOutput` Intended for implementors, this argument allows you to return the raw output from the parser. 2020 * @param {Boolean} `returnState` Adds the state to a `state` property on the returned regex. Useful for implementors and debugging. 2021 * @return {RegExp} 2022 * @api public 2023 */ 2024 2025 picomatch.compileRe = (state, options, returnOutput = false, returnState = false) => { 2026 if (returnOutput === true) { 2027 return state.output; 2028 } 2029 2030 const opts = options || {}; 2031 const prepend = opts.contains ? '' : '^'; 2032 const append = opts.contains ? '' : '$'; 2033 2034 let source = `${prepend}(?:${state.output})${append}`; 2035 if (state && state.negated === true) { 2036 source = `^(?!${source}).*$`; 2037 } 2038 2039 const regex = picomatch.toRegex(source, options); 2040 if (returnState === true) { 2041 regex.state = state; 2042 } 2043 2044 return regex; 2045 }; 2046 2047 /** 2048 * Create a regular expression from a parsed glob pattern. 2049 * 2050 * ```js 2051 * const picomatch = require('picomatch'); 2052 * const state = picomatch.parse('*.js'); 2053 * // picomatch.compileRe(state[, options]); 2054 * 2055 * console.log(picomatch.compileRe(state)); 2056 * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/ 2057 * ``` 2058 * @param {String} `state` The object returned from the `.parse` method. 2059 * @param {Object} `options` 2060 * @param {Boolean} `returnOutput` Implementors may use this argument to return the compiled output, instead of a regular expression. This is not exposed on the options to prevent end-users from mutating the result. 2061 * @param {Boolean} `returnState` Implementors may use this argument to return the state from the parsed glob with the returned regular expression. 2062 * @return {RegExp} Returns a regex created from the given pattern. 2063 * @api public 2064 */ 2065 2066 picomatch.makeRe = (input, options = {}, returnOutput = false, returnState = false) => { 2067 if (!input || typeof input !== 'string') { 2068 throw new TypeError('Expected a non-empty string'); 2069 } 2070 2071 let parsed = { negated: false, fastpaths: true }; 2072 2073 if (options.fastpaths !== false && (input[0] === '.' || input[0] === '*')) { 2074 parsed.output = parse.fastpaths(input, options); 2075 } 2076 2077 if (!parsed.output) { 2078 parsed = parse(input, options); 2079 } 2080 2081 return picomatch.compileRe(parsed, options, returnOutput, returnState); 2082 }; 2083 2084 /** 2085 * Create a regular expression from the given regex source string. 2086 * 2087 * ```js 2088 * const picomatch = require('picomatch'); 2089 * // picomatch.toRegex(source[, options]); 2090 * 2091 * const { output } = picomatch.parse('*.js'); 2092 * console.log(picomatch.toRegex(output)); 2093 * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/ 2094 * ``` 2095 * @param {String} `source` Regular expression source string. 2096 * @param {Object} `options` 2097 * @return {RegExp} 2098 * @api public 2099 */ 2100 2101 picomatch.toRegex = (source, options) => { 2102 try { 2103 const opts = options || {}; 2104 return new RegExp(source, opts.flags || (opts.nocase ? 'i' : '')); 2105 } catch (err) { 2106 if (options && options.debug === true) throw err; 2107 return /$^/; 2108 } 2109 }; 2110 2111 /** 2112 * Picomatch constants. 2113 * @return {Object} 2114 */ 2115 2116 picomatch.constants = constants; 2117 2118 /** 2119 * Expose "picomatch" 2120 */ 2121 2122 picomatch_1$1 = picomatch; 2123 return picomatch_1$1; 2124 } 2125 2126 var picomatch$1; 2127 var hasRequiredPicomatch$2; 2128 2129 function requirePicomatch$2 () { 2130 if (hasRequiredPicomatch$2) return picomatch$1; 2131 hasRequiredPicomatch$2 = 1; 2132 2133 picomatch$1 = /*@__PURE__*/ requirePicomatch$3(); 2134 return picomatch$1; 2135 } 2136 2137 var readdirp_1; 2138 var hasRequiredReaddirp; 2139 2140 function requireReaddirp () { 2141 if (hasRequiredReaddirp) return readdirp_1; 2142 hasRequiredReaddirp = 1; 2143 2144 const fs = require$$0$2; 2145 const { Readable } = require$$1; 2146 const sysPath = require$$0$1; 2147 const { promisify } = require$$2; 2148 const picomatch = /*@__PURE__*/ requirePicomatch$2(); 2149 2150 const readdir = promisify(fs.readdir); 2151 const stat = promisify(fs.stat); 2152 const lstat = promisify(fs.lstat); 2153 const realpath = promisify(fs.realpath); 2154 2155 /** 2156 * @typedef {Object} EntryInfo 2157 * @property {String} path 2158 * @property {String} fullPath 2159 * @property {fs.Stats=} stats 2160 * @property {fs.Dirent=} dirent 2161 * @property {String} basename 2162 */ 2163 2164 const BANG = '!'; 2165 const RECURSIVE_ERROR_CODE = 'READDIRP_RECURSIVE_ERROR'; 2166 const NORMAL_FLOW_ERRORS = new Set(['ENOENT', 'EPERM', 'EACCES', 'ELOOP', RECURSIVE_ERROR_CODE]); 2167 const FILE_TYPE = 'files'; 2168 const DIR_TYPE = 'directories'; 2169 const FILE_DIR_TYPE = 'files_directories'; 2170 const EVERYTHING_TYPE = 'all'; 2171 const ALL_TYPES = [FILE_TYPE, DIR_TYPE, FILE_DIR_TYPE, EVERYTHING_TYPE]; 2172 2173 const isNormalFlowError = error => NORMAL_FLOW_ERRORS.has(error.code); 2174 const [maj, min] = process.versions.node.split('.').slice(0, 2).map(n => Number.parseInt(n, 10)); 2175 const wantBigintFsStats = process.platform === 'win32' && (maj > 10 || (maj === 10 && min >= 5)); 2176 2177 const normalizeFilter = filter => { 2178 if (filter === undefined) return; 2179 if (typeof filter === 'function') return filter; 2180 2181 if (typeof filter === 'string') { 2182 const glob = picomatch(filter.trim()); 2183 return entry => glob(entry.basename); 2184 } 2185 2186 if (Array.isArray(filter)) { 2187 const positive = []; 2188 const negative = []; 2189 for (const item of filter) { 2190 const trimmed = item.trim(); 2191 if (trimmed.charAt(0) === BANG) { 2192 negative.push(picomatch(trimmed.slice(1))); 2193 } else { 2194 positive.push(picomatch(trimmed)); 2195 } 2196 } 2197 2198 if (negative.length > 0) { 2199 if (positive.length > 0) { 2200 return entry => 2201 positive.some(f => f(entry.basename)) && !negative.some(f => f(entry.basename)); 2202 } 2203 return entry => !negative.some(f => f(entry.basename)); 2204 } 2205 return entry => positive.some(f => f(entry.basename)); 2206 } 2207 }; 2208 2209 class ReaddirpStream extends Readable { 2210 static get defaultOptions() { 2211 return { 2212 root: '.', 2213 /* eslint-disable no-unused-vars */ 2214 fileFilter: (path) => true, 2215 directoryFilter: (path) => true, 2216 /* eslint-enable no-unused-vars */ 2217 type: FILE_TYPE, 2218 lstat: false, 2219 depth: 2147483648, 2220 alwaysStat: false 2221 }; 2222 } 2223 2224 constructor(options = {}) { 2225 super({ 2226 objectMode: true, 2227 autoDestroy: true, 2228 highWaterMark: options.highWaterMark || 4096 2229 }); 2230 const opts = { ...ReaddirpStream.defaultOptions, ...options }; 2231 const { root, type } = opts; 2232 2233 this._fileFilter = normalizeFilter(opts.fileFilter); 2234 this._directoryFilter = normalizeFilter(opts.directoryFilter); 2235 2236 const statMethod = opts.lstat ? lstat : stat; 2237 // Use bigint stats if it's windows and stat() supports options (node 10+). 2238 if (wantBigintFsStats) { 2239 this._stat = path => statMethod(path, { bigint: true }); 2240 } else { 2241 this._stat = statMethod; 2242 } 2243 2244 this._maxDepth = opts.depth; 2245 this._wantsDir = [DIR_TYPE, FILE_DIR_TYPE, EVERYTHING_TYPE].includes(type); 2246 this._wantsFile = [FILE_TYPE, FILE_DIR_TYPE, EVERYTHING_TYPE].includes(type); 2247 this._wantsEverything = type === EVERYTHING_TYPE; 2248 this._root = sysPath.resolve(root); 2249 this._isDirent = ('Dirent' in fs) && !opts.alwaysStat; 2250 this._statsProp = this._isDirent ? 'dirent' : 'stats'; 2251 this._rdOptions = { encoding: 'utf8', withFileTypes: this._isDirent }; 2252 2253 // Launch stream with one parent, the root dir. 2254 this.parents = [this._exploreDir(root, 1)]; 2255 this.reading = false; 2256 this.parent = undefined; 2257 } 2258 2259 async _read(batch) { 2260 if (this.reading) return; 2261 this.reading = true; 2262 2263 try { 2264 while (!this.destroyed && batch > 0) { 2265 const { path, depth, files = [] } = this.parent || {}; 2266 2267 if (files.length > 0) { 2268 const slice = files.splice(0, batch).map(dirent => this._formatEntry(dirent, path)); 2269 for (const entry of await Promise.all(slice)) { 2270 if (this.destroyed) return; 2271 2272 const entryType = await this._getEntryType(entry); 2273 if (entryType === 'directory' && this._directoryFilter(entry)) { 2274 if (depth <= this._maxDepth) { 2275 this.parents.push(this._exploreDir(entry.fullPath, depth + 1)); 2276 } 2277 2278 if (this._wantsDir) { 2279 this.push(entry); 2280 batch--; 2281 } 2282 } else if ((entryType === 'file' || this._includeAsFile(entry)) && this._fileFilter(entry)) { 2283 if (this._wantsFile) { 2284 this.push(entry); 2285 batch--; 2286 } 2287 } 2288 } 2289 } else { 2290 const parent = this.parents.pop(); 2291 if (!parent) { 2292 this.push(null); 2293 break; 2294 } 2295 this.parent = await parent; 2296 if (this.destroyed) return; 2297 } 2298 } 2299 } catch (error) { 2300 this.destroy(error); 2301 } finally { 2302 this.reading = false; 2303 } 2304 } 2305 2306 async _exploreDir(path, depth) { 2307 let files; 2308 try { 2309 files = await readdir(path, this._rdOptions); 2310 } catch (error) { 2311 this._onError(error); 2312 } 2313 return { files, depth, path }; 2314 } 2315 2316 async _formatEntry(dirent, path) { 2317 let entry; 2318 try { 2319 const basename = this._isDirent ? dirent.name : dirent; 2320 const fullPath = sysPath.resolve(sysPath.join(path, basename)); 2321 entry = { path: sysPath.relative(this._root, fullPath), fullPath, basename }; 2322 entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath); 2323 } catch (err) { 2324 this._onError(err); 2325 } 2326 return entry; 2327 } 2328 2329 _onError(err) { 2330 if (isNormalFlowError(err) && !this.destroyed) { 2331 this.emit('warn', err); 2332 } else { 2333 this.destroy(err); 2334 } 2335 } 2336 2337 async _getEntryType(entry) { 2338 // entry may be undefined, because a warning or an error were emitted 2339 // and the statsProp is undefined 2340 const stats = entry && entry[this._statsProp]; 2341 if (!stats) { 2342 return; 2343 } 2344 if (stats.isFile()) { 2345 return 'file'; 2346 } 2347 if (stats.isDirectory()) { 2348 return 'directory'; 2349 } 2350 if (stats && stats.isSymbolicLink()) { 2351 const full = entry.fullPath; 2352 try { 2353 const entryRealPath = await realpath(full); 2354 const entryRealPathStats = await lstat(entryRealPath); 2355 if (entryRealPathStats.isFile()) { 2356 return 'file'; 2357 } 2358 if (entryRealPathStats.isDirectory()) { 2359 const len = entryRealPath.length; 2360 if (full.startsWith(entryRealPath) && full.substr(len, 1) === sysPath.sep) { 2361 const recursiveError = new Error( 2362 `Circular symlink detected: "${full}" points to "${entryRealPath}"` 2363 ); 2364 recursiveError.code = RECURSIVE_ERROR_CODE; 2365 return this._onError(recursiveError); 2366 } 2367 return 'directory'; 2368 } 2369 } catch (error) { 2370 this._onError(error); 2371 } 2372 } 2373 } 2374 2375 _includeAsFile(entry) { 2376 const stats = entry && entry[this._statsProp]; 2377 2378 return stats && this._wantsEverything && !stats.isDirectory(); 2379 } 2380 } 2381 2382 /** 2383 * @typedef {Object} ReaddirpArguments 2384 * @property {Function=} fileFilter 2385 * @property {Function=} directoryFilter 2386 * @property {String=} type 2387 * @property {Number=} depth 2388 * @property {String=} root 2389 * @property {Boolean=} lstat 2390 * @property {Boolean=} bigint 2391 */ 2392 2393 /** 2394 * Main function which ends up calling readdirRec and reads all files and directories in given root recursively. 2395 * @param {String} root Root directory 2396 * @param {ReaddirpArguments=} options Options to specify root (start directory), filters and recursion depth 2397 */ 2398 const readdirp = (root, options = {}) => { 2399 let type = options.entryType || options.type; 2400 if (type === 'both') type = FILE_DIR_TYPE; // backwards-compatibility 2401 if (type) options.type = type; 2402 if (!root) { 2403 throw new Error('readdirp: root argument is required. Usage: readdirp(root, options)'); 2404 } else if (typeof root !== 'string') { 2405 throw new TypeError('readdirp: root argument must be a string. Usage: readdirp(root, options)'); 2406 } else if (type && !ALL_TYPES.includes(type)) { 2407 throw new Error(`readdirp: Invalid type passed. Use one of ${ALL_TYPES.join(', ')}`); 2408 } 2409 2410 options.root = root; 2411 return new ReaddirpStream(options); 2412 }; 2413 2414 const readdirpPromise = (root, options = {}) => { 2415 return new Promise((resolve, reject) => { 2416 const files = []; 2417 readdirp(root, options) 2418 .on('data', entry => files.push(entry)) 2419 .on('end', () => resolve(files)) 2420 .on('error', error => reject(error)); 2421 }); 2422 }; 2423 2424 readdirp.promise = readdirpPromise; 2425 readdirp.ReaddirpStream = ReaddirpStream; 2426 readdirp.default = readdirp; 2427 2428 readdirp_1 = readdirp; 2429 return readdirp_1; 2430 } 2431 2432 var anymatch = {exports: {}}; 2433 2434 var utils$1 = {}; 2435 2436 var constants$2; 2437 var hasRequiredConstants$2; 2438 2439 function requireConstants$2 () { 2440 if (hasRequiredConstants$2) return constants$2; 2441 hasRequiredConstants$2 = 1; 2442 2443 const path = require$$0$1; 2444 const WIN_SLASH = '\\\\/'; 2445 const WIN_NO_SLASH = `[^${WIN_SLASH}]`; 2446 2447 /** 2448 * Posix glob regex 2449 */ 2450 2451 const DOT_LITERAL = '\\.'; 2452 const PLUS_LITERAL = '\\+'; 2453 const QMARK_LITERAL = '\\?'; 2454 const SLASH_LITERAL = '\\/'; 2455 const ONE_CHAR = '(?=.)'; 2456 const QMARK = '[^/]'; 2457 const END_ANCHOR = `(?:${SLASH_LITERAL}|$)`; 2458 const START_ANCHOR = `(?:^|${SLASH_LITERAL})`; 2459 const DOTS_SLASH = `${DOT_LITERAL}{1,2}${END_ANCHOR}`; 2460 const NO_DOT = `(?!${DOT_LITERAL})`; 2461 const NO_DOTS = `(?!${START_ANCHOR}${DOTS_SLASH})`; 2462 const NO_DOT_SLASH = `(?!${DOT_LITERAL}{0,1}${END_ANCHOR})`; 2463 const NO_DOTS_SLASH = `(?!${DOTS_SLASH})`; 2464 const QMARK_NO_DOT = `[^.${SLASH_LITERAL}]`; 2465 const STAR = `${QMARK}*?`; 2466 2467 const POSIX_CHARS = { 2468 DOT_LITERAL, 2469 PLUS_LITERAL, 2470 QMARK_LITERAL, 2471 SLASH_LITERAL, 2472 ONE_CHAR, 2473 QMARK, 2474 END_ANCHOR, 2475 DOTS_SLASH, 2476 NO_DOT, 2477 NO_DOTS, 2478 NO_DOT_SLASH, 2479 NO_DOTS_SLASH, 2480 QMARK_NO_DOT, 2481 STAR, 2482 START_ANCHOR 2483 }; 2484 2485 /** 2486 * Windows glob regex 2487 */ 2488 2489 const WINDOWS_CHARS = { 2490 ...POSIX_CHARS, 2491 2492 SLASH_LITERAL: `[${WIN_SLASH}]`, 2493 QMARK: WIN_NO_SLASH, 2494 STAR: `${WIN_NO_SLASH}*?`, 2495 DOTS_SLASH: `${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$)`, 2496 NO_DOT: `(?!${DOT_LITERAL})`, 2497 NO_DOTS: `(?!(?:^|[${WIN_SLASH}])${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`, 2498 NO_DOT_SLASH: `(?!${DOT_LITERAL}{0,1}(?:[${WIN_SLASH}]|$))`, 2499 NO_DOTS_SLASH: `(?!${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`, 2500 QMARK_NO_DOT: `[^.${WIN_SLASH}]`, 2501 START_ANCHOR: `(?:^|[${WIN_SLASH}])`, 2502 END_ANCHOR: `(?:[${WIN_SLASH}]|$)` 2503 }; 2504 2505 /** 2506 * POSIX Bracket Regex 2507 */ 2508 2509 const POSIX_REGEX_SOURCE = { 2510 alnum: 'a-zA-Z0-9', 2511 alpha: 'a-zA-Z', 2512 ascii: '\\x00-\\x7F', 2513 blank: ' \\t', 2514 cntrl: '\\x00-\\x1F\\x7F', 2515 digit: '0-9', 2516 graph: '\\x21-\\x7E', 2517 lower: 'a-z', 2518 print: '\\x20-\\x7E ', 2519 punct: '\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~', 2520 space: ' \\t\\r\\n\\v\\f', 2521 upper: 'A-Z', 2522 word: 'A-Za-z0-9_', 2523 xdigit: 'A-Fa-f0-9' 2524 }; 2525 2526 constants$2 = { 2527 MAX_LENGTH: 1024 * 64, 2528 POSIX_REGEX_SOURCE, 2529 2530 // regular expressions 2531 REGEX_BACKSLASH: /\\(?![*+?^${}(|)[\]])/g, 2532 REGEX_NON_SPECIAL_CHARS: /^[^@![\].,$*+?^{}()|\\/]+/, 2533 REGEX_SPECIAL_CHARS: /[-*+?.^${}(|)[\]]/, 2534 REGEX_SPECIAL_CHARS_BACKREF: /(\\?)((\W)(\3*))/g, 2535 REGEX_SPECIAL_CHARS_GLOBAL: /([-*+?.^${}(|)[\]])/g, 2536 REGEX_REMOVE_BACKSLASH: /(?:\[.*?[^\\]\]|\\(?=.))/g, 2537 2538 // Replace globs with equivalent patterns to reduce parsing time. 2539 REPLACEMENTS: { 2540 '***': '*', 2541 '**/**': '**', 2542 '**/**/**': '**' 2543 }, 2544 2545 // Digits 2546 CHAR_0: 48, /* 0 */ 2547 CHAR_9: 57, /* 9 */ 2548 2549 // Alphabet chars. 2550 CHAR_UPPERCASE_A: 65, /* A */ 2551 CHAR_LOWERCASE_A: 97, /* a */ 2552 CHAR_UPPERCASE_Z: 90, /* Z */ 2553 CHAR_LOWERCASE_Z: 122, /* z */ 2554 2555 CHAR_LEFT_PARENTHESES: 40, /* ( */ 2556 CHAR_RIGHT_PARENTHESES: 41, /* ) */ 2557 2558 CHAR_ASTERISK: 42, /* * */ 2559 2560 // Non-alphabetic chars. 2561 CHAR_AMPERSAND: 38, /* & */ 2562 CHAR_AT: 64, /* @ */ 2563 CHAR_BACKWARD_SLASH: 92, /* \ */ 2564 CHAR_CARRIAGE_RETURN: 13, /* \r */ 2565 CHAR_CIRCUMFLEX_ACCENT: 94, /* ^ */ 2566 CHAR_COLON: 58, /* : */ 2567 CHAR_COMMA: 44, /* , */ 2568 CHAR_DOT: 46, /* . */ 2569 CHAR_DOUBLE_QUOTE: 34, /* " */ 2570 CHAR_EQUAL: 61, /* = */ 2571 CHAR_EXCLAMATION_MARK: 33, /* ! */ 2572 CHAR_FORM_FEED: 12, /* \f */ 2573 CHAR_FORWARD_SLASH: 47, /* / */ 2574 CHAR_GRAVE_ACCENT: 96, /* ` */ 2575 CHAR_HASH: 35, /* # */ 2576 CHAR_HYPHEN_MINUS: 45, /* - */ 2577 CHAR_LEFT_ANGLE_BRACKET: 60, /* < */ 2578 CHAR_LEFT_CURLY_BRACE: 123, /* { */ 2579 CHAR_LEFT_SQUARE_BRACKET: 91, /* [ */ 2580 CHAR_LINE_FEED: 10, /* \n */ 2581 CHAR_NO_BREAK_SPACE: 160, /* \u00A0 */ 2582 CHAR_PERCENT: 37, /* % */ 2583 CHAR_PLUS: 43, /* + */ 2584 CHAR_QUESTION_MARK: 63, /* ? */ 2585 CHAR_RIGHT_ANGLE_BRACKET: 62, /* > */ 2586 CHAR_RIGHT_CURLY_BRACE: 125, /* } */ 2587 CHAR_RIGHT_SQUARE_BRACKET: 93, /* ] */ 2588 CHAR_SEMICOLON: 59, /* ; */ 2589 CHAR_SINGLE_QUOTE: 39, /* ' */ 2590 CHAR_SPACE: 32, /* */ 2591 CHAR_TAB: 9, /* \t */ 2592 CHAR_UNDERSCORE: 95, /* _ */ 2593 CHAR_VERTICAL_LINE: 124, /* | */ 2594 CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279, /* \uFEFF */ 2595 2596 SEP: path.sep, 2597 2598 /** 2599 * Create EXTGLOB_CHARS 2600 */ 2601 2602 extglobChars(chars) { 2603 return { 2604 '!': { type: 'negate', open: '(?:(?!(?:', close: `))${chars.STAR})` }, 2605 '?': { type: 'qmark', open: '(?:', close: ')?' }, 2606 '+': { type: 'plus', open: '(?:', close: ')+' }, 2607 '*': { type: 'star', open: '(?:', close: ')*' }, 2608 '@': { type: 'at', open: '(?:', close: ')' } 2609 }; 2610 }, 2611 2612 /** 2613 * Create GLOB_CHARS 2614 */ 2615 2616 globChars(win32) { 2617 return win32 === true ? WINDOWS_CHARS : POSIX_CHARS; 2618 } 2619 }; 2620 return constants$2; 2621 } 2622 2623 var hasRequiredUtils$1; 2624 2625 function requireUtils$1 () { 2626 if (hasRequiredUtils$1) return utils$1; 2627 hasRequiredUtils$1 = 1; 2628 (function (exports) { 2629 2630 const path = require$$0$1; 2631 const win32 = process.platform === 'win32'; 2632 const { 2633 REGEX_BACKSLASH, 2634 REGEX_REMOVE_BACKSLASH, 2635 REGEX_SPECIAL_CHARS, 2636 REGEX_SPECIAL_CHARS_GLOBAL 2637 } = /*@__PURE__*/ requireConstants$2(); 2638 2639 exports.isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); 2640 exports.hasRegexChars = str => REGEX_SPECIAL_CHARS.test(str); 2641 exports.isRegexChar = str => str.length === 1 && exports.hasRegexChars(str); 2642 exports.escapeRegex = str => str.replace(REGEX_SPECIAL_CHARS_GLOBAL, '\\$1'); 2643 exports.toPosixSlashes = str => str.replace(REGEX_BACKSLASH, '/'); 2644 2645 exports.removeBackslashes = str => { 2646 return str.replace(REGEX_REMOVE_BACKSLASH, match => { 2647 return match === '\\' ? '' : match; 2648 }); 2649 }; 2650 2651 exports.supportsLookbehinds = () => { 2652 const segs = process.version.slice(1).split('.').map(Number); 2653 if (segs.length === 3 && segs[0] >= 9 || (segs[0] === 8 && segs[1] >= 10)) { 2654 return true; 2655 } 2656 return false; 2657 }; 2658 2659 exports.isWindows = options => { 2660 if (options && typeof options.windows === 'boolean') { 2661 return options.windows; 2662 } 2663 return win32 === true || path.sep === '\\'; 2664 }; 2665 2666 exports.escapeLast = (input, char, lastIdx) => { 2667 const idx = input.lastIndexOf(char, lastIdx); 2668 if (idx === -1) return input; 2669 if (input[idx - 1] === '\\') return exports.escapeLast(input, char, idx - 1); 2670 return `${input.slice(0, idx)}\\${input.slice(idx)}`; 2671 }; 2672 2673 exports.removePrefix = (input, state = {}) => { 2674 let output = input; 2675 if (output.startsWith('./')) { 2676 output = output.slice(2); 2677 state.prefix = './'; 2678 } 2679 return output; 2680 }; 2681 2682 exports.wrapOutput = (input, state = {}, options = {}) => { 2683 const prepend = options.contains ? '' : '^'; 2684 const append = options.contains ? '' : '$'; 2685 2686 let output = `${prepend}(?:${input})${append}`; 2687 if (state.negated === true) { 2688 output = `(?:^(?!${output}).*$)`; 2689 } 2690 return output; 2691 }; 2692 } (utils$1)); 2693 return utils$1; 2694 } 2695 2696 var scan_1; 2697 var hasRequiredScan; 2698 2699 function requireScan () { 2700 if (hasRequiredScan) return scan_1; 2701 hasRequiredScan = 1; 2702 2703 const utils = /*@__PURE__*/ requireUtils$1(); 2704 const { 2705 CHAR_ASTERISK, /* * */ 2706 CHAR_AT, /* @ */ 2707 CHAR_BACKWARD_SLASH, /* \ */ 2708 CHAR_COMMA, /* , */ 2709 CHAR_DOT, /* . */ 2710 CHAR_EXCLAMATION_MARK, /* ! */ 2711 CHAR_FORWARD_SLASH, /* / */ 2712 CHAR_LEFT_CURLY_BRACE, /* { */ 2713 CHAR_LEFT_PARENTHESES, /* ( */ 2714 CHAR_LEFT_SQUARE_BRACKET, /* [ */ 2715 CHAR_PLUS, /* + */ 2716 CHAR_QUESTION_MARK, /* ? */ 2717 CHAR_RIGHT_CURLY_BRACE, /* } */ 2718 CHAR_RIGHT_PARENTHESES, /* ) */ 2719 CHAR_RIGHT_SQUARE_BRACKET /* ] */ 2720 } = /*@__PURE__*/ requireConstants$2(); 2721 2722 const isPathSeparator = code => { 2723 return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; 2724 }; 2725 2726 const depth = token => { 2727 if (token.isPrefix !== true) { 2728 token.depth = token.isGlobstar ? Infinity : 1; 2729 } 2730 }; 2731 2732 /** 2733 * Quickly scans a glob pattern and returns an object with a handful of 2734 * useful properties, like `isGlob`, `path` (the leading non-glob, if it exists), 2735 * `glob` (the actual pattern), `negated` (true if the path starts with `!` but not 2736 * with `!(`) and `negatedExtglob` (true if the path starts with `!(`). 2737 * 2738 * ```js 2739 * const pm = require('picomatch'); 2740 * console.log(pm.scan('foo/bar/*.js')); 2741 * { isGlob: true, input: 'foo/bar/*.js', base: 'foo/bar', glob: '*.js' } 2742 * ``` 2743 * @param {String} `str` 2744 * @param {Object} `options` 2745 * @return {Object} Returns an object with tokens and regex source string. 2746 * @api public 2747 */ 2748 2749 const scan = (input, options) => { 2750 const opts = options || {}; 2751 2752 const length = input.length - 1; 2753 const scanToEnd = opts.parts === true || opts.scanToEnd === true; 2754 const slashes = []; 2755 const tokens = []; 2756 const parts = []; 2757 2758 let str = input; 2759 let index = -1; 2760 let start = 0; 2761 let lastIndex = 0; 2762 let isBrace = false; 2763 let isBracket = false; 2764 let isGlob = false; 2765 let isExtglob = false; 2766 let isGlobstar = false; 2767 let braceEscaped = false; 2768 let backslashes = false; 2769 let negated = false; 2770 let negatedExtglob = false; 2771 let finished = false; 2772 let braces = 0; 2773 let prev; 2774 let code; 2775 let token = { value: '', depth: 0, isGlob: false }; 2776 2777 const eos = () => index >= length; 2778 const peek = () => str.charCodeAt(index + 1); 2779 const advance = () => { 2780 prev = code; 2781 return str.charCodeAt(++index); 2782 }; 2783 2784 while (index < length) { 2785 code = advance(); 2786 let next; 2787 2788 if (code === CHAR_BACKWARD_SLASH) { 2789 backslashes = token.backslashes = true; 2790 code = advance(); 2791 2792 if (code === CHAR_LEFT_CURLY_BRACE) { 2793 braceEscaped = true; 2794 } 2795 continue; 2796 } 2797 2798 if (braceEscaped === true || code === CHAR_LEFT_CURLY_BRACE) { 2799 braces++; 2800 2801 while (eos() !== true && (code = advance())) { 2802 if (code === CHAR_BACKWARD_SLASH) { 2803 backslashes = token.backslashes = true; 2804 advance(); 2805 continue; 2806 } 2807 2808 if (code === CHAR_LEFT_CURLY_BRACE) { 2809 braces++; 2810 continue; 2811 } 2812 2813 if (braceEscaped !== true && code === CHAR_DOT && (code = advance()) === CHAR_DOT) { 2814 isBrace = token.isBrace = true; 2815 isGlob = token.isGlob = true; 2816 finished = true; 2817 2818 if (scanToEnd === true) { 2819 continue; 2820 } 2821 2822 break; 2823 } 2824 2825 if (braceEscaped !== true && code === CHAR_COMMA) { 2826 isBrace = token.isBrace = true; 2827 isGlob = token.isGlob = true; 2828 finished = true; 2829 2830 if (scanToEnd === true) { 2831 continue; 2832 } 2833 2834 break; 2835 } 2836 2837 if (code === CHAR_RIGHT_CURLY_BRACE) { 2838 braces--; 2839 2840 if (braces === 0) { 2841 braceEscaped = false; 2842 isBrace = token.isBrace = true; 2843 finished = true; 2844 break; 2845 } 2846 } 2847 } 2848 2849 if (scanToEnd === true) { 2850 continue; 2851 } 2852 2853 break; 2854 } 2855 2856 if (code === CHAR_FORWARD_SLASH) { 2857 slashes.push(index); 2858 tokens.push(token); 2859 token = { value: '', depth: 0, isGlob: false }; 2860 2861 if (finished === true) continue; 2862 if (prev === CHAR_DOT && index === (start + 1)) { 2863 start += 2; 2864 continue; 2865 } 2866 2867 lastIndex = index + 1; 2868 continue; 2869 } 2870 2871 if (opts.noext !== true) { 2872 const isExtglobChar = code === CHAR_PLUS 2873 || code === CHAR_AT 2874 || code === CHAR_ASTERISK 2875 || code === CHAR_QUESTION_MARK 2876 || code === CHAR_EXCLAMATION_MARK; 2877 2878 if (isExtglobChar === true && peek() === CHAR_LEFT_PARENTHESES) { 2879 isGlob = token.isGlob = true; 2880 isExtglob = token.isExtglob = true; 2881 finished = true; 2882 if (code === CHAR_EXCLAMATION_MARK && index === start) { 2883 negatedExtglob = true; 2884 } 2885 2886 if (scanToEnd === true) { 2887 while (eos() !== true && (code = advance())) { 2888 if (code === CHAR_BACKWARD_SLASH) { 2889 backslashes = token.backslashes = true; 2890 code = advance(); 2891 continue; 2892 } 2893 2894 if (code === CHAR_RIGHT_PARENTHESES) { 2895 isGlob = token.isGlob = true; 2896 finished = true; 2897 break; 2898 } 2899 } 2900 continue; 2901 } 2902 break; 2903 } 2904 } 2905 2906 if (code === CHAR_ASTERISK) { 2907 if (prev === CHAR_ASTERISK) isGlobstar = token.isGlobstar = true; 2908 isGlob = token.isGlob = true; 2909 finished = true; 2910 2911 if (scanToEnd === true) { 2912 continue; 2913 } 2914 break; 2915 } 2916 2917 if (code === CHAR_QUESTION_MARK) { 2918 isGlob = token.isGlob = true; 2919 finished = true; 2920 2921 if (scanToEnd === true) { 2922 continue; 2923 } 2924 break; 2925 } 2926 2927 if (code === CHAR_LEFT_SQUARE_BRACKET) { 2928 while (eos() !== true && (next = advance())) { 2929 if (next === CHAR_BACKWARD_SLASH) { 2930 backslashes = token.backslashes = true; 2931 advance(); 2932 continue; 2933 } 2934 2935 if (next === CHAR_RIGHT_SQUARE_BRACKET) { 2936 isBracket = token.isBracket = true; 2937 isGlob = token.isGlob = true; 2938 finished = true; 2939 break; 2940 } 2941 } 2942 2943 if (scanToEnd === true) { 2944 continue; 2945 } 2946 2947 break; 2948 } 2949 2950 if (opts.nonegate !== true && code === CHAR_EXCLAMATION_MARK && index === start) { 2951 negated = token.negated = true; 2952 start++; 2953 continue; 2954 } 2955 2956 if (opts.noparen !== true && code === CHAR_LEFT_PARENTHESES) { 2957 isGlob = token.isGlob = true; 2958 2959 if (scanToEnd === true) { 2960 while (eos() !== true && (code = advance())) { 2961 if (code === CHAR_LEFT_PARENTHESES) { 2962 backslashes = token.backslashes = true; 2963 code = advance(); 2964 continue; 2965 } 2966 2967 if (code === CHAR_RIGHT_PARENTHESES) { 2968 finished = true; 2969 break; 2970 } 2971 } 2972 continue; 2973 } 2974 break; 2975 } 2976 2977 if (isGlob === true) { 2978 finished = true; 2979 2980 if (scanToEnd === true) { 2981 continue; 2982 } 2983 2984 break; 2985 } 2986 } 2987 2988 if (opts.noext === true) { 2989 isExtglob = false; 2990 isGlob = false; 2991 } 2992 2993 let base = str; 2994 let prefix = ''; 2995 let glob = ''; 2996 2997 if (start > 0) { 2998 prefix = str.slice(0, start); 2999 str = str.slice(start); 3000 lastIndex -= start; 3001 } 3002 3003 if (base && isGlob === true && lastIndex > 0) { 3004 base = str.slice(0, lastIndex); 3005 glob = str.slice(lastIndex); 3006 } else if (isGlob === true) { 3007 base = ''; 3008 glob = str; 3009 } else { 3010 base = str; 3011 } 3012 3013 if (base && base !== '' && base !== '/' && base !== str) { 3014 if (isPathSeparator(base.charCodeAt(base.length - 1))) { 3015 base = base.slice(0, -1); 3016 } 3017 } 3018 3019 if (opts.unescape === true) { 3020 if (glob) glob = utils.removeBackslashes(glob); 3021 3022 if (base && backslashes === true) { 3023 base = utils.removeBackslashes(base); 3024 } 3025 } 3026 3027 const state = { 3028 prefix, 3029 input, 3030 start, 3031 base, 3032 glob, 3033 isBrace, 3034 isBracket, 3035 isGlob, 3036 isExtglob, 3037 isGlobstar, 3038 negated, 3039 negatedExtglob 3040 }; 3041 3042 if (opts.tokens === true) { 3043 state.maxDepth = 0; 3044 if (!isPathSeparator(code)) { 3045 tokens.push(token); 3046 } 3047 state.tokens = tokens; 3048 } 3049 3050 if (opts.parts === true || opts.tokens === true) { 3051 let prevIndex; 3052 3053 for (let idx = 0; idx < slashes.length; idx++) { 3054 const n = prevIndex ? prevIndex + 1 : start; 3055 const i = slashes[idx]; 3056 const value = input.slice(n, i); 3057 if (opts.tokens) { 3058 if (idx === 0 && start !== 0) { 3059 tokens[idx].isPrefix = true; 3060 tokens[idx].value = prefix; 3061 } else { 3062 tokens[idx].value = value; 3063 } 3064 depth(tokens[idx]); 3065 state.maxDepth += tokens[idx].depth; 3066 } 3067 if (idx !== 0 || value !== '') { 3068 parts.push(value); 3069 } 3070 prevIndex = i; 3071 } 3072 3073 if (prevIndex && prevIndex + 1 < input.length) { 3074 const value = input.slice(prevIndex + 1); 3075 parts.push(value); 3076 3077 if (opts.tokens) { 3078 tokens[tokens.length - 1].value = value; 3079 depth(tokens[tokens.length - 1]); 3080 state.maxDepth += tokens[tokens.length - 1].depth; 3081 } 3082 } 3083 3084 state.slashes = slashes; 3085 state.parts = parts; 3086 } 3087 3088 return state; 3089 }; 3090 3091 scan_1 = scan; 3092 return scan_1; 3093 } 3094 3095 var parse_1$1; 3096 var hasRequiredParse$1; 3097 3098 function requireParse$1 () { 3099 if (hasRequiredParse$1) return parse_1$1; 3100 hasRequiredParse$1 = 1; 3101 3102 const constants = /*@__PURE__*/ requireConstants$2(); 3103 const utils = /*@__PURE__*/ requireUtils$1(); 3104 3105 /** 3106 * Constants 3107 */ 3108 3109 const { 3110 MAX_LENGTH, 3111 POSIX_REGEX_SOURCE, 3112 REGEX_NON_SPECIAL_CHARS, 3113 REGEX_SPECIAL_CHARS_BACKREF, 3114 REPLACEMENTS 3115 } = constants; 3116 3117 /** 3118 * Helpers 3119 */ 3120 3121 const expandRange = (args, options) => { 3122 if (typeof options.expandRange === 'function') { 3123 return options.expandRange(...args, options); 3124 } 3125 3126 args.sort(); 3127 const value = `[${args.join('-')}]`; 3128 3129 return value; 3130 }; 3131 3132 /** 3133 * Create the message for a syntax error 3134 */ 3135 3136 const syntaxError = (type, char) => { 3137 return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`; 3138 }; 3139 3140 /** 3141 * Parse the given input string. 3142 * @param {String} input 3143 * @param {Object} options 3144 * @return {Object} 3145 */ 3146 3147 const parse = (input, options) => { 3148 if (typeof input !== 'string') { 3149 throw new TypeError('Expected a string'); 3150 } 3151 3152 input = REPLACEMENTS[input] || input; 3153 3154 const opts = { ...options }; 3155 const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; 3156 3157 let len = input.length; 3158 if (len > max) { 3159 throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`); 3160 } 3161 3162 const bos = { type: 'bos', value: '', output: opts.prepend || '' }; 3163 const tokens = [bos]; 3164 3165 const capture = opts.capture ? '' : '?:'; 3166 const win32 = utils.isWindows(options); 3167 3168 // create constants based on platform, for windows or posix 3169 const PLATFORM_CHARS = constants.globChars(win32); 3170 const EXTGLOB_CHARS = constants.extglobChars(PLATFORM_CHARS); 3171 3172 const { 3173 DOT_LITERAL, 3174 PLUS_LITERAL, 3175 SLASH_LITERAL, 3176 ONE_CHAR, 3177 DOTS_SLASH, 3178 NO_DOT, 3179 NO_DOT_SLASH, 3180 NO_DOTS_SLASH, 3181 QMARK, 3182 QMARK_NO_DOT, 3183 STAR, 3184 START_ANCHOR 3185 } = PLATFORM_CHARS; 3186 3187 const globstar = opts => { 3188 return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`; 3189 }; 3190 3191 const nodot = opts.dot ? '' : NO_DOT; 3192 const qmarkNoDot = opts.dot ? QMARK : QMARK_NO_DOT; 3193 let star = opts.bash === true ? globstar(opts) : STAR; 3194 3195 if (opts.capture) { 3196 star = `(${star})`; 3197 } 3198 3199 // minimatch options support 3200 if (typeof opts.noext === 'boolean') { 3201 opts.noextglob = opts.noext; 3202 } 3203 3204 const state = { 3205 input, 3206 index: -1, 3207 start: 0, 3208 dot: opts.dot === true, 3209 consumed: '', 3210 output: '', 3211 prefix: '', 3212 backtrack: false, 3213 negated: false, 3214 brackets: 0, 3215 braces: 0, 3216 parens: 0, 3217 quotes: 0, 3218 globstar: false, 3219 tokens 3220 }; 3221 3222 input = utils.removePrefix(input, state); 3223 len = input.length; 3224 3225 const extglobs = []; 3226 const braces = []; 3227 const stack = []; 3228 let prev = bos; 3229 let value; 3230 3231 /** 3232 * Tokenizing helpers 3233 */ 3234 3235 const eos = () => state.index === len - 1; 3236 const peek = state.peek = (n = 1) => input[state.index + n]; 3237 const advance = state.advance = () => input[++state.index] || ''; 3238 const remaining = () => input.slice(state.index + 1); 3239 const consume = (value = '', num = 0) => { 3240 state.consumed += value; 3241 state.index += num; 3242 }; 3243 3244 const append = token => { 3245 state.output += token.output != null ? token.output : token.value; 3246 consume(token.value); 3247 }; 3248 3249 const negate = () => { 3250 let count = 1; 3251 3252 while (peek() === '!' && (peek(2) !== '(' || peek(3) === '?')) { 3253 advance(); 3254 state.start++; 3255 count++; 3256 } 3257 3258 if (count % 2 === 0) { 3259 return false; 3260 } 3261 3262 state.negated = true; 3263 state.start++; 3264 return true; 3265 }; 3266 3267 const increment = type => { 3268 state[type]++; 3269 stack.push(type); 3270 }; 3271 3272 const decrement = type => { 3273 state[type]--; 3274 stack.pop(); 3275 }; 3276 3277 /** 3278 * Push tokens onto the tokens array. This helper speeds up 3279 * tokenizing by 1) helping us avoid backtracking as much as possible, 3280 * and 2) helping us avoid creating extra tokens when consecutive 3281 * characters are plain text. This improves performance and simplifies 3282 * lookbehinds. 3283 */ 3284 3285 const push = tok => { 3286 if (prev.type === 'globstar') { 3287 const isBrace = state.braces > 0 && (tok.type === 'comma' || tok.type === 'brace'); 3288 const isExtglob = tok.extglob === true || (extglobs.length && (tok.type === 'pipe' || tok.type === 'paren')); 3289 3290 if (tok.type !== 'slash' && tok.type !== 'paren' && !isBrace && !isExtglob) { 3291 state.output = state.output.slice(0, -prev.output.length); 3292 prev.type = 'star'; 3293 prev.value = '*'; 3294 prev.output = star; 3295 state.output += prev.output; 3296 } 3297 } 3298 3299 if (extglobs.length && tok.type !== 'paren') { 3300 extglobs[extglobs.length - 1].inner += tok.value; 3301 } 3302 3303 if (tok.value || tok.output) append(tok); 3304 if (prev && prev.type === 'text' && tok.type === 'text') { 3305 prev.value += tok.value; 3306 prev.output = (prev.output || '') + tok.value; 3307 return; 3308 } 3309 3310 tok.prev = prev; 3311 tokens.push(tok); 3312 prev = tok; 3313 }; 3314 3315 const extglobOpen = (type, value) => { 3316 const token = { ...EXTGLOB_CHARS[value], conditions: 1, inner: '' }; 3317 3318 token.prev = prev; 3319 token.parens = state.parens; 3320 token.output = state.output; 3321 const output = (opts.capture ? '(' : '') + token.open; 3322 3323 increment('parens'); 3324 push({ type, value, output: state.output ? '' : ONE_CHAR }); 3325 push({ type: 'paren', extglob: true, value: advance(), output }); 3326 extglobs.push(token); 3327 }; 3328 3329 const extglobClose = token => { 3330 let output = token.close + (opts.capture ? ')' : ''); 3331 let rest; 3332 3333 if (token.type === 'negate') { 3334 let extglobStar = star; 3335 3336 if (token.inner && token.inner.length > 1 && token.inner.includes('/')) { 3337 extglobStar = globstar(opts); 3338 } 3339 3340 if (extglobStar !== star || eos() || /^\)+$/.test(remaining())) { 3341 output = token.close = `)$))${extglobStar}`; 3342 } 3343 3344 if (token.inner.includes('*') && (rest = remaining()) && /^\.[^\\/.]+$/.test(rest)) { 3345 // Any non-magical string (`.ts`) or even nested expression (`.{ts,tsx}`) can follow after the closing parenthesis. 3346 // In this case, we need to parse the string and use it in the output of the original pattern. 3347 // Suitable patterns: `/!(*.d).ts`, `/!(*.d).{ts,tsx}`, `**/!(*-dbg).@(js)`. 3348 // 3349 // Disabling the `fastpaths` option due to a problem with parsing strings as `.ts` in the pattern like `**/!(*.d).ts`. 3350 const expression = parse(rest, { ...options, fastpaths: false }).output; 3351 3352 output = token.close = `)${expression})${extglobStar})`; 3353 } 3354 3355 if (token.prev.type === 'bos') { 3356 state.negatedExtglob = true; 3357 } 3358 } 3359 3360 push({ type: 'paren', extglob: true, value, output }); 3361 decrement('parens'); 3362 }; 3363 3364 /** 3365 * Fast paths 3366 */ 3367 3368 if (opts.fastpaths !== false && !/(^[*!]|[/()[\]{}"])/.test(input)) { 3369 let backslashes = false; 3370 3371 let output = input.replace(REGEX_SPECIAL_CHARS_BACKREF, (m, esc, chars, first, rest, index) => { 3372 if (first === '\\') { 3373 backslashes = true; 3374 return m; 3375 } 3376 3377 if (first === '?') { 3378 if (esc) { 3379 return esc + first + (rest ? QMARK.repeat(rest.length) : ''); 3380 } 3381 if (index === 0) { 3382 return qmarkNoDot + (rest ? QMARK.repeat(rest.length) : ''); 3383 } 3384 return QMARK.repeat(chars.length); 3385 } 3386 3387 if (first === '.') { 3388 return DOT_LITERAL.repeat(chars.length); 3389 } 3390 3391 if (first === '*') { 3392 if (esc) { 3393 return esc + first + (rest ? star : ''); 3394 } 3395 return star; 3396 } 3397 return esc ? m : `\\${m}`; 3398 }); 3399 3400 if (backslashes === true) { 3401 if (opts.unescape === true) { 3402 output = output.replace(/\\/g, ''); 3403 } else { 3404 output = output.replace(/\\+/g, m => { 3405 return m.length % 2 === 0 ? '\\\\' : (m ? '\\' : ''); 3406 }); 3407 } 3408 } 3409 3410 if (output === input && opts.contains === true) { 3411 state.output = input; 3412 return state; 3413 } 3414 3415 state.output = utils.wrapOutput(output, state, options); 3416 return state; 3417 } 3418 3419 /** 3420 * Tokenize input until we reach end-of-string 3421 */ 3422 3423 while (!eos()) { 3424 value = advance(); 3425 3426 if (value === '\u0000') { 3427 continue; 3428 } 3429 3430 /** 3431 * Escaped characters 3432 */ 3433 3434 if (value === '\\') { 3435 const next = peek(); 3436 3437 if (next === '/' && opts.bash !== true) { 3438 continue; 3439 } 3440 3441 if (next === '.' || next === ';') { 3442 continue; 3443 } 3444 3445 if (!next) { 3446 value += '\\'; 3447 push({ type: 'text', value }); 3448 continue; 3449 } 3450 3451 // collapse slashes to reduce potential for exploits 3452 const match = /^\\+/.exec(remaining()); 3453 let slashes = 0; 3454 3455 if (match && match[0].length > 2) { 3456 slashes = match[0].length; 3457 state.index += slashes; 3458 if (slashes % 2 !== 0) { 3459 value += '\\'; 3460 } 3461 } 3462 3463 if (opts.unescape === true) { 3464 value = advance(); 3465 } else { 3466 value += advance(); 3467 } 3468 3469 if (state.brackets === 0) { 3470 push({ type: 'text', value }); 3471 continue; 3472 } 3473 } 3474 3475 /** 3476 * If we're inside a regex character class, continue 3477 * until we reach the closing bracket. 3478 */ 3479 3480 if (state.brackets > 0 && (value !== ']' || prev.value === '[' || prev.value === '[^')) { 3481 if (opts.posix !== false && value === ':') { 3482 const inner = prev.value.slice(1); 3483 if (inner.includes('[')) { 3484 prev.posix = true; 3485 3486 if (inner.includes(':')) { 3487 const idx = prev.value.lastIndexOf('['); 3488 const pre = prev.value.slice(0, idx); 3489 const rest = prev.value.slice(idx + 2); 3490 const posix = POSIX_REGEX_SOURCE[rest]; 3491 if (posix) { 3492 prev.value = pre + posix; 3493 state.backtrack = true; 3494 advance(); 3495 3496 if (!bos.output && tokens.indexOf(prev) === 1) { 3497 bos.output = ONE_CHAR; 3498 } 3499 continue; 3500 } 3501 } 3502 } 3503 } 3504 3505 if ((value === '[' && peek() !== ':') || (value === '-' && peek() === ']')) { 3506 value = `\\${value}`; 3507 } 3508 3509 if (value === ']' && (prev.value === '[' || prev.value === '[^')) { 3510 value = `\\${value}`; 3511 } 3512 3513 if (opts.posix === true && value === '!' && prev.value === '[') { 3514 value = '^'; 3515 } 3516 3517 prev.value += value; 3518 append({ value }); 3519 continue; 3520 } 3521 3522 /** 3523 * If we're inside a quoted string, continue 3524 * until we reach the closing double quote. 3525 */ 3526 3527 if (state.quotes === 1 && value !== '"') { 3528 value = utils.escapeRegex(value); 3529 prev.value += value; 3530 append({ value }); 3531 continue; 3532 } 3533 3534 /** 3535 * Double quotes 3536 */ 3537 3538 if (value === '"') { 3539 state.quotes = state.quotes === 1 ? 0 : 1; 3540 if (opts.keepQuotes === true) { 3541 push({ type: 'text', value }); 3542 } 3543 continue; 3544 } 3545 3546 /** 3547 * Parentheses 3548 */ 3549 3550 if (value === '(') { 3551 increment('parens'); 3552 push({ type: 'paren', value }); 3553 continue; 3554 } 3555 3556 if (value === ')') { 3557 if (state.parens === 0 && opts.strictBrackets === true) { 3558 throw new SyntaxError(syntaxError('opening', '(')); 3559 } 3560 3561 const extglob = extglobs[extglobs.length - 1]; 3562 if (extglob && state.parens === extglob.parens + 1) { 3563 extglobClose(extglobs.pop()); 3564 continue; 3565 } 3566 3567 push({ type: 'paren', value, output: state.parens ? ')' : '\\)' }); 3568 decrement('parens'); 3569 continue; 3570 } 3571 3572 /** 3573 * Square brackets 3574 */ 3575 3576 if (value === '[') { 3577 if (opts.nobracket === true || !remaining().includes(']')) { 3578 if (opts.nobracket !== true && opts.strictBrackets === true) { 3579 throw new SyntaxError(syntaxError('closing', ']')); 3580 } 3581 3582 value = `\\${value}`; 3583 } else { 3584 increment('brackets'); 3585 } 3586 3587 push({ type: 'bracket', value }); 3588 continue; 3589 } 3590 3591 if (value === ']') { 3592 if (opts.nobracket === true || (prev && prev.type === 'bracket' && prev.value.length === 1)) { 3593 push({ type: 'text', value, output: `\\${value}` }); 3594 continue; 3595 } 3596 3597 if (state.brackets === 0) { 3598 if (opts.strictBrackets === true) { 3599 throw new SyntaxError(syntaxError('opening', '[')); 3600 } 3601 3602 push({ type: 'text', value, output: `\\${value}` }); 3603 continue; 3604 } 3605 3606 decrement('brackets'); 3607 3608 const prevValue = prev.value.slice(1); 3609 if (prev.posix !== true && prevValue[0] === '^' && !prevValue.includes('/')) { 3610 value = `/${value}`; 3611 } 3612 3613 prev.value += value; 3614 append({ value }); 3615 3616 // when literal brackets are explicitly disabled 3617 // assume we should match with a regex character class 3618 if (opts.literalBrackets === false || utils.hasRegexChars(prevValue)) { 3619 continue; 3620 } 3621 3622 const escaped = utils.escapeRegex(prev.value); 3623 state.output = state.output.slice(0, -prev.value.length); 3624 3625 // when literal brackets are explicitly enabled 3626 // assume we should escape the brackets to match literal characters 3627 if (opts.literalBrackets === true) { 3628 state.output += escaped; 3629 prev.value = escaped; 3630 continue; 3631 } 3632 3633 // when the user specifies nothing, try to match both 3634 prev.value = `(${capture}${escaped}|${prev.value})`; 3635 state.output += prev.value; 3636 continue; 3637 } 3638 3639 /** 3640 * Braces 3641 */ 3642 3643 if (value === '{' && opts.nobrace !== true) { 3644 increment('braces'); 3645 3646 const open = { 3647 type: 'brace', 3648 value, 3649 output: '(', 3650 outputIndex: state.output.length, 3651 tokensIndex: state.tokens.length 3652 }; 3653 3654 braces.push(open); 3655 push(open); 3656 continue; 3657 } 3658 3659 if (value === '}') { 3660 const brace = braces[braces.length - 1]; 3661 3662 if (opts.nobrace === true || !brace) { 3663 push({ type: 'text', value, output: value }); 3664 continue; 3665 } 3666 3667 let output = ')'; 3668 3669 if (brace.dots === true) { 3670 const arr = tokens.slice(); 3671 const range = []; 3672 3673 for (let i = arr.length - 1; i >= 0; i--) { 3674 tokens.pop(); 3675 if (arr[i].type === 'brace') { 3676 break; 3677 } 3678 if (arr[i].type !== 'dots') { 3679 range.unshift(arr[i].value); 3680 } 3681 } 3682 3683 output = expandRange(range, opts); 3684 state.backtrack = true; 3685 } 3686 3687 if (brace.comma !== true && brace.dots !== true) { 3688 const out = state.output.slice(0, brace.outputIndex); 3689 const toks = state.tokens.slice(brace.tokensIndex); 3690 brace.value = brace.output = '\\{'; 3691 value = output = '\\}'; 3692 state.output = out; 3693 for (const t of toks) { 3694 state.output += (t.output || t.value); 3695 } 3696 } 3697 3698 push({ type: 'brace', value, output }); 3699 decrement('braces'); 3700 braces.pop(); 3701 continue; 3702 } 3703 3704 /** 3705 * Pipes 3706 */ 3707 3708 if (value === '|') { 3709 if (extglobs.length > 0) { 3710 extglobs[extglobs.length - 1].conditions++; 3711 } 3712 push({ type: 'text', value }); 3713 continue; 3714 } 3715 3716 /** 3717 * Commas 3718 */ 3719 3720 if (value === ',') { 3721 let output = value; 3722 3723 const brace = braces[braces.length - 1]; 3724 if (brace && stack[stack.length - 1] === 'braces') { 3725 brace.comma = true; 3726 output = '|'; 3727 } 3728 3729 push({ type: 'comma', value, output }); 3730 continue; 3731 } 3732 3733 /** 3734 * Slashes 3735 */ 3736 3737 if (value === '/') { 3738 // if the beginning of the glob is "./", advance the start 3739 // to the current index, and don't add the "./" characters 3740 // to the state. This greatly simplifies lookbehinds when 3741 // checking for BOS characters like "!" and "." (not "./") 3742 if (prev.type === 'dot' && state.index === state.start + 1) { 3743 state.start = state.index + 1; 3744 state.consumed = ''; 3745 state.output = ''; 3746 tokens.pop(); 3747 prev = bos; // reset "prev" to the first token 3748 continue; 3749 } 3750 3751 push({ type: 'slash', value, output: SLASH_LITERAL }); 3752 continue; 3753 } 3754 3755 /** 3756 * Dots 3757 */ 3758 3759 if (value === '.') { 3760 if (state.braces > 0 && prev.type === 'dot') { 3761 if (prev.value === '.') prev.output = DOT_LITERAL; 3762 const brace = braces[braces.length - 1]; 3763 prev.type = 'dots'; 3764 prev.output += value; 3765 prev.value += value; 3766 brace.dots = true; 3767 continue; 3768 } 3769 3770 if ((state.braces + state.parens) === 0 && prev.type !== 'bos' && prev.type !== 'slash') { 3771 push({ type: 'text', value, output: DOT_LITERAL }); 3772 continue; 3773 } 3774 3775 push({ type: 'dot', value, output: DOT_LITERAL }); 3776 continue; 3777 } 3778 3779 /** 3780 * Question marks 3781 */ 3782 3783 if (value === '?') { 3784 const isGroup = prev && prev.value === '('; 3785 if (!isGroup && opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { 3786 extglobOpen('qmark', value); 3787 continue; 3788 } 3789 3790 if (prev && prev.type === 'paren') { 3791 const next = peek(); 3792 let output = value; 3793 3794 if (next === '<' && !utils.supportsLookbehinds()) { 3795 throw new Error('Node.js v10 or higher is required for regex lookbehinds'); 3796 } 3797 3798 if ((prev.value === '(' && !/[!=<:]/.test(next)) || (next === '<' && !/<([!=]|\w+>)/.test(remaining()))) { 3799 output = `\\${value}`; 3800 } 3801 3802 push({ type: 'text', value, output }); 3803 continue; 3804 } 3805 3806 if (opts.dot !== true && (prev.type === 'slash' || prev.type === 'bos')) { 3807 push({ type: 'qmark', value, output: QMARK_NO_DOT }); 3808 continue; 3809 } 3810 3811 push({ type: 'qmark', value, output: QMARK }); 3812 continue; 3813 } 3814 3815 /** 3816 * Exclamation 3817 */ 3818 3819 if (value === '!') { 3820 if (opts.noextglob !== true && peek() === '(') { 3821 if (peek(2) !== '?' || !/[!=<:]/.test(peek(3))) { 3822 extglobOpen('negate', value); 3823 continue; 3824 } 3825 } 3826 3827 if (opts.nonegate !== true && state.index === 0) { 3828 negate(); 3829 continue; 3830 } 3831 } 3832 3833 /** 3834 * Plus 3835 */ 3836 3837 if (value === '+') { 3838 if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { 3839 extglobOpen('plus', value); 3840 continue; 3841 } 3842 3843 if ((prev && prev.value === '(') || opts.regex === false) { 3844 push({ type: 'plus', value, output: PLUS_LITERAL }); 3845 continue; 3846 } 3847 3848 if ((prev && (prev.type === 'bracket' || prev.type === 'paren' || prev.type === 'brace')) || state.parens > 0) { 3849 push({ type: 'plus', value }); 3850 continue; 3851 } 3852 3853 push({ type: 'plus', value: PLUS_LITERAL }); 3854 continue; 3855 } 3856 3857 /** 3858 * Plain text 3859 */ 3860 3861 if (value === '@') { 3862 if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { 3863 push({ type: 'at', extglob: true, value, output: '' }); 3864 continue; 3865 } 3866 3867 push({ type: 'text', value }); 3868 continue; 3869 } 3870 3871 /** 3872 * Plain text 3873 */ 3874 3875 if (value !== '*') { 3876 if (value === '$' || value === '^') { 3877 value = `\\${value}`; 3878 } 3879 3880 const match = REGEX_NON_SPECIAL_CHARS.exec(remaining()); 3881 if (match) { 3882 value += match[0]; 3883 state.index += match[0].length; 3884 } 3885 3886 push({ type: 'text', value }); 3887 continue; 3888 } 3889 3890 /** 3891 * Stars 3892 */ 3893 3894 if (prev && (prev.type === 'globstar' || prev.star === true)) { 3895 prev.type = 'star'; 3896 prev.star = true; 3897 prev.value += value; 3898 prev.output = star; 3899 state.backtrack = true; 3900 state.globstar = true; 3901 consume(value); 3902 continue; 3903 } 3904 3905 let rest = remaining(); 3906 if (opts.noextglob !== true && /^\([^?]/.test(rest)) { 3907 extglobOpen('star', value); 3908 continue; 3909 } 3910 3911 if (prev.type === 'star') { 3912 if (opts.noglobstar === true) { 3913 consume(value); 3914 continue; 3915 } 3916 3917 const prior = prev.prev; 3918 const before = prior.prev; 3919 const isStart = prior.type === 'slash' || prior.type === 'bos'; 3920 const afterStar = before && (before.type === 'star' || before.type === 'globstar'); 3921 3922 if (opts.bash === true && (!isStart || (rest[0] && rest[0] !== '/'))) { 3923 push({ type: 'star', value, output: '' }); 3924 continue; 3925 } 3926 3927 const isBrace = state.braces > 0 && (prior.type === 'comma' || prior.type === 'brace'); 3928 const isExtglob = extglobs.length && (prior.type === 'pipe' || prior.type === 'paren'); 3929 if (!isStart && prior.type !== 'paren' && !isBrace && !isExtglob) { 3930 push({ type: 'star', value, output: '' }); 3931 continue; 3932 } 3933 3934 // strip consecutive `/**/` 3935 while (rest.slice(0, 3) === '/**') { 3936 const after = input[state.index + 4]; 3937 if (after && after !== '/') { 3938 break; 3939 } 3940 rest = rest.slice(3); 3941 consume('/**', 3); 3942 } 3943 3944 if (prior.type === 'bos' && eos()) { 3945 prev.type = 'globstar'; 3946 prev.value += value; 3947 prev.output = globstar(opts); 3948 state.output = prev.output; 3949 state.globstar = true; 3950 consume(value); 3951 continue; 3952 } 3953 3954 if (prior.type === 'slash' && prior.prev.type !== 'bos' && !afterStar && eos()) { 3955 state.output = state.output.slice(0, -(prior.output + prev.output).length); 3956 prior.output = `(?:${prior.output}`; 3957 3958 prev.type = 'globstar'; 3959 prev.output = globstar(opts) + (opts.strictSlashes ? ')' : '|$)'); 3960 prev.value += value; 3961 state.globstar = true; 3962 state.output += prior.output + prev.output; 3963 consume(value); 3964 continue; 3965 } 3966 3967 if (prior.type === 'slash' && prior.prev.type !== 'bos' && rest[0] === '/') { 3968 const end = rest[1] !== void 0 ? '|$' : ''; 3969 3970 state.output = state.output.slice(0, -(prior.output + prev.output).length); 3971 prior.output = `(?:${prior.output}`; 3972 3973 prev.type = 'globstar'; 3974 prev.output = `${globstar(opts)}${SLASH_LITERAL}|${SLASH_LITERAL}${end})`; 3975 prev.value += value; 3976 3977 state.output += prior.output + prev.output; 3978 state.globstar = true; 3979 3980 consume(value + advance()); 3981 3982 push({ type: 'slash', value: '/', output: '' }); 3983 continue; 3984 } 3985 3986 if (prior.type === 'bos' && rest[0] === '/') { 3987 prev.type = 'globstar'; 3988 prev.value += value; 3989 prev.output = `(?:^|${SLASH_LITERAL}|${globstar(opts)}${SLASH_LITERAL})`; 3990 state.output = prev.output; 3991 state.globstar = true; 3992 consume(value + advance()); 3993 push({ type: 'slash', value: '/', output: '' }); 3994 continue; 3995 } 3996 3997 // remove single star from output 3998 state.output = state.output.slice(0, -prev.output.length); 3999 4000 // reset previous token to globstar 4001 prev.type = 'globstar'; 4002 prev.output = globstar(opts); 4003 prev.value += value; 4004 4005 // reset output with globstar 4006 state.output += prev.output; 4007 state.globstar = true; 4008 consume(value); 4009 continue; 4010 } 4011 4012 const token = { type: 'star', value, output: star }; 4013 4014 if (opts.bash === true) { 4015 token.output = '.*?'; 4016 if (prev.type === 'bos' || prev.type === 'slash') { 4017 token.output = nodot + token.output; 4018 } 4019 push(token); 4020 continue; 4021 } 4022 4023 if (prev && (prev.type === 'bracket' || prev.type === 'paren') && opts.regex === true) { 4024 token.output = value; 4025 push(token); 4026 continue; 4027 } 4028 4029 if (state.index === state.start || prev.type === 'slash' || prev.type === 'dot') { 4030 if (prev.type === 'dot') { 4031 state.output += NO_DOT_SLASH; 4032 prev.output += NO_DOT_SLASH; 4033 4034 } else if (opts.dot === true) { 4035 state.output += NO_DOTS_SLASH; 4036 prev.output += NO_DOTS_SLASH; 4037 4038 } else { 4039 state.output += nodot; 4040 prev.output += nodot; 4041 } 4042 4043 if (peek() !== '*') { 4044 state.output += ONE_CHAR; 4045 prev.output += ONE_CHAR; 4046 } 4047 } 4048 4049 push(token); 4050 } 4051 4052 while (state.brackets > 0) { 4053 if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ']')); 4054 state.output = utils.escapeLast(state.output, '['); 4055 decrement('brackets'); 4056 } 4057 4058 while (state.parens > 0) { 4059 if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ')')); 4060 state.output = utils.escapeLast(state.output, '('); 4061 decrement('parens'); 4062 } 4063 4064 while (state.braces > 0) { 4065 if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', '}')); 4066 state.output = utils.escapeLast(state.output, '{'); 4067 decrement('braces'); 4068 } 4069 4070 if (opts.strictSlashes !== true && (prev.type === 'star' || prev.type === 'bracket')) { 4071 push({ type: 'maybe_slash', value: '', output: `${SLASH_LITERAL}?` }); 4072 } 4073 4074 // rebuild the output if we had to backtrack at any point 4075 if (state.backtrack === true) { 4076 state.output = ''; 4077 4078 for (const token of state.tokens) { 4079 state.output += token.output != null ? token.output : token.value; 4080 4081 if (token.suffix) { 4082 state.output += token.suffix; 4083 } 4084 } 4085 } 4086 4087 return state; 4088 }; 4089 4090 /** 4091 * Fast paths for creating regular expressions for common glob patterns. 4092 * This can significantly speed up processing and has very little downside 4093 * impact when none of the fast paths match. 4094 */ 4095 4096 parse.fastpaths = (input, options) => { 4097 const opts = { ...options }; 4098 const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; 4099 const len = input.length; 4100 if (len > max) { 4101 throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`); 4102 } 4103 4104 input = REPLACEMENTS[input] || input; 4105 const win32 = utils.isWindows(options); 4106 4107 // create constants based on platform, for windows or posix 4108 const { 4109 DOT_LITERAL, 4110 SLASH_LITERAL, 4111 ONE_CHAR, 4112 DOTS_SLASH, 4113 NO_DOT, 4114 NO_DOTS, 4115 NO_DOTS_SLASH, 4116 STAR, 4117 START_ANCHOR 4118 } = constants.globChars(win32); 4119 4120 const nodot = opts.dot ? NO_DOTS : NO_DOT; 4121 const slashDot = opts.dot ? NO_DOTS_SLASH : NO_DOT; 4122 const capture = opts.capture ? '' : '?:'; 4123 const state = { negated: false, prefix: '' }; 4124 let star = opts.bash === true ? '.*?' : STAR; 4125 4126 if (opts.capture) { 4127 star = `(${star})`; 4128 } 4129 4130 const globstar = opts => { 4131 if (opts.noglobstar === true) return star; 4132 return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`; 4133 }; 4134 4135 const create = str => { 4136 switch (str) { 4137 case '*': 4138 return `${nodot}${ONE_CHAR}${star}`; 4139 4140 case '.*': 4141 return `${DOT_LITERAL}${ONE_CHAR}${star}`; 4142 4143 case '*.*': 4144 return `${nodot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`; 4145 4146 case '*/*': 4147 return `${nodot}${star}${SLASH_LITERAL}${ONE_CHAR}${slashDot}${star}`; 4148 4149 case '**': 4150 return nodot + globstar(opts); 4151 4152 case '**/*': 4153 return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${ONE_CHAR}${star}`; 4154 4155 case '**/*.*': 4156 return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`; 4157 4158 case '**/.*': 4159 return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${DOT_LITERAL}${ONE_CHAR}${star}`; 4160 4161 default: { 4162 const match = /^(.*?)\.(\w+)$/.exec(str); 4163 if (!match) return; 4164 4165 const source = create(match[1]); 4166 if (!source) return; 4167 4168 return source + DOT_LITERAL + match[2]; 4169 } 4170 } 4171 }; 4172 4173 const output = utils.removePrefix(input, state); 4174 let source = create(output); 4175 4176 if (source && opts.strictSlashes !== true) { 4177 source += `${SLASH_LITERAL}?`; 4178 } 4179 4180 return source; 4181 }; 4182 4183 parse_1$1 = parse; 4184 return parse_1$1; 4185 } 4186 4187 var picomatch_1; 4188 var hasRequiredPicomatch$1; 4189 4190 function requirePicomatch$1 () { 4191 if (hasRequiredPicomatch$1) return picomatch_1; 4192 hasRequiredPicomatch$1 = 1; 4193 4194 const path = require$$0$1; 4195 const scan = /*@__PURE__*/ requireScan(); 4196 const parse = /*@__PURE__*/ requireParse$1(); 4197 const utils = /*@__PURE__*/ requireUtils$1(); 4198 const constants = /*@__PURE__*/ requireConstants$2(); 4199 const isObject = val => val && typeof val === 'object' && !Array.isArray(val); 4200 4201 /** 4202 * Creates a matcher function from one or more glob patterns. The 4203 * returned function takes a string to match as its first argument, 4204 * and returns true if the string is a match. The returned matcher 4205 * function also takes a boolean as the second argument that, when true, 4206 * returns an object with additional information. 4207 * 4208 * ```js 4209 * const picomatch = require('picomatch'); 4210 * // picomatch(glob[, options]); 4211 * 4212 * const isMatch = picomatch('*.!(*a)'); 4213 * console.log(isMatch('a.a')); //=> false 4214 * console.log(isMatch('a.b')); //=> true 4215 * ``` 4216 * @name picomatch 4217 * @param {String|Array} `globs` One or more glob patterns. 4218 * @param {Object=} `options` 4219 * @return {Function=} Returns a matcher function. 4220 * @api public 4221 */ 4222 4223 const picomatch = (glob, options, returnState = false) => { 4224 if (Array.isArray(glob)) { 4225 const fns = glob.map(input => picomatch(input, options, returnState)); 4226 const arrayMatcher = str => { 4227 for (const isMatch of fns) { 4228 const state = isMatch(str); 4229 if (state) return state; 4230 } 4231 return false; 4232 }; 4233 return arrayMatcher; 4234 } 4235 4236 const isState = isObject(glob) && glob.tokens && glob.input; 4237 4238 if (glob === '' || (typeof glob !== 'string' && !isState)) { 4239 throw new TypeError('Expected pattern to be a non-empty string'); 4240 } 4241 4242 const opts = options || {}; 4243 const posix = utils.isWindows(options); 4244 const regex = isState 4245 ? picomatch.compileRe(glob, options) 4246 : picomatch.makeRe(glob, options, false, true); 4247 4248 const state = regex.state; 4249 delete regex.state; 4250 4251 let isIgnored = () => false; 4252 if (opts.ignore) { 4253 const ignoreOpts = { ...options, ignore: null, onMatch: null, onResult: null }; 4254 isIgnored = picomatch(opts.ignore, ignoreOpts, returnState); 4255 } 4256 4257 const matcher = (input, returnObject = false) => { 4258 const { isMatch, match, output } = picomatch.test(input, regex, options, { glob, posix }); 4259 const result = { glob, state, regex, posix, input, output, match, isMatch }; 4260 4261 if (typeof opts.onResult === 'function') { 4262 opts.onResult(result); 4263 } 4264 4265 if (isMatch === false) { 4266 result.isMatch = false; 4267 return returnObject ? result : false; 4268 } 4269 4270 if (isIgnored(input)) { 4271 if (typeof opts.onIgnore === 'function') { 4272 opts.onIgnore(result); 4273 } 4274 result.isMatch = false; 4275 return returnObject ? result : false; 4276 } 4277 4278 if (typeof opts.onMatch === 'function') { 4279 opts.onMatch(result); 4280 } 4281 return returnObject ? result : true; 4282 }; 4283 4284 if (returnState) { 4285 matcher.state = state; 4286 } 4287 4288 return matcher; 4289 }; 4290 4291 /** 4292 * Test `input` with the given `regex`. This is used by the main 4293 * `picomatch()` function to test the input string. 4294 * 4295 * ```js 4296 * const picomatch = require('picomatch'); 4297 * // picomatch.test(input, regex[, options]); 4298 * 4299 * console.log(picomatch.test('foo/bar', /^(?:([^/]*?)\/([^/]*?))$/)); 4300 * // { isMatch: true, match: [ 'foo/', 'foo', 'bar' ], output: 'foo/bar' } 4301 * ``` 4302 * @param {String} `input` String to test. 4303 * @param {RegExp} `regex` 4304 * @return {Object} Returns an object with matching info. 4305 * @api public 4306 */ 4307 4308 picomatch.test = (input, regex, options, { glob, posix } = {}) => { 4309 if (typeof input !== 'string') { 4310 throw new TypeError('Expected input to be a string'); 4311 } 4312 4313 if (input === '') { 4314 return { isMatch: false, output: '' }; 4315 } 4316 4317 const opts = options || {}; 4318 const format = opts.format || (posix ? utils.toPosixSlashes : null); 4319 let match = input === glob; 4320 let output = (match && format) ? format(input) : input; 4321 4322 if (match === false) { 4323 output = format ? format(input) : input; 4324 match = output === glob; 4325 } 4326 4327 if (match === false || opts.capture === true) { 4328 if (opts.matchBase === true || opts.basename === true) { 4329 match = picomatch.matchBase(input, regex, options, posix); 4330 } else { 4331 match = regex.exec(output); 4332 } 4333 } 4334 4335 return { isMatch: Boolean(match), match, output }; 4336 }; 4337 4338 /** 4339 * Match the basename of a filepath. 4340 * 4341 * ```js 4342 * const picomatch = require('picomatch'); 4343 * // picomatch.matchBase(input, glob[, options]); 4344 * console.log(picomatch.matchBase('foo/bar.js', '*.js'); // true 4345 * ``` 4346 * @param {String} `input` String to test. 4347 * @param {RegExp|String} `glob` Glob pattern or regex created by [.makeRe](#makeRe). 4348 * @return {Boolean} 4349 * @api public 4350 */ 4351 4352 picomatch.matchBase = (input, glob, options, posix = utils.isWindows(options)) => { 4353 const regex = glob instanceof RegExp ? glob : picomatch.makeRe(glob, options); 4354 return regex.test(path.basename(input)); 4355 }; 4356 4357 /** 4358 * Returns true if **any** of the given glob `patterns` match the specified `string`. 4359 * 4360 * ```js 4361 * const picomatch = require('picomatch'); 4362 * // picomatch.isMatch(string, patterns[, options]); 4363 * 4364 * console.log(picomatch.isMatch('a.a', ['b.*', '*.a'])); //=> true 4365 * console.log(picomatch.isMatch('a.a', 'b.*')); //=> false 4366 * ``` 4367 * @param {String|Array} str The string to test. 4368 * @param {String|Array} patterns One or more glob patterns to use for matching. 4369 * @param {Object} [options] See available [options](#options). 4370 * @return {Boolean} Returns true if any patterns match `str` 4371 * @api public 4372 */ 4373 4374 picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str); 4375 4376 /** 4377 * Parse a glob pattern to create the source string for a regular 4378 * expression. 4379 * 4380 * ```js 4381 * const picomatch = require('picomatch'); 4382 * const result = picomatch.parse(pattern[, options]); 4383 * ``` 4384 * @param {String} `pattern` 4385 * @param {Object} `options` 4386 * @return {Object} Returns an object with useful properties and output to be used as a regex source string. 4387 * @api public 4388 */ 4389 4390 picomatch.parse = (pattern, options) => { 4391 if (Array.isArray(pattern)) return pattern.map(p => picomatch.parse(p, options)); 4392 return parse(pattern, { ...options, fastpaths: false }); 4393 }; 4394 4395 /** 4396 * Scan a glob pattern to separate the pattern into segments. 4397 * 4398 * ```js 4399 * const picomatch = require('picomatch'); 4400 * // picomatch.scan(input[, options]); 4401 * 4402 * const result = picomatch.scan('!./foo/*.js'); 4403 * console.log(result); 4404 * { prefix: '!./', 4405 * input: '!./foo/*.js', 4406 * start: 3, 4407 * base: 'foo', 4408 * glob: '*.js', 4409 * isBrace: false, 4410 * isBracket: false, 4411 * isGlob: true, 4412 * isExtglob: false, 4413 * isGlobstar: false, 4414 * negated: true } 4415 * ``` 4416 * @param {String} `input` Glob pattern to scan. 4417 * @param {Object} `options` 4418 * @return {Object} Returns an object with 4419 * @api public 4420 */ 4421 4422 picomatch.scan = (input, options) => scan(input, options); 4423 4424 /** 4425 * Compile a regular expression from the `state` object returned by the 4426 * [parse()](#parse) method. 4427 * 4428 * @param {Object} `state` 4429 * @param {Object} `options` 4430 * @param {Boolean} `returnOutput` Intended for implementors, this argument allows you to return the raw output from the parser. 4431 * @param {Boolean} `returnState` Adds the state to a `state` property on the returned regex. Useful for implementors and debugging. 4432 * @return {RegExp} 4433 * @api public 4434 */ 4435 4436 picomatch.compileRe = (state, options, returnOutput = false, returnState = false) => { 4437 if (returnOutput === true) { 4438 return state.output; 4439 } 4440 4441 const opts = options || {}; 4442 const prepend = opts.contains ? '' : '^'; 4443 const append = opts.contains ? '' : '$'; 4444 4445 let source = `${prepend}(?:${state.output})${append}`; 4446 if (state && state.negated === true) { 4447 source = `^(?!${source}).*$`; 4448 } 4449 4450 const regex = picomatch.toRegex(source, options); 4451 if (returnState === true) { 4452 regex.state = state; 4453 } 4454 4455 return regex; 4456 }; 4457 4458 /** 4459 * Create a regular expression from a parsed glob pattern. 4460 * 4461 * ```js 4462 * const picomatch = require('picomatch'); 4463 * const state = picomatch.parse('*.js'); 4464 * // picomatch.compileRe(state[, options]); 4465 * 4466 * console.log(picomatch.compileRe(state)); 4467 * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/ 4468 * ``` 4469 * @param {String} `state` The object returned from the `.parse` method. 4470 * @param {Object} `options` 4471 * @param {Boolean} `returnOutput` Implementors may use this argument to return the compiled output, instead of a regular expression. This is not exposed on the options to prevent end-users from mutating the result. 4472 * @param {Boolean} `returnState` Implementors may use this argument to return the state from the parsed glob with the returned regular expression. 4473 * @return {RegExp} Returns a regex created from the given pattern. 4474 * @api public 4475 */ 4476 4477 picomatch.makeRe = (input, options = {}, returnOutput = false, returnState = false) => { 4478 if (!input || typeof input !== 'string') { 4479 throw new TypeError('Expected a non-empty string'); 4480 } 4481 4482 let parsed = { negated: false, fastpaths: true }; 4483 4484 if (options.fastpaths !== false && (input[0] === '.' || input[0] === '*')) { 4485 parsed.output = parse.fastpaths(input, options); 4486 } 4487 4488 if (!parsed.output) { 4489 parsed = parse(input, options); 4490 } 4491 4492 return picomatch.compileRe(parsed, options, returnOutput, returnState); 4493 }; 4494 4495 /** 4496 * Create a regular expression from the given regex source string. 4497 * 4498 * ```js 4499 * const picomatch = require('picomatch'); 4500 * // picomatch.toRegex(source[, options]); 4501 * 4502 * const { output } = picomatch.parse('*.js'); 4503 * console.log(picomatch.toRegex(output)); 4504 * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/ 4505 * ``` 4506 * @param {String} `source` Regular expression source string. 4507 * @param {Object} `options` 4508 * @return {RegExp} 4509 * @api public 4510 */ 4511 4512 picomatch.toRegex = (source, options) => { 4513 try { 4514 const opts = options || {}; 4515 return new RegExp(source, opts.flags || (opts.nocase ? 'i' : '')); 4516 } catch (err) { 4517 if (options && options.debug === true) throw err; 4518 return /$^/; 4519 } 4520 }; 4521 4522 /** 4523 * Picomatch constants. 4524 * @return {Object} 4525 */ 4526 4527 picomatch.constants = constants; 4528 4529 /** 4530 * Expose "picomatch" 4531 */ 4532 4533 picomatch_1 = picomatch; 4534 return picomatch_1; 4535 } 4536 4537 var picomatch; 4538 var hasRequiredPicomatch; 4539 4540 function requirePicomatch () { 4541 if (hasRequiredPicomatch) return picomatch; 4542 hasRequiredPicomatch = 1; 4543 4544 picomatch = /*@__PURE__*/ requirePicomatch$1(); 4545 return picomatch; 4546 } 310 4547 311 4548 /*! … … 316 4553 */ 317 4554 318 var normalizePath$2 = function(path, stripTrailing) { 319 if (typeof path !== 'string') { 320 throw new TypeError('expected path to be a string'); 321 } 322 323 if (path === '\\' || path === '/') return '/'; 324 325 var len = path.length; 326 if (len <= 1) return path; 327 328 // ensure that win32 namespaces has two leading slashes, so that the path is 329 // handled properly by the win32 version of path.parse() after being normalized 330 // https://msdn.microsoft.com/library/windows/desktop/aa365247(v=vs.85).aspx#namespaces 331 var prefix = ''; 332 if (len > 4 && path[3] === '\\') { 333 var ch = path[2]; 334 if ((ch === '?' || ch === '.') && path.slice(0, 2) === '\\\\') { 335 path = path.slice(2); 336 prefix = '//'; 337 } 338 } 339 340 var segs = path.split(/[/\\]+/); 341 if (stripTrailing !== false && segs[segs.length - 1] === '') { 342 segs.pop(); 343 } 344 return prefix + segs.join('/'); 345 }; 346 347 var anymatch_1 = anymatch$2.exports; 348 349 Object.defineProperty(anymatch_1, "__esModule", { value: true }); 350 351 const picomatch = rollup.picomatch; 352 const normalizePath$1 = normalizePath$2; 353 354 /** 355 * @typedef {(testString: string) => boolean} AnymatchFn 356 * @typedef {string|RegExp|AnymatchFn} AnymatchPattern 357 * @typedef {AnymatchPattern|AnymatchPattern[]} AnymatchMatcher 358 */ 359 const BANG$1 = '!'; 360 const DEFAULT_OPTIONS = {returnIndex: false}; 361 const arrify$1 = (item) => Array.isArray(item) ? item : [item]; 362 363 /** 364 * @param {AnymatchPattern} matcher 365 * @param {object} options 366 * @returns {AnymatchFn} 367 */ 368 const createPattern = (matcher, options) => { 369 if (typeof matcher === 'function') { 370 return matcher; 371 } 372 if (typeof matcher === 'string') { 373 const glob = picomatch(matcher, options); 374 return (string) => matcher === string || glob(string); 375 } 376 if (matcher instanceof RegExp) { 377 return (string) => matcher.test(string); 378 } 379 return (string) => false; 380 }; 381 382 /** 383 * @param {Array<Function>} patterns 384 * @param {Array<Function>} negPatterns 385 * @param {String|Array} args 386 * @param {Boolean} returnIndex 387 * @returns {boolean|number} 388 */ 389 const matchPatterns = (patterns, negPatterns, args, returnIndex) => { 390 const isList = Array.isArray(args); 391 const _path = isList ? args[0] : args; 392 if (!isList && typeof _path !== 'string') { 393 throw new TypeError('anymatch: second argument must be a string: got ' + 394 Object.prototype.toString.call(_path)) 395 } 396 const path = normalizePath$1(_path, false); 397 398 for (let index = 0; index < negPatterns.length; index++) { 399 const nglob = negPatterns[index]; 400 if (nglob(path)) { 401 return returnIndex ? -1 : false; 402 } 403 } 404 405 const applied = isList && [path].concat(args.slice(1)); 406 for (let index = 0; index < patterns.length; index++) { 407 const pattern = patterns[index]; 408 if (isList ? pattern(...applied) : pattern(path)) { 409 return returnIndex ? index : true; 410 } 411 } 412 413 return returnIndex ? -1 : false; 414 }; 415 416 /** 417 * @param {AnymatchMatcher} matchers 418 * @param {Array|string} testString 419 * @param {object} options 420 * @returns {boolean|number|Function} 421 */ 422 const anymatch$1 = (matchers, testString, options = DEFAULT_OPTIONS) => { 423 if (matchers == null) { 424 throw new TypeError('anymatch: specify first argument'); 425 } 426 const opts = typeof options === 'boolean' ? {returnIndex: options} : options; 427 const returnIndex = opts.returnIndex || false; 428 429 // Early cache for matchers. 430 const mtchers = arrify$1(matchers); 431 const negatedGlobs = mtchers 432 .filter(item => typeof item === 'string' && item.charAt(0) === BANG$1) 433 .map(item => item.slice(1)) 434 .map(item => picomatch(item, opts)); 435 const patterns = mtchers 436 .filter(item => typeof item !== 'string' || (typeof item === 'string' && item.charAt(0) !== BANG$1)) 437 .map(matcher => createPattern(matcher, opts)); 438 439 if (testString == null) { 440 return (testString, ri = false) => { 441 const returnIndex = typeof ri === 'boolean' ? ri : false; 442 return matchPatterns(patterns, negatedGlobs, testString, returnIndex); 443 } 444 } 445 446 return matchPatterns(patterns, negatedGlobs, testString, returnIndex); 447 }; 448 449 anymatch$1.default = anymatch$1; 450 anymatch$2.exports = anymatch$1; 451 452 var anymatchExports = anymatch$2.exports; 4555 var normalizePath; 4556 var hasRequiredNormalizePath; 4557 4558 function requireNormalizePath () { 4559 if (hasRequiredNormalizePath) return normalizePath; 4560 hasRequiredNormalizePath = 1; 4561 normalizePath = function(path, stripTrailing) { 4562 if (typeof path !== 'string') { 4563 throw new TypeError('expected path to be a string'); 4564 } 4565 4566 if (path === '\\' || path === '/') return '/'; 4567 4568 var len = path.length; 4569 if (len <= 1) return path; 4570 4571 // ensure that win32 namespaces has two leading slashes, so that the path is 4572 // handled properly by the win32 version of path.parse() after being normalized 4573 // https://msdn.microsoft.com/library/windows/desktop/aa365247(v=vs.85).aspx#namespaces 4574 var prefix = ''; 4575 if (len > 4 && path[3] === '\\') { 4576 var ch = path[2]; 4577 if ((ch === '?' || ch === '.') && path.slice(0, 2) === '\\\\') { 4578 path = path.slice(2); 4579 prefix = '//'; 4580 } 4581 } 4582 4583 var segs = path.split(/[/\\]+/); 4584 if (stripTrailing !== false && segs[segs.length - 1] === '') { 4585 segs.pop(); 4586 } 4587 return prefix + segs.join('/'); 4588 }; 4589 return normalizePath; 4590 } 4591 4592 var anymatch_1 = anymatch.exports; 4593 4594 var hasRequiredAnymatch; 4595 4596 function requireAnymatch () { 4597 if (hasRequiredAnymatch) return anymatch.exports; 4598 hasRequiredAnymatch = 1; 4599 4600 Object.defineProperty(anymatch_1, "__esModule", { value: true }); 4601 4602 const picomatch = /*@__PURE__*/ requirePicomatch(); 4603 const normalizePath = /*@__PURE__*/ requireNormalizePath(); 4604 4605 /** 4606 * @typedef {(testString: string) => boolean} AnymatchFn 4607 * @typedef {string|RegExp|AnymatchFn} AnymatchPattern 4608 * @typedef {AnymatchPattern|AnymatchPattern[]} AnymatchMatcher 4609 */ 4610 const BANG = '!'; 4611 const DEFAULT_OPTIONS = {returnIndex: false}; 4612 const arrify = (item) => Array.isArray(item) ? item : [item]; 4613 4614 /** 4615 * @param {AnymatchPattern} matcher 4616 * @param {object} options 4617 * @returns {AnymatchFn} 4618 */ 4619 const createPattern = (matcher, options) => { 4620 if (typeof matcher === 'function') { 4621 return matcher; 4622 } 4623 if (typeof matcher === 'string') { 4624 const glob = picomatch(matcher, options); 4625 return (string) => matcher === string || glob(string); 4626 } 4627 if (matcher instanceof RegExp) { 4628 return (string) => matcher.test(string); 4629 } 4630 return (string) => false; 4631 }; 4632 4633 /** 4634 * @param {Array<Function>} patterns 4635 * @param {Array<Function>} negPatterns 4636 * @param {String|Array} args 4637 * @param {Boolean} returnIndex 4638 * @returns {boolean|number} 4639 */ 4640 const matchPatterns = (patterns, negPatterns, args, returnIndex) => { 4641 const isList = Array.isArray(args); 4642 const _path = isList ? args[0] : args; 4643 if (!isList && typeof _path !== 'string') { 4644 throw new TypeError('anymatch: second argument must be a string: got ' + 4645 Object.prototype.toString.call(_path)) 4646 } 4647 const path = normalizePath(_path, false); 4648 4649 for (let index = 0; index < negPatterns.length; index++) { 4650 const nglob = negPatterns[index]; 4651 if (nglob(path)) { 4652 return returnIndex ? -1 : false; 4653 } 4654 } 4655 4656 const applied = isList && [path].concat(args.slice(1)); 4657 for (let index = 0; index < patterns.length; index++) { 4658 const pattern = patterns[index]; 4659 if (isList ? pattern(...applied) : pattern(path)) { 4660 return returnIndex ? index : true; 4661 } 4662 } 4663 4664 return returnIndex ? -1 : false; 4665 }; 4666 4667 /** 4668 * @param {AnymatchMatcher} matchers 4669 * @param {Array|string} testString 4670 * @param {object} options 4671 * @returns {boolean|number|Function} 4672 */ 4673 const anymatch$1 = (matchers, testString, options = DEFAULT_OPTIONS) => { 4674 if (matchers == null) { 4675 throw new TypeError('anymatch: specify first argument'); 4676 } 4677 const opts = typeof options === 'boolean' ? {returnIndex: options} : options; 4678 const returnIndex = opts.returnIndex || false; 4679 4680 // Early cache for matchers. 4681 const mtchers = arrify(matchers); 4682 const negatedGlobs = mtchers 4683 .filter(item => typeof item === 'string' && item.charAt(0) === BANG) 4684 .map(item => item.slice(1)) 4685 .map(item => picomatch(item, opts)); 4686 const patterns = mtchers 4687 .filter(item => typeof item !== 'string' || (typeof item === 'string' && item.charAt(0) !== BANG)) 4688 .map(matcher => createPattern(matcher, opts)); 4689 4690 if (testString == null) { 4691 return (testString, ri = false) => { 4692 const returnIndex = typeof ri === 'boolean' ? ri : false; 4693 return matchPatterns(patterns, negatedGlobs, testString, returnIndex); 4694 } 4695 } 4696 4697 return matchPatterns(patterns, negatedGlobs, testString, returnIndex); 4698 }; 4699 4700 anymatch$1.default = anymatch$1; 4701 anymatch.exports = anymatch$1; 4702 return anymatch.exports; 4703 } 453 4704 454 4705 /*! … … 459 4710 */ 460 4711 461 var isExtglob$1 = function isExtglob(str) { 462 if (typeof str !== 'string' || str === '') { 463 return false; 464 } 465 466 var match; 467 while ((match = /(\\).|([@?!+*]\(.*\))/g.exec(str))) { 468 if (match[2]) return true; 469 str = str.slice(match.index + match[0].length); 470 } 471 472 return false; 473 }; 4712 var isExtglob; 4713 var hasRequiredIsExtglob; 4714 4715 function requireIsExtglob () { 4716 if (hasRequiredIsExtglob) return isExtglob; 4717 hasRequiredIsExtglob = 1; 4718 isExtglob = function isExtglob(str) { 4719 if (typeof str !== 'string' || str === '') { 4720 return false; 4721 } 4722 4723 var match; 4724 while ((match = /(\\).|([@?!+*]\(.*\))/g.exec(str))) { 4725 if (match[2]) return true; 4726 str = str.slice(match.index + match[0].length); 4727 } 4728 4729 return false; 4730 }; 4731 return isExtglob; 4732 } 474 4733 475 4734 /*! … … 480 4739 */ 481 4740 482 var isExtglob = isExtglob$1; 483 var chars = { '{': '}', '(': ')', '[': ']'}; 484 var strictCheck = function(str) { 485 if (str[0] === '!') { 486 return true; 487 } 488 var index = 0; 489 var pipeIndex = -2; 490 var closeSquareIndex = -2; 491 var closeCurlyIndex = -2; 492 var closeParenIndex = -2; 493 var backSlashIndex = -2; 494 while (index < str.length) { 495 if (str[index] === '*') { 496 return true; 497 } 498 499 if (str[index + 1] === '?' && /[\].+)]/.test(str[index])) { 500 return true; 501 } 502 503 if (closeSquareIndex !== -1 && str[index] === '[' && str[index + 1] !== ']') { 504 if (closeSquareIndex < index) { 505 closeSquareIndex = str.indexOf(']', index); 506 } 507 if (closeSquareIndex > index) { 508 if (backSlashIndex === -1 || backSlashIndex > closeSquareIndex) { 509 return true; 510 } 511 backSlashIndex = str.indexOf('\\', index); 512 if (backSlashIndex === -1 || backSlashIndex > closeSquareIndex) { 513 return true; 514 } 515 } 516 } 517 518 if (closeCurlyIndex !== -1 && str[index] === '{' && str[index + 1] !== '}') { 519 closeCurlyIndex = str.indexOf('}', index); 520 if (closeCurlyIndex > index) { 521 backSlashIndex = str.indexOf('\\', index); 522 if (backSlashIndex === -1 || backSlashIndex > closeCurlyIndex) { 523 return true; 524 } 525 } 526 } 527 528 if (closeParenIndex !== -1 && str[index] === '(' && str[index + 1] === '?' && /[:!=]/.test(str[index + 2]) && str[index + 3] !== ')') { 529 closeParenIndex = str.indexOf(')', index); 530 if (closeParenIndex > index) { 531 backSlashIndex = str.indexOf('\\', index); 532 if (backSlashIndex === -1 || backSlashIndex > closeParenIndex) { 533 return true; 534 } 535 } 536 } 537 538 if (pipeIndex !== -1 && str[index] === '(' && str[index + 1] !== '|') { 539 if (pipeIndex < index) { 540 pipeIndex = str.indexOf('|', index); 541 } 542 if (pipeIndex !== -1 && str[pipeIndex + 1] !== ')') { 543 closeParenIndex = str.indexOf(')', pipeIndex); 544 if (closeParenIndex > pipeIndex) { 545 backSlashIndex = str.indexOf('\\', pipeIndex); 546 if (backSlashIndex === -1 || backSlashIndex > closeParenIndex) { 547 return true; 548 } 549 } 550 } 551 } 552 553 if (str[index] === '\\') { 554 var open = str[index + 1]; 555 index += 2; 556 var close = chars[open]; 557 558 if (close) { 559 var n = str.indexOf(close, index); 560 if (n !== -1) { 561 index = n + 1; 562 } 563 } 564 565 if (str[index] === '!') { 566 return true; 567 } 568 } else { 569 index++; 570 } 571 } 572 return false; 573 }; 574 575 var relaxedCheck = function(str) { 576 if (str[0] === '!') { 577 return true; 578 } 579 var index = 0; 580 while (index < str.length) { 581 if (/[*?{}()[\]]/.test(str[index])) { 582 return true; 583 } 584 585 if (str[index] === '\\') { 586 var open = str[index + 1]; 587 index += 2; 588 var close = chars[open]; 589 590 if (close) { 591 var n = str.indexOf(close, index); 592 if (n !== -1) { 593 index = n + 1; 594 } 595 } 596 597 if (str[index] === '!') { 598 return true; 599 } 600 } else { 601 index++; 602 } 603 } 604 return false; 605 }; 606 607 var isGlob$2 = function isGlob(str, options) { 608 if (typeof str !== 'string' || str === '') { 609 return false; 610 } 611 612 if (isExtglob(str)) { 613 return true; 614 } 615 616 var check = strictCheck; 617 618 // optionally relax check 619 if (options && options.strict === false) { 620 check = relaxedCheck; 621 } 622 623 return check(str); 624 }; 625 626 var isGlob$1 = isGlob$2; 627 var pathPosixDirname = require$$0$2.posix.dirname; 628 var isWin32 = require$$2$1.platform() === 'win32'; 629 630 var slash = '/'; 631 var backslash = /\\/g; 632 var enclosure = /[\{\[].*[\}\]]$/; 633 var globby = /(^|[^\\])([\{\[]|\([^\)]+$)/; 634 var escaped = /\\([\!\*\?\|\[\]\(\)\{\}])/g; 635 636 /** 637 * @param {string} str 638 * @param {Object} opts 639 * @param {boolean} [opts.flipBackslashes=true] 640 * @returns {string} 641 */ 642 var globParent$1 = function globParent(str, opts) { 643 var options = Object.assign({ flipBackslashes: true }, opts); 644 645 // flip windows path separators 646 if (options.flipBackslashes && isWin32 && str.indexOf(slash) < 0) { 647 str = str.replace(backslash, slash); 648 } 649 650 // special case for strings ending in enclosure containing path separator 651 if (enclosure.test(str)) { 652 str += slash; 653 } 654 655 // preserves full path in case of trailing path separator 656 str += 'a'; 657 658 // remove path parts that are globby 659 do { 660 str = pathPosixDirname(str); 661 } while (isGlob$1(str) || globby.test(str)); 662 663 // remove escape chars and return result 664 return str.replace(escaped, '$1'); 665 }; 666 667 var utils$3 = {}; 668 669 (function (exports) { 670 671 exports.isInteger = num => { 672 if (typeof num === 'number') { 673 return Number.isInteger(num); 674 } 675 if (typeof num === 'string' && num.trim() !== '') { 676 return Number.isInteger(Number(num)); 4741 var isGlob; 4742 var hasRequiredIsGlob; 4743 4744 function requireIsGlob () { 4745 if (hasRequiredIsGlob) return isGlob; 4746 hasRequiredIsGlob = 1; 4747 var isExtglob = /*@__PURE__*/ requireIsExtglob(); 4748 var chars = { '{': '}', '(': ')', '[': ']'}; 4749 var strictCheck = function(str) { 4750 if (str[0] === '!') { 4751 return true; 4752 } 4753 var index = 0; 4754 var pipeIndex = -2; 4755 var closeSquareIndex = -2; 4756 var closeCurlyIndex = -2; 4757 var closeParenIndex = -2; 4758 var backSlashIndex = -2; 4759 while (index < str.length) { 4760 if (str[index] === '*') { 4761 return true; 4762 } 4763 4764 if (str[index + 1] === '?' && /[\].+)]/.test(str[index])) { 4765 return true; 4766 } 4767 4768 if (closeSquareIndex !== -1 && str[index] === '[' && str[index + 1] !== ']') { 4769 if (closeSquareIndex < index) { 4770 closeSquareIndex = str.indexOf(']', index); 4771 } 4772 if (closeSquareIndex > index) { 4773 if (backSlashIndex === -1 || backSlashIndex > closeSquareIndex) { 4774 return true; 4775 } 4776 backSlashIndex = str.indexOf('\\', index); 4777 if (backSlashIndex === -1 || backSlashIndex > closeSquareIndex) { 4778 return true; 4779 } 4780 } 4781 } 4782 4783 if (closeCurlyIndex !== -1 && str[index] === '{' && str[index + 1] !== '}') { 4784 closeCurlyIndex = str.indexOf('}', index); 4785 if (closeCurlyIndex > index) { 4786 backSlashIndex = str.indexOf('\\', index); 4787 if (backSlashIndex === -1 || backSlashIndex > closeCurlyIndex) { 4788 return true; 4789 } 4790 } 4791 } 4792 4793 if (closeParenIndex !== -1 && str[index] === '(' && str[index + 1] === '?' && /[:!=]/.test(str[index + 2]) && str[index + 3] !== ')') { 4794 closeParenIndex = str.indexOf(')', index); 4795 if (closeParenIndex > index) { 4796 backSlashIndex = str.indexOf('\\', index); 4797 if (backSlashIndex === -1 || backSlashIndex > closeParenIndex) { 4798 return true; 4799 } 4800 } 4801 } 4802 4803 if (pipeIndex !== -1 && str[index] === '(' && str[index + 1] !== '|') { 4804 if (pipeIndex < index) { 4805 pipeIndex = str.indexOf('|', index); 4806 } 4807 if (pipeIndex !== -1 && str[pipeIndex + 1] !== ')') { 4808 closeParenIndex = str.indexOf(')', pipeIndex); 4809 if (closeParenIndex > pipeIndex) { 4810 backSlashIndex = str.indexOf('\\', pipeIndex); 4811 if (backSlashIndex === -1 || backSlashIndex > closeParenIndex) { 4812 return true; 4813 } 4814 } 4815 } 4816 } 4817 4818 if (str[index] === '\\') { 4819 var open = str[index + 1]; 4820 index += 2; 4821 var close = chars[open]; 4822 4823 if (close) { 4824 var n = str.indexOf(close, index); 4825 if (n !== -1) { 4826 index = n + 1; 4827 } 4828 } 4829 4830 if (str[index] === '!') { 4831 return true; 4832 } 4833 } else { 4834 index++; 4835 } 677 4836 } 678 4837 return false; 679 4838 }; 680 4839 681 /** 682 * Find a node of the given type 683 */ 684 685 exports.find = (node, type) => node.nodes.find(node => node.type === type); 686 687 /** 688 * Find a node of the given type 689 */ 690 691 exports.exceedsLimit = (min, max, step = 1, limit) => { 692 if (limit === false) return false; 693 if (!exports.isInteger(min) || !exports.isInteger(max)) return false; 694 return ((Number(max) - Number(min)) / Number(step)) >= limit; 695 }; 696 697 /** 698 * Escape the given node with '\\' before node.value 699 */ 700 701 exports.escapeNode = (block, n = 0, type) => { 702 const node = block.nodes[n]; 703 if (!node) return; 704 705 if ((type && node.type === type) || node.type === 'open' || node.type === 'close') { 706 if (node.escaped !== true) { 707 node.value = '\\' + node.value; 708 node.escaped = true; 709 } 710 } 711 }; 712 713 /** 714 * Returns true if the given brace node should be enclosed in literal braces 715 */ 716 717 exports.encloseBrace = node => { 718 if (node.type !== 'brace') return false; 719 if ((node.commas >> 0 + node.ranges >> 0) === 0) { 720 node.invalid = true; 4840 var relaxedCheck = function(str) { 4841 if (str[0] === '!') { 721 4842 return true; 722 4843 } 4844 var index = 0; 4845 while (index < str.length) { 4846 if (/[*?{}()[\]]/.test(str[index])) { 4847 return true; 4848 } 4849 4850 if (str[index] === '\\') { 4851 var open = str[index + 1]; 4852 index += 2; 4853 var close = chars[open]; 4854 4855 if (close) { 4856 var n = str.indexOf(close, index); 4857 if (n !== -1) { 4858 index = n + 1; 4859 } 4860 } 4861 4862 if (str[index] === '!') { 4863 return true; 4864 } 4865 } else { 4866 index++; 4867 } 4868 } 723 4869 return false; 724 4870 }; 725 4871 726 /** 727 * Returns true if a brace node is invalid. 728 */ 729 730 exports.isInvalidBrace = block => { 731 if (block.type !== 'brace') return false; 732 if (block.invalid === true || block.dollar) return true; 733 if ((block.commas >> 0 + block.ranges >> 0) === 0) { 734 block.invalid = true; 4872 isGlob = function isGlob(str, options) { 4873 if (typeof str !== 'string' || str === '') { 4874 return false; 4875 } 4876 4877 if (isExtglob(str)) { 735 4878 return true; 736 4879 } 737 if (block.open !== true || block.close !== true) { 738 block.invalid = true; 739 return true; 740 } 741 return false; 742 }; 743 744 /** 745 * Returns true if a node is an open or close node 746 */ 747 748 exports.isOpenOrClose = node => { 749 if (node.type === 'open' || node.type === 'close') { 750 return true; 751 } 752 return node.open === true || node.close === true; 753 }; 754 755 /** 756 * Reduce an array of text nodes. 757 */ 758 759 exports.reduce = nodes => nodes.reduce((acc, node) => { 760 if (node.type === 'text') acc.push(node.value); 761 if (node.type === 'range') node.type = 'text'; 762 return acc; 763 }, []); 764 765 /** 766 * Flatten an array 767 */ 768 769 exports.flatten = (...args) => { 770 const result = []; 771 772 const flat = arr => { 773 for (let i = 0; i < arr.length; i++) { 774 const ele = arr[i]; 775 776 if (Array.isArray(ele)) { 777 flat(ele); 778 continue; 779 } 780 781 if (ele !== undefined) { 782 result.push(ele); 783 } 784 } 785 return result; 4880 4881 var check = strictCheck; 4882 4883 // optionally relax check 4884 if (options && options.strict === false) { 4885 check = relaxedCheck; 4886 } 4887 4888 return check(str); 4889 }; 4890 return isGlob; 4891 } 4892 4893 var globParent; 4894 var hasRequiredGlobParent; 4895 4896 function requireGlobParent () { 4897 if (hasRequiredGlobParent) return globParent; 4898 hasRequiredGlobParent = 1; 4899 4900 var isGlob = /*@__PURE__*/ requireIsGlob(); 4901 var pathPosixDirname = require$$0$1.posix.dirname; 4902 var isWin32 = require$$2$1.platform() === 'win32'; 4903 4904 var slash = '/'; 4905 var backslash = /\\/g; 4906 var enclosure = /[\{\[].*[\}\]]$/; 4907 var globby = /(^|[^\\])([\{\[]|\([^\)]+$)/; 4908 var escaped = /\\([\!\*\?\|\[\]\(\)\{\}])/g; 4909 4910 /** 4911 * @param {string} str 4912 * @param {Object} opts 4913 * @param {boolean} [opts.flipBackslashes=true] 4914 * @returns {string} 4915 */ 4916 globParent = function globParent(str, opts) { 4917 var options = Object.assign({ flipBackslashes: true }, opts); 4918 4919 // flip windows path separators 4920 if (options.flipBackslashes && isWin32 && str.indexOf(slash) < 0) { 4921 str = str.replace(backslash, slash); 4922 } 4923 4924 // special case for strings ending in enclosure containing path separator 4925 if (enclosure.test(str)) { 4926 str += slash; 4927 } 4928 4929 // preserves full path in case of trailing path separator 4930 str += 'a'; 4931 4932 // remove path parts that are globby 4933 do { 4934 str = pathPosixDirname(str); 4935 } while (isGlob(str) || globby.test(str)); 4936 4937 // remove escape chars and return result 4938 return str.replace(escaped, '$1'); 4939 }; 4940 return globParent; 4941 } 4942 4943 var utils = {}; 4944 4945 var hasRequiredUtils; 4946 4947 function requireUtils () { 4948 if (hasRequiredUtils) return utils; 4949 hasRequiredUtils = 1; 4950 (function (exports) { 4951 4952 exports.isInteger = num => { 4953 if (typeof num === 'number') { 4954 return Number.isInteger(num); 4955 } 4956 if (typeof num === 'string' && num.trim() !== '') { 4957 return Number.isInteger(Number(num)); 4958 } 4959 return false; 4960 }; 4961 4962 /** 4963 * Find a node of the given type 4964 */ 4965 4966 exports.find = (node, type) => node.nodes.find(node => node.type === type); 4967 4968 /** 4969 * Find a node of the given type 4970 */ 4971 4972 exports.exceedsLimit = (min, max, step = 1, limit) => { 4973 if (limit === false) return false; 4974 if (!exports.isInteger(min) || !exports.isInteger(max)) return false; 4975 return ((Number(max) - Number(min)) / Number(step)) >= limit; 4976 }; 4977 4978 /** 4979 * Escape the given node with '\\' before node.value 4980 */ 4981 4982 exports.escapeNode = (block, n = 0, type) => { 4983 const node = block.nodes[n]; 4984 if (!node) return; 4985 4986 if ((type && node.type === type) || node.type === 'open' || node.type === 'close') { 4987 if (node.escaped !== true) { 4988 node.value = '\\' + node.value; 4989 node.escaped = true; 4990 } 4991 } 4992 }; 4993 4994 /** 4995 * Returns true if the given brace node should be enclosed in literal braces 4996 */ 4997 4998 exports.encloseBrace = node => { 4999 if (node.type !== 'brace') return false; 5000 if ((node.commas >> 0 + node.ranges >> 0) === 0) { 5001 node.invalid = true; 5002 return true; 5003 } 5004 return false; 5005 }; 5006 5007 /** 5008 * Returns true if a brace node is invalid. 5009 */ 5010 5011 exports.isInvalidBrace = block => { 5012 if (block.type !== 'brace') return false; 5013 if (block.invalid === true || block.dollar) return true; 5014 if ((block.commas >> 0 + block.ranges >> 0) === 0) { 5015 block.invalid = true; 5016 return true; 5017 } 5018 if (block.open !== true || block.close !== true) { 5019 block.invalid = true; 5020 return true; 5021 } 5022 return false; 5023 }; 5024 5025 /** 5026 * Returns true if a node is an open or close node 5027 */ 5028 5029 exports.isOpenOrClose = node => { 5030 if (node.type === 'open' || node.type === 'close') { 5031 return true; 5032 } 5033 return node.open === true || node.close === true; 5034 }; 5035 5036 /** 5037 * Reduce an array of text nodes. 5038 */ 5039 5040 exports.reduce = nodes => nodes.reduce((acc, node) => { 5041 if (node.type === 'text') acc.push(node.value); 5042 if (node.type === 'range') node.type = 'text'; 5043 return acc; 5044 }, []); 5045 5046 /** 5047 * Flatten an array 5048 */ 5049 5050 exports.flatten = (...args) => { 5051 const result = []; 5052 5053 const flat = arr => { 5054 for (let i = 0; i < arr.length; i++) { 5055 const ele = arr[i]; 5056 5057 if (Array.isArray(ele)) { 5058 flat(ele); 5059 continue; 5060 } 5061 5062 if (ele !== undefined) { 5063 result.push(ele); 5064 } 5065 } 5066 return result; 5067 }; 5068 5069 flat(args); 5070 return result; 5071 }; 5072 } (utils)); 5073 return utils; 5074 } 5075 5076 var stringify; 5077 var hasRequiredStringify; 5078 5079 function requireStringify () { 5080 if (hasRequiredStringify) return stringify; 5081 hasRequiredStringify = 1; 5082 5083 const utils = /*@__PURE__*/ requireUtils(); 5084 5085 stringify = (ast, options = {}) => { 5086 const stringify = (node, parent = {}) => { 5087 const invalidBlock = options.escapeInvalid && utils.isInvalidBrace(parent); 5088 const invalidNode = node.invalid === true && options.escapeInvalid === true; 5089 let output = ''; 5090 5091 if (node.value) { 5092 if ((invalidBlock || invalidNode) && utils.isOpenOrClose(node)) { 5093 return '\\' + node.value; 5094 } 5095 return node.value; 5096 } 5097 5098 if (node.value) { 5099 return node.value; 5100 } 5101 5102 if (node.nodes) { 5103 for (const child of node.nodes) { 5104 output += stringify(child); 5105 } 5106 } 5107 return output; 786 5108 }; 787 5109 788 flat(args); 789 return result; 790 }; 791 } (utils$3)); 792 793 const utils$2 = utils$3; 794 795 var stringify$4 = (ast, options = {}) => { 796 const stringify = (node, parent = {}) => { 797 const invalidBlock = options.escapeInvalid && utils$2.isInvalidBrace(parent); 798 const invalidNode = node.invalid === true && options.escapeInvalid === true; 799 let output = ''; 800 801 if (node.value) { 802 if ((invalidBlock || invalidNode) && utils$2.isOpenOrClose(node)) { 803 return '\\' + node.value; 804 } 805 return node.value; 806 } 807 808 if (node.value) { 809 return node.value; 810 } 811 812 if (node.nodes) { 813 for (const child of node.nodes) { 814 output += stringify(child); 815 } 816 } 817 return output; 818 }; 819 820 return stringify(ast); 821 }; 5110 return stringify(ast); 5111 }; 5112 return stringify; 5113 } 822 5114 823 5115 /*! … … 828 5120 */ 829 5121 830 var isNumber$2 = function(num) { 831 if (typeof num === 'number') { 832 return num - num === 0; 833 } 834 if (typeof num === 'string' && num.trim() !== '') { 835 return Number.isFinite ? Number.isFinite(+num) : isFinite(+num); 836 } 837 return false; 838 }; 5122 var isNumber; 5123 var hasRequiredIsNumber; 5124 5125 function requireIsNumber () { 5126 if (hasRequiredIsNumber) return isNumber; 5127 hasRequiredIsNumber = 1; 5128 5129 isNumber = function(num) { 5130 if (typeof num === 'number') { 5131 return num - num === 0; 5132 } 5133 if (typeof num === 'string' && num.trim() !== '') { 5134 return Number.isFinite ? Number.isFinite(+num) : isFinite(+num); 5135 } 5136 return false; 5137 }; 5138 return isNumber; 5139 } 839 5140 840 5141 /*! … … 845 5146 */ 846 5147 847 const isNumber$1 = isNumber$2; 848 849 const toRegexRange$1 = (min, max, options) => { 850 if (isNumber$1(min) === false) { 851 throw new TypeError('toRegexRange: expected the first argument to be a number'); 852 } 853 854 if (max === void 0 || min === max) { 855 return String(min); 856 } 857 858 if (isNumber$1(max) === false) { 859 throw new TypeError('toRegexRange: expected the second argument to be a number.'); 860 } 861 862 let opts = { relaxZeros: true, ...options }; 863 if (typeof opts.strictZeros === 'boolean') { 864 opts.relaxZeros = opts.strictZeros === false; 865 } 866 867 let relax = String(opts.relaxZeros); 868 let shorthand = String(opts.shorthand); 869 let capture = String(opts.capture); 870 let wrap = String(opts.wrap); 871 let cacheKey = min + ':' + max + '=' + relax + shorthand + capture + wrap; 872 873 if (toRegexRange$1.cache.hasOwnProperty(cacheKey)) { 874 return toRegexRange$1.cache[cacheKey].result; 875 } 876 877 let a = Math.min(min, max); 878 let b = Math.max(min, max); 879 880 if (Math.abs(a - b) === 1) { 881 let result = min + '|' + max; 882 if (opts.capture) { 883 return `(${result})`; 884 } 885 if (opts.wrap === false) { 886 return result; 887 } 888 return `(?:${result})`; 889 } 890 891 let isPadded = hasPadding(min) || hasPadding(max); 892 let state = { min, max, a, b }; 893 let positives = []; 894 let negatives = []; 895 896 if (isPadded) { 897 state.isPadded = isPadded; 898 state.maxLen = String(state.max).length; 899 } 900 901 if (a < 0) { 902 let newMin = b < 0 ? Math.abs(b) : 1; 903 negatives = splitToPatterns(newMin, Math.abs(a), state, opts); 904 a = state.a = 0; 905 } 906 907 if (b >= 0) { 908 positives = splitToPatterns(a, b, state, opts); 909 } 910 911 state.negatives = negatives; 912 state.positives = positives; 913 state.result = collatePatterns(negatives, positives); 914 915 if (opts.capture === true) { 916 state.result = `(${state.result})`; 917 } else if (opts.wrap !== false && (positives.length + negatives.length) > 1) { 918 state.result = `(?:${state.result})`; 919 } 920 921 toRegexRange$1.cache[cacheKey] = state; 922 return state.result; 923 }; 924 925 function collatePatterns(neg, pos, options) { 926 let onlyNegative = filterPatterns(neg, pos, '-', false) || []; 927 let onlyPositive = filterPatterns(pos, neg, '', false) || []; 928 let intersected = filterPatterns(neg, pos, '-?', true) || []; 929 let subpatterns = onlyNegative.concat(intersected).concat(onlyPositive); 930 return subpatterns.join('|'); 5148 var toRegexRange_1; 5149 var hasRequiredToRegexRange; 5150 5151 function requireToRegexRange () { 5152 if (hasRequiredToRegexRange) return toRegexRange_1; 5153 hasRequiredToRegexRange = 1; 5154 5155 const isNumber = /*@__PURE__*/ requireIsNumber(); 5156 5157 const toRegexRange = (min, max, options) => { 5158 if (isNumber(min) === false) { 5159 throw new TypeError('toRegexRange: expected the first argument to be a number'); 5160 } 5161 5162 if (max === void 0 || min === max) { 5163 return String(min); 5164 } 5165 5166 if (isNumber(max) === false) { 5167 throw new TypeError('toRegexRange: expected the second argument to be a number.'); 5168 } 5169 5170 let opts = { relaxZeros: true, ...options }; 5171 if (typeof opts.strictZeros === 'boolean') { 5172 opts.relaxZeros = opts.strictZeros === false; 5173 } 5174 5175 let relax = String(opts.relaxZeros); 5176 let shorthand = String(opts.shorthand); 5177 let capture = String(opts.capture); 5178 let wrap = String(opts.wrap); 5179 let cacheKey = min + ':' + max + '=' + relax + shorthand + capture + wrap; 5180 5181 if (toRegexRange.cache.hasOwnProperty(cacheKey)) { 5182 return toRegexRange.cache[cacheKey].result; 5183 } 5184 5185 let a = Math.min(min, max); 5186 let b = Math.max(min, max); 5187 5188 if (Math.abs(a - b) === 1) { 5189 let result = min + '|' + max; 5190 if (opts.capture) { 5191 return `(${result})`; 5192 } 5193 if (opts.wrap === false) { 5194 return result; 5195 } 5196 return `(?:${result})`; 5197 } 5198 5199 let isPadded = hasPadding(min) || hasPadding(max); 5200 let state = { min, max, a, b }; 5201 let positives = []; 5202 let negatives = []; 5203 5204 if (isPadded) { 5205 state.isPadded = isPadded; 5206 state.maxLen = String(state.max).length; 5207 } 5208 5209 if (a < 0) { 5210 let newMin = b < 0 ? Math.abs(b) : 1; 5211 negatives = splitToPatterns(newMin, Math.abs(a), state, opts); 5212 a = state.a = 0; 5213 } 5214 5215 if (b >= 0) { 5216 positives = splitToPatterns(a, b, state, opts); 5217 } 5218 5219 state.negatives = negatives; 5220 state.positives = positives; 5221 state.result = collatePatterns(negatives, positives); 5222 5223 if (opts.capture === true) { 5224 state.result = `(${state.result})`; 5225 } else if (opts.wrap !== false && (positives.length + negatives.length) > 1) { 5226 state.result = `(?:${state.result})`; 5227 } 5228 5229 toRegexRange.cache[cacheKey] = state; 5230 return state.result; 5231 }; 5232 5233 function collatePatterns(neg, pos, options) { 5234 let onlyNegative = filterPatterns(neg, pos, '-', false) || []; 5235 let onlyPositive = filterPatterns(pos, neg, '', false) || []; 5236 let intersected = filterPatterns(neg, pos, '-?', true) || []; 5237 let subpatterns = onlyNegative.concat(intersected).concat(onlyPositive); 5238 return subpatterns.join('|'); 5239 } 5240 5241 function splitToRanges(min, max) { 5242 let nines = 1; 5243 let zeros = 1; 5244 5245 let stop = countNines(min, nines); 5246 let stops = new Set([max]); 5247 5248 while (min <= stop && stop <= max) { 5249 stops.add(stop); 5250 nines += 1; 5251 stop = countNines(min, nines); 5252 } 5253 5254 stop = countZeros(max + 1, zeros) - 1; 5255 5256 while (min < stop && stop <= max) { 5257 stops.add(stop); 5258 zeros += 1; 5259 stop = countZeros(max + 1, zeros) - 1; 5260 } 5261 5262 stops = [...stops]; 5263 stops.sort(compare); 5264 return stops; 5265 } 5266 5267 /** 5268 * Convert a range to a regex pattern 5269 * @param {Number} `start` 5270 * @param {Number} `stop` 5271 * @return {String} 5272 */ 5273 5274 function rangeToPattern(start, stop, options) { 5275 if (start === stop) { 5276 return { pattern: start, count: [], digits: 0 }; 5277 } 5278 5279 let zipped = zip(start, stop); 5280 let digits = zipped.length; 5281 let pattern = ''; 5282 let count = 0; 5283 5284 for (let i = 0; i < digits; i++) { 5285 let [startDigit, stopDigit] = zipped[i]; 5286 5287 if (startDigit === stopDigit) { 5288 pattern += startDigit; 5289 5290 } else if (startDigit !== '0' || stopDigit !== '9') { 5291 pattern += toCharacterClass(startDigit, stopDigit); 5292 5293 } else { 5294 count++; 5295 } 5296 } 5297 5298 if (count) { 5299 pattern += options.shorthand === true ? '\\d' : '[0-9]'; 5300 } 5301 5302 return { pattern, count: [count], digits }; 5303 } 5304 5305 function splitToPatterns(min, max, tok, options) { 5306 let ranges = splitToRanges(min, max); 5307 let tokens = []; 5308 let start = min; 5309 let prev; 5310 5311 for (let i = 0; i < ranges.length; i++) { 5312 let max = ranges[i]; 5313 let obj = rangeToPattern(String(start), String(max), options); 5314 let zeros = ''; 5315 5316 if (!tok.isPadded && prev && prev.pattern === obj.pattern) { 5317 if (prev.count.length > 1) { 5318 prev.count.pop(); 5319 } 5320 5321 prev.count.push(obj.count[0]); 5322 prev.string = prev.pattern + toQuantifier(prev.count); 5323 start = max + 1; 5324 continue; 5325 } 5326 5327 if (tok.isPadded) { 5328 zeros = padZeros(max, tok, options); 5329 } 5330 5331 obj.string = zeros + obj.pattern + toQuantifier(obj.count); 5332 tokens.push(obj); 5333 start = max + 1; 5334 prev = obj; 5335 } 5336 5337 return tokens; 5338 } 5339 5340 function filterPatterns(arr, comparison, prefix, intersection, options) { 5341 let result = []; 5342 5343 for (let ele of arr) { 5344 let { string } = ele; 5345 5346 // only push if _both_ are negative... 5347 if (!intersection && !contains(comparison, 'string', string)) { 5348 result.push(prefix + string); 5349 } 5350 5351 // or _both_ are positive 5352 if (intersection && contains(comparison, 'string', string)) { 5353 result.push(prefix + string); 5354 } 5355 } 5356 return result; 5357 } 5358 5359 /** 5360 * Zip strings 5361 */ 5362 5363 function zip(a, b) { 5364 let arr = []; 5365 for (let i = 0; i < a.length; i++) arr.push([a[i], b[i]]); 5366 return arr; 5367 } 5368 5369 function compare(a, b) { 5370 return a > b ? 1 : b > a ? -1 : 0; 5371 } 5372 5373 function contains(arr, key, val) { 5374 return arr.some(ele => ele[key] === val); 5375 } 5376 5377 function countNines(min, len) { 5378 return Number(String(min).slice(0, -len) + '9'.repeat(len)); 5379 } 5380 5381 function countZeros(integer, zeros) { 5382 return integer - (integer % Math.pow(10, zeros)); 5383 } 5384 5385 function toQuantifier(digits) { 5386 let [start = 0, stop = ''] = digits; 5387 if (stop || start > 1) { 5388 return `{${start + (stop ? ',' + stop : '')}}`; 5389 } 5390 return ''; 5391 } 5392 5393 function toCharacterClass(a, b, options) { 5394 return `[${a}${(b - a === 1) ? '' : '-'}${b}]`; 5395 } 5396 5397 function hasPadding(str) { 5398 return /^-?(0+)\d/.test(str); 5399 } 5400 5401 function padZeros(value, tok, options) { 5402 if (!tok.isPadded) { 5403 return value; 5404 } 5405 5406 let diff = Math.abs(tok.maxLen - String(value).length); 5407 let relax = options.relaxZeros !== false; 5408 5409 switch (diff) { 5410 case 0: 5411 return ''; 5412 case 1: 5413 return relax ? '0?' : '0'; 5414 case 2: 5415 return relax ? '0{0,2}' : '00'; 5416 default: { 5417 return relax ? `0{0,${diff}}` : `0{${diff}}`; 5418 } 5419 } 5420 } 5421 5422 /** 5423 * Cache 5424 */ 5425 5426 toRegexRange.cache = {}; 5427 toRegexRange.clearCache = () => (toRegexRange.cache = {}); 5428 5429 /** 5430 * Expose `toRegexRange` 5431 */ 5432 5433 toRegexRange_1 = toRegexRange; 5434 return toRegexRange_1; 931 5435 } 932 933 function splitToRanges(min, max) {934 let nines = 1;935 let zeros = 1;936 937 let stop = countNines(min, nines);938 let stops = new Set([max]);939 940 while (min <= stop && stop <= max) {941 stops.add(stop);942 nines += 1;943 stop = countNines(min, nines);944 }945 946 stop = countZeros(max + 1, zeros) - 1;947 948 while (min < stop && stop <= max) {949 stops.add(stop);950 zeros += 1;951 stop = countZeros(max + 1, zeros) - 1;952 }953 954 stops = [...stops];955 stops.sort(compare);956 return stops;957 }958 959 /**960 * Convert a range to a regex pattern961 * @param {Number} `start`962 * @param {Number} `stop`963 * @return {String}964 */965 966 function rangeToPattern(start, stop, options) {967 if (start === stop) {968 return { pattern: start, count: [], digits: 0 };969 }970 971 let zipped = zip(start, stop);972 let digits = zipped.length;973 let pattern = '';974 let count = 0;975 976 for (let i = 0; i < digits; i++) {977 let [startDigit, stopDigit] = zipped[i];978 979 if (startDigit === stopDigit) {980 pattern += startDigit;981 982 } else if (startDigit !== '0' || stopDigit !== '9') {983 pattern += toCharacterClass(startDigit, stopDigit);984 985 } else {986 count++;987 }988 }989 990 if (count) {991 pattern += options.shorthand === true ? '\\d' : '[0-9]';992 }993 994 return { pattern, count: [count], digits };995 }996 997 function splitToPatterns(min, max, tok, options) {998 let ranges = splitToRanges(min, max);999 let tokens = [];1000 let start = min;1001 let prev;1002 1003 for (let i = 0; i < ranges.length; i++) {1004 let max = ranges[i];1005 let obj = rangeToPattern(String(start), String(max), options);1006 let zeros = '';1007 1008 if (!tok.isPadded && prev && prev.pattern === obj.pattern) {1009 if (prev.count.length > 1) {1010 prev.count.pop();1011 }1012 1013 prev.count.push(obj.count[0]);1014 prev.string = prev.pattern + toQuantifier(prev.count);1015 start = max + 1;1016 continue;1017 }1018 1019 if (tok.isPadded) {1020 zeros = padZeros(max, tok, options);1021 }1022 1023 obj.string = zeros + obj.pattern + toQuantifier(obj.count);1024 tokens.push(obj);1025 start = max + 1;1026 prev = obj;1027 }1028 1029 return tokens;1030 }1031 1032 function filterPatterns(arr, comparison, prefix, intersection, options) {1033 let result = [];1034 1035 for (let ele of arr) {1036 let { string } = ele;1037 1038 // only push if _both_ are negative...1039 if (!intersection && !contains(comparison, 'string', string)) {1040 result.push(prefix + string);1041 }1042 1043 // or _both_ are positive1044 if (intersection && contains(comparison, 'string', string)) {1045 result.push(prefix + string);1046 }1047 }1048 return result;1049 }1050 1051 /**1052 * Zip strings1053 */1054 1055 function zip(a, b) {1056 let arr = [];1057 for (let i = 0; i < a.length; i++) arr.push([a[i], b[i]]);1058 return arr;1059 }1060 1061 function compare(a, b) {1062 return a > b ? 1 : b > a ? -1 : 0;1063 }1064 1065 function contains(arr, key, val) {1066 return arr.some(ele => ele[key] === val);1067 }1068 1069 function countNines(min, len) {1070 return Number(String(min).slice(0, -len) + '9'.repeat(len));1071 }1072 1073 function countZeros(integer, zeros) {1074 return integer - (integer % Math.pow(10, zeros));1075 }1076 1077 function toQuantifier(digits) {1078 let [start = 0, stop = ''] = digits;1079 if (stop || start > 1) {1080 return `{${start + (stop ? ',' + stop : '')}}`;1081 }1082 return '';1083 }1084 1085 function toCharacterClass(a, b, options) {1086 return `[${a}${(b - a === 1) ? '' : '-'}${b}]`;1087 }1088 1089 function hasPadding(str) {1090 return /^-?(0+)\d/.test(str);1091 }1092 1093 function padZeros(value, tok, options) {1094 if (!tok.isPadded) {1095 return value;1096 }1097 1098 let diff = Math.abs(tok.maxLen - String(value).length);1099 let relax = options.relaxZeros !== false;1100 1101 switch (diff) {1102 case 0:1103 return '';1104 case 1:1105 return relax ? '0?' : '0';1106 case 2:1107 return relax ? '0{0,2}' : '00';1108 default: {1109 return relax ? `0{0,${diff}}` : `0{${diff}}`;1110 }1111 }1112 }1113 1114 /**1115 * Cache1116 */1117 1118 toRegexRange$1.cache = {};1119 toRegexRange$1.clearCache = () => (toRegexRange$1.cache = {});1120 1121 /**1122 * Expose `toRegexRange`1123 */1124 1125 var toRegexRange_1 = toRegexRange$1;1126 5436 1127 5437 /*! … … 1132 5442 */ 1133 5443 1134 const util = require$$2; 1135 const toRegexRange = toRegexRange_1; 1136 1137 const isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); 1138 1139 const transform = toNumber => { 1140 return value => toNumber === true ? Number(value) : String(value); 1141 }; 1142 1143 const isValidValue = value => { 1144 return typeof value === 'number' || (typeof value === 'string' && value !== ''); 1145 }; 1146 1147 const isNumber = num => Number.isInteger(+num); 1148 1149 const zeros = input => { 1150 let value = `${input}`; 1151 let index = -1; 1152 if (value[0] === '-') value = value.slice(1); 1153 if (value === '0') return false; 1154 while (value[++index] === '0'); 1155 return index > 0; 1156 }; 1157 1158 const stringify$3 = (start, end, options) => { 1159 if (typeof start === 'string' || typeof end === 'string') { 1160 return true; 1161 } 1162 return options.stringify === true; 1163 }; 1164 1165 const pad = (input, maxLength, toNumber) => { 1166 if (maxLength > 0) { 1167 let dash = input[0] === '-' ? '-' : ''; 1168 if (dash) input = input.slice(1); 1169 input = (dash + input.padStart(dash ? maxLength - 1 : maxLength, '0')); 1170 } 1171 if (toNumber === false) { 1172 return String(input); 1173 } 1174 return input; 1175 }; 1176 1177 const toMaxLen = (input, maxLength) => { 1178 let negative = input[0] === '-' ? '-' : ''; 1179 if (negative) { 1180 input = input.slice(1); 1181 maxLength--; 1182 } 1183 while (input.length < maxLength) input = '0' + input; 1184 return negative ? ('-' + input) : input; 1185 }; 1186 1187 const toSequence = (parts, options, maxLen) => { 1188 parts.negatives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0); 1189 parts.positives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0); 1190 1191 let prefix = options.capture ? '' : '?:'; 1192 let positives = ''; 1193 let negatives = ''; 1194 let result; 1195 1196 if (parts.positives.length) { 1197 positives = parts.positives.map(v => toMaxLen(String(v), maxLen)).join('|'); 1198 } 1199 1200 if (parts.negatives.length) { 1201 negatives = `-(${prefix}${parts.negatives.map(v => toMaxLen(String(v), maxLen)).join('|')})`; 1202 } 1203 1204 if (positives && negatives) { 1205 result = `${positives}|${negatives}`; 1206 } else { 1207 result = positives || negatives; 1208 } 1209 1210 if (options.wrap) { 1211 return `(${prefix}${result})`; 1212 } 1213 1214 return result; 1215 }; 1216 1217 const toRange = (a, b, isNumbers, options) => { 1218 if (isNumbers) { 1219 return toRegexRange(a, b, { wrap: false, ...options }); 1220 } 1221 1222 let start = String.fromCharCode(a); 1223 if (a === b) return start; 1224 1225 let stop = String.fromCharCode(b); 1226 return `[${start}-${stop}]`; 1227 }; 1228 1229 const toRegex = (start, end, options) => { 1230 if (Array.isArray(start)) { 1231 let wrap = options.wrap === true; 1232 let prefix = options.capture ? '' : '?:'; 1233 return wrap ? `(${prefix}${start.join('|')})` : start.join('|'); 1234 } 1235 return toRegexRange(start, end, options); 1236 }; 1237 1238 const rangeError = (...args) => { 1239 return new RangeError('Invalid range arguments: ' + util.inspect(...args)); 1240 }; 1241 1242 const invalidRange = (start, end, options) => { 1243 if (options.strictRanges === true) throw rangeError([start, end]); 1244 return []; 1245 }; 1246 1247 const invalidStep = (step, options) => { 1248 if (options.strictRanges === true) { 1249 throw new TypeError(`Expected step "${step}" to be a number`); 1250 } 1251 return []; 1252 }; 1253 1254 const fillNumbers = (start, end, step = 1, options = {}) => { 1255 let a = Number(start); 1256 let b = Number(end); 1257 1258 if (!Number.isInteger(a) || !Number.isInteger(b)) { 1259 if (options.strictRanges === true) throw rangeError([start, end]); 1260 return []; 1261 } 1262 1263 // fix negative zero 1264 if (a === 0) a = 0; 1265 if (b === 0) b = 0; 1266 1267 let descending = a > b; 1268 let startString = String(start); 1269 let endString = String(end); 1270 let stepString = String(step); 1271 step = Math.max(Math.abs(step), 1); 1272 1273 let padded = zeros(startString) || zeros(endString) || zeros(stepString); 1274 let maxLen = padded ? Math.max(startString.length, endString.length, stepString.length) : 0; 1275 let toNumber = padded === false && stringify$3(start, end, options) === false; 1276 let format = options.transform || transform(toNumber); 1277 1278 if (options.toRegex && step === 1) { 1279 return toRange(toMaxLen(start, maxLen), toMaxLen(end, maxLen), true, options); 1280 } 1281 1282 let parts = { negatives: [], positives: [] }; 1283 let push = num => parts[num < 0 ? 'negatives' : 'positives'].push(Math.abs(num)); 1284 let range = []; 1285 let index = 0; 1286 1287 while (descending ? a >= b : a <= b) { 1288 if (options.toRegex === true && step > 1) { 1289 push(a); 1290 } else { 1291 range.push(pad(format(a, index), maxLen, toNumber)); 1292 } 1293 a = descending ? a - step : a + step; 1294 index++; 1295 } 1296 1297 if (options.toRegex === true) { 1298 return step > 1 1299 ? toSequence(parts, options, maxLen) 1300 : toRegex(range, null, { wrap: false, ...options }); 1301 } 1302 1303 return range; 1304 }; 1305 1306 const fillLetters = (start, end, step = 1, options = {}) => { 1307 if ((!isNumber(start) && start.length > 1) || (!isNumber(end) && end.length > 1)) { 1308 return invalidRange(start, end, options); 1309 } 1310 1311 let format = options.transform || (val => String.fromCharCode(val)); 1312 let a = `${start}`.charCodeAt(0); 1313 let b = `${end}`.charCodeAt(0); 1314 1315 let descending = a > b; 1316 let min = Math.min(a, b); 1317 let max = Math.max(a, b); 1318 1319 if (options.toRegex && step === 1) { 1320 return toRange(min, max, false, options); 1321 } 1322 1323 let range = []; 1324 let index = 0; 1325 1326 while (descending ? a >= b : a <= b) { 1327 range.push(format(a, index)); 1328 a = descending ? a - step : a + step; 1329 index++; 1330 } 1331 1332 if (options.toRegex === true) { 1333 return toRegex(range, null, { wrap: false, options }); 1334 } 1335 1336 return range; 1337 }; 1338 1339 const fill$2 = (start, end, step, options = {}) => { 1340 if (end == null && isValidValue(start)) { 1341 return [start]; 1342 } 1343 1344 if (!isValidValue(start) || !isValidValue(end)) { 1345 return invalidRange(start, end, options); 1346 } 1347 1348 if (typeof step === 'function') { 1349 return fill$2(start, end, 1, { transform: step }); 1350 } 1351 1352 if (isObject(step)) { 1353 return fill$2(start, end, 0, step); 1354 } 1355 1356 let opts = { ...options }; 1357 if (opts.capture === true) opts.wrap = true; 1358 step = step || opts.step || 1; 1359 1360 if (!isNumber(step)) { 1361 if (step != null && !isObject(step)) return invalidStep(step, opts); 1362 return fill$2(start, end, 1, step); 1363 } 1364 1365 if (isNumber(start) && isNumber(end)) { 1366 return fillNumbers(start, end, step, opts); 1367 } 1368 1369 return fillLetters(start, end, Math.max(Math.abs(step), 1), opts); 1370 }; 1371 1372 var fillRange = fill$2; 1373 1374 const fill$1 = fillRange; 1375 const utils$1 = utils$3; 1376 1377 const compile$1 = (ast, options = {}) => { 1378 const walk = (node, parent = {}) => { 1379 const invalidBlock = utils$1.isInvalidBrace(parent); 1380 const invalidNode = node.invalid === true && options.escapeInvalid === true; 1381 const invalid = invalidBlock === true || invalidNode === true; 1382 const prefix = options.escapeInvalid === true ? '\\' : ''; 1383 let output = ''; 1384 1385 if (node.isOpen === true) { 1386 return prefix + node.value; 1387 } 1388 1389 if (node.isClose === true) { 1390 console.log('node.isClose', prefix, node.value); 1391 return prefix + node.value; 1392 } 1393 1394 if (node.type === 'open') { 1395 return invalid ? prefix + node.value : '('; 1396 } 1397 1398 if (node.type === 'close') { 1399 return invalid ? prefix + node.value : ')'; 1400 } 1401 1402 if (node.type === 'comma') { 1403 return node.prev.type === 'comma' ? '' : invalid ? node.value : '|'; 1404 } 1405 1406 if (node.value) { 1407 return node.value; 1408 } 1409 1410 if (node.nodes && node.ranges > 0) { 1411 const args = utils$1.reduce(node.nodes); 1412 const range = fill$1(...args, { ...options, wrap: false, toRegex: true, strictZeros: true }); 1413 1414 if (range.length !== 0) { 1415 return args.length > 1 && range.length > 1 ? `(${range})` : range; 1416 } 1417 } 1418 1419 if (node.nodes) { 1420 for (const child of node.nodes) { 1421 output += walk(child, node); 1422 } 1423 } 1424 1425 return output; 1426 }; 1427 1428 return walk(ast); 1429 }; 1430 1431 var compile_1 = compile$1; 1432 1433 const fill = fillRange; 1434 const stringify$2 = stringify$4; 1435 const utils = utils$3; 1436 1437 const append = (queue = '', stash = '', enclose = false) => { 1438 const result = []; 1439 1440 queue = [].concat(queue); 1441 stash = [].concat(stash); 1442 1443 if (!stash.length) return queue; 1444 if (!queue.length) { 1445 return enclose ? utils.flatten(stash).map(ele => `{${ele}}`) : stash; 1446 } 1447 1448 for (const item of queue) { 1449 if (Array.isArray(item)) { 1450 for (const value of item) { 1451 result.push(append(value, stash, enclose)); 1452 } 1453 } else { 1454 for (let ele of stash) { 1455 if (enclose === true && typeof ele === 'string') ele = `{${ele}}`; 1456 result.push(Array.isArray(ele) ? append(item, ele, enclose) : item + ele); 1457 } 1458 } 1459 } 1460 return utils.flatten(result); 1461 }; 1462 1463 const expand$1 = (ast, options = {}) => { 1464 const rangeLimit = options.rangeLimit === undefined ? 1000 : options.rangeLimit; 1465 1466 const walk = (node, parent = {}) => { 1467 node.queue = []; 1468 1469 let p = parent; 1470 let q = parent.queue; 1471 1472 while (p.type !== 'brace' && p.type !== 'root' && p.parent) { 1473 p = p.parent; 1474 q = p.queue; 1475 } 1476 1477 if (node.invalid || node.dollar) { 1478 q.push(append(q.pop(), stringify$2(node, options))); 1479 return; 1480 } 1481 1482 if (node.type === 'brace' && node.invalid !== true && node.nodes.length === 2) { 1483 q.push(append(q.pop(), ['{}'])); 1484 return; 1485 } 1486 1487 if (node.nodes && node.ranges > 0) { 1488 const args = utils.reduce(node.nodes); 1489 1490 if (utils.exceedsLimit(...args, options.step, rangeLimit)) { 1491 throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.'); 1492 } 1493 1494 let range = fill(...args, options); 1495 if (range.length === 0) { 1496 range = stringify$2(node, options); 1497 } 1498 1499 q.push(append(q.pop(), range)); 1500 node.nodes = []; 1501 return; 1502 } 1503 1504 const enclose = utils.encloseBrace(node); 1505 let queue = node.queue; 1506 let block = node; 1507 1508 while (block.type !== 'brace' && block.type !== 'root' && block.parent) { 1509 block = block.parent; 1510 queue = block.queue; 1511 } 1512 1513 for (let i = 0; i < node.nodes.length; i++) { 1514 const child = node.nodes[i]; 1515 1516 if (child.type === 'comma' && node.type === 'brace') { 1517 if (i === 1) queue.push(''); 1518 queue.push(''); 1519 continue; 1520 } 1521 1522 if (child.type === 'close') { 1523 q.push(append(q.pop(), queue, enclose)); 1524 continue; 1525 } 1526 1527 if (child.value && child.type !== 'open') { 1528 queue.push(append(queue.pop(), child.value)); 1529 continue; 1530 } 1531 1532 if (child.nodes) { 1533 walk(child, node); 1534 } 1535 } 1536 1537 return queue; 1538 }; 1539 1540 return utils.flatten(walk(ast)); 1541 }; 1542 1543 var expand_1 = expand$1; 1544 1545 var constants$1 = { 1546 MAX_LENGTH: 10000, 1547 1548 // Digits 1549 CHAR_0: '0', /* 0 */ 1550 CHAR_9: '9', /* 9 */ 1551 1552 // Alphabet chars. 1553 CHAR_UPPERCASE_A: 'A', /* A */ 1554 CHAR_LOWERCASE_A: 'a', /* a */ 1555 CHAR_UPPERCASE_Z: 'Z', /* Z */ 1556 CHAR_LOWERCASE_Z: 'z', /* z */ 1557 1558 CHAR_LEFT_PARENTHESES: '(', /* ( */ 1559 CHAR_RIGHT_PARENTHESES: ')', /* ) */ 1560 1561 CHAR_ASTERISK: '*', /* * */ 1562 1563 // Non-alphabetic chars. 1564 CHAR_AMPERSAND: '&', /* & */ 1565 CHAR_AT: '@', /* @ */ 1566 CHAR_BACKSLASH: '\\', /* \ */ 1567 CHAR_BACKTICK: '`', /* ` */ 1568 CHAR_CARRIAGE_RETURN: '\r', /* \r */ 1569 CHAR_CIRCUMFLEX_ACCENT: '^', /* ^ */ 1570 CHAR_COLON: ':', /* : */ 1571 CHAR_COMMA: ',', /* , */ 1572 CHAR_DOLLAR: '$', /* . */ 1573 CHAR_DOT: '.', /* . */ 1574 CHAR_DOUBLE_QUOTE: '"', /* " */ 1575 CHAR_EQUAL: '=', /* = */ 1576 CHAR_EXCLAMATION_MARK: '!', /* ! */ 1577 CHAR_FORM_FEED: '\f', /* \f */ 1578 CHAR_FORWARD_SLASH: '/', /* / */ 1579 CHAR_HASH: '#', /* # */ 1580 CHAR_HYPHEN_MINUS: '-', /* - */ 1581 CHAR_LEFT_ANGLE_BRACKET: '<', /* < */ 1582 CHAR_LEFT_CURLY_BRACE: '{', /* { */ 1583 CHAR_LEFT_SQUARE_BRACKET: '[', /* [ */ 1584 CHAR_LINE_FEED: '\n', /* \n */ 1585 CHAR_NO_BREAK_SPACE: '\u00A0', /* \u00A0 */ 1586 CHAR_PERCENT: '%', /* % */ 1587 CHAR_PLUS: '+', /* + */ 1588 CHAR_QUESTION_MARK: '?', /* ? */ 1589 CHAR_RIGHT_ANGLE_BRACKET: '>', /* > */ 1590 CHAR_RIGHT_CURLY_BRACE: '}', /* } */ 1591 CHAR_RIGHT_SQUARE_BRACKET: ']', /* ] */ 1592 CHAR_SEMICOLON: ';', /* ; */ 1593 CHAR_SINGLE_QUOTE: '\'', /* ' */ 1594 CHAR_SPACE: ' ', /* */ 1595 CHAR_TAB: '\t', /* \t */ 1596 CHAR_UNDERSCORE: '_', /* _ */ 1597 CHAR_VERTICAL_LINE: '|', /* | */ 1598 CHAR_ZERO_WIDTH_NOBREAK_SPACE: '\uFEFF' /* \uFEFF */ 1599 }; 1600 1601 const stringify$1 = stringify$4; 1602 1603 /** 1604 * Constants 1605 */ 1606 1607 const { 1608 MAX_LENGTH, 1609 CHAR_BACKSLASH, /* \ */ 1610 CHAR_BACKTICK, /* ` */ 1611 CHAR_COMMA, /* , */ 1612 CHAR_DOT, /* . */ 1613 CHAR_LEFT_PARENTHESES, /* ( */ 1614 CHAR_RIGHT_PARENTHESES, /* ) */ 1615 CHAR_LEFT_CURLY_BRACE, /* { */ 1616 CHAR_RIGHT_CURLY_BRACE, /* } */ 1617 CHAR_LEFT_SQUARE_BRACKET, /* [ */ 1618 CHAR_RIGHT_SQUARE_BRACKET, /* ] */ 1619 CHAR_DOUBLE_QUOTE, /* " */ 1620 CHAR_SINGLE_QUOTE, /* ' */ 1621 CHAR_NO_BREAK_SPACE, 1622 CHAR_ZERO_WIDTH_NOBREAK_SPACE 1623 } = constants$1; 1624 1625 /** 1626 * parse 1627 */ 1628 1629 const parse$1 = (input, options = {}) => { 1630 if (typeof input !== 'string') { 1631 throw new TypeError('Expected a string'); 1632 } 1633 1634 const opts = options || {}; 1635 const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; 1636 if (input.length > max) { 1637 throw new SyntaxError(`Input length (${input.length}), exceeds max characters (${max})`); 1638 } 1639 1640 const ast = { type: 'root', input, nodes: [] }; 1641 const stack = [ast]; 1642 let block = ast; 1643 let prev = ast; 1644 let brackets = 0; 1645 const length = input.length; 1646 let index = 0; 1647 let depth = 0; 1648 let value; 1649 1650 /** 1651 * Helpers 1652 */ 1653 1654 const advance = () => input[index++]; 1655 const push = node => { 1656 if (node.type === 'text' && prev.type === 'dot') { 1657 prev.type = 'text'; 1658 } 1659 1660 if (prev && prev.type === 'text' && node.type === 'text') { 1661 prev.value += node.value; 1662 return; 1663 } 1664 1665 block.nodes.push(node); 1666 node.parent = block; 1667 node.prev = prev; 1668 prev = node; 1669 return node; 1670 }; 1671 1672 push({ type: 'bos' }); 1673 1674 while (index < length) { 1675 block = stack[stack.length - 1]; 1676 value = advance(); 1677 1678 /** 1679 * Invalid chars 1680 */ 1681 1682 if (value === CHAR_ZERO_WIDTH_NOBREAK_SPACE || value === CHAR_NO_BREAK_SPACE) { 1683 continue; 1684 } 1685 1686 /** 1687 * Escaped chars 1688 */ 1689 1690 if (value === CHAR_BACKSLASH) { 1691 push({ type: 'text', value: (options.keepEscaping ? value : '') + advance() }); 1692 continue; 1693 } 1694 1695 /** 1696 * Right square bracket (literal): ']' 1697 */ 1698 1699 if (value === CHAR_RIGHT_SQUARE_BRACKET) { 1700 push({ type: 'text', value: '\\' + value }); 1701 continue; 1702 } 1703 1704 /** 1705 * Left square bracket: '[' 1706 */ 1707 1708 if (value === CHAR_LEFT_SQUARE_BRACKET) { 1709 brackets++; 1710 1711 let next; 1712 1713 while (index < length && (next = advance())) { 1714 value += next; 1715 1716 if (next === CHAR_LEFT_SQUARE_BRACKET) { 1717 brackets++; 1718 continue; 1719 } 1720 1721 if (next === CHAR_BACKSLASH) { 1722 value += advance(); 1723 continue; 1724 } 1725 1726 if (next === CHAR_RIGHT_SQUARE_BRACKET) { 1727 brackets--; 1728 1729 if (brackets === 0) { 1730 break; 1731 } 1732 } 1733 } 1734 1735 push({ type: 'text', value }); 1736 continue; 1737 } 1738 1739 /** 1740 * Parentheses 1741 */ 1742 1743 if (value === CHAR_LEFT_PARENTHESES) { 1744 block = push({ type: 'paren', nodes: [] }); 1745 stack.push(block); 1746 push({ type: 'text', value }); 1747 continue; 1748 } 1749 1750 if (value === CHAR_RIGHT_PARENTHESES) { 1751 if (block.type !== 'paren') { 1752 push({ type: 'text', value }); 1753 continue; 1754 } 1755 block = stack.pop(); 1756 push({ type: 'text', value }); 1757 block = stack[stack.length - 1]; 1758 continue; 1759 } 1760 1761 /** 1762 * Quotes: '|"|` 1763 */ 1764 1765 if (value === CHAR_DOUBLE_QUOTE || value === CHAR_SINGLE_QUOTE || value === CHAR_BACKTICK) { 1766 const open = value; 1767 let next; 1768 1769 if (options.keepQuotes !== true) { 1770 value = ''; 1771 } 1772 1773 while (index < length && (next = advance())) { 1774 if (next === CHAR_BACKSLASH) { 1775 value += next + advance(); 1776 continue; 1777 } 1778 1779 if (next === open) { 1780 if (options.keepQuotes === true) value += next; 1781 break; 1782 } 1783 1784 value += next; 1785 } 1786 1787 push({ type: 'text', value }); 1788 continue; 1789 } 1790 1791 /** 1792 * Left curly brace: '{' 1793 */ 1794 1795 if (value === CHAR_LEFT_CURLY_BRACE) { 1796 depth++; 1797 1798 const dollar = prev.value && prev.value.slice(-1) === '$' || block.dollar === true; 1799 const brace = { 1800 type: 'brace', 1801 open: true, 1802 close: false, 1803 dollar, 1804 depth, 1805 commas: 0, 1806 ranges: 0, 1807 nodes: [] 1808 }; 1809 1810 block = push(brace); 1811 stack.push(block); 1812 push({ type: 'open', value }); 1813 continue; 1814 } 1815 1816 /** 1817 * Right curly brace: '}' 1818 */ 1819 1820 if (value === CHAR_RIGHT_CURLY_BRACE) { 1821 if (block.type !== 'brace') { 1822 push({ type: 'text', value }); 1823 continue; 1824 } 1825 1826 const type = 'close'; 1827 block = stack.pop(); 1828 block.close = true; 1829 1830 push({ type, value }); 1831 depth--; 1832 1833 block = stack[stack.length - 1]; 1834 continue; 1835 } 1836 1837 /** 1838 * Comma: ',' 1839 */ 1840 1841 if (value === CHAR_COMMA && depth > 0) { 1842 if (block.ranges > 0) { 1843 block.ranges = 0; 1844 const open = block.nodes.shift(); 1845 block.nodes = [open, { type: 'text', value: stringify$1(block) }]; 1846 } 1847 1848 push({ type: 'comma', value }); 1849 block.commas++; 1850 continue; 1851 } 1852 1853 /** 1854 * Dot: '.' 1855 */ 1856 1857 if (value === CHAR_DOT && depth > 0 && block.commas === 0) { 1858 const siblings = block.nodes; 1859 1860 if (depth === 0 || siblings.length === 0) { 1861 push({ type: 'text', value }); 1862 continue; 1863 } 1864 1865 if (prev.type === 'dot') { 1866 block.range = []; 1867 prev.value += value; 1868 prev.type = 'range'; 1869 1870 if (block.nodes.length !== 3 && block.nodes.length !== 5) { 1871 block.invalid = true; 1872 block.ranges = 0; 1873 prev.type = 'text'; 1874 continue; 1875 } 1876 1877 block.ranges++; 1878 block.args = []; 1879 continue; 1880 } 1881 1882 if (prev.type === 'range') { 1883 siblings.pop(); 1884 1885 const before = siblings[siblings.length - 1]; 1886 before.value += prev.value + value; 1887 prev = before; 1888 block.ranges--; 1889 continue; 1890 } 1891 1892 push({ type: 'dot', value }); 1893 continue; 1894 } 1895 1896 /** 1897 * Text 1898 */ 1899 1900 push({ type: 'text', value }); 1901 } 1902 1903 // Mark imbalanced braces and brackets as invalid 1904 do { 1905 block = stack.pop(); 1906 1907 if (block.type !== 'root') { 1908 block.nodes.forEach(node => { 1909 if (!node.nodes) { 1910 if (node.type === 'open') node.isOpen = true; 1911 if (node.type === 'close') node.isClose = true; 1912 if (!node.nodes) node.type = 'text'; 1913 node.invalid = true; 1914 } 1915 }); 1916 1917 // get the location of the block on parent.nodes (block's siblings) 1918 const parent = stack[stack.length - 1]; 1919 const index = parent.nodes.indexOf(block); 1920 // replace the (invalid) block with it's nodes 1921 parent.nodes.splice(index, 1, ...block.nodes); 1922 } 1923 } while (stack.length > 0); 1924 1925 push({ type: 'eos' }); 1926 return ast; 1927 }; 1928 1929 var parse_1 = parse$1; 1930 1931 const stringify = stringify$4; 1932 const compile = compile_1; 1933 const expand = expand_1; 1934 const parse = parse_1; 1935 1936 /** 1937 * Expand the given pattern or create a regex-compatible string. 1938 * 1939 * ```js 1940 * const braces = require('braces'); 1941 * console.log(braces('{a,b,c}', { compile: true })); //=> ['(a|b|c)'] 1942 * console.log(braces('{a,b,c}')); //=> ['a', 'b', 'c'] 1943 * ``` 1944 * @param {String} `str` 1945 * @param {Object} `options` 1946 * @return {String} 1947 * @api public 1948 */ 1949 1950 const braces$1 = (input, options = {}) => { 1951 let output = []; 1952 1953 if (Array.isArray(input)) { 1954 for (const pattern of input) { 1955 const result = braces$1.create(pattern, options); 1956 if (Array.isArray(result)) { 1957 output.push(...result); 1958 } else { 1959 output.push(result); 1960 } 1961 } 1962 } else { 1963 output = [].concat(braces$1.create(input, options)); 1964 } 1965 1966 if (options && options.expand === true && options.nodupes === true) { 1967 output = [...new Set(output)]; 1968 } 1969 return output; 1970 }; 1971 1972 /** 1973 * Parse the given `str` with the given `options`. 1974 * 1975 * ```js 1976 * // braces.parse(pattern, [, options]); 1977 * const ast = braces.parse('a/{b,c}/d'); 1978 * console.log(ast); 1979 * ``` 1980 * @param {String} pattern Brace pattern to parse 1981 * @param {Object} options 1982 * @return {Object} Returns an AST 1983 * @api public 1984 */ 1985 1986 braces$1.parse = (input, options = {}) => parse(input, options); 1987 1988 /** 1989 * Creates a braces string from an AST, or an AST node. 1990 * 1991 * ```js 1992 * const braces = require('braces'); 1993 * let ast = braces.parse('foo/{a,b}/bar'); 1994 * console.log(stringify(ast.nodes[2])); //=> '{a,b}' 1995 * ``` 1996 * @param {String} `input` Brace pattern or AST. 1997 * @param {Object} `options` 1998 * @return {Array} Returns an array of expanded values. 1999 * @api public 2000 */ 2001 2002 braces$1.stringify = (input, options = {}) => { 2003 if (typeof input === 'string') { 2004 return stringify(braces$1.parse(input, options), options); 2005 } 2006 return stringify(input, options); 2007 }; 2008 2009 /** 2010 * Compiles a brace pattern into a regex-compatible, optimized string. 2011 * This method is called by the main [braces](#braces) function by default. 2012 * 2013 * ```js 2014 * const braces = require('braces'); 2015 * console.log(braces.compile('a/{b,c}/d')); 2016 * //=> ['a/(b|c)/d'] 2017 * ``` 2018 * @param {String} `input` Brace pattern or AST. 2019 * @param {Object} `options` 2020 * @return {Array} Returns an array of expanded values. 2021 * @api public 2022 */ 2023 2024 braces$1.compile = (input, options = {}) => { 2025 if (typeof input === 'string') { 2026 input = braces$1.parse(input, options); 2027 } 2028 return compile(input, options); 2029 }; 2030 2031 /** 2032 * Expands a brace pattern into an array. This method is called by the 2033 * main [braces](#braces) function when `options.expand` is true. Before 2034 * using this method it's recommended that you read the [performance notes](#performance)) 2035 * and advantages of using [.compile](#compile) instead. 2036 * 2037 * ```js 2038 * const braces = require('braces'); 2039 * console.log(braces.expand('a/{b,c}/d')); 2040 * //=> ['a/b/d', 'a/c/d']; 2041 * ``` 2042 * @param {String} `pattern` Brace pattern 2043 * @param {Object} `options` 2044 * @return {Array} Returns an array of expanded values. 2045 * @api public 2046 */ 2047 2048 braces$1.expand = (input, options = {}) => { 2049 if (typeof input === 'string') { 2050 input = braces$1.parse(input, options); 2051 } 2052 2053 let result = expand(input, options); 2054 2055 // filter out empty strings if specified 2056 if (options.noempty === true) { 2057 result = result.filter(Boolean); 2058 } 2059 2060 // filter out duplicates if specified 2061 if (options.nodupes === true) { 2062 result = [...new Set(result)]; 2063 } 2064 2065 return result; 2066 }; 2067 2068 /** 2069 * Processes a brace pattern and returns either an expanded array 2070 * (if `options.expand` is true), a highly optimized regex-compatible string. 2071 * This method is called by the main [braces](#braces) function. 2072 * 2073 * ```js 2074 * const braces = require('braces'); 2075 * console.log(braces.create('user-{200..300}/project-{a,b,c}-{1..10}')) 2076 * //=> 'user-(20[0-9]|2[1-9][0-9]|300)/project-(a|b|c)-([1-9]|10)' 2077 * ``` 2078 * @param {String} `pattern` Brace pattern 2079 * @param {Object} `options` 2080 * @return {Array} Returns an array of expanded values. 2081 * @api public 2082 */ 2083 2084 braces$1.create = (input, options = {}) => { 2085 if (input === '' || input.length < 3) { 2086 return [input]; 2087 } 2088 2089 return options.expand !== true 2090 ? braces$1.compile(input, options) 2091 : braces$1.expand(input, options); 2092 }; 2093 2094 /** 2095 * Expose "braces" 2096 */ 2097 2098 var braces_1 = braces$1; 5444 var fillRange; 5445 var hasRequiredFillRange; 5446 5447 function requireFillRange () { 5448 if (hasRequiredFillRange) return fillRange; 5449 hasRequiredFillRange = 1; 5450 5451 const util = require$$2; 5452 const toRegexRange = /*@__PURE__*/ requireToRegexRange(); 5453 5454 const isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); 5455 5456 const transform = toNumber => { 5457 return value => toNumber === true ? Number(value) : String(value); 5458 }; 5459 5460 const isValidValue = value => { 5461 return typeof value === 'number' || (typeof value === 'string' && value !== ''); 5462 }; 5463 5464 const isNumber = num => Number.isInteger(+num); 5465 5466 const zeros = input => { 5467 let value = `${input}`; 5468 let index = -1; 5469 if (value[0] === '-') value = value.slice(1); 5470 if (value === '0') return false; 5471 while (value[++index] === '0'); 5472 return index > 0; 5473 }; 5474 5475 const stringify = (start, end, options) => { 5476 if (typeof start === 'string' || typeof end === 'string') { 5477 return true; 5478 } 5479 return options.stringify === true; 5480 }; 5481 5482 const pad = (input, maxLength, toNumber) => { 5483 if (maxLength > 0) { 5484 let dash = input[0] === '-' ? '-' : ''; 5485 if (dash) input = input.slice(1); 5486 input = (dash + input.padStart(dash ? maxLength - 1 : maxLength, '0')); 5487 } 5488 if (toNumber === false) { 5489 return String(input); 5490 } 5491 return input; 5492 }; 5493 5494 const toMaxLen = (input, maxLength) => { 5495 let negative = input[0] === '-' ? '-' : ''; 5496 if (negative) { 5497 input = input.slice(1); 5498 maxLength--; 5499 } 5500 while (input.length < maxLength) input = '0' + input; 5501 return negative ? ('-' + input) : input; 5502 }; 5503 5504 const toSequence = (parts, options, maxLen) => { 5505 parts.negatives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0); 5506 parts.positives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0); 5507 5508 let prefix = options.capture ? '' : '?:'; 5509 let positives = ''; 5510 let negatives = ''; 5511 let result; 5512 5513 if (parts.positives.length) { 5514 positives = parts.positives.map(v => toMaxLen(String(v), maxLen)).join('|'); 5515 } 5516 5517 if (parts.negatives.length) { 5518 negatives = `-(${prefix}${parts.negatives.map(v => toMaxLen(String(v), maxLen)).join('|')})`; 5519 } 5520 5521 if (positives && negatives) { 5522 result = `${positives}|${negatives}`; 5523 } else { 5524 result = positives || negatives; 5525 } 5526 5527 if (options.wrap) { 5528 return `(${prefix}${result})`; 5529 } 5530 5531 return result; 5532 }; 5533 5534 const toRange = (a, b, isNumbers, options) => { 5535 if (isNumbers) { 5536 return toRegexRange(a, b, { wrap: false, ...options }); 5537 } 5538 5539 let start = String.fromCharCode(a); 5540 if (a === b) return start; 5541 5542 let stop = String.fromCharCode(b); 5543 return `[${start}-${stop}]`; 5544 }; 5545 5546 const toRegex = (start, end, options) => { 5547 if (Array.isArray(start)) { 5548 let wrap = options.wrap === true; 5549 let prefix = options.capture ? '' : '?:'; 5550 return wrap ? `(${prefix}${start.join('|')})` : start.join('|'); 5551 } 5552 return toRegexRange(start, end, options); 5553 }; 5554 5555 const rangeError = (...args) => { 5556 return new RangeError('Invalid range arguments: ' + util.inspect(...args)); 5557 }; 5558 5559 const invalidRange = (start, end, options) => { 5560 if (options.strictRanges === true) throw rangeError([start, end]); 5561 return []; 5562 }; 5563 5564 const invalidStep = (step, options) => { 5565 if (options.strictRanges === true) { 5566 throw new TypeError(`Expected step "${step}" to be a number`); 5567 } 5568 return []; 5569 }; 5570 5571 const fillNumbers = (start, end, step = 1, options = {}) => { 5572 let a = Number(start); 5573 let b = Number(end); 5574 5575 if (!Number.isInteger(a) || !Number.isInteger(b)) { 5576 if (options.strictRanges === true) throw rangeError([start, end]); 5577 return []; 5578 } 5579 5580 // fix negative zero 5581 if (a === 0) a = 0; 5582 if (b === 0) b = 0; 5583 5584 let descending = a > b; 5585 let startString = String(start); 5586 let endString = String(end); 5587 let stepString = String(step); 5588 step = Math.max(Math.abs(step), 1); 5589 5590 let padded = zeros(startString) || zeros(endString) || zeros(stepString); 5591 let maxLen = padded ? Math.max(startString.length, endString.length, stepString.length) : 0; 5592 let toNumber = padded === false && stringify(start, end, options) === false; 5593 let format = options.transform || transform(toNumber); 5594 5595 if (options.toRegex && step === 1) { 5596 return toRange(toMaxLen(start, maxLen), toMaxLen(end, maxLen), true, options); 5597 } 5598 5599 let parts = { negatives: [], positives: [] }; 5600 let push = num => parts[num < 0 ? 'negatives' : 'positives'].push(Math.abs(num)); 5601 let range = []; 5602 let index = 0; 5603 5604 while (descending ? a >= b : a <= b) { 5605 if (options.toRegex === true && step > 1) { 5606 push(a); 5607 } else { 5608 range.push(pad(format(a, index), maxLen, toNumber)); 5609 } 5610 a = descending ? a - step : a + step; 5611 index++; 5612 } 5613 5614 if (options.toRegex === true) { 5615 return step > 1 5616 ? toSequence(parts, options, maxLen) 5617 : toRegex(range, null, { wrap: false, ...options }); 5618 } 5619 5620 return range; 5621 }; 5622 5623 const fillLetters = (start, end, step = 1, options = {}) => { 5624 if ((!isNumber(start) && start.length > 1) || (!isNumber(end) && end.length > 1)) { 5625 return invalidRange(start, end, options); 5626 } 5627 5628 let format = options.transform || (val => String.fromCharCode(val)); 5629 let a = `${start}`.charCodeAt(0); 5630 let b = `${end}`.charCodeAt(0); 5631 5632 let descending = a > b; 5633 let min = Math.min(a, b); 5634 let max = Math.max(a, b); 5635 5636 if (options.toRegex && step === 1) { 5637 return toRange(min, max, false, options); 5638 } 5639 5640 let range = []; 5641 let index = 0; 5642 5643 while (descending ? a >= b : a <= b) { 5644 range.push(format(a, index)); 5645 a = descending ? a - step : a + step; 5646 index++; 5647 } 5648 5649 if (options.toRegex === true) { 5650 return toRegex(range, null, { wrap: false, options }); 5651 } 5652 5653 return range; 5654 }; 5655 5656 const fill = (start, end, step, options = {}) => { 5657 if (end == null && isValidValue(start)) { 5658 return [start]; 5659 } 5660 5661 if (!isValidValue(start) || !isValidValue(end)) { 5662 return invalidRange(start, end, options); 5663 } 5664 5665 if (typeof step === 'function') { 5666 return fill(start, end, 1, { transform: step }); 5667 } 5668 5669 if (isObject(step)) { 5670 return fill(start, end, 0, step); 5671 } 5672 5673 let opts = { ...options }; 5674 if (opts.capture === true) opts.wrap = true; 5675 step = step || opts.step || 1; 5676 5677 if (!isNumber(step)) { 5678 if (step != null && !isObject(step)) return invalidStep(step, opts); 5679 return fill(start, end, 1, step); 5680 } 5681 5682 if (isNumber(start) && isNumber(end)) { 5683 return fillNumbers(start, end, step, opts); 5684 } 5685 5686 return fillLetters(start, end, Math.max(Math.abs(step), 1), opts); 5687 }; 5688 5689 fillRange = fill; 5690 return fillRange; 5691 } 5692 5693 var compile_1; 5694 var hasRequiredCompile; 5695 5696 function requireCompile () { 5697 if (hasRequiredCompile) return compile_1; 5698 hasRequiredCompile = 1; 5699 5700 const fill = /*@__PURE__*/ requireFillRange(); 5701 const utils = /*@__PURE__*/ requireUtils(); 5702 5703 const compile = (ast, options = {}) => { 5704 const walk = (node, parent = {}) => { 5705 const invalidBlock = utils.isInvalidBrace(parent); 5706 const invalidNode = node.invalid === true && options.escapeInvalid === true; 5707 const invalid = invalidBlock === true || invalidNode === true; 5708 const prefix = options.escapeInvalid === true ? '\\' : ''; 5709 let output = ''; 5710 5711 if (node.isOpen === true) { 5712 return prefix + node.value; 5713 } 5714 5715 if (node.isClose === true) { 5716 console.log('node.isClose', prefix, node.value); 5717 return prefix + node.value; 5718 } 5719 5720 if (node.type === 'open') { 5721 return invalid ? prefix + node.value : '('; 5722 } 5723 5724 if (node.type === 'close') { 5725 return invalid ? prefix + node.value : ')'; 5726 } 5727 5728 if (node.type === 'comma') { 5729 return node.prev.type === 'comma' ? '' : invalid ? node.value : '|'; 5730 } 5731 5732 if (node.value) { 5733 return node.value; 5734 } 5735 5736 if (node.nodes && node.ranges > 0) { 5737 const args = utils.reduce(node.nodes); 5738 const range = fill(...args, { ...options, wrap: false, toRegex: true, strictZeros: true }); 5739 5740 if (range.length !== 0) { 5741 return args.length > 1 && range.length > 1 ? `(${range})` : range; 5742 } 5743 } 5744 5745 if (node.nodes) { 5746 for (const child of node.nodes) { 5747 output += walk(child, node); 5748 } 5749 } 5750 5751 return output; 5752 }; 5753 5754 return walk(ast); 5755 }; 5756 5757 compile_1 = compile; 5758 return compile_1; 5759 } 5760 5761 var expand_1; 5762 var hasRequiredExpand; 5763 5764 function requireExpand () { 5765 if (hasRequiredExpand) return expand_1; 5766 hasRequiredExpand = 1; 5767 5768 const fill = /*@__PURE__*/ requireFillRange(); 5769 const stringify = /*@__PURE__*/ requireStringify(); 5770 const utils = /*@__PURE__*/ requireUtils(); 5771 5772 const append = (queue = '', stash = '', enclose = false) => { 5773 const result = []; 5774 5775 queue = [].concat(queue); 5776 stash = [].concat(stash); 5777 5778 if (!stash.length) return queue; 5779 if (!queue.length) { 5780 return enclose ? utils.flatten(stash).map(ele => `{${ele}}`) : stash; 5781 } 5782 5783 for (const item of queue) { 5784 if (Array.isArray(item)) { 5785 for (const value of item) { 5786 result.push(append(value, stash, enclose)); 5787 } 5788 } else { 5789 for (let ele of stash) { 5790 if (enclose === true && typeof ele === 'string') ele = `{${ele}}`; 5791 result.push(Array.isArray(ele) ? append(item, ele, enclose) : item + ele); 5792 } 5793 } 5794 } 5795 return utils.flatten(result); 5796 }; 5797 5798 const expand = (ast, options = {}) => { 5799 const rangeLimit = options.rangeLimit === undefined ? 1000 : options.rangeLimit; 5800 5801 const walk = (node, parent = {}) => { 5802 node.queue = []; 5803 5804 let p = parent; 5805 let q = parent.queue; 5806 5807 while (p.type !== 'brace' && p.type !== 'root' && p.parent) { 5808 p = p.parent; 5809 q = p.queue; 5810 } 5811 5812 if (node.invalid || node.dollar) { 5813 q.push(append(q.pop(), stringify(node, options))); 5814 return; 5815 } 5816 5817 if (node.type === 'brace' && node.invalid !== true && node.nodes.length === 2) { 5818 q.push(append(q.pop(), ['{}'])); 5819 return; 5820 } 5821 5822 if (node.nodes && node.ranges > 0) { 5823 const args = utils.reduce(node.nodes); 5824 5825 if (utils.exceedsLimit(...args, options.step, rangeLimit)) { 5826 throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.'); 5827 } 5828 5829 let range = fill(...args, options); 5830 if (range.length === 0) { 5831 range = stringify(node, options); 5832 } 5833 5834 q.push(append(q.pop(), range)); 5835 node.nodes = []; 5836 return; 5837 } 5838 5839 const enclose = utils.encloseBrace(node); 5840 let queue = node.queue; 5841 let block = node; 5842 5843 while (block.type !== 'brace' && block.type !== 'root' && block.parent) { 5844 block = block.parent; 5845 queue = block.queue; 5846 } 5847 5848 for (let i = 0; i < node.nodes.length; i++) { 5849 const child = node.nodes[i]; 5850 5851 if (child.type === 'comma' && node.type === 'brace') { 5852 if (i === 1) queue.push(''); 5853 queue.push(''); 5854 continue; 5855 } 5856 5857 if (child.type === 'close') { 5858 q.push(append(q.pop(), queue, enclose)); 5859 continue; 5860 } 5861 5862 if (child.value && child.type !== 'open') { 5863 queue.push(append(queue.pop(), child.value)); 5864 continue; 5865 } 5866 5867 if (child.nodes) { 5868 walk(child, node); 5869 } 5870 } 5871 5872 return queue; 5873 }; 5874 5875 return utils.flatten(walk(ast)); 5876 }; 5877 5878 expand_1 = expand; 5879 return expand_1; 5880 } 5881 5882 var constants$1; 5883 var hasRequiredConstants$1; 5884 5885 function requireConstants$1 () { 5886 if (hasRequiredConstants$1) return constants$1; 5887 hasRequiredConstants$1 = 1; 5888 5889 constants$1 = { 5890 MAX_LENGTH: 10000, 5891 5892 // Digits 5893 CHAR_0: '0', /* 0 */ 5894 CHAR_9: '9', /* 9 */ 5895 5896 // Alphabet chars. 5897 CHAR_UPPERCASE_A: 'A', /* A */ 5898 CHAR_LOWERCASE_A: 'a', /* a */ 5899 CHAR_UPPERCASE_Z: 'Z', /* Z */ 5900 CHAR_LOWERCASE_Z: 'z', /* z */ 5901 5902 CHAR_LEFT_PARENTHESES: '(', /* ( */ 5903 CHAR_RIGHT_PARENTHESES: ')', /* ) */ 5904 5905 CHAR_ASTERISK: '*', /* * */ 5906 5907 // Non-alphabetic chars. 5908 CHAR_AMPERSAND: '&', /* & */ 5909 CHAR_AT: '@', /* @ */ 5910 CHAR_BACKSLASH: '\\', /* \ */ 5911 CHAR_BACKTICK: '`', /* ` */ 5912 CHAR_CARRIAGE_RETURN: '\r', /* \r */ 5913 CHAR_CIRCUMFLEX_ACCENT: '^', /* ^ */ 5914 CHAR_COLON: ':', /* : */ 5915 CHAR_COMMA: ',', /* , */ 5916 CHAR_DOLLAR: '$', /* . */ 5917 CHAR_DOT: '.', /* . */ 5918 CHAR_DOUBLE_QUOTE: '"', /* " */ 5919 CHAR_EQUAL: '=', /* = */ 5920 CHAR_EXCLAMATION_MARK: '!', /* ! */ 5921 CHAR_FORM_FEED: '\f', /* \f */ 5922 CHAR_FORWARD_SLASH: '/', /* / */ 5923 CHAR_HASH: '#', /* # */ 5924 CHAR_HYPHEN_MINUS: '-', /* - */ 5925 CHAR_LEFT_ANGLE_BRACKET: '<', /* < */ 5926 CHAR_LEFT_CURLY_BRACE: '{', /* { */ 5927 CHAR_LEFT_SQUARE_BRACKET: '[', /* [ */ 5928 CHAR_LINE_FEED: '\n', /* \n */ 5929 CHAR_NO_BREAK_SPACE: '\u00A0', /* \u00A0 */ 5930 CHAR_PERCENT: '%', /* % */ 5931 CHAR_PLUS: '+', /* + */ 5932 CHAR_QUESTION_MARK: '?', /* ? */ 5933 CHAR_RIGHT_ANGLE_BRACKET: '>', /* > */ 5934 CHAR_RIGHT_CURLY_BRACE: '}', /* } */ 5935 CHAR_RIGHT_SQUARE_BRACKET: ']', /* ] */ 5936 CHAR_SEMICOLON: ';', /* ; */ 5937 CHAR_SINGLE_QUOTE: '\'', /* ' */ 5938 CHAR_SPACE: ' ', /* */ 5939 CHAR_TAB: '\t', /* \t */ 5940 CHAR_UNDERSCORE: '_', /* _ */ 5941 CHAR_VERTICAL_LINE: '|', /* | */ 5942 CHAR_ZERO_WIDTH_NOBREAK_SPACE: '\uFEFF' /* \uFEFF */ 5943 }; 5944 return constants$1; 5945 } 5946 5947 var parse_1; 5948 var hasRequiredParse; 5949 5950 function requireParse () { 5951 if (hasRequiredParse) return parse_1; 5952 hasRequiredParse = 1; 5953 5954 const stringify = /*@__PURE__*/ requireStringify(); 5955 5956 /** 5957 * Constants 5958 */ 5959 5960 const { 5961 MAX_LENGTH, 5962 CHAR_BACKSLASH, /* \ */ 5963 CHAR_BACKTICK, /* ` */ 5964 CHAR_COMMA, /* , */ 5965 CHAR_DOT, /* . */ 5966 CHAR_LEFT_PARENTHESES, /* ( */ 5967 CHAR_RIGHT_PARENTHESES, /* ) */ 5968 CHAR_LEFT_CURLY_BRACE, /* { */ 5969 CHAR_RIGHT_CURLY_BRACE, /* } */ 5970 CHAR_LEFT_SQUARE_BRACKET, /* [ */ 5971 CHAR_RIGHT_SQUARE_BRACKET, /* ] */ 5972 CHAR_DOUBLE_QUOTE, /* " */ 5973 CHAR_SINGLE_QUOTE, /* ' */ 5974 CHAR_NO_BREAK_SPACE, 5975 CHAR_ZERO_WIDTH_NOBREAK_SPACE 5976 } = /*@__PURE__*/ requireConstants$1(); 5977 5978 /** 5979 * parse 5980 */ 5981 5982 const parse = (input, options = {}) => { 5983 if (typeof input !== 'string') { 5984 throw new TypeError('Expected a string'); 5985 } 5986 5987 const opts = options || {}; 5988 const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; 5989 if (input.length > max) { 5990 throw new SyntaxError(`Input length (${input.length}), exceeds max characters (${max})`); 5991 } 5992 5993 const ast = { type: 'root', input, nodes: [] }; 5994 const stack = [ast]; 5995 let block = ast; 5996 let prev = ast; 5997 let brackets = 0; 5998 const length = input.length; 5999 let index = 0; 6000 let depth = 0; 6001 let value; 6002 6003 /** 6004 * Helpers 6005 */ 6006 6007 const advance = () => input[index++]; 6008 const push = node => { 6009 if (node.type === 'text' && prev.type === 'dot') { 6010 prev.type = 'text'; 6011 } 6012 6013 if (prev && prev.type === 'text' && node.type === 'text') { 6014 prev.value += node.value; 6015 return; 6016 } 6017 6018 block.nodes.push(node); 6019 node.parent = block; 6020 node.prev = prev; 6021 prev = node; 6022 return node; 6023 }; 6024 6025 push({ type: 'bos' }); 6026 6027 while (index < length) { 6028 block = stack[stack.length - 1]; 6029 value = advance(); 6030 6031 /** 6032 * Invalid chars 6033 */ 6034 6035 if (value === CHAR_ZERO_WIDTH_NOBREAK_SPACE || value === CHAR_NO_BREAK_SPACE) { 6036 continue; 6037 } 6038 6039 /** 6040 * Escaped chars 6041 */ 6042 6043 if (value === CHAR_BACKSLASH) { 6044 push({ type: 'text', value: (options.keepEscaping ? value : '') + advance() }); 6045 continue; 6046 } 6047 6048 /** 6049 * Right square bracket (literal): ']' 6050 */ 6051 6052 if (value === CHAR_RIGHT_SQUARE_BRACKET) { 6053 push({ type: 'text', value: '\\' + value }); 6054 continue; 6055 } 6056 6057 /** 6058 * Left square bracket: '[' 6059 */ 6060 6061 if (value === CHAR_LEFT_SQUARE_BRACKET) { 6062 brackets++; 6063 6064 let next; 6065 6066 while (index < length && (next = advance())) { 6067 value += next; 6068 6069 if (next === CHAR_LEFT_SQUARE_BRACKET) { 6070 brackets++; 6071 continue; 6072 } 6073 6074 if (next === CHAR_BACKSLASH) { 6075 value += advance(); 6076 continue; 6077 } 6078 6079 if (next === CHAR_RIGHT_SQUARE_BRACKET) { 6080 brackets--; 6081 6082 if (brackets === 0) { 6083 break; 6084 } 6085 } 6086 } 6087 6088 push({ type: 'text', value }); 6089 continue; 6090 } 6091 6092 /** 6093 * Parentheses 6094 */ 6095 6096 if (value === CHAR_LEFT_PARENTHESES) { 6097 block = push({ type: 'paren', nodes: [] }); 6098 stack.push(block); 6099 push({ type: 'text', value }); 6100 continue; 6101 } 6102 6103 if (value === CHAR_RIGHT_PARENTHESES) { 6104 if (block.type !== 'paren') { 6105 push({ type: 'text', value }); 6106 continue; 6107 } 6108 block = stack.pop(); 6109 push({ type: 'text', value }); 6110 block = stack[stack.length - 1]; 6111 continue; 6112 } 6113 6114 /** 6115 * Quotes: '|"|` 6116 */ 6117 6118 if (value === CHAR_DOUBLE_QUOTE || value === CHAR_SINGLE_QUOTE || value === CHAR_BACKTICK) { 6119 const open = value; 6120 let next; 6121 6122 if (options.keepQuotes !== true) { 6123 value = ''; 6124 } 6125 6126 while (index < length && (next = advance())) { 6127 if (next === CHAR_BACKSLASH) { 6128 value += next + advance(); 6129 continue; 6130 } 6131 6132 if (next === open) { 6133 if (options.keepQuotes === true) value += next; 6134 break; 6135 } 6136 6137 value += next; 6138 } 6139 6140 push({ type: 'text', value }); 6141 continue; 6142 } 6143 6144 /** 6145 * Left curly brace: '{' 6146 */ 6147 6148 if (value === CHAR_LEFT_CURLY_BRACE) { 6149 depth++; 6150 6151 const dollar = prev.value && prev.value.slice(-1) === '$' || block.dollar === true; 6152 const brace = { 6153 type: 'brace', 6154 open: true, 6155 close: false, 6156 dollar, 6157 depth, 6158 commas: 0, 6159 ranges: 0, 6160 nodes: [] 6161 }; 6162 6163 block = push(brace); 6164 stack.push(block); 6165 push({ type: 'open', value }); 6166 continue; 6167 } 6168 6169 /** 6170 * Right curly brace: '}' 6171 */ 6172 6173 if (value === CHAR_RIGHT_CURLY_BRACE) { 6174 if (block.type !== 'brace') { 6175 push({ type: 'text', value }); 6176 continue; 6177 } 6178 6179 const type = 'close'; 6180 block = stack.pop(); 6181 block.close = true; 6182 6183 push({ type, value }); 6184 depth--; 6185 6186 block = stack[stack.length - 1]; 6187 continue; 6188 } 6189 6190 /** 6191 * Comma: ',' 6192 */ 6193 6194 if (value === CHAR_COMMA && depth > 0) { 6195 if (block.ranges > 0) { 6196 block.ranges = 0; 6197 const open = block.nodes.shift(); 6198 block.nodes = [open, { type: 'text', value: stringify(block) }]; 6199 } 6200 6201 push({ type: 'comma', value }); 6202 block.commas++; 6203 continue; 6204 } 6205 6206 /** 6207 * Dot: '.' 6208 */ 6209 6210 if (value === CHAR_DOT && depth > 0 && block.commas === 0) { 6211 const siblings = block.nodes; 6212 6213 if (depth === 0 || siblings.length === 0) { 6214 push({ type: 'text', value }); 6215 continue; 6216 } 6217 6218 if (prev.type === 'dot') { 6219 block.range = []; 6220 prev.value += value; 6221 prev.type = 'range'; 6222 6223 if (block.nodes.length !== 3 && block.nodes.length !== 5) { 6224 block.invalid = true; 6225 block.ranges = 0; 6226 prev.type = 'text'; 6227 continue; 6228 } 6229 6230 block.ranges++; 6231 block.args = []; 6232 continue; 6233 } 6234 6235 if (prev.type === 'range') { 6236 siblings.pop(); 6237 6238 const before = siblings[siblings.length - 1]; 6239 before.value += prev.value + value; 6240 prev = before; 6241 block.ranges--; 6242 continue; 6243 } 6244 6245 push({ type: 'dot', value }); 6246 continue; 6247 } 6248 6249 /** 6250 * Text 6251 */ 6252 6253 push({ type: 'text', value }); 6254 } 6255 6256 // Mark imbalanced braces and brackets as invalid 6257 do { 6258 block = stack.pop(); 6259 6260 if (block.type !== 'root') { 6261 block.nodes.forEach(node => { 6262 if (!node.nodes) { 6263 if (node.type === 'open') node.isOpen = true; 6264 if (node.type === 'close') node.isClose = true; 6265 if (!node.nodes) node.type = 'text'; 6266 node.invalid = true; 6267 } 6268 }); 6269 6270 // get the location of the block on parent.nodes (block's siblings) 6271 const parent = stack[stack.length - 1]; 6272 const index = parent.nodes.indexOf(block); 6273 // replace the (invalid) block with it's nodes 6274 parent.nodes.splice(index, 1, ...block.nodes); 6275 } 6276 } while (stack.length > 0); 6277 6278 push({ type: 'eos' }); 6279 return ast; 6280 }; 6281 6282 parse_1 = parse; 6283 return parse_1; 6284 } 6285 6286 var braces_1; 6287 var hasRequiredBraces; 6288 6289 function requireBraces () { 6290 if (hasRequiredBraces) return braces_1; 6291 hasRequiredBraces = 1; 6292 6293 const stringify = /*@__PURE__*/ requireStringify(); 6294 const compile = /*@__PURE__*/ requireCompile(); 6295 const expand = /*@__PURE__*/ requireExpand(); 6296 const parse = /*@__PURE__*/ requireParse(); 6297 6298 /** 6299 * Expand the given pattern or create a regex-compatible string. 6300 * 6301 * ```js 6302 * const braces = require('braces'); 6303 * console.log(braces('{a,b,c}', { compile: true })); //=> ['(a|b|c)'] 6304 * console.log(braces('{a,b,c}')); //=> ['a', 'b', 'c'] 6305 * ``` 6306 * @param {String} `str` 6307 * @param {Object} `options` 6308 * @return {String} 6309 * @api public 6310 */ 6311 6312 const braces = (input, options = {}) => { 6313 let output = []; 6314 6315 if (Array.isArray(input)) { 6316 for (const pattern of input) { 6317 const result = braces.create(pattern, options); 6318 if (Array.isArray(result)) { 6319 output.push(...result); 6320 } else { 6321 output.push(result); 6322 } 6323 } 6324 } else { 6325 output = [].concat(braces.create(input, options)); 6326 } 6327 6328 if (options && options.expand === true && options.nodupes === true) { 6329 output = [...new Set(output)]; 6330 } 6331 return output; 6332 }; 6333 6334 /** 6335 * Parse the given `str` with the given `options`. 6336 * 6337 * ```js 6338 * // braces.parse(pattern, [, options]); 6339 * const ast = braces.parse('a/{b,c}/d'); 6340 * console.log(ast); 6341 * ``` 6342 * @param {String} pattern Brace pattern to parse 6343 * @param {Object} options 6344 * @return {Object} Returns an AST 6345 * @api public 6346 */ 6347 6348 braces.parse = (input, options = {}) => parse(input, options); 6349 6350 /** 6351 * Creates a braces string from an AST, or an AST node. 6352 * 6353 * ```js 6354 * const braces = require('braces'); 6355 * let ast = braces.parse('foo/{a,b}/bar'); 6356 * console.log(stringify(ast.nodes[2])); //=> '{a,b}' 6357 * ``` 6358 * @param {String} `input` Brace pattern or AST. 6359 * @param {Object} `options` 6360 * @return {Array} Returns an array of expanded values. 6361 * @api public 6362 */ 6363 6364 braces.stringify = (input, options = {}) => { 6365 if (typeof input === 'string') { 6366 return stringify(braces.parse(input, options), options); 6367 } 6368 return stringify(input, options); 6369 }; 6370 6371 /** 6372 * Compiles a brace pattern into a regex-compatible, optimized string. 6373 * This method is called by the main [braces](#braces) function by default. 6374 * 6375 * ```js 6376 * const braces = require('braces'); 6377 * console.log(braces.compile('a/{b,c}/d')); 6378 * //=> ['a/(b|c)/d'] 6379 * ``` 6380 * @param {String} `input` Brace pattern or AST. 6381 * @param {Object} `options` 6382 * @return {Array} Returns an array of expanded values. 6383 * @api public 6384 */ 6385 6386 braces.compile = (input, options = {}) => { 6387 if (typeof input === 'string') { 6388 input = braces.parse(input, options); 6389 } 6390 return compile(input, options); 6391 }; 6392 6393 /** 6394 * Expands a brace pattern into an array. This method is called by the 6395 * main [braces](#braces) function when `options.expand` is true. Before 6396 * using this method it's recommended that you read the [performance notes](#performance)) 6397 * and advantages of using [.compile](#compile) instead. 6398 * 6399 * ```js 6400 * const braces = require('braces'); 6401 * console.log(braces.expand('a/{b,c}/d')); 6402 * //=> ['a/b/d', 'a/c/d']; 6403 * ``` 6404 * @param {String} `pattern` Brace pattern 6405 * @param {Object} `options` 6406 * @return {Array} Returns an array of expanded values. 6407 * @api public 6408 */ 6409 6410 braces.expand = (input, options = {}) => { 6411 if (typeof input === 'string') { 6412 input = braces.parse(input, options); 6413 } 6414 6415 let result = expand(input, options); 6416 6417 // filter out empty strings if specified 6418 if (options.noempty === true) { 6419 result = result.filter(Boolean); 6420 } 6421 6422 // filter out duplicates if specified 6423 if (options.nodupes === true) { 6424 result = [...new Set(result)]; 6425 } 6426 6427 return result; 6428 }; 6429 6430 /** 6431 * Processes a brace pattern and returns either an expanded array 6432 * (if `options.expand` is true), a highly optimized regex-compatible string. 6433 * This method is called by the main [braces](#braces) function. 6434 * 6435 * ```js 6436 * const braces = require('braces'); 6437 * console.log(braces.create('user-{200..300}/project-{a,b,c}-{1..10}')) 6438 * //=> 'user-(20[0-9]|2[1-9][0-9]|300)/project-(a|b|c)-([1-9]|10)' 6439 * ``` 6440 * @param {String} `pattern` Brace pattern 6441 * @param {Object} `options` 6442 * @return {Array} Returns an array of expanded values. 6443 * @api public 6444 */ 6445 6446 braces.create = (input, options = {}) => { 6447 if (input === '' || input.length < 3) { 6448 return [input]; 6449 } 6450 6451 return options.expand !== true 6452 ? braces.compile(input, options) 6453 : braces.expand(input, options); 6454 }; 6455 6456 /** 6457 * Expose "braces" 6458 */ 6459 6460 braces_1 = braces; 6461 return braces_1; 6462 } 2099 6463 2100 6464 const require$$0 = [ … … 2362 6726 ]; 2363 6727 2364 var binaryExtensions$1 = require$$0; 2365 2366 const path = require$$0$2; 2367 const binaryExtensions = binaryExtensions$1; 2368 2369 const extensions = new Set(binaryExtensions); 2370 2371 var isBinaryPath$1 = filePath => extensions.has(path.extname(filePath).slice(1).toLowerCase()); 6728 var binaryExtensions; 6729 var hasRequiredBinaryExtensions; 6730 6731 function requireBinaryExtensions () { 6732 if (hasRequiredBinaryExtensions) return binaryExtensions; 6733 hasRequiredBinaryExtensions = 1; 6734 binaryExtensions = require$$0; 6735 return binaryExtensions; 6736 } 6737 6738 var isBinaryPath; 6739 var hasRequiredIsBinaryPath; 6740 6741 function requireIsBinaryPath () { 6742 if (hasRequiredIsBinaryPath) return isBinaryPath; 6743 hasRequiredIsBinaryPath = 1; 6744 const path = require$$0$1; 6745 const binaryExtensions = /*@__PURE__*/ requireBinaryExtensions(); 6746 6747 const extensions = new Set(binaryExtensions); 6748 6749 isBinaryPath = filePath => extensions.has(path.extname(filePath).slice(1).toLowerCase()); 6750 return isBinaryPath; 6751 } 2372 6752 2373 6753 var constants = {}; 2374 6754 2375 (function (exports) { 2376 2377 const {sep} = require$$0$2; 2378 const {platform} = process; 2379 const os = require$$2$1; 2380 2381 exports.EV_ALL = 'all'; 2382 exports.EV_READY = 'ready'; 2383 exports.EV_ADD = 'add'; 2384 exports.EV_CHANGE = 'change'; 2385 exports.EV_ADD_DIR = 'addDir'; 2386 exports.EV_UNLINK = 'unlink'; 2387 exports.EV_UNLINK_DIR = 'unlinkDir'; 2388 exports.EV_RAW = 'raw'; 2389 exports.EV_ERROR = 'error'; 2390 2391 exports.STR_DATA = 'data'; 2392 exports.STR_END = 'end'; 2393 exports.STR_CLOSE = 'close'; 2394 2395 exports.FSEVENT_CREATED = 'created'; 2396 exports.FSEVENT_MODIFIED = 'modified'; 2397 exports.FSEVENT_DELETED = 'deleted'; 2398 exports.FSEVENT_MOVED = 'moved'; 2399 exports.FSEVENT_CLONED = 'cloned'; 2400 exports.FSEVENT_UNKNOWN = 'unknown'; 2401 exports.FSEVENT_FLAG_MUST_SCAN_SUBDIRS = 1; 2402 exports.FSEVENT_TYPE_FILE = 'file'; 2403 exports.FSEVENT_TYPE_DIRECTORY = 'directory'; 2404 exports.FSEVENT_TYPE_SYMLINK = 'symlink'; 2405 2406 exports.KEY_LISTENERS = 'listeners'; 2407 exports.KEY_ERR = 'errHandlers'; 2408 exports.KEY_RAW = 'rawEmitters'; 2409 exports.HANDLER_KEYS = [exports.KEY_LISTENERS, exports.KEY_ERR, exports.KEY_RAW]; 2410 2411 exports.DOT_SLASH = `.${sep}`; 2412 2413 exports.BACK_SLASH_RE = /\\/g; 2414 exports.DOUBLE_SLASH_RE = /\/\//; 2415 exports.SLASH_OR_BACK_SLASH_RE = /[/\\]/; 2416 exports.DOT_RE = /\..*\.(sw[px])$|~$|\.subl.*\.tmp/; 2417 exports.REPLACER_RE = /^\.[/\\]/; 2418 2419 exports.SLASH = '/'; 2420 exports.SLASH_SLASH = '//'; 2421 exports.BRACE_START = '{'; 2422 exports.BANG = '!'; 2423 exports.ONE_DOT = '.'; 2424 exports.TWO_DOTS = '..'; 2425 exports.STAR = '*'; 2426 exports.GLOBSTAR = '**'; 2427 exports.ROOT_GLOBSTAR = '/**/*'; 2428 exports.SLASH_GLOBSTAR = '/**'; 2429 exports.DIR_SUFFIX = 'Dir'; 2430 exports.ANYMATCH_OPTS = {dot: true}; 2431 exports.STRING_TYPE = 'string'; 2432 exports.FUNCTION_TYPE = 'function'; 2433 exports.EMPTY_STR = ''; 2434 exports.EMPTY_FN = () => {}; 2435 exports.IDENTITY_FN = val => val; 2436 2437 exports.isWindows = platform === 'win32'; 2438 exports.isMacos = platform === 'darwin'; 2439 exports.isLinux = platform === 'linux'; 2440 exports.isIBMi = os.type() === 'OS400'; 2441 } (constants)); 2442 2443 const fs$2 = require$$0$1; 2444 const sysPath$2 = require$$0$2; 2445 const { promisify: promisify$2 } = require$$2; 2446 const isBinaryPath = isBinaryPath$1; 2447 const { 2448 isWindows: isWindows$1, 2449 isLinux, 2450 EMPTY_FN: EMPTY_FN$2, 2451 EMPTY_STR: EMPTY_STR$1, 2452 KEY_LISTENERS, 2453 KEY_ERR, 2454 KEY_RAW, 2455 HANDLER_KEYS, 2456 EV_CHANGE: EV_CHANGE$2, 2457 EV_ADD: EV_ADD$2, 2458 EV_ADD_DIR: EV_ADD_DIR$2, 2459 EV_ERROR: EV_ERROR$2, 2460 STR_DATA: STR_DATA$1, 2461 STR_END: STR_END$2, 2462 BRACE_START: BRACE_START$1, 2463 STAR 2464 } = constants; 2465 2466 const THROTTLE_MODE_WATCH = 'watch'; 2467 2468 const open = promisify$2(fs$2.open); 2469 const stat$2 = promisify$2(fs$2.stat); 2470 const lstat$1 = promisify$2(fs$2.lstat); 2471 const close = promisify$2(fs$2.close); 2472 const fsrealpath = promisify$2(fs$2.realpath); 2473 2474 const statMethods$1 = { lstat: lstat$1, stat: stat$2 }; 2475 2476 // TODO: emit errors properly. Example: EMFILE on Macos. 2477 const foreach = (val, fn) => { 2478 if (val instanceof Set) { 2479 val.forEach(fn); 2480 } else { 2481 fn(val); 2482 } 2483 }; 2484 2485 const addAndConvert = (main, prop, item) => { 2486 let container = main[prop]; 2487 if (!(container instanceof Set)) { 2488 main[prop] = container = new Set([container]); 2489 } 2490 container.add(item); 2491 }; 2492 2493 const clearItem = cont => key => { 2494 const set = cont[key]; 2495 if (set instanceof Set) { 2496 set.clear(); 2497 } else { 2498 delete cont[key]; 2499 } 2500 }; 2501 2502 const delFromSet = (main, prop, item) => { 2503 const container = main[prop]; 2504 if (container instanceof Set) { 2505 container.delete(item); 2506 } else if (container === item) { 2507 delete main[prop]; 2508 } 2509 }; 2510 2511 const isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val; 2512 2513 /** 2514 * @typedef {String} Path 2515 */ 2516 2517 // fs_watch helpers 2518 2519 // object to hold per-process fs_watch instances 2520 // (may be shared across chokidar FSWatcher instances) 2521 2522 /** 2523 * @typedef {Object} FsWatchContainer 2524 * @property {Set} listeners 2525 * @property {Set} errHandlers 2526 * @property {Set} rawEmitters 2527 * @property {fs.FSWatcher=} watcher 2528 * @property {Boolean=} watcherUnusable 2529 */ 2530 2531 /** 2532 * @type {Map<String,FsWatchContainer>} 2533 */ 2534 const FsWatchInstances = new Map(); 2535 2536 /** 2537 * Instantiates the fs_watch interface 2538 * @param {String} path to be watched 2539 * @param {Object} options to be passed to fs_watch 2540 * @param {Function} listener main event handler 2541 * @param {Function} errHandler emits info about errors 2542 * @param {Function} emitRaw emits raw event data 2543 * @returns {fs.FSWatcher} new fsevents instance 2544 */ 2545 function createFsWatchInstance(path, options, listener, errHandler, emitRaw) { 2546 const handleEvent = (rawEvent, evPath) => { 2547 listener(path); 2548 emitRaw(rawEvent, evPath, {watchedPath: path}); 2549 2550 // emit based on events occurring for files from a directory's watcher in 2551 // case the file's watcher misses it (and rely on throttling to de-dupe) 2552 if (evPath && path !== evPath) { 2553 fsWatchBroadcast( 2554 sysPath$2.resolve(path, evPath), KEY_LISTENERS, sysPath$2.join(path, evPath) 2555 ); 2556 } 2557 }; 2558 try { 2559 return fs$2.watch(path, options, handleEvent); 2560 } catch (error) { 2561 errHandler(error); 2562 } 6755 var hasRequiredConstants; 6756 6757 function requireConstants () { 6758 if (hasRequiredConstants) return constants; 6759 hasRequiredConstants = 1; 6760 (function (exports) { 6761 6762 const {sep} = require$$0$1; 6763 const {platform} = process; 6764 const os = require$$2$1; 6765 6766 exports.EV_ALL = 'all'; 6767 exports.EV_READY = 'ready'; 6768 exports.EV_ADD = 'add'; 6769 exports.EV_CHANGE = 'change'; 6770 exports.EV_ADD_DIR = 'addDir'; 6771 exports.EV_UNLINK = 'unlink'; 6772 exports.EV_UNLINK_DIR = 'unlinkDir'; 6773 exports.EV_RAW = 'raw'; 6774 exports.EV_ERROR = 'error'; 6775 6776 exports.STR_DATA = 'data'; 6777 exports.STR_END = 'end'; 6778 exports.STR_CLOSE = 'close'; 6779 6780 exports.FSEVENT_CREATED = 'created'; 6781 exports.FSEVENT_MODIFIED = 'modified'; 6782 exports.FSEVENT_DELETED = 'deleted'; 6783 exports.FSEVENT_MOVED = 'moved'; 6784 exports.FSEVENT_CLONED = 'cloned'; 6785 exports.FSEVENT_UNKNOWN = 'unknown'; 6786 exports.FSEVENT_FLAG_MUST_SCAN_SUBDIRS = 1; 6787 exports.FSEVENT_TYPE_FILE = 'file'; 6788 exports.FSEVENT_TYPE_DIRECTORY = 'directory'; 6789 exports.FSEVENT_TYPE_SYMLINK = 'symlink'; 6790 6791 exports.KEY_LISTENERS = 'listeners'; 6792 exports.KEY_ERR = 'errHandlers'; 6793 exports.KEY_RAW = 'rawEmitters'; 6794 exports.HANDLER_KEYS = [exports.KEY_LISTENERS, exports.KEY_ERR, exports.KEY_RAW]; 6795 6796 exports.DOT_SLASH = `.${sep}`; 6797 6798 exports.BACK_SLASH_RE = /\\/g; 6799 exports.DOUBLE_SLASH_RE = /\/\//; 6800 exports.SLASH_OR_BACK_SLASH_RE = /[/\\]/; 6801 exports.DOT_RE = /\..*\.(sw[px])$|~$|\.subl.*\.tmp/; 6802 exports.REPLACER_RE = /^\.[/\\]/; 6803 6804 exports.SLASH = '/'; 6805 exports.SLASH_SLASH = '//'; 6806 exports.BRACE_START = '{'; 6807 exports.BANG = '!'; 6808 exports.ONE_DOT = '.'; 6809 exports.TWO_DOTS = '..'; 6810 exports.STAR = '*'; 6811 exports.GLOBSTAR = '**'; 6812 exports.ROOT_GLOBSTAR = '/**/*'; 6813 exports.SLASH_GLOBSTAR = '/**'; 6814 exports.DIR_SUFFIX = 'Dir'; 6815 exports.ANYMATCH_OPTS = {dot: true}; 6816 exports.STRING_TYPE = 'string'; 6817 exports.FUNCTION_TYPE = 'function'; 6818 exports.EMPTY_STR = ''; 6819 exports.EMPTY_FN = () => {}; 6820 exports.IDENTITY_FN = val => val; 6821 6822 exports.isWindows = platform === 'win32'; 6823 exports.isMacos = platform === 'darwin'; 6824 exports.isLinux = platform === 'linux'; 6825 exports.isIBMi = os.type() === 'OS400'; 6826 } (constants)); 6827 return constants; 2563 6828 } 2564 6829 2565 /** 2566 * Helper for passing fs_watch event data to a collection of listeners 2567 * @param {Path} fullPath absolute path bound to fs_watch instance 2568 * @param {String} type listener type 2569 * @param {*=} val1 arguments to be passed to listeners 2570 * @param {*=} val2 2571 * @param {*=} val3 2572 */ 2573 const fsWatchBroadcast = (fullPath, type, val1, val2, val3) => { 2574 const cont = FsWatchInstances.get(fullPath); 2575 if (!cont) return; 2576 foreach(cont[type], (listener) => { 2577 listener(val1, val2, val3); 2578 }); 2579 }; 2580 2581 /** 2582 * Instantiates the fs_watch interface or binds listeners 2583 * to an existing one covering the same file system entry 2584 * @param {String} path 2585 * @param {String} fullPath absolute path 2586 * @param {Object} options to be passed to fs_watch 2587 * @param {Object} handlers container for event listener functions 2588 */ 2589 const setFsWatchListener = (path, fullPath, options, handlers) => { 2590 const {listener, errHandler, rawEmitter} = handlers; 2591 let cont = FsWatchInstances.get(fullPath); 2592 2593 /** @type {fs.FSWatcher=} */ 2594 let watcher; 2595 if (!options.persistent) { 2596 watcher = createFsWatchInstance( 2597 path, options, listener, errHandler, rawEmitter 2598 ); 2599 return watcher.close.bind(watcher); 2600 } 2601 if (cont) { 2602 addAndConvert(cont, KEY_LISTENERS, listener); 2603 addAndConvert(cont, KEY_ERR, errHandler); 2604 addAndConvert(cont, KEY_RAW, rawEmitter); 2605 } else { 2606 watcher = createFsWatchInstance( 2607 path, 2608 options, 2609 fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS), 2610 errHandler, // no need to use broadcast here 2611 fsWatchBroadcast.bind(null, fullPath, KEY_RAW) 2612 ); 2613 if (!watcher) return; 2614 watcher.on(EV_ERROR$2, async (error) => { 2615 const broadcastErr = fsWatchBroadcast.bind(null, fullPath, KEY_ERR); 2616 cont.watcherUnusable = true; // documented since Node 10.4.1 2617 // Workaround for https://github.com/joyent/node/issues/4337 2618 if (isWindows$1 && error.code === 'EPERM') { 2619 try { 2620 const fd = await open(path, 'r'); 2621 await close(fd); 2622 broadcastErr(error); 2623 } catch (err) {} 2624 } else { 2625 broadcastErr(error); 2626 } 2627 }); 2628 cont = { 2629 listeners: listener, 2630 errHandlers: errHandler, 2631 rawEmitters: rawEmitter, 2632 watcher 2633 }; 2634 FsWatchInstances.set(fullPath, cont); 2635 } 2636 // const index = cont.listeners.indexOf(listener); 2637 2638 // removes this instance's listeners and closes the underlying fs_watch 2639 // instance if there are no more listeners left 2640 return () => { 2641 delFromSet(cont, KEY_LISTENERS, listener); 2642 delFromSet(cont, KEY_ERR, errHandler); 2643 delFromSet(cont, KEY_RAW, rawEmitter); 2644 if (isEmptySet(cont.listeners)) { 2645 // Check to protect against issue gh-730. 2646 // if (cont.watcherUnusable) { 2647 cont.watcher.close(); 2648 // } 2649 FsWatchInstances.delete(fullPath); 2650 HANDLER_KEYS.forEach(clearItem(cont)); 2651 cont.watcher = undefined; 2652 Object.freeze(cont); 2653 } 2654 }; 2655 }; 2656 2657 // fs_watchFile helpers 2658 2659 // object to hold per-process fs_watchFile instances 2660 // (may be shared across chokidar FSWatcher instances) 2661 const FsWatchFileInstances = new Map(); 2662 2663 /** 2664 * Instantiates the fs_watchFile interface or binds listeners 2665 * to an existing one covering the same file system entry 2666 * @param {String} path to be watched 2667 * @param {String} fullPath absolute path 2668 * @param {Object} options options to be passed to fs_watchFile 2669 * @param {Object} handlers container for event listener functions 2670 * @returns {Function} closer 2671 */ 2672 const setFsWatchFileListener = (path, fullPath, options, handlers) => { 2673 const {listener, rawEmitter} = handlers; 2674 let cont = FsWatchFileInstances.get(fullPath); 2675 2676 const copts = cont && cont.options; 2677 if (copts && (copts.persistent < options.persistent || copts.interval > options.interval)) { 2678 fs$2.unwatchFile(fullPath); 2679 cont = undefined; 2680 } 2681 2682 /* eslint-enable no-unused-vars, prefer-destructuring */ 2683 2684 if (cont) { 2685 addAndConvert(cont, KEY_LISTENERS, listener); 2686 addAndConvert(cont, KEY_RAW, rawEmitter); 2687 } else { 2688 // TODO 2689 // listeners.add(listener); 2690 // rawEmitters.add(rawEmitter); 2691 cont = { 2692 listeners: listener, 2693 rawEmitters: rawEmitter, 2694 options, 2695 watcher: fs$2.watchFile(fullPath, options, (curr, prev) => { 2696 foreach(cont.rawEmitters, (rawEmitter) => { 2697 rawEmitter(EV_CHANGE$2, fullPath, {curr, prev}); 2698 }); 2699 const currmtime = curr.mtimeMs; 2700 if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) { 2701 foreach(cont.listeners, (listener) => listener(path, curr)); 2702 } 2703 }) 2704 }; 2705 FsWatchFileInstances.set(fullPath, cont); 2706 } 2707 // const index = cont.listeners.indexOf(listener); 2708 2709 // Removes this instance's listeners and closes the underlying fs_watchFile 2710 // instance if there are no more listeners left. 2711 return () => { 2712 delFromSet(cont, KEY_LISTENERS, listener); 2713 delFromSet(cont, KEY_RAW, rawEmitter); 2714 if (isEmptySet(cont.listeners)) { 2715 FsWatchFileInstances.delete(fullPath); 2716 fs$2.unwatchFile(fullPath); 2717 cont.options = cont.watcher = undefined; 2718 Object.freeze(cont); 2719 } 2720 }; 2721 }; 2722 2723 /** 2724 * @mixin 2725 */ 2726 let NodeFsHandler$1 = class NodeFsHandler { 2727 2728 /** 2729 * @param {import("../index").FSWatcher} fsW 2730 */ 2731 constructor(fsW) { 2732 this.fsw = fsW; 2733 this._boundHandleError = (error) => fsW._handleError(error); 6830 var nodefsHandler; 6831 var hasRequiredNodefsHandler; 6832 6833 function requireNodefsHandler () { 6834 if (hasRequiredNodefsHandler) return nodefsHandler; 6835 hasRequiredNodefsHandler = 1; 6836 6837 const fs = require$$0$2; 6838 const sysPath = require$$0$1; 6839 const { promisify } = require$$2; 6840 const isBinaryPath = /*@__PURE__*/ requireIsBinaryPath(); 6841 const { 6842 isWindows, 6843 isLinux, 6844 EMPTY_FN, 6845 EMPTY_STR, 6846 KEY_LISTENERS, 6847 KEY_ERR, 6848 KEY_RAW, 6849 HANDLER_KEYS, 6850 EV_CHANGE, 6851 EV_ADD, 6852 EV_ADD_DIR, 6853 EV_ERROR, 6854 STR_DATA, 6855 STR_END, 6856 BRACE_START, 6857 STAR 6858 } = /*@__PURE__*/ requireConstants(); 6859 6860 const THROTTLE_MODE_WATCH = 'watch'; 6861 6862 const open = promisify(fs.open); 6863 const stat = promisify(fs.stat); 6864 const lstat = promisify(fs.lstat); 6865 const close = promisify(fs.close); 6866 const fsrealpath = promisify(fs.realpath); 6867 6868 const statMethods = { lstat, stat }; 6869 6870 // TODO: emit errors properly. Example: EMFILE on Macos. 6871 const foreach = (val, fn) => { 6872 if (val instanceof Set) { 6873 val.forEach(fn); 6874 } else { 6875 fn(val); 6876 } 6877 }; 6878 6879 const addAndConvert = (main, prop, item) => { 6880 let container = main[prop]; 6881 if (!(container instanceof Set)) { 6882 main[prop] = container = new Set([container]); 6883 } 6884 container.add(item); 6885 }; 6886 6887 const clearItem = cont => key => { 6888 const set = cont[key]; 6889 if (set instanceof Set) { 6890 set.clear(); 6891 } else { 6892 delete cont[key]; 6893 } 6894 }; 6895 6896 const delFromSet = (main, prop, item) => { 6897 const container = main[prop]; 6898 if (container instanceof Set) { 6899 container.delete(item); 6900 } else if (container === item) { 6901 delete main[prop]; 6902 } 6903 }; 6904 6905 const isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val; 6906 6907 /** 6908 * @typedef {String} Path 6909 */ 6910 6911 // fs_watch helpers 6912 6913 // object to hold per-process fs_watch instances 6914 // (may be shared across chokidar FSWatcher instances) 6915 6916 /** 6917 * @typedef {Object} FsWatchContainer 6918 * @property {Set} listeners 6919 * @property {Set} errHandlers 6920 * @property {Set} rawEmitters 6921 * @property {fs.FSWatcher=} watcher 6922 * @property {Boolean=} watcherUnusable 6923 */ 6924 6925 /** 6926 * @type {Map<String,FsWatchContainer>} 6927 */ 6928 const FsWatchInstances = new Map(); 6929 6930 /** 6931 * Instantiates the fs_watch interface 6932 * @param {String} path to be watched 6933 * @param {Object} options to be passed to fs_watch 6934 * @param {Function} listener main event handler 6935 * @param {Function} errHandler emits info about errors 6936 * @param {Function} emitRaw emits raw event data 6937 * @returns {fs.FSWatcher} new fsevents instance 6938 */ 6939 function createFsWatchInstance(path, options, listener, errHandler, emitRaw) { 6940 const handleEvent = (rawEvent, evPath) => { 6941 listener(path); 6942 emitRaw(rawEvent, evPath, {watchedPath: path}); 6943 6944 // emit based on events occurring for files from a directory's watcher in 6945 // case the file's watcher misses it (and rely on throttling to de-dupe) 6946 if (evPath && path !== evPath) { 6947 fsWatchBroadcast( 6948 sysPath.resolve(path, evPath), KEY_LISTENERS, sysPath.join(path, evPath) 6949 ); 6950 } 6951 }; 6952 try { 6953 return fs.watch(path, options, handleEvent); 6954 } catch (error) { 6955 errHandler(error); 6956 } 6957 } 6958 6959 /** 6960 * Helper for passing fs_watch event data to a collection of listeners 6961 * @param {Path} fullPath absolute path bound to fs_watch instance 6962 * @param {String} type listener type 6963 * @param {*=} val1 arguments to be passed to listeners 6964 * @param {*=} val2 6965 * @param {*=} val3 6966 */ 6967 const fsWatchBroadcast = (fullPath, type, val1, val2, val3) => { 6968 const cont = FsWatchInstances.get(fullPath); 6969 if (!cont) return; 6970 foreach(cont[type], (listener) => { 6971 listener(val1, val2, val3); 6972 }); 6973 }; 6974 6975 /** 6976 * Instantiates the fs_watch interface or binds listeners 6977 * to an existing one covering the same file system entry 6978 * @param {String} path 6979 * @param {String} fullPath absolute path 6980 * @param {Object} options to be passed to fs_watch 6981 * @param {Object} handlers container for event listener functions 6982 */ 6983 const setFsWatchListener = (path, fullPath, options, handlers) => { 6984 const {listener, errHandler, rawEmitter} = handlers; 6985 let cont = FsWatchInstances.get(fullPath); 6986 6987 /** @type {fs.FSWatcher=} */ 6988 let watcher; 6989 if (!options.persistent) { 6990 watcher = createFsWatchInstance( 6991 path, options, listener, errHandler, rawEmitter 6992 ); 6993 return watcher.close.bind(watcher); 6994 } 6995 if (cont) { 6996 addAndConvert(cont, KEY_LISTENERS, listener); 6997 addAndConvert(cont, KEY_ERR, errHandler); 6998 addAndConvert(cont, KEY_RAW, rawEmitter); 6999 } else { 7000 watcher = createFsWatchInstance( 7001 path, 7002 options, 7003 fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS), 7004 errHandler, // no need to use broadcast here 7005 fsWatchBroadcast.bind(null, fullPath, KEY_RAW) 7006 ); 7007 if (!watcher) return; 7008 watcher.on(EV_ERROR, async (error) => { 7009 const broadcastErr = fsWatchBroadcast.bind(null, fullPath, KEY_ERR); 7010 cont.watcherUnusable = true; // documented since Node 10.4.1 7011 // Workaround for https://github.com/joyent/node/issues/4337 7012 if (isWindows && error.code === 'EPERM') { 7013 try { 7014 const fd = await open(path, 'r'); 7015 await close(fd); 7016 broadcastErr(error); 7017 } catch (err) {} 7018 } else { 7019 broadcastErr(error); 7020 } 7021 }); 7022 cont = { 7023 listeners: listener, 7024 errHandlers: errHandler, 7025 rawEmitters: rawEmitter, 7026 watcher 7027 }; 7028 FsWatchInstances.set(fullPath, cont); 7029 } 7030 // const index = cont.listeners.indexOf(listener); 7031 7032 // removes this instance's listeners and closes the underlying fs_watch 7033 // instance if there are no more listeners left 7034 return () => { 7035 delFromSet(cont, KEY_LISTENERS, listener); 7036 delFromSet(cont, KEY_ERR, errHandler); 7037 delFromSet(cont, KEY_RAW, rawEmitter); 7038 if (isEmptySet(cont.listeners)) { 7039 // Check to protect against issue gh-730. 7040 // if (cont.watcherUnusable) { 7041 cont.watcher.close(); 7042 // } 7043 FsWatchInstances.delete(fullPath); 7044 HANDLER_KEYS.forEach(clearItem(cont)); 7045 cont.watcher = undefined; 7046 Object.freeze(cont); 7047 } 7048 }; 7049 }; 7050 7051 // fs_watchFile helpers 7052 7053 // object to hold per-process fs_watchFile instances 7054 // (may be shared across chokidar FSWatcher instances) 7055 const FsWatchFileInstances = new Map(); 7056 7057 /** 7058 * Instantiates the fs_watchFile interface or binds listeners 7059 * to an existing one covering the same file system entry 7060 * @param {String} path to be watched 7061 * @param {String} fullPath absolute path 7062 * @param {Object} options options to be passed to fs_watchFile 7063 * @param {Object} handlers container for event listener functions 7064 * @returns {Function} closer 7065 */ 7066 const setFsWatchFileListener = (path, fullPath, options, handlers) => { 7067 const {listener, rawEmitter} = handlers; 7068 let cont = FsWatchFileInstances.get(fullPath); 7069 7070 const copts = cont && cont.options; 7071 if (copts && (copts.persistent < options.persistent || copts.interval > options.interval)) { 7072 fs.unwatchFile(fullPath); 7073 cont = undefined; 7074 } 7075 7076 /* eslint-enable no-unused-vars, prefer-destructuring */ 7077 7078 if (cont) { 7079 addAndConvert(cont, KEY_LISTENERS, listener); 7080 addAndConvert(cont, KEY_RAW, rawEmitter); 7081 } else { 7082 // TODO 7083 // listeners.add(listener); 7084 // rawEmitters.add(rawEmitter); 7085 cont = { 7086 listeners: listener, 7087 rawEmitters: rawEmitter, 7088 options, 7089 watcher: fs.watchFile(fullPath, options, (curr, prev) => { 7090 foreach(cont.rawEmitters, (rawEmitter) => { 7091 rawEmitter(EV_CHANGE, fullPath, {curr, prev}); 7092 }); 7093 const currmtime = curr.mtimeMs; 7094 if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) { 7095 foreach(cont.listeners, (listener) => listener(path, curr)); 7096 } 7097 }) 7098 }; 7099 FsWatchFileInstances.set(fullPath, cont); 7100 } 7101 // const index = cont.listeners.indexOf(listener); 7102 7103 // Removes this instance's listeners and closes the underlying fs_watchFile 7104 // instance if there are no more listeners left. 7105 return () => { 7106 delFromSet(cont, KEY_LISTENERS, listener); 7107 delFromSet(cont, KEY_RAW, rawEmitter); 7108 if (isEmptySet(cont.listeners)) { 7109 FsWatchFileInstances.delete(fullPath); 7110 fs.unwatchFile(fullPath); 7111 cont.options = cont.watcher = undefined; 7112 Object.freeze(cont); 7113 } 7114 }; 7115 }; 7116 7117 /** 7118 * @mixin 7119 */ 7120 class NodeFsHandler { 7121 7122 /** 7123 * @param {import("../index").FSWatcher} fsW 7124 */ 7125 constructor(fsW) { 7126 this.fsw = fsW; 7127 this._boundHandleError = (error) => fsW._handleError(error); 7128 } 7129 7130 /** 7131 * Watch file for changes with fs_watchFile or fs_watch. 7132 * @param {String} path to file or dir 7133 * @param {Function} listener on fs change 7134 * @returns {Function} closer for the watcher instance 7135 */ 7136 _watchWithNodeFs(path, listener) { 7137 const opts = this.fsw.options; 7138 const directory = sysPath.dirname(path); 7139 const basename = sysPath.basename(path); 7140 const parent = this.fsw._getWatchedDir(directory); 7141 parent.add(basename); 7142 const absolutePath = sysPath.resolve(path); 7143 const options = {persistent: opts.persistent}; 7144 if (!listener) listener = EMPTY_FN; 7145 7146 let closer; 7147 if (opts.usePolling) { 7148 options.interval = opts.enableBinaryInterval && isBinaryPath(basename) ? 7149 opts.binaryInterval : opts.interval; 7150 closer = setFsWatchFileListener(path, absolutePath, options, { 7151 listener, 7152 rawEmitter: this.fsw._emitRaw 7153 }); 7154 } else { 7155 closer = setFsWatchListener(path, absolutePath, options, { 7156 listener, 7157 errHandler: this._boundHandleError, 7158 rawEmitter: this.fsw._emitRaw 7159 }); 7160 } 7161 return closer; 7162 } 7163 7164 /** 7165 * Watch a file and emit add event if warranted. 7166 * @param {Path} file Path 7167 * @param {fs.Stats} stats result of fs_stat 7168 * @param {Boolean} initialAdd was the file added at watch instantiation? 7169 * @returns {Function} closer for the watcher instance 7170 */ 7171 _handleFile(file, stats, initialAdd) { 7172 if (this.fsw.closed) { 7173 return; 7174 } 7175 const dirname = sysPath.dirname(file); 7176 const basename = sysPath.basename(file); 7177 const parent = this.fsw._getWatchedDir(dirname); 7178 // stats is always present 7179 let prevStats = stats; 7180 7181 // if the file is already being watched, do nothing 7182 if (parent.has(basename)) return; 7183 7184 const listener = async (path, newStats) => { 7185 if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5)) return; 7186 if (!newStats || newStats.mtimeMs === 0) { 7187 try { 7188 const newStats = await stat(file); 7189 if (this.fsw.closed) return; 7190 // Check that change event was not fired because of changed only accessTime. 7191 const at = newStats.atimeMs; 7192 const mt = newStats.mtimeMs; 7193 if (!at || at <= mt || mt !== prevStats.mtimeMs) { 7194 this.fsw._emit(EV_CHANGE, file, newStats); 7195 } 7196 if (isLinux && prevStats.ino !== newStats.ino) { 7197 this.fsw._closeFile(path); 7198 prevStats = newStats; 7199 this.fsw._addPathCloser(path, this._watchWithNodeFs(file, listener)); 7200 } else { 7201 prevStats = newStats; 7202 } 7203 } catch (error) { 7204 // Fix issues where mtime is null but file is still present 7205 this.fsw._remove(dirname, basename); 7206 } 7207 // add is about to be emitted if file not already tracked in parent 7208 } else if (parent.has(basename)) { 7209 // Check that change event was not fired because of changed only accessTime. 7210 const at = newStats.atimeMs; 7211 const mt = newStats.mtimeMs; 7212 if (!at || at <= mt || mt !== prevStats.mtimeMs) { 7213 this.fsw._emit(EV_CHANGE, file, newStats); 7214 } 7215 prevStats = newStats; 7216 } 7217 }; 7218 // kick off the watcher 7219 const closer = this._watchWithNodeFs(file, listener); 7220 7221 // emit an add event if we're supposed to 7222 if (!(initialAdd && this.fsw.options.ignoreInitial) && this.fsw._isntIgnored(file)) { 7223 if (!this.fsw._throttle(EV_ADD, file, 0)) return; 7224 this.fsw._emit(EV_ADD, file, stats); 7225 } 7226 7227 return closer; 7228 } 7229 7230 /** 7231 * Handle symlinks encountered while reading a dir. 7232 * @param {Object} entry returned by readdirp 7233 * @param {String} directory path of dir being read 7234 * @param {String} path of this item 7235 * @param {String} item basename of this item 7236 * @returns {Promise<Boolean>} true if no more processing is needed for this entry. 7237 */ 7238 async _handleSymlink(entry, directory, path, item) { 7239 if (this.fsw.closed) { 7240 return; 7241 } 7242 const full = entry.fullPath; 7243 const dir = this.fsw._getWatchedDir(directory); 7244 7245 if (!this.fsw.options.followSymlinks) { 7246 // watch symlink directly (don't follow) and detect changes 7247 this.fsw._incrReadyCount(); 7248 7249 let linkPath; 7250 try { 7251 linkPath = await fsrealpath(path); 7252 } catch (e) { 7253 this.fsw._emitReady(); 7254 return true; 7255 } 7256 7257 if (this.fsw.closed) return; 7258 if (dir.has(item)) { 7259 if (this.fsw._symlinkPaths.get(full) !== linkPath) { 7260 this.fsw._symlinkPaths.set(full, linkPath); 7261 this.fsw._emit(EV_CHANGE, path, entry.stats); 7262 } 7263 } else { 7264 dir.add(item); 7265 this.fsw._symlinkPaths.set(full, linkPath); 7266 this.fsw._emit(EV_ADD, path, entry.stats); 7267 } 7268 this.fsw._emitReady(); 7269 return true; 7270 } 7271 7272 // don't follow the same symlink more than once 7273 if (this.fsw._symlinkPaths.has(full)) { 7274 return true; 7275 } 7276 7277 this.fsw._symlinkPaths.set(full, true); 7278 } 7279 7280 _handleRead(directory, initialAdd, wh, target, dir, depth, throttler) { 7281 // Normalize the directory name on Windows 7282 directory = sysPath.join(directory, EMPTY_STR); 7283 7284 if (!wh.hasGlob) { 7285 throttler = this.fsw._throttle('readdir', directory, 1000); 7286 if (!throttler) return; 7287 } 7288 7289 const previous = this.fsw._getWatchedDir(wh.path); 7290 const current = new Set(); 7291 7292 let stream = this.fsw._readdirp(directory, { 7293 fileFilter: entry => wh.filterPath(entry), 7294 directoryFilter: entry => wh.filterDir(entry), 7295 depth: 0 7296 }).on(STR_DATA, async (entry) => { 7297 if (this.fsw.closed) { 7298 stream = undefined; 7299 return; 7300 } 7301 const item = entry.path; 7302 let path = sysPath.join(directory, item); 7303 current.add(item); 7304 7305 if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path, item)) { 7306 return; 7307 } 7308 7309 if (this.fsw.closed) { 7310 stream = undefined; 7311 return; 7312 } 7313 // Files that present in current directory snapshot 7314 // but absent in previous are added to watch list and 7315 // emit `add` event. 7316 if (item === target || !target && !previous.has(item)) { 7317 this.fsw._incrReadyCount(); 7318 7319 // ensure relativeness of path is preserved in case of watcher reuse 7320 path = sysPath.join(dir, sysPath.relative(dir, path)); 7321 7322 this._addToNodeFs(path, initialAdd, wh, depth + 1); 7323 } 7324 }).on(EV_ERROR, this._boundHandleError); 7325 7326 return new Promise(resolve => 7327 stream.once(STR_END, () => { 7328 if (this.fsw.closed) { 7329 stream = undefined; 7330 return; 7331 } 7332 const wasThrottled = throttler ? throttler.clear() : false; 7333 7334 resolve(); 7335 7336 // Files that absent in current directory snapshot 7337 // but present in previous emit `remove` event 7338 // and are removed from @watched[directory]. 7339 previous.getChildren().filter((item) => { 7340 return item !== directory && 7341 !current.has(item) && 7342 // in case of intersecting globs; 7343 // a path may have been filtered out of this readdir, but 7344 // shouldn't be removed because it matches a different glob 7345 (!wh.hasGlob || wh.filterPath({ 7346 fullPath: sysPath.resolve(directory, item) 7347 })); 7348 }).forEach((item) => { 7349 this.fsw._remove(directory, item); 7350 }); 7351 7352 stream = undefined; 7353 7354 // one more time for any missed in case changes came in extremely quickly 7355 if (wasThrottled) this._handleRead(directory, false, wh, target, dir, depth, throttler); 7356 }) 7357 ); 7358 } 7359 7360 /** 7361 * Read directory to add / remove files from `@watched` list and re-read it on change. 7362 * @param {String} dir fs path 7363 * @param {fs.Stats} stats 7364 * @param {Boolean} initialAdd 7365 * @param {Number} depth relative to user-supplied path 7366 * @param {String} target child path targeted for watch 7367 * @param {Object} wh Common watch helpers for this path 7368 * @param {String} realpath 7369 * @returns {Promise<Function>} closer for the watcher instance. 7370 */ 7371 async _handleDir(dir, stats, initialAdd, depth, target, wh, realpath) { 7372 const parentDir = this.fsw._getWatchedDir(sysPath.dirname(dir)); 7373 const tracked = parentDir.has(sysPath.basename(dir)); 7374 if (!(initialAdd && this.fsw.options.ignoreInitial) && !target && !tracked) { 7375 if (!wh.hasGlob || wh.globFilter(dir)) this.fsw._emit(EV_ADD_DIR, dir, stats); 7376 } 7377 7378 // ensure dir is tracked (harmless if redundant) 7379 parentDir.add(sysPath.basename(dir)); 7380 this.fsw._getWatchedDir(dir); 7381 let throttler; 7382 let closer; 7383 7384 const oDepth = this.fsw.options.depth; 7385 if ((oDepth == null || depth <= oDepth) && !this.fsw._symlinkPaths.has(realpath)) { 7386 if (!target) { 7387 await this._handleRead(dir, initialAdd, wh, target, dir, depth, throttler); 7388 if (this.fsw.closed) return; 7389 } 7390 7391 closer = this._watchWithNodeFs(dir, (dirPath, stats) => { 7392 // if current directory is removed, do nothing 7393 if (stats && stats.mtimeMs === 0) return; 7394 7395 this._handleRead(dirPath, false, wh, target, dir, depth, throttler); 7396 }); 7397 } 7398 return closer; 7399 } 7400 7401 /** 7402 * Handle added file, directory, or glob pattern. 7403 * Delegates call to _handleFile / _handleDir after checks. 7404 * @param {String} path to file or ir 7405 * @param {Boolean} initialAdd was the file added at watch instantiation? 7406 * @param {Object} priorWh depth relative to user-supplied path 7407 * @param {Number} depth Child path actually targeted for watch 7408 * @param {String=} target Child path actually targeted for watch 7409 * @returns {Promise} 7410 */ 7411 async _addToNodeFs(path, initialAdd, priorWh, depth, target) { 7412 const ready = this.fsw._emitReady; 7413 if (this.fsw._isIgnored(path) || this.fsw.closed) { 7414 ready(); 7415 return false; 7416 } 7417 7418 const wh = this.fsw._getWatchHelpers(path, depth); 7419 if (!wh.hasGlob && priorWh) { 7420 wh.hasGlob = priorWh.hasGlob; 7421 wh.globFilter = priorWh.globFilter; 7422 wh.filterPath = entry => priorWh.filterPath(entry); 7423 wh.filterDir = entry => priorWh.filterDir(entry); 7424 } 7425 7426 // evaluate what is at the path we're being asked to watch 7427 try { 7428 const stats = await statMethods[wh.statMethod](wh.watchPath); 7429 if (this.fsw.closed) return; 7430 if (this.fsw._isIgnored(wh.watchPath, stats)) { 7431 ready(); 7432 return false; 7433 } 7434 7435 const follow = this.fsw.options.followSymlinks && !path.includes(STAR) && !path.includes(BRACE_START); 7436 let closer; 7437 if (stats.isDirectory()) { 7438 const absPath = sysPath.resolve(path); 7439 const targetPath = follow ? await fsrealpath(path) : path; 7440 if (this.fsw.closed) return; 7441 closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath); 7442 if (this.fsw.closed) return; 7443 // preserve this symlink's target path 7444 if (absPath !== targetPath && targetPath !== undefined) { 7445 this.fsw._symlinkPaths.set(absPath, targetPath); 7446 } 7447 } else if (stats.isSymbolicLink()) { 7448 const targetPath = follow ? await fsrealpath(path) : path; 7449 if (this.fsw.closed) return; 7450 const parent = sysPath.dirname(wh.watchPath); 7451 this.fsw._getWatchedDir(parent).add(wh.watchPath); 7452 this.fsw._emit(EV_ADD, wh.watchPath, stats); 7453 closer = await this._handleDir(parent, stats, initialAdd, depth, path, wh, targetPath); 7454 if (this.fsw.closed) return; 7455 7456 // preserve this symlink's target path 7457 if (targetPath !== undefined) { 7458 this.fsw._symlinkPaths.set(sysPath.resolve(path), targetPath); 7459 } 7460 } else { 7461 closer = this._handleFile(wh.watchPath, stats, initialAdd); 7462 } 7463 ready(); 7464 7465 this.fsw._addPathCloser(path, closer); 7466 return false; 7467 7468 } catch (error) { 7469 if (this.fsw._handleError(error)) { 7470 ready(); 7471 return path; 7472 } 7473 } 7474 } 7475 7476 } 7477 7478 nodefsHandler = NodeFsHandler; 7479 return nodefsHandler; 2734 7480 } 2735 7481 2736 /** 2737 * Watch file for changes with fs_watchFile or fs_watch. 2738 * @param {String} path to file or dir 2739 * @param {Function} listener on fs change 2740 * @returns {Function} closer for the watcher instance 2741 */ 2742 _watchWithNodeFs(path, listener) { 2743 const opts = this.fsw.options; 2744 const directory = sysPath$2.dirname(path); 2745 const basename = sysPath$2.basename(path); 2746 const parent = this.fsw._getWatchedDir(directory); 2747 parent.add(basename); 2748 const absolutePath = sysPath$2.resolve(path); 2749 const options = {persistent: opts.persistent}; 2750 if (!listener) listener = EMPTY_FN$2; 2751 2752 let closer; 2753 if (opts.usePolling) { 2754 options.interval = opts.enableBinaryInterval && isBinaryPath(basename) ? 2755 opts.binaryInterval : opts.interval; 2756 closer = setFsWatchFileListener(path, absolutePath, options, { 2757 listener, 2758 rawEmitter: this.fsw._emitRaw 2759 }); 2760 } else { 2761 closer = setFsWatchListener(path, absolutePath, options, { 2762 listener, 2763 errHandler: this._boundHandleError, 2764 rawEmitter: this.fsw._emitRaw 2765 }); 2766 } 2767 return closer; 7482 var fseventsHandler = {exports: {}}; 7483 7484 const require$$3 = /*@__PURE__*/rollup.getAugmentedNamespace(fseventsImporter.fseventsImporter); 7485 7486 var hasRequiredFseventsHandler; 7487 7488 function requireFseventsHandler () { 7489 if (hasRequiredFseventsHandler) return fseventsHandler.exports; 7490 hasRequiredFseventsHandler = 1; 7491 7492 const fs = require$$0$2; 7493 const sysPath = require$$0$1; 7494 const { promisify } = require$$2; 7495 7496 let fsevents; 7497 try { 7498 fsevents = require$$3.getFsEvents(); 7499 } catch (error) { 7500 if (process.env.CHOKIDAR_PRINT_FSEVENTS_REQUIRE_ERROR) console.error(error); 7501 } 7502 7503 if (fsevents) { 7504 // TODO: real check 7505 const mtch = process.version.match(/v(\d+)\.(\d+)/); 7506 if (mtch && mtch[1] && mtch[2]) { 7507 const maj = Number.parseInt(mtch[1], 10); 7508 const min = Number.parseInt(mtch[2], 10); 7509 if (maj === 8 && min < 16) { 7510 fsevents = undefined; 7511 } 7512 } 7513 } 7514 7515 const { 7516 EV_ADD, 7517 EV_CHANGE, 7518 EV_ADD_DIR, 7519 EV_UNLINK, 7520 EV_ERROR, 7521 STR_DATA, 7522 STR_END, 7523 FSEVENT_CREATED, 7524 FSEVENT_MODIFIED, 7525 FSEVENT_DELETED, 7526 FSEVENT_MOVED, 7527 // FSEVENT_CLONED, 7528 FSEVENT_UNKNOWN, 7529 FSEVENT_FLAG_MUST_SCAN_SUBDIRS, 7530 FSEVENT_TYPE_FILE, 7531 FSEVENT_TYPE_DIRECTORY, 7532 FSEVENT_TYPE_SYMLINK, 7533 7534 ROOT_GLOBSTAR, 7535 DIR_SUFFIX, 7536 DOT_SLASH, 7537 FUNCTION_TYPE, 7538 EMPTY_FN, 7539 IDENTITY_FN 7540 } = /*@__PURE__*/ requireConstants(); 7541 7542 const Depth = (value) => isNaN(value) ? {} : {depth: value}; 7543 7544 const stat = promisify(fs.stat); 7545 const lstat = promisify(fs.lstat); 7546 const realpath = promisify(fs.realpath); 7547 7548 const statMethods = { stat, lstat }; 7549 7550 /** 7551 * @typedef {String} Path 7552 */ 7553 7554 /** 7555 * @typedef {Object} FsEventsWatchContainer 7556 * @property {Set<Function>} listeners 7557 * @property {Function} rawEmitter 7558 * @property {{stop: Function}} watcher 7559 */ 7560 7561 // fsevents instance helper functions 7562 /** 7563 * Object to hold per-process fsevents instances (may be shared across chokidar FSWatcher instances) 7564 * @type {Map<Path,FsEventsWatchContainer>} 7565 */ 7566 const FSEventsWatchers = new Map(); 7567 7568 // Threshold of duplicate path prefixes at which to start 7569 // consolidating going forward 7570 const consolidateThreshhold = 10; 7571 7572 const wrongEventFlags = new Set([ 7573 69888, 70400, 71424, 72704, 73472, 131328, 131840, 262912 7574 ]); 7575 7576 /** 7577 * Instantiates the fsevents interface 7578 * @param {Path} path path to be watched 7579 * @param {Function} callback called when fsevents is bound and ready 7580 * @returns {{stop: Function}} new fsevents instance 7581 */ 7582 const createFSEventsInstance = (path, callback) => { 7583 const stop = fsevents.watch(path, callback); 7584 return {stop}; 7585 }; 7586 7587 /** 7588 * Instantiates the fsevents interface or binds listeners to an existing one covering 7589 * the same file tree. 7590 * @param {Path} path - to be watched 7591 * @param {Path} realPath - real path for symlinks 7592 * @param {Function} listener - called when fsevents emits events 7593 * @param {Function} rawEmitter - passes data to listeners of the 'raw' event 7594 * @returns {Function} closer 7595 */ 7596 function setFSEventsListener(path, realPath, listener, rawEmitter) { 7597 let watchPath = sysPath.extname(realPath) ? sysPath.dirname(realPath) : realPath; 7598 7599 const parentPath = sysPath.dirname(watchPath); 7600 let cont = FSEventsWatchers.get(watchPath); 7601 7602 // If we've accumulated a substantial number of paths that 7603 // could have been consolidated by watching one directory 7604 // above the current one, create a watcher on the parent 7605 // path instead, so that we do consolidate going forward. 7606 if (couldConsolidate(parentPath)) { 7607 watchPath = parentPath; 7608 } 7609 7610 const resolvedPath = sysPath.resolve(path); 7611 const hasSymlink = resolvedPath !== realPath; 7612 7613 const filteredListener = (fullPath, flags, info) => { 7614 if (hasSymlink) fullPath = fullPath.replace(realPath, resolvedPath); 7615 if ( 7616 fullPath === resolvedPath || 7617 !fullPath.indexOf(resolvedPath + sysPath.sep) 7618 ) listener(fullPath, flags, info); 7619 }; 7620 7621 // check if there is already a watcher on a parent path 7622 // modifies `watchPath` to the parent path when it finds a match 7623 let watchedParent = false; 7624 for (const watchedPath of FSEventsWatchers.keys()) { 7625 if (realPath.indexOf(sysPath.resolve(watchedPath) + sysPath.sep) === 0) { 7626 watchPath = watchedPath; 7627 cont = FSEventsWatchers.get(watchPath); 7628 watchedParent = true; 7629 break; 7630 } 7631 } 7632 7633 if (cont || watchedParent) { 7634 cont.listeners.add(filteredListener); 7635 } else { 7636 cont = { 7637 listeners: new Set([filteredListener]), 7638 rawEmitter, 7639 watcher: createFSEventsInstance(watchPath, (fullPath, flags) => { 7640 if (!cont.listeners.size) return; 7641 if (flags & FSEVENT_FLAG_MUST_SCAN_SUBDIRS) return; 7642 const info = fsevents.getInfo(fullPath, flags); 7643 cont.listeners.forEach(list => { 7644 list(fullPath, flags, info); 7645 }); 7646 7647 cont.rawEmitter(info.event, fullPath, info); 7648 }) 7649 }; 7650 FSEventsWatchers.set(watchPath, cont); 7651 } 7652 7653 // removes this instance's listeners and closes the underlying fsevents 7654 // instance if there are no more listeners left 7655 return () => { 7656 const lst = cont.listeners; 7657 7658 lst.delete(filteredListener); 7659 if (!lst.size) { 7660 FSEventsWatchers.delete(watchPath); 7661 if (cont.watcher) return cont.watcher.stop().then(() => { 7662 cont.rawEmitter = cont.watcher = undefined; 7663 Object.freeze(cont); 7664 }); 7665 } 7666 }; 7667 } 7668 7669 // Decide whether or not we should start a new higher-level 7670 // parent watcher 7671 const couldConsolidate = (path) => { 7672 let count = 0; 7673 for (const watchPath of FSEventsWatchers.keys()) { 7674 if (watchPath.indexOf(path) === 0) { 7675 count++; 7676 if (count >= consolidateThreshhold) { 7677 return true; 7678 } 7679 } 7680 } 7681 7682 return false; 7683 }; 7684 7685 // returns boolean indicating whether fsevents can be used 7686 const canUse = () => fsevents && FSEventsWatchers.size < 128; 7687 7688 // determines subdirectory traversal levels from root to path 7689 const calcDepth = (path, root) => { 7690 let i = 0; 7691 while (!path.indexOf(root) && (path = sysPath.dirname(path)) !== root) i++; 7692 return i; 7693 }; 7694 7695 // returns boolean indicating whether the fsevents' event info has the same type 7696 // as the one returned by fs.stat 7697 const sameTypes = (info, stats) => ( 7698 info.type === FSEVENT_TYPE_DIRECTORY && stats.isDirectory() || 7699 info.type === FSEVENT_TYPE_SYMLINK && stats.isSymbolicLink() || 7700 info.type === FSEVENT_TYPE_FILE && stats.isFile() 7701 ); 7702 7703 /** 7704 * @mixin 7705 */ 7706 class FsEventsHandler { 7707 7708 /** 7709 * @param {import('../index').FSWatcher} fsw 7710 */ 7711 constructor(fsw) { 7712 this.fsw = fsw; 7713 } 7714 checkIgnored(path, stats) { 7715 const ipaths = this.fsw._ignoredPaths; 7716 if (this.fsw._isIgnored(path, stats)) { 7717 ipaths.add(path); 7718 if (stats && stats.isDirectory()) { 7719 ipaths.add(path + ROOT_GLOBSTAR); 7720 } 7721 return true; 7722 } 7723 7724 ipaths.delete(path); 7725 ipaths.delete(path + ROOT_GLOBSTAR); 7726 } 7727 7728 addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts) { 7729 const event = watchedDir.has(item) ? EV_CHANGE : EV_ADD; 7730 this.handleEvent(event, path, fullPath, realPath, parent, watchedDir, item, info, opts); 7731 } 7732 7733 async checkExists(path, fullPath, realPath, parent, watchedDir, item, info, opts) { 7734 try { 7735 const stats = await stat(path); 7736 if (this.fsw.closed) return; 7737 if (sameTypes(info, stats)) { 7738 this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts); 7739 } else { 7740 this.handleEvent(EV_UNLINK, path, fullPath, realPath, parent, watchedDir, item, info, opts); 7741 } 7742 } catch (error) { 7743 if (error.code === 'EACCES') { 7744 this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts); 7745 } else { 7746 this.handleEvent(EV_UNLINK, path, fullPath, realPath, parent, watchedDir, item, info, opts); 7747 } 7748 } 7749 } 7750 7751 handleEvent(event, path, fullPath, realPath, parent, watchedDir, item, info, opts) { 7752 if (this.fsw.closed || this.checkIgnored(path)) return; 7753 7754 if (event === EV_UNLINK) { 7755 const isDirectory = info.type === FSEVENT_TYPE_DIRECTORY; 7756 // suppress unlink events on never before seen files 7757 if (isDirectory || watchedDir.has(item)) { 7758 this.fsw._remove(parent, item, isDirectory); 7759 } 7760 } else { 7761 if (event === EV_ADD) { 7762 // track new directories 7763 if (info.type === FSEVENT_TYPE_DIRECTORY) this.fsw._getWatchedDir(path); 7764 7765 if (info.type === FSEVENT_TYPE_SYMLINK && opts.followSymlinks) { 7766 // push symlinks back to the top of the stack to get handled 7767 const curDepth = opts.depth === undefined ? 7768 undefined : calcDepth(fullPath, realPath) + 1; 7769 return this._addToFsEvents(path, false, true, curDepth); 7770 } 7771 7772 // track new paths 7773 // (other than symlinks being followed, which will be tracked soon) 7774 this.fsw._getWatchedDir(parent).add(item); 7775 } 7776 /** 7777 * @type {'add'|'addDir'|'unlink'|'unlinkDir'} 7778 */ 7779 const eventName = info.type === FSEVENT_TYPE_DIRECTORY ? event + DIR_SUFFIX : event; 7780 this.fsw._emit(eventName, path); 7781 if (eventName === EV_ADD_DIR) this._addToFsEvents(path, false, true); 7782 } 7783 } 7784 7785 /** 7786 * Handle symlinks encountered during directory scan 7787 * @param {String} watchPath - file/dir path to be watched with fsevents 7788 * @param {String} realPath - real path (in case of symlinks) 7789 * @param {Function} transform - path transformer 7790 * @param {Function} globFilter - path filter in case a glob pattern was provided 7791 * @returns {Function} closer for the watcher instance 7792 */ 7793 _watchWithFsEvents(watchPath, realPath, transform, globFilter) { 7794 if (this.fsw.closed || this.fsw._isIgnored(watchPath)) return; 7795 const opts = this.fsw.options; 7796 const watchCallback = async (fullPath, flags, info) => { 7797 if (this.fsw.closed) return; 7798 if ( 7799 opts.depth !== undefined && 7800 calcDepth(fullPath, realPath) > opts.depth 7801 ) return; 7802 const path = transform(sysPath.join( 7803 watchPath, sysPath.relative(watchPath, fullPath) 7804 )); 7805 if (globFilter && !globFilter(path)) return; 7806 // ensure directories are tracked 7807 const parent = sysPath.dirname(path); 7808 const item = sysPath.basename(path); 7809 const watchedDir = this.fsw._getWatchedDir( 7810 info.type === FSEVENT_TYPE_DIRECTORY ? path : parent 7811 ); 7812 7813 // correct for wrong events emitted 7814 if (wrongEventFlags.has(flags) || info.event === FSEVENT_UNKNOWN) { 7815 if (typeof opts.ignored === FUNCTION_TYPE) { 7816 let stats; 7817 try { 7818 stats = await stat(path); 7819 } catch (error) {} 7820 if (this.fsw.closed) return; 7821 if (this.checkIgnored(path, stats)) return; 7822 if (sameTypes(info, stats)) { 7823 this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts); 7824 } else { 7825 this.handleEvent(EV_UNLINK, path, fullPath, realPath, parent, watchedDir, item, info, opts); 7826 } 7827 } else { 7828 this.checkExists(path, fullPath, realPath, parent, watchedDir, item, info, opts); 7829 } 7830 } else { 7831 switch (info.event) { 7832 case FSEVENT_CREATED: 7833 case FSEVENT_MODIFIED: 7834 return this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts); 7835 case FSEVENT_DELETED: 7836 case FSEVENT_MOVED: 7837 return this.checkExists(path, fullPath, realPath, parent, watchedDir, item, info, opts); 7838 } 7839 } 7840 }; 7841 7842 const closer = setFSEventsListener( 7843 watchPath, 7844 realPath, 7845 watchCallback, 7846 this.fsw._emitRaw 7847 ); 7848 7849 this.fsw._emitReady(); 7850 return closer; 7851 } 7852 7853 /** 7854 * Handle symlinks encountered during directory scan 7855 * @param {String} linkPath path to symlink 7856 * @param {String} fullPath absolute path to the symlink 7857 * @param {Function} transform pre-existing path transformer 7858 * @param {Number} curDepth level of subdirectories traversed to where symlink is 7859 * @returns {Promise<void>} 7860 */ 7861 async _handleFsEventsSymlink(linkPath, fullPath, transform, curDepth) { 7862 // don't follow the same symlink more than once 7863 if (this.fsw.closed || this.fsw._symlinkPaths.has(fullPath)) return; 7864 7865 this.fsw._symlinkPaths.set(fullPath, true); 7866 this.fsw._incrReadyCount(); 7867 7868 try { 7869 const linkTarget = await realpath(linkPath); 7870 if (this.fsw.closed) return; 7871 if (this.fsw._isIgnored(linkTarget)) { 7872 return this.fsw._emitReady(); 7873 } 7874 7875 this.fsw._incrReadyCount(); 7876 7877 // add the linkTarget for watching with a wrapper for transform 7878 // that causes emitted paths to incorporate the link's path 7879 this._addToFsEvents(linkTarget || linkPath, (path) => { 7880 let aliasedPath = linkPath; 7881 if (linkTarget && linkTarget !== DOT_SLASH) { 7882 aliasedPath = path.replace(linkTarget, linkPath); 7883 } else if (path !== DOT_SLASH) { 7884 aliasedPath = sysPath.join(linkPath, path); 7885 } 7886 return transform(aliasedPath); 7887 }, false, curDepth); 7888 } catch(error) { 7889 if (this.fsw._handleError(error)) { 7890 return this.fsw._emitReady(); 7891 } 7892 } 7893 } 7894 7895 /** 7896 * 7897 * @param {Path} newPath 7898 * @param {fs.Stats} stats 7899 */ 7900 emitAdd(newPath, stats, processPath, opts, forceAdd) { 7901 const pp = processPath(newPath); 7902 const isDir = stats.isDirectory(); 7903 const dirObj = this.fsw._getWatchedDir(sysPath.dirname(pp)); 7904 const base = sysPath.basename(pp); 7905 7906 // ensure empty dirs get tracked 7907 if (isDir) this.fsw._getWatchedDir(pp); 7908 if (dirObj.has(base)) return; 7909 dirObj.add(base); 7910 7911 if (!opts.ignoreInitial || forceAdd === true) { 7912 this.fsw._emit(isDir ? EV_ADD_DIR : EV_ADD, pp, stats); 7913 } 7914 } 7915 7916 initWatch(realPath, path, wh, processPath) { 7917 if (this.fsw.closed) return; 7918 const closer = this._watchWithFsEvents( 7919 wh.watchPath, 7920 sysPath.resolve(realPath || wh.watchPath), 7921 processPath, 7922 wh.globFilter 7923 ); 7924 this.fsw._addPathCloser(path, closer); 7925 } 7926 7927 /** 7928 * Handle added path with fsevents 7929 * @param {String} path file/dir path or glob pattern 7930 * @param {Function|Boolean=} transform converts working path to what the user expects 7931 * @param {Boolean=} forceAdd ensure add is emitted 7932 * @param {Number=} priorDepth Level of subdirectories already traversed. 7933 * @returns {Promise<void>} 7934 */ 7935 async _addToFsEvents(path, transform, forceAdd, priorDepth) { 7936 if (this.fsw.closed) { 7937 return; 7938 } 7939 const opts = this.fsw.options; 7940 const processPath = typeof transform === FUNCTION_TYPE ? transform : IDENTITY_FN; 7941 7942 const wh = this.fsw._getWatchHelpers(path); 7943 7944 // evaluate what is at the path we're being asked to watch 7945 try { 7946 const stats = await statMethods[wh.statMethod](wh.watchPath); 7947 if (this.fsw.closed) return; 7948 if (this.fsw._isIgnored(wh.watchPath, stats)) { 7949 throw null; 7950 } 7951 if (stats.isDirectory()) { 7952 // emit addDir unless this is a glob parent 7953 if (!wh.globFilter) this.emitAdd(processPath(path), stats, processPath, opts, forceAdd); 7954 7955 // don't recurse further if it would exceed depth setting 7956 if (priorDepth && priorDepth > opts.depth) return; 7957 7958 // scan the contents of the dir 7959 this.fsw._readdirp(wh.watchPath, { 7960 fileFilter: entry => wh.filterPath(entry), 7961 directoryFilter: entry => wh.filterDir(entry), 7962 ...Depth(opts.depth - (priorDepth || 0)) 7963 }).on(STR_DATA, (entry) => { 7964 // need to check filterPath on dirs b/c filterDir is less restrictive 7965 if (this.fsw.closed) { 7966 return; 7967 } 7968 if (entry.stats.isDirectory() && !wh.filterPath(entry)) return; 7969 7970 const joinedPath = sysPath.join(wh.watchPath, entry.path); 7971 const {fullPath} = entry; 7972 7973 if (wh.followSymlinks && entry.stats.isSymbolicLink()) { 7974 // preserve the current depth here since it can't be derived from 7975 // real paths past the symlink 7976 const curDepth = opts.depth === undefined ? 7977 undefined : calcDepth(joinedPath, sysPath.resolve(wh.watchPath)) + 1; 7978 7979 this._handleFsEventsSymlink(joinedPath, fullPath, processPath, curDepth); 7980 } else { 7981 this.emitAdd(joinedPath, entry.stats, processPath, opts, forceAdd); 7982 } 7983 }).on(EV_ERROR, EMPTY_FN).on(STR_END, () => { 7984 this.fsw._emitReady(); 7985 }); 7986 } else { 7987 this.emitAdd(wh.watchPath, stats, processPath, opts, forceAdd); 7988 this.fsw._emitReady(); 7989 } 7990 } catch (error) { 7991 if (!error || this.fsw._handleError(error)) { 7992 // TODO: Strange thing: "should not choke on an ignored watch path" will be failed without 2 ready calls -__- 7993 this.fsw._emitReady(); 7994 this.fsw._emitReady(); 7995 } 7996 } 7997 7998 if (opts.persistent && forceAdd !== true) { 7999 if (typeof transform === FUNCTION_TYPE) { 8000 // realpath has already been resolved 8001 this.initWatch(undefined, path, wh, processPath); 8002 } else { 8003 let realPath; 8004 try { 8005 realPath = await realpath(wh.watchPath); 8006 } catch (e) {} 8007 this.initWatch(realPath, path, wh, processPath); 8008 } 8009 } 8010 } 8011 8012 } 8013 8014 fseventsHandler.exports = FsEventsHandler; 8015 fseventsHandler.exports.canUse = canUse; 8016 return fseventsHandler.exports; 2768 8017 } 2769 8018 2770 /** 2771 * Watch a file and emit add event if warranted. 2772 * @param {Path} file Path 2773 * @param {fs.Stats} stats result of fs_stat 2774 * @param {Boolean} initialAdd was the file added at watch instantiation? 2775 * @returns {Function} closer for the watcher instance 2776 */ 2777 _handleFile(file, stats, initialAdd) { 2778 if (this.fsw.closed) { 2779 return; 2780 } 2781 const dirname = sysPath$2.dirname(file); 2782 const basename = sysPath$2.basename(file); 2783 const parent = this.fsw._getWatchedDir(dirname); 2784 // stats is always present 2785 let prevStats = stats; 2786 2787 // if the file is already being watched, do nothing 2788 if (parent.has(basename)) return; 2789 2790 const listener = async (path, newStats) => { 2791 if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5)) return; 2792 if (!newStats || newStats.mtimeMs === 0) { 2793 try { 2794 const newStats = await stat$2(file); 2795 if (this.fsw.closed) return; 2796 // Check that change event was not fired because of changed only accessTime. 2797 const at = newStats.atimeMs; 2798 const mt = newStats.mtimeMs; 2799 if (!at || at <= mt || mt !== prevStats.mtimeMs) { 2800 this.fsw._emit(EV_CHANGE$2, file, newStats); 2801 } 2802 if (isLinux && prevStats.ino !== newStats.ino) { 2803 this.fsw._closeFile(path); 2804 prevStats = newStats; 2805 this.fsw._addPathCloser(path, this._watchWithNodeFs(file, listener)); 2806 } else { 2807 prevStats = newStats; 2808 } 2809 } catch (error) { 2810 // Fix issues where mtime is null but file is still present 2811 this.fsw._remove(dirname, basename); 2812 } 2813 // add is about to be emitted if file not already tracked in parent 2814 } else if (parent.has(basename)) { 2815 // Check that change event was not fired because of changed only accessTime. 2816 const at = newStats.atimeMs; 2817 const mt = newStats.mtimeMs; 2818 if (!at || at <= mt || mt !== prevStats.mtimeMs) { 2819 this.fsw._emit(EV_CHANGE$2, file, newStats); 2820 } 2821 prevStats = newStats; 2822 } 2823 }; 2824 // kick off the watcher 2825 const closer = this._watchWithNodeFs(file, listener); 2826 2827 // emit an add event if we're supposed to 2828 if (!(initialAdd && this.fsw.options.ignoreInitial) && this.fsw._isntIgnored(file)) { 2829 if (!this.fsw._throttle(EV_ADD$2, file, 0)) return; 2830 this.fsw._emit(EV_ADD$2, file, stats); 2831 } 2832 2833 return closer; 8019 var hasRequiredChokidar; 8020 8021 function requireChokidar () { 8022 if (hasRequiredChokidar) return chokidar$1; 8023 hasRequiredChokidar = 1; 8024 8025 const { EventEmitter } = require$$0$3; 8026 const fs = require$$0$2; 8027 const sysPath = require$$0$1; 8028 const { promisify } = require$$2; 8029 const readdirp = /*@__PURE__*/ requireReaddirp(); 8030 const anymatch = /*@__PURE__*/ requireAnymatch().default; 8031 const globParent = /*@__PURE__*/ requireGlobParent(); 8032 const isGlob = /*@__PURE__*/ requireIsGlob(); 8033 const braces = /*@__PURE__*/ requireBraces(); 8034 const normalizePath = /*@__PURE__*/ requireNormalizePath(); 8035 8036 const NodeFsHandler = /*@__PURE__*/ requireNodefsHandler(); 8037 const FsEventsHandler = /*@__PURE__*/ requireFseventsHandler(); 8038 const { 8039 EV_ALL, 8040 EV_READY, 8041 EV_ADD, 8042 EV_CHANGE, 8043 EV_UNLINK, 8044 EV_ADD_DIR, 8045 EV_UNLINK_DIR, 8046 EV_RAW, 8047 EV_ERROR, 8048 8049 STR_CLOSE, 8050 STR_END, 8051 8052 BACK_SLASH_RE, 8053 DOUBLE_SLASH_RE, 8054 SLASH_OR_BACK_SLASH_RE, 8055 DOT_RE, 8056 REPLACER_RE, 8057 8058 SLASH, 8059 SLASH_SLASH, 8060 BRACE_START, 8061 BANG, 8062 ONE_DOT, 8063 TWO_DOTS, 8064 GLOBSTAR, 8065 SLASH_GLOBSTAR, 8066 ANYMATCH_OPTS, 8067 STRING_TYPE, 8068 FUNCTION_TYPE, 8069 EMPTY_STR, 8070 EMPTY_FN, 8071 8072 isWindows, 8073 isMacos, 8074 isIBMi 8075 } = /*@__PURE__*/ requireConstants(); 8076 8077 const stat = promisify(fs.stat); 8078 const readdir = promisify(fs.readdir); 8079 8080 /** 8081 * @typedef {String} Path 8082 * @typedef {'all'|'add'|'addDir'|'change'|'unlink'|'unlinkDir'|'raw'|'error'|'ready'} EventName 8083 * @typedef {'readdir'|'watch'|'add'|'remove'|'change'} ThrottleType 8084 */ 8085 8086 /** 8087 * 8088 * @typedef {Object} WatchHelpers 8089 * @property {Boolean} followSymlinks 8090 * @property {'stat'|'lstat'} statMethod 8091 * @property {Path} path 8092 * @property {Path} watchPath 8093 * @property {Function} entryPath 8094 * @property {Boolean} hasGlob 8095 * @property {Object} globFilter 8096 * @property {Function} filterPath 8097 * @property {Function} filterDir 8098 */ 8099 8100 const arrify = (value = []) => Array.isArray(value) ? value : [value]; 8101 const flatten = (list, result = []) => { 8102 list.forEach(item => { 8103 if (Array.isArray(item)) { 8104 flatten(item, result); 8105 } else { 8106 result.push(item); 8107 } 8108 }); 8109 return result; 8110 }; 8111 8112 const unifyPaths = (paths_) => { 8113 /** 8114 * @type {Array<String>} 8115 */ 8116 const paths = flatten(arrify(paths_)); 8117 if (!paths.every(p => typeof p === STRING_TYPE)) { 8118 throw new TypeError(`Non-string provided as watch path: ${paths}`); 8119 } 8120 return paths.map(normalizePathToUnix); 8121 }; 8122 8123 // If SLASH_SLASH occurs at the beginning of path, it is not replaced 8124 // because "//StoragePC/DrivePool/Movies" is a valid network path 8125 const toUnix = (string) => { 8126 let str = string.replace(BACK_SLASH_RE, SLASH); 8127 let prepend = false; 8128 if (str.startsWith(SLASH_SLASH)) { 8129 prepend = true; 8130 } 8131 while (str.match(DOUBLE_SLASH_RE)) { 8132 str = str.replace(DOUBLE_SLASH_RE, SLASH); 8133 } 8134 if (prepend) { 8135 str = SLASH + str; 8136 } 8137 return str; 8138 }; 8139 8140 // Our version of upath.normalize 8141 // TODO: this is not equal to path-normalize module - investigate why 8142 const normalizePathToUnix = (path) => toUnix(sysPath.normalize(toUnix(path))); 8143 8144 const normalizeIgnored = (cwd = EMPTY_STR) => (path) => { 8145 if (typeof path !== STRING_TYPE) return path; 8146 return normalizePathToUnix(sysPath.isAbsolute(path) ? path : sysPath.join(cwd, path)); 8147 }; 8148 8149 const getAbsolutePath = (path, cwd) => { 8150 if (sysPath.isAbsolute(path)) { 8151 return path; 8152 } 8153 if (path.startsWith(BANG)) { 8154 return BANG + sysPath.join(cwd, path.slice(1)); 8155 } 8156 return sysPath.join(cwd, path); 8157 }; 8158 8159 const undef = (opts, key) => opts[key] === undefined; 8160 8161 /** 8162 * Directory entry. 8163 * @property {Path} path 8164 * @property {Set<Path>} items 8165 */ 8166 class DirEntry { 8167 /** 8168 * @param {Path} dir 8169 * @param {Function} removeWatcher 8170 */ 8171 constructor(dir, removeWatcher) { 8172 this.path = dir; 8173 this._removeWatcher = removeWatcher; 8174 /** @type {Set<Path>} */ 8175 this.items = new Set(); 8176 } 8177 8178 add(item) { 8179 const {items} = this; 8180 if (!items) return; 8181 if (item !== ONE_DOT && item !== TWO_DOTS) items.add(item); 8182 } 8183 8184 async remove(item) { 8185 const {items} = this; 8186 if (!items) return; 8187 items.delete(item); 8188 if (items.size > 0) return; 8189 8190 const dir = this.path; 8191 try { 8192 await readdir(dir); 8193 } catch (err) { 8194 if (this._removeWatcher) { 8195 this._removeWatcher(sysPath.dirname(dir), sysPath.basename(dir)); 8196 } 8197 } 8198 } 8199 8200 has(item) { 8201 const {items} = this; 8202 if (!items) return; 8203 return items.has(item); 8204 } 8205 8206 /** 8207 * @returns {Array<String>} 8208 */ 8209 getChildren() { 8210 const {items} = this; 8211 if (!items) return; 8212 return [...items.values()]; 8213 } 8214 8215 dispose() { 8216 this.items.clear(); 8217 delete this.path; 8218 delete this._removeWatcher; 8219 delete this.items; 8220 Object.freeze(this); 8221 } 8222 } 8223 8224 const STAT_METHOD_F = 'stat'; 8225 const STAT_METHOD_L = 'lstat'; 8226 class WatchHelper { 8227 constructor(path, watchPath, follow, fsw) { 8228 this.fsw = fsw; 8229 this.path = path = path.replace(REPLACER_RE, EMPTY_STR); 8230 this.watchPath = watchPath; 8231 this.fullWatchPath = sysPath.resolve(watchPath); 8232 this.hasGlob = watchPath !== path; 8233 /** @type {object|boolean} */ 8234 if (path === EMPTY_STR) this.hasGlob = false; 8235 this.globSymlink = this.hasGlob && follow ? undefined : false; 8236 this.globFilter = this.hasGlob ? anymatch(path, undefined, ANYMATCH_OPTS) : false; 8237 this.dirParts = this.getDirParts(path); 8238 this.dirParts.forEach((parts) => { 8239 if (parts.length > 1) parts.pop(); 8240 }); 8241 this.followSymlinks = follow; 8242 this.statMethod = follow ? STAT_METHOD_F : STAT_METHOD_L; 8243 } 8244 8245 checkGlobSymlink(entry) { 8246 // only need to resolve once 8247 // first entry should always have entry.parentDir === EMPTY_STR 8248 if (this.globSymlink === undefined) { 8249 this.globSymlink = entry.fullParentDir === this.fullWatchPath ? 8250 false : {realPath: entry.fullParentDir, linkPath: this.fullWatchPath}; 8251 } 8252 8253 if (this.globSymlink) { 8254 return entry.fullPath.replace(this.globSymlink.realPath, this.globSymlink.linkPath); 8255 } 8256 8257 return entry.fullPath; 8258 } 8259 8260 entryPath(entry) { 8261 return sysPath.join(this.watchPath, 8262 sysPath.relative(this.watchPath, this.checkGlobSymlink(entry)) 8263 ); 8264 } 8265 8266 filterPath(entry) { 8267 const {stats} = entry; 8268 if (stats && stats.isSymbolicLink()) return this.filterDir(entry); 8269 const resolvedPath = this.entryPath(entry); 8270 const matchesGlob = this.hasGlob && typeof this.globFilter === FUNCTION_TYPE ? 8271 this.globFilter(resolvedPath) : true; 8272 return matchesGlob && 8273 this.fsw._isntIgnored(resolvedPath, stats) && 8274 this.fsw._hasReadPermissions(stats); 8275 } 8276 8277 getDirParts(path) { 8278 if (!this.hasGlob) return []; 8279 const parts = []; 8280 const expandedPath = path.includes(BRACE_START) ? braces.expand(path) : [path]; 8281 expandedPath.forEach((path) => { 8282 parts.push(sysPath.relative(this.watchPath, path).split(SLASH_OR_BACK_SLASH_RE)); 8283 }); 8284 return parts; 8285 } 8286 8287 filterDir(entry) { 8288 if (this.hasGlob) { 8289 const entryParts = this.getDirParts(this.checkGlobSymlink(entry)); 8290 let globstar = false; 8291 this.unmatchedGlob = !this.dirParts.some((parts) => { 8292 return parts.every((part, i) => { 8293 if (part === GLOBSTAR) globstar = true; 8294 return globstar || !entryParts[0][i] || anymatch(part, entryParts[0][i], ANYMATCH_OPTS); 8295 }); 8296 }); 8297 } 8298 return !this.unmatchedGlob && this.fsw._isntIgnored(this.entryPath(entry), entry.stats); 8299 } 8300 } 8301 8302 /** 8303 * Watches files & directories for changes. Emitted events: 8304 * `add`, `addDir`, `change`, `unlink`, `unlinkDir`, `all`, `error` 8305 * 8306 * new FSWatcher() 8307 * .add(directories) 8308 * .on('add', path => log('File', path, 'was added')) 8309 */ 8310 class FSWatcher extends EventEmitter { 8311 // Not indenting methods for history sake; for now. 8312 constructor(_opts) { 8313 super(); 8314 8315 const opts = {}; 8316 if (_opts) Object.assign(opts, _opts); // for frozen objects 8317 8318 /** @type {Map<String, DirEntry>} */ 8319 this._watched = new Map(); 8320 /** @type {Map<String, Array>} */ 8321 this._closers = new Map(); 8322 /** @type {Set<String>} */ 8323 this._ignoredPaths = new Set(); 8324 8325 /** @type {Map<ThrottleType, Map>} */ 8326 this._throttled = new Map(); 8327 8328 /** @type {Map<Path, String|Boolean>} */ 8329 this._symlinkPaths = new Map(); 8330 8331 this._streams = new Set(); 8332 this.closed = false; 8333 8334 // Set up default options. 8335 if (undef(opts, 'persistent')) opts.persistent = true; 8336 if (undef(opts, 'ignoreInitial')) opts.ignoreInitial = false; 8337 if (undef(opts, 'ignorePermissionErrors')) opts.ignorePermissionErrors = false; 8338 if (undef(opts, 'interval')) opts.interval = 100; 8339 if (undef(opts, 'binaryInterval')) opts.binaryInterval = 300; 8340 if (undef(opts, 'disableGlobbing')) opts.disableGlobbing = false; 8341 opts.enableBinaryInterval = opts.binaryInterval !== opts.interval; 8342 8343 // Enable fsevents on OS X when polling isn't explicitly enabled. 8344 if (undef(opts, 'useFsEvents')) opts.useFsEvents = !opts.usePolling; 8345 8346 // If we can't use fsevents, ensure the options reflect it's disabled. 8347 const canUseFsEvents = FsEventsHandler.canUse(); 8348 if (!canUseFsEvents) opts.useFsEvents = false; 8349 8350 // Use polling on Mac if not using fsevents. 8351 // Other platforms use non-polling fs_watch. 8352 if (undef(opts, 'usePolling') && !opts.useFsEvents) { 8353 opts.usePolling = isMacos; 8354 } 8355 8356 // Always default to polling on IBM i because fs.watch() is not available on IBM i. 8357 if(isIBMi) { 8358 opts.usePolling = true; 8359 } 8360 8361 // Global override (useful for end-developers that need to force polling for all 8362 // instances of chokidar, regardless of usage/dependency depth) 8363 const envPoll = process.env.CHOKIDAR_USEPOLLING; 8364 if (envPoll !== undefined) { 8365 const envLower = envPoll.toLowerCase(); 8366 8367 if (envLower === 'false' || envLower === '0') { 8368 opts.usePolling = false; 8369 } else if (envLower === 'true' || envLower === '1') { 8370 opts.usePolling = true; 8371 } else { 8372 opts.usePolling = !!envLower; 8373 } 8374 } 8375 const envInterval = process.env.CHOKIDAR_INTERVAL; 8376 if (envInterval) { 8377 opts.interval = Number.parseInt(envInterval, 10); 8378 } 8379 8380 // Editor atomic write normalization enabled by default with fs.watch 8381 if (undef(opts, 'atomic')) opts.atomic = !opts.usePolling && !opts.useFsEvents; 8382 if (opts.atomic) this._pendingUnlinks = new Map(); 8383 8384 if (undef(opts, 'followSymlinks')) opts.followSymlinks = true; 8385 8386 if (undef(opts, 'awaitWriteFinish')) opts.awaitWriteFinish = false; 8387 if (opts.awaitWriteFinish === true) opts.awaitWriteFinish = {}; 8388 const awf = opts.awaitWriteFinish; 8389 if (awf) { 8390 if (!awf.stabilityThreshold) awf.stabilityThreshold = 2000; 8391 if (!awf.pollInterval) awf.pollInterval = 100; 8392 this._pendingWrites = new Map(); 8393 } 8394 if (opts.ignored) opts.ignored = arrify(opts.ignored); 8395 8396 let readyCalls = 0; 8397 this._emitReady = () => { 8398 readyCalls++; 8399 if (readyCalls >= this._readyCount) { 8400 this._emitReady = EMPTY_FN; 8401 this._readyEmitted = true; 8402 // use process.nextTick to allow time for listener to be bound 8403 process.nextTick(() => this.emit(EV_READY)); 8404 } 8405 }; 8406 this._emitRaw = (...args) => this.emit(EV_RAW, ...args); 8407 this._readyEmitted = false; 8408 this.options = opts; 8409 8410 // Initialize with proper watcher. 8411 if (opts.useFsEvents) { 8412 this._fsEventsHandler = new FsEventsHandler(this); 8413 } else { 8414 this._nodeFsHandler = new NodeFsHandler(this); 8415 } 8416 8417 // You’re frozen when your heart’s not open. 8418 Object.freeze(opts); 8419 } 8420 8421 // Public methods 8422 8423 /** 8424 * Adds paths to be watched on an existing FSWatcher instance 8425 * @param {Path|Array<Path>} paths_ 8426 * @param {String=} _origAdd private; for handling non-existent paths to be watched 8427 * @param {Boolean=} _internal private; indicates a non-user add 8428 * @returns {FSWatcher} for chaining 8429 */ 8430 add(paths_, _origAdd, _internal) { 8431 const {cwd, disableGlobbing} = this.options; 8432 this.closed = false; 8433 let paths = unifyPaths(paths_); 8434 if (cwd) { 8435 paths = paths.map((path) => { 8436 const absPath = getAbsolutePath(path, cwd); 8437 8438 // Check `path` instead of `absPath` because the cwd portion can't be a glob 8439 if (disableGlobbing || !isGlob(path)) { 8440 return absPath; 8441 } 8442 return normalizePath(absPath); 8443 }); 8444 } 8445 8446 // set aside negated glob strings 8447 paths = paths.filter((path) => { 8448 if (path.startsWith(BANG)) { 8449 this._ignoredPaths.add(path.slice(1)); 8450 return false; 8451 } 8452 8453 // if a path is being added that was previously ignored, stop ignoring it 8454 this._ignoredPaths.delete(path); 8455 this._ignoredPaths.delete(path + SLASH_GLOBSTAR); 8456 8457 // reset the cached userIgnored anymatch fn 8458 // to make ignoredPaths changes effective 8459 this._userIgnored = undefined; 8460 8461 return true; 8462 }); 8463 8464 if (this.options.useFsEvents && this._fsEventsHandler) { 8465 if (!this._readyCount) this._readyCount = paths.length; 8466 if (this.options.persistent) this._readyCount += paths.length; 8467 paths.forEach((path) => this._fsEventsHandler._addToFsEvents(path)); 8468 } else { 8469 if (!this._readyCount) this._readyCount = 0; 8470 this._readyCount += paths.length; 8471 Promise.all( 8472 paths.map(async path => { 8473 const res = await this._nodeFsHandler._addToNodeFs(path, !_internal, 0, 0, _origAdd); 8474 if (res) this._emitReady(); 8475 return res; 8476 }) 8477 ).then(results => { 8478 if (this.closed) return; 8479 results.filter(item => item).forEach(item => { 8480 this.add(sysPath.dirname(item), sysPath.basename(_origAdd || item)); 8481 }); 8482 }); 8483 } 8484 8485 return this; 8486 } 8487 8488 /** 8489 * Close watchers or start ignoring events from specified paths. 8490 * @param {Path|Array<Path>} paths_ - string or array of strings, file/directory paths and/or globs 8491 * @returns {FSWatcher} for chaining 8492 */ 8493 unwatch(paths_) { 8494 if (this.closed) return this; 8495 const paths = unifyPaths(paths_); 8496 const {cwd} = this.options; 8497 8498 paths.forEach((path) => { 8499 // convert to absolute path unless relative path already matches 8500 if (!sysPath.isAbsolute(path) && !this._closers.has(path)) { 8501 if (cwd) path = sysPath.join(cwd, path); 8502 path = sysPath.resolve(path); 8503 } 8504 8505 this._closePath(path); 8506 8507 this._ignoredPaths.add(path); 8508 if (this._watched.has(path)) { 8509 this._ignoredPaths.add(path + SLASH_GLOBSTAR); 8510 } 8511 8512 // reset the cached userIgnored anymatch fn 8513 // to make ignoredPaths changes effective 8514 this._userIgnored = undefined; 8515 }); 8516 8517 return this; 8518 } 8519 8520 /** 8521 * Close watchers and remove all listeners from watched paths. 8522 * @returns {Promise<void>}. 8523 */ 8524 close() { 8525 if (this.closed) return this._closePromise; 8526 this.closed = true; 8527 8528 // Memory management. 8529 this.removeAllListeners(); 8530 const closers = []; 8531 this._closers.forEach(closerList => closerList.forEach(closer => { 8532 const promise = closer(); 8533 if (promise instanceof Promise) closers.push(promise); 8534 })); 8535 this._streams.forEach(stream => stream.destroy()); 8536 this._userIgnored = undefined; 8537 this._readyCount = 0; 8538 this._readyEmitted = false; 8539 this._watched.forEach(dirent => dirent.dispose()); 8540 ['closers', 'watched', 'streams', 'symlinkPaths', 'throttled'].forEach(key => { 8541 this[`_${key}`].clear(); 8542 }); 8543 8544 this._closePromise = closers.length ? Promise.all(closers).then(() => undefined) : Promise.resolve(); 8545 return this._closePromise; 8546 } 8547 8548 /** 8549 * Expose list of watched paths 8550 * @returns {Object} for chaining 8551 */ 8552 getWatched() { 8553 const watchList = {}; 8554 this._watched.forEach((entry, dir) => { 8555 const key = this.options.cwd ? sysPath.relative(this.options.cwd, dir) : dir; 8556 watchList[key || ONE_DOT] = entry.getChildren().sort(); 8557 }); 8558 return watchList; 8559 } 8560 8561 emitWithAll(event, args) { 8562 this.emit(...args); 8563 if (event !== EV_ERROR) this.emit(EV_ALL, ...args); 8564 } 8565 8566 // Common helpers 8567 // -------------- 8568 8569 /** 8570 * Normalize and emit events. 8571 * Calling _emit DOES NOT MEAN emit() would be called! 8572 * @param {EventName} event Type of event 8573 * @param {Path} path File or directory path 8574 * @param {*=} val1 arguments to be passed with event 8575 * @param {*=} val2 8576 * @param {*=} val3 8577 * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag 8578 */ 8579 async _emit(event, path, val1, val2, val3) { 8580 if (this.closed) return; 8581 8582 const opts = this.options; 8583 if (isWindows) path = sysPath.normalize(path); 8584 if (opts.cwd) path = sysPath.relative(opts.cwd, path); 8585 /** @type Array<any> */ 8586 const args = [event, path]; 8587 if (val3 !== undefined) args.push(val1, val2, val3); 8588 else if (val2 !== undefined) args.push(val1, val2); 8589 else if (val1 !== undefined) args.push(val1); 8590 8591 const awf = opts.awaitWriteFinish; 8592 let pw; 8593 if (awf && (pw = this._pendingWrites.get(path))) { 8594 pw.lastChange = new Date(); 8595 return this; 8596 } 8597 8598 if (opts.atomic) { 8599 if (event === EV_UNLINK) { 8600 this._pendingUnlinks.set(path, args); 8601 setTimeout(() => { 8602 this._pendingUnlinks.forEach((entry, path) => { 8603 this.emit(...entry); 8604 this.emit(EV_ALL, ...entry); 8605 this._pendingUnlinks.delete(path); 8606 }); 8607 }, typeof opts.atomic === 'number' ? opts.atomic : 100); 8608 return this; 8609 } 8610 if (event === EV_ADD && this._pendingUnlinks.has(path)) { 8611 event = args[0] = EV_CHANGE; 8612 this._pendingUnlinks.delete(path); 8613 } 8614 } 8615 8616 if (awf && (event === EV_ADD || event === EV_CHANGE) && this._readyEmitted) { 8617 const awfEmit = (err, stats) => { 8618 if (err) { 8619 event = args[0] = EV_ERROR; 8620 args[1] = err; 8621 this.emitWithAll(event, args); 8622 } else if (stats) { 8623 // if stats doesn't exist the file must have been deleted 8624 if (args.length > 2) { 8625 args[2] = stats; 8626 } else { 8627 args.push(stats); 8628 } 8629 this.emitWithAll(event, args); 8630 } 8631 }; 8632 8633 this._awaitWriteFinish(path, awf.stabilityThreshold, event, awfEmit); 8634 return this; 8635 } 8636 8637 if (event === EV_CHANGE) { 8638 const isThrottled = !this._throttle(EV_CHANGE, path, 50); 8639 if (isThrottled) return this; 8640 } 8641 8642 if (opts.alwaysStat && val1 === undefined && 8643 (event === EV_ADD || event === EV_ADD_DIR || event === EV_CHANGE) 8644 ) { 8645 const fullPath = opts.cwd ? sysPath.join(opts.cwd, path) : path; 8646 let stats; 8647 try { 8648 stats = await stat(fullPath); 8649 } catch (err) {} 8650 // Suppress event when fs_stat fails, to avoid sending undefined 'stat' 8651 if (!stats || this.closed) return; 8652 args.push(stats); 8653 } 8654 this.emitWithAll(event, args); 8655 8656 return this; 8657 } 8658 8659 /** 8660 * Common handler for errors 8661 * @param {Error} error 8662 * @returns {Error|Boolean} The error if defined, otherwise the value of the FSWatcher instance's `closed` flag 8663 */ 8664 _handleError(error) { 8665 const code = error && error.code; 8666 if (error && code !== 'ENOENT' && code !== 'ENOTDIR' && 8667 (!this.options.ignorePermissionErrors || (code !== 'EPERM' && code !== 'EACCES')) 8668 ) { 8669 this.emit(EV_ERROR, error); 8670 } 8671 return error || this.closed; 8672 } 8673 8674 /** 8675 * Helper utility for throttling 8676 * @param {ThrottleType} actionType type being throttled 8677 * @param {Path} path being acted upon 8678 * @param {Number} timeout duration of time to suppress duplicate actions 8679 * @returns {Object|false} tracking object or false if action should be suppressed 8680 */ 8681 _throttle(actionType, path, timeout) { 8682 if (!this._throttled.has(actionType)) { 8683 this._throttled.set(actionType, new Map()); 8684 } 8685 8686 /** @type {Map<Path, Object>} */ 8687 const action = this._throttled.get(actionType); 8688 /** @type {Object} */ 8689 const actionPath = action.get(path); 8690 8691 if (actionPath) { 8692 actionPath.count++; 8693 return false; 8694 } 8695 8696 let timeoutObject; 8697 const clear = () => { 8698 const item = action.get(path); 8699 const count = item ? item.count : 0; 8700 action.delete(path); 8701 clearTimeout(timeoutObject); 8702 if (item) clearTimeout(item.timeoutObject); 8703 return count; 8704 }; 8705 timeoutObject = setTimeout(clear, timeout); 8706 const thr = {timeoutObject, clear, count: 0}; 8707 action.set(path, thr); 8708 return thr; 8709 } 8710 8711 _incrReadyCount() { 8712 return this._readyCount++; 8713 } 8714 8715 /** 8716 * Awaits write operation to finish. 8717 * Polls a newly created file for size variations. When files size does not change for 'threshold' milliseconds calls callback. 8718 * @param {Path} path being acted upon 8719 * @param {Number} threshold Time in milliseconds a file size must be fixed before acknowledging write OP is finished 8720 * @param {EventName} event 8721 * @param {Function} awfEmit Callback to be called when ready for event to be emitted. 8722 */ 8723 _awaitWriteFinish(path, threshold, event, awfEmit) { 8724 let timeoutHandler; 8725 8726 let fullPath = path; 8727 if (this.options.cwd && !sysPath.isAbsolute(path)) { 8728 fullPath = sysPath.join(this.options.cwd, path); 8729 } 8730 8731 const now = new Date(); 8732 8733 const awaitWriteFinish = (prevStat) => { 8734 fs.stat(fullPath, (err, curStat) => { 8735 if (err || !this._pendingWrites.has(path)) { 8736 if (err && err.code !== 'ENOENT') awfEmit(err); 8737 return; 8738 } 8739 8740 const now = Number(new Date()); 8741 8742 if (prevStat && curStat.size !== prevStat.size) { 8743 this._pendingWrites.get(path).lastChange = now; 8744 } 8745 const pw = this._pendingWrites.get(path); 8746 const df = now - pw.lastChange; 8747 8748 if (df >= threshold) { 8749 this._pendingWrites.delete(path); 8750 awfEmit(undefined, curStat); 8751 } else { 8752 timeoutHandler = setTimeout( 8753 awaitWriteFinish, 8754 this.options.awaitWriteFinish.pollInterval, 8755 curStat 8756 ); 8757 } 8758 }); 8759 }; 8760 8761 if (!this._pendingWrites.has(path)) { 8762 this._pendingWrites.set(path, { 8763 lastChange: now, 8764 cancelWait: () => { 8765 this._pendingWrites.delete(path); 8766 clearTimeout(timeoutHandler); 8767 return event; 8768 } 8769 }); 8770 timeoutHandler = setTimeout( 8771 awaitWriteFinish, 8772 this.options.awaitWriteFinish.pollInterval 8773 ); 8774 } 8775 } 8776 8777 _getGlobIgnored() { 8778 return [...this._ignoredPaths.values()]; 8779 } 8780 8781 /** 8782 * Determines whether user has asked to ignore this path. 8783 * @param {Path} path filepath or dir 8784 * @param {fs.Stats=} stats result of fs.stat 8785 * @returns {Boolean} 8786 */ 8787 _isIgnored(path, stats) { 8788 if (this.options.atomic && DOT_RE.test(path)) return true; 8789 if (!this._userIgnored) { 8790 const {cwd} = this.options; 8791 const ign = this.options.ignored; 8792 8793 const ignored = ign && ign.map(normalizeIgnored(cwd)); 8794 const paths = arrify(ignored) 8795 .filter((path) => typeof path === STRING_TYPE && !isGlob(path)) 8796 .map((path) => path + SLASH_GLOBSTAR); 8797 const list = this._getGlobIgnored().map(normalizeIgnored(cwd)).concat(ignored, paths); 8798 this._userIgnored = anymatch(list, undefined, ANYMATCH_OPTS); 8799 } 8800 8801 return this._userIgnored([path, stats]); 8802 } 8803 8804 _isntIgnored(path, stat) { 8805 return !this._isIgnored(path, stat); 8806 } 8807 8808 /** 8809 * Provides a set of common helpers and properties relating to symlink and glob handling. 8810 * @param {Path} path file, directory, or glob pattern being watched 8811 * @param {Number=} depth at any depth > 0, this isn't a glob 8812 * @returns {WatchHelper} object containing helpers for this path 8813 */ 8814 _getWatchHelpers(path, depth) { 8815 const watchPath = depth || this.options.disableGlobbing || !isGlob(path) ? path : globParent(path); 8816 const follow = this.options.followSymlinks; 8817 8818 return new WatchHelper(path, watchPath, follow, this); 8819 } 8820 8821 // Directory helpers 8822 // ----------------- 8823 8824 /** 8825 * Provides directory tracking objects 8826 * @param {String} directory path of the directory 8827 * @returns {DirEntry} the directory's tracking object 8828 */ 8829 _getWatchedDir(directory) { 8830 if (!this._boundRemove) this._boundRemove = this._remove.bind(this); 8831 const dir = sysPath.resolve(directory); 8832 if (!this._watched.has(dir)) this._watched.set(dir, new DirEntry(dir, this._boundRemove)); 8833 return this._watched.get(dir); 8834 } 8835 8836 // File helpers 8837 // ------------ 8838 8839 /** 8840 * Check for read permissions. 8841 * Based on this answer on SO: https://stackoverflow.com/a/11781404/1358405 8842 * @param {fs.Stats} stats - object, result of fs_stat 8843 * @returns {Boolean} indicates whether the file can be read 8844 */ 8845 _hasReadPermissions(stats) { 8846 if (this.options.ignorePermissionErrors) return true; 8847 8848 // stats.mode may be bigint 8849 const md = stats && Number.parseInt(stats.mode, 10); 8850 const st = md & 0o777; 8851 const it = Number.parseInt(st.toString(8)[0], 10); 8852 return Boolean(4 & it); 8853 } 8854 8855 /** 8856 * Handles emitting unlink events for 8857 * files and directories, and via recursion, for 8858 * files and directories within directories that are unlinked 8859 * @param {String} directory within which the following item is located 8860 * @param {String} item base path of item/directory 8861 * @returns {void} 8862 */ 8863 _remove(directory, item, isDirectory) { 8864 // if what is being deleted is a directory, get that directory's paths 8865 // for recursive deleting and cleaning of watched object 8866 // if it is not a directory, nestedDirectoryChildren will be empty array 8867 const path = sysPath.join(directory, item); 8868 const fullPath = sysPath.resolve(path); 8869 isDirectory = isDirectory != null 8870 ? isDirectory 8871 : this._watched.has(path) || this._watched.has(fullPath); 8872 8873 // prevent duplicate handling in case of arriving here nearly simultaneously 8874 // via multiple paths (such as _handleFile and _handleDir) 8875 if (!this._throttle('remove', path, 100)) return; 8876 8877 // if the only watched file is removed, watch for its return 8878 if (!isDirectory && !this.options.useFsEvents && this._watched.size === 1) { 8879 this.add(directory, item, true); 8880 } 8881 8882 // This will create a new entry in the watched object in either case 8883 // so we got to do the directory check beforehand 8884 const wp = this._getWatchedDir(path); 8885 const nestedDirectoryChildren = wp.getChildren(); 8886 8887 // Recursively remove children directories / files. 8888 nestedDirectoryChildren.forEach(nested => this._remove(path, nested)); 8889 8890 // Check if item was on the watched list and remove it 8891 const parent = this._getWatchedDir(directory); 8892 const wasTracked = parent.has(item); 8893 parent.remove(item); 8894 8895 // Fixes issue #1042 -> Relative paths were detected and added as symlinks 8896 // (https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L612), 8897 // but never removed from the map in case the path was deleted. 8898 // This leads to an incorrect state if the path was recreated: 8899 // https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L553 8900 if (this._symlinkPaths.has(fullPath)) { 8901 this._symlinkPaths.delete(fullPath); 8902 } 8903 8904 // If we wait for this file to be fully written, cancel the wait. 8905 let relPath = path; 8906 if (this.options.cwd) relPath = sysPath.relative(this.options.cwd, path); 8907 if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) { 8908 const event = this._pendingWrites.get(relPath).cancelWait(); 8909 if (event === EV_ADD) return; 8910 } 8911 8912 // The Entry will either be a directory that just got removed 8913 // or a bogus entry to a file, in either case we have to remove it 8914 this._watched.delete(path); 8915 this._watched.delete(fullPath); 8916 const eventName = isDirectory ? EV_UNLINK_DIR : EV_UNLINK; 8917 if (wasTracked && !this._isIgnored(path)) this._emit(eventName, path); 8918 8919 // Avoid conflicts if we later create another file with the same name 8920 if (!this.options.useFsEvents) { 8921 this._closePath(path); 8922 } 8923 } 8924 8925 /** 8926 * Closes all watchers for a path 8927 * @param {Path} path 8928 */ 8929 _closePath(path) { 8930 this._closeFile(path); 8931 const dir = sysPath.dirname(path); 8932 this._getWatchedDir(dir).remove(sysPath.basename(path)); 8933 } 8934 8935 /** 8936 * Closes only file-specific watchers 8937 * @param {Path} path 8938 */ 8939 _closeFile(path) { 8940 const closers = this._closers.get(path); 8941 if (!closers) return; 8942 closers.forEach(closer => closer()); 8943 this._closers.delete(path); 8944 } 8945 8946 /** 8947 * 8948 * @param {Path} path 8949 * @param {Function} closer 8950 */ 8951 _addPathCloser(path, closer) { 8952 if (!closer) return; 8953 let list = this._closers.get(path); 8954 if (!list) { 8955 list = []; 8956 this._closers.set(path, list); 8957 } 8958 list.push(closer); 8959 } 8960 8961 _readdirp(root, opts) { 8962 if (this.closed) return; 8963 const options = {type: EV_ALL, alwaysStat: true, lstat: true, ...opts}; 8964 let stream = readdirp(root, options); 8965 this._streams.add(stream); 8966 stream.once(STR_CLOSE, () => { 8967 stream = undefined; 8968 }); 8969 stream.once(STR_END, () => { 8970 if (stream) { 8971 this._streams.delete(stream); 8972 stream = undefined; 8973 } 8974 }); 8975 return stream; 8976 } 8977 8978 } 8979 8980 // Export FSWatcher class 8981 chokidar$1.FSWatcher = FSWatcher; 8982 8983 /** 8984 * Instantiates watcher with paths to be tracked. 8985 * @param {String|Array<String>} paths file/directory paths and/or globs 8986 * @param {Object=} options chokidar opts 8987 * @returns an instance of FSWatcher for chaining. 8988 */ 8989 const watch = (paths, options) => { 8990 const watcher = new FSWatcher(options); 8991 watcher.add(paths); 8992 return watcher; 8993 }; 8994 8995 chokidar$1.watch = watch; 8996 return chokidar$1; 2834 8997 } 2835 8998 2836 /** 2837 * Handle symlinks encountered while reading a dir. 2838 * @param {Object} entry returned by readdirp 2839 * @param {String} directory path of dir being read 2840 * @param {String} path of this item 2841 * @param {String} item basename of this item 2842 * @returns {Promise<Boolean>} true if no more processing is needed for this entry. 2843 */ 2844 async _handleSymlink(entry, directory, path, item) { 2845 if (this.fsw.closed) { 2846 return; 2847 } 2848 const full = entry.fullPath; 2849 const dir = this.fsw._getWatchedDir(directory); 2850 2851 if (!this.fsw.options.followSymlinks) { 2852 // watch symlink directly (don't follow) and detect changes 2853 this.fsw._incrReadyCount(); 2854 2855 let linkPath; 2856 try { 2857 linkPath = await fsrealpath(path); 2858 } catch (e) { 2859 this.fsw._emitReady(); 2860 return true; 2861 } 2862 2863 if (this.fsw.closed) return; 2864 if (dir.has(item)) { 2865 if (this.fsw._symlinkPaths.get(full) !== linkPath) { 2866 this.fsw._symlinkPaths.set(full, linkPath); 2867 this.fsw._emit(EV_CHANGE$2, path, entry.stats); 2868 } 2869 } else { 2870 dir.add(item); 2871 this.fsw._symlinkPaths.set(full, linkPath); 2872 this.fsw._emit(EV_ADD$2, path, entry.stats); 2873 } 2874 this.fsw._emitReady(); 2875 return true; 2876 } 2877 2878 // don't follow the same symlink more than once 2879 if (this.fsw._symlinkPaths.has(full)) { 2880 return true; 2881 } 2882 2883 this.fsw._symlinkPaths.set(full, true); 2884 } 2885 2886 _handleRead(directory, initialAdd, wh, target, dir, depth, throttler) { 2887 // Normalize the directory name on Windows 2888 directory = sysPath$2.join(directory, EMPTY_STR$1); 2889 2890 if (!wh.hasGlob) { 2891 throttler = this.fsw._throttle('readdir', directory, 1000); 2892 if (!throttler) return; 2893 } 2894 2895 const previous = this.fsw._getWatchedDir(wh.path); 2896 const current = new Set(); 2897 2898 let stream = this.fsw._readdirp(directory, { 2899 fileFilter: entry => wh.filterPath(entry), 2900 directoryFilter: entry => wh.filterDir(entry), 2901 depth: 0 2902 }).on(STR_DATA$1, async (entry) => { 2903 if (this.fsw.closed) { 2904 stream = undefined; 2905 return; 2906 } 2907 const item = entry.path; 2908 let path = sysPath$2.join(directory, item); 2909 current.add(item); 2910 2911 if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path, item)) { 2912 return; 2913 } 2914 2915 if (this.fsw.closed) { 2916 stream = undefined; 2917 return; 2918 } 2919 // Files that present in current directory snapshot 2920 // but absent in previous are added to watch list and 2921 // emit `add` event. 2922 if (item === target || !target && !previous.has(item)) { 2923 this.fsw._incrReadyCount(); 2924 2925 // ensure relativeness of path is preserved in case of watcher reuse 2926 path = sysPath$2.join(dir, sysPath$2.relative(dir, path)); 2927 2928 this._addToNodeFs(path, initialAdd, wh, depth + 1); 2929 } 2930 }).on(EV_ERROR$2, this._boundHandleError); 2931 2932 return new Promise(resolve => 2933 stream.once(STR_END$2, () => { 2934 if (this.fsw.closed) { 2935 stream = undefined; 2936 return; 2937 } 2938 const wasThrottled = throttler ? throttler.clear() : false; 2939 2940 resolve(); 2941 2942 // Files that absent in current directory snapshot 2943 // but present in previous emit `remove` event 2944 // and are removed from @watched[directory]. 2945 previous.getChildren().filter((item) => { 2946 return item !== directory && 2947 !current.has(item) && 2948 // in case of intersecting globs; 2949 // a path may have been filtered out of this readdir, but 2950 // shouldn't be removed because it matches a different glob 2951 (!wh.hasGlob || wh.filterPath({ 2952 fullPath: sysPath$2.resolve(directory, item) 2953 })); 2954 }).forEach((item) => { 2955 this.fsw._remove(directory, item); 2956 }); 2957 2958 stream = undefined; 2959 2960 // one more time for any missed in case changes came in extremely quickly 2961 if (wasThrottled) this._handleRead(directory, false, wh, target, dir, depth, throttler); 2962 }) 2963 ); 2964 } 2965 2966 /** 2967 * Read directory to add / remove files from `@watched` list and re-read it on change. 2968 * @param {String} dir fs path 2969 * @param {fs.Stats} stats 2970 * @param {Boolean} initialAdd 2971 * @param {Number} depth relative to user-supplied path 2972 * @param {String} target child path targeted for watch 2973 * @param {Object} wh Common watch helpers for this path 2974 * @param {String} realpath 2975 * @returns {Promise<Function>} closer for the watcher instance. 2976 */ 2977 async _handleDir(dir, stats, initialAdd, depth, target, wh, realpath) { 2978 const parentDir = this.fsw._getWatchedDir(sysPath$2.dirname(dir)); 2979 const tracked = parentDir.has(sysPath$2.basename(dir)); 2980 if (!(initialAdd && this.fsw.options.ignoreInitial) && !target && !tracked) { 2981 if (!wh.hasGlob || wh.globFilter(dir)) this.fsw._emit(EV_ADD_DIR$2, dir, stats); 2982 } 2983 2984 // ensure dir is tracked (harmless if redundant) 2985 parentDir.add(sysPath$2.basename(dir)); 2986 this.fsw._getWatchedDir(dir); 2987 let throttler; 2988 let closer; 2989 2990 const oDepth = this.fsw.options.depth; 2991 if ((oDepth == null || depth <= oDepth) && !this.fsw._symlinkPaths.has(realpath)) { 2992 if (!target) { 2993 await this._handleRead(dir, initialAdd, wh, target, dir, depth, throttler); 2994 if (this.fsw.closed) return; 2995 } 2996 2997 closer = this._watchWithNodeFs(dir, (dirPath, stats) => { 2998 // if current directory is removed, do nothing 2999 if (stats && stats.mtimeMs === 0) return; 3000 3001 this._handleRead(dirPath, false, wh, target, dir, depth, throttler); 3002 }); 3003 } 3004 return closer; 3005 } 3006 3007 /** 3008 * Handle added file, directory, or glob pattern. 3009 * Delegates call to _handleFile / _handleDir after checks. 3010 * @param {String} path to file or ir 3011 * @param {Boolean} initialAdd was the file added at watch instantiation? 3012 * @param {Object} priorWh depth relative to user-supplied path 3013 * @param {Number} depth Child path actually targeted for watch 3014 * @param {String=} target Child path actually targeted for watch 3015 * @returns {Promise} 3016 */ 3017 async _addToNodeFs(path, initialAdd, priorWh, depth, target) { 3018 const ready = this.fsw._emitReady; 3019 if (this.fsw._isIgnored(path) || this.fsw.closed) { 3020 ready(); 3021 return false; 3022 } 3023 3024 const wh = this.fsw._getWatchHelpers(path, depth); 3025 if (!wh.hasGlob && priorWh) { 3026 wh.hasGlob = priorWh.hasGlob; 3027 wh.globFilter = priorWh.globFilter; 3028 wh.filterPath = entry => priorWh.filterPath(entry); 3029 wh.filterDir = entry => priorWh.filterDir(entry); 3030 } 3031 3032 // evaluate what is at the path we're being asked to watch 3033 try { 3034 const stats = await statMethods$1[wh.statMethod](wh.watchPath); 3035 if (this.fsw.closed) return; 3036 if (this.fsw._isIgnored(wh.watchPath, stats)) { 3037 ready(); 3038 return false; 3039 } 3040 3041 const follow = this.fsw.options.followSymlinks && !path.includes(STAR) && !path.includes(BRACE_START$1); 3042 let closer; 3043 if (stats.isDirectory()) { 3044 const absPath = sysPath$2.resolve(path); 3045 const targetPath = follow ? await fsrealpath(path) : path; 3046 if (this.fsw.closed) return; 3047 closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath); 3048 if (this.fsw.closed) return; 3049 // preserve this symlink's target path 3050 if (absPath !== targetPath && targetPath !== undefined) { 3051 this.fsw._symlinkPaths.set(absPath, targetPath); 3052 } 3053 } else if (stats.isSymbolicLink()) { 3054 const targetPath = follow ? await fsrealpath(path) : path; 3055 if (this.fsw.closed) return; 3056 const parent = sysPath$2.dirname(wh.watchPath); 3057 this.fsw._getWatchedDir(parent).add(wh.watchPath); 3058 this.fsw._emit(EV_ADD$2, wh.watchPath, stats); 3059 closer = await this._handleDir(parent, stats, initialAdd, depth, path, wh, targetPath); 3060 if (this.fsw.closed) return; 3061 3062 // preserve this symlink's target path 3063 if (targetPath !== undefined) { 3064 this.fsw._symlinkPaths.set(sysPath$2.resolve(path), targetPath); 3065 } 3066 } else { 3067 closer = this._handleFile(wh.watchPath, stats, initialAdd); 3068 } 3069 ready(); 3070 3071 this.fsw._addPathCloser(path, closer); 3072 return false; 3073 3074 } catch (error) { 3075 if (this.fsw._handleError(error)) { 3076 ready(); 3077 return path; 3078 } 3079 } 3080 } 3081 3082 }; 3083 3084 var nodefsHandler = NodeFsHandler$1; 3085 3086 var fseventsHandler = {exports: {}}; 3087 3088 const require$$3 = /*@__PURE__*/rollup.getAugmentedNamespace(fseventsImporter.fseventsImporter); 3089 3090 const fs$1 = require$$0$1; 3091 const sysPath$1 = require$$0$2; 3092 const { promisify: promisify$1 } = require$$2; 3093 3094 let fsevents; 3095 try { 3096 fsevents = require$$3.getFsEvents(); 3097 } catch (error) { 3098 if (process.env.CHOKIDAR_PRINT_FSEVENTS_REQUIRE_ERROR) console.error(error); 3099 } 3100 3101 if (fsevents) { 3102 // TODO: real check 3103 const mtch = process.version.match(/v(\d+)\.(\d+)/); 3104 if (mtch && mtch[1] && mtch[2]) { 3105 const maj = Number.parseInt(mtch[1], 10); 3106 const min = Number.parseInt(mtch[2], 10); 3107 if (maj === 8 && min < 16) { 3108 fsevents = undefined; 3109 } 3110 } 3111 } 3112 3113 const { 3114 EV_ADD: EV_ADD$1, 3115 EV_CHANGE: EV_CHANGE$1, 3116 EV_ADD_DIR: EV_ADD_DIR$1, 3117 EV_UNLINK: EV_UNLINK$1, 3118 EV_ERROR: EV_ERROR$1, 3119 STR_DATA, 3120 STR_END: STR_END$1, 3121 FSEVENT_CREATED, 3122 FSEVENT_MODIFIED, 3123 FSEVENT_DELETED, 3124 FSEVENT_MOVED, 3125 // FSEVENT_CLONED, 3126 FSEVENT_UNKNOWN, 3127 FSEVENT_FLAG_MUST_SCAN_SUBDIRS, 3128 FSEVENT_TYPE_FILE, 3129 FSEVENT_TYPE_DIRECTORY, 3130 FSEVENT_TYPE_SYMLINK, 3131 3132 ROOT_GLOBSTAR, 3133 DIR_SUFFIX, 3134 DOT_SLASH, 3135 FUNCTION_TYPE: FUNCTION_TYPE$1, 3136 EMPTY_FN: EMPTY_FN$1, 3137 IDENTITY_FN 3138 } = constants; 3139 3140 const Depth = (value) => isNaN(value) ? {} : {depth: value}; 3141 3142 const stat$1 = promisify$1(fs$1.stat); 3143 const lstat = promisify$1(fs$1.lstat); 3144 const realpath = promisify$1(fs$1.realpath); 3145 3146 const statMethods = { stat: stat$1, lstat }; 3147 3148 /** 3149 * @typedef {String} Path 3150 */ 3151 3152 /** 3153 * @typedef {Object} FsEventsWatchContainer 3154 * @property {Set<Function>} listeners 3155 * @property {Function} rawEmitter 3156 * @property {{stop: Function}} watcher 3157 */ 3158 3159 // fsevents instance helper functions 3160 /** 3161 * Object to hold per-process fsevents instances (may be shared across chokidar FSWatcher instances) 3162 * @type {Map<Path,FsEventsWatchContainer>} 3163 */ 3164 const FSEventsWatchers = new Map(); 3165 3166 // Threshold of duplicate path prefixes at which to start 3167 // consolidating going forward 3168 const consolidateThreshhold = 10; 3169 3170 const wrongEventFlags = new Set([ 3171 69888, 70400, 71424, 72704, 73472, 131328, 131840, 262912 3172 ]); 3173 3174 /** 3175 * Instantiates the fsevents interface 3176 * @param {Path} path path to be watched 3177 * @param {Function} callback called when fsevents is bound and ready 3178 * @returns {{stop: Function}} new fsevents instance 3179 */ 3180 const createFSEventsInstance = (path, callback) => { 3181 const stop = fsevents.watch(path, callback); 3182 return {stop}; 3183 }; 3184 3185 /** 3186 * Instantiates the fsevents interface or binds listeners to an existing one covering 3187 * the same file tree. 3188 * @param {Path} path - to be watched 3189 * @param {Path} realPath - real path for symlinks 3190 * @param {Function} listener - called when fsevents emits events 3191 * @param {Function} rawEmitter - passes data to listeners of the 'raw' event 3192 * @returns {Function} closer 3193 */ 3194 function setFSEventsListener(path, realPath, listener, rawEmitter) { 3195 let watchPath = sysPath$1.extname(realPath) ? sysPath$1.dirname(realPath) : realPath; 3196 3197 const parentPath = sysPath$1.dirname(watchPath); 3198 let cont = FSEventsWatchers.get(watchPath); 3199 3200 // If we've accumulated a substantial number of paths that 3201 // could have been consolidated by watching one directory 3202 // above the current one, create a watcher on the parent 3203 // path instead, so that we do consolidate going forward. 3204 if (couldConsolidate(parentPath)) { 3205 watchPath = parentPath; 3206 } 3207 3208 const resolvedPath = sysPath$1.resolve(path); 3209 const hasSymlink = resolvedPath !== realPath; 3210 3211 const filteredListener = (fullPath, flags, info) => { 3212 if (hasSymlink) fullPath = fullPath.replace(realPath, resolvedPath); 3213 if ( 3214 fullPath === resolvedPath || 3215 !fullPath.indexOf(resolvedPath + sysPath$1.sep) 3216 ) listener(fullPath, flags, info); 3217 }; 3218 3219 // check if there is already a watcher on a parent path 3220 // modifies `watchPath` to the parent path when it finds a match 3221 let watchedParent = false; 3222 for (const watchedPath of FSEventsWatchers.keys()) { 3223 if (realPath.indexOf(sysPath$1.resolve(watchedPath) + sysPath$1.sep) === 0) { 3224 watchPath = watchedPath; 3225 cont = FSEventsWatchers.get(watchPath); 3226 watchedParent = true; 3227 break; 3228 } 3229 } 3230 3231 if (cont || watchedParent) { 3232 cont.listeners.add(filteredListener); 3233 } else { 3234 cont = { 3235 listeners: new Set([filteredListener]), 3236 rawEmitter, 3237 watcher: createFSEventsInstance(watchPath, (fullPath, flags) => { 3238 if (!cont.listeners.size) return; 3239 if (flags & FSEVENT_FLAG_MUST_SCAN_SUBDIRS) return; 3240 const info = fsevents.getInfo(fullPath, flags); 3241 cont.listeners.forEach(list => { 3242 list(fullPath, flags, info); 3243 }); 3244 3245 cont.rawEmitter(info.event, fullPath, info); 3246 }) 3247 }; 3248 FSEventsWatchers.set(watchPath, cont); 3249 } 3250 3251 // removes this instance's listeners and closes the underlying fsevents 3252 // instance if there are no more listeners left 3253 return () => { 3254 const lst = cont.listeners; 3255 3256 lst.delete(filteredListener); 3257 if (!lst.size) { 3258 FSEventsWatchers.delete(watchPath); 3259 if (cont.watcher) return cont.watcher.stop().then(() => { 3260 cont.rawEmitter = cont.watcher = undefined; 3261 Object.freeze(cont); 3262 }); 3263 } 3264 }; 3265 } 3266 3267 // Decide whether or not we should start a new higher-level 3268 // parent watcher 3269 const couldConsolidate = (path) => { 3270 let count = 0; 3271 for (const watchPath of FSEventsWatchers.keys()) { 3272 if (watchPath.indexOf(path) === 0) { 3273 count++; 3274 if (count >= consolidateThreshhold) { 3275 return true; 3276 } 3277 } 3278 } 3279 3280 return false; 3281 }; 3282 3283 // returns boolean indicating whether fsevents can be used 3284 const canUse = () => fsevents && FSEventsWatchers.size < 128; 3285 3286 // determines subdirectory traversal levels from root to path 3287 const calcDepth = (path, root) => { 3288 let i = 0; 3289 while (!path.indexOf(root) && (path = sysPath$1.dirname(path)) !== root) i++; 3290 return i; 3291 }; 3292 3293 // returns boolean indicating whether the fsevents' event info has the same type 3294 // as the one returned by fs.stat 3295 const sameTypes = (info, stats) => ( 3296 info.type === FSEVENT_TYPE_DIRECTORY && stats.isDirectory() || 3297 info.type === FSEVENT_TYPE_SYMLINK && stats.isSymbolicLink() || 3298 info.type === FSEVENT_TYPE_FILE && stats.isFile() 3299 ); 3300 3301 /** 3302 * @mixin 3303 */ 3304 let FsEventsHandler$1 = class FsEventsHandler { 3305 3306 /** 3307 * @param {import('../index').FSWatcher} fsw 3308 */ 3309 constructor(fsw) { 3310 this.fsw = fsw; 3311 } 3312 checkIgnored(path, stats) { 3313 const ipaths = this.fsw._ignoredPaths; 3314 if (this.fsw._isIgnored(path, stats)) { 3315 ipaths.add(path); 3316 if (stats && stats.isDirectory()) { 3317 ipaths.add(path + ROOT_GLOBSTAR); 3318 } 3319 return true; 3320 } 3321 3322 ipaths.delete(path); 3323 ipaths.delete(path + ROOT_GLOBSTAR); 3324 } 3325 3326 addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts) { 3327 const event = watchedDir.has(item) ? EV_CHANGE$1 : EV_ADD$1; 3328 this.handleEvent(event, path, fullPath, realPath, parent, watchedDir, item, info, opts); 3329 } 3330 3331 async checkExists(path, fullPath, realPath, parent, watchedDir, item, info, opts) { 3332 try { 3333 const stats = await stat$1(path); 3334 if (this.fsw.closed) return; 3335 if (sameTypes(info, stats)) { 3336 this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts); 3337 } else { 3338 this.handleEvent(EV_UNLINK$1, path, fullPath, realPath, parent, watchedDir, item, info, opts); 3339 } 3340 } catch (error) { 3341 if (error.code === 'EACCES') { 3342 this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts); 3343 } else { 3344 this.handleEvent(EV_UNLINK$1, path, fullPath, realPath, parent, watchedDir, item, info, opts); 3345 } 3346 } 3347 } 3348 3349 handleEvent(event, path, fullPath, realPath, parent, watchedDir, item, info, opts) { 3350 if (this.fsw.closed || this.checkIgnored(path)) return; 3351 3352 if (event === EV_UNLINK$1) { 3353 const isDirectory = info.type === FSEVENT_TYPE_DIRECTORY; 3354 // suppress unlink events on never before seen files 3355 if (isDirectory || watchedDir.has(item)) { 3356 this.fsw._remove(parent, item, isDirectory); 3357 } 3358 } else { 3359 if (event === EV_ADD$1) { 3360 // track new directories 3361 if (info.type === FSEVENT_TYPE_DIRECTORY) this.fsw._getWatchedDir(path); 3362 3363 if (info.type === FSEVENT_TYPE_SYMLINK && opts.followSymlinks) { 3364 // push symlinks back to the top of the stack to get handled 3365 const curDepth = opts.depth === undefined ? 3366 undefined : calcDepth(fullPath, realPath) + 1; 3367 return this._addToFsEvents(path, false, true, curDepth); 3368 } 3369 3370 // track new paths 3371 // (other than symlinks being followed, which will be tracked soon) 3372 this.fsw._getWatchedDir(parent).add(item); 3373 } 3374 /** 3375 * @type {'add'|'addDir'|'unlink'|'unlinkDir'} 3376 */ 3377 const eventName = info.type === FSEVENT_TYPE_DIRECTORY ? event + DIR_SUFFIX : event; 3378 this.fsw._emit(eventName, path); 3379 if (eventName === EV_ADD_DIR$1) this._addToFsEvents(path, false, true); 3380 } 3381 } 3382 3383 /** 3384 * Handle symlinks encountered during directory scan 3385 * @param {String} watchPath - file/dir path to be watched with fsevents 3386 * @param {String} realPath - real path (in case of symlinks) 3387 * @param {Function} transform - path transformer 3388 * @param {Function} globFilter - path filter in case a glob pattern was provided 3389 * @returns {Function} closer for the watcher instance 3390 */ 3391 _watchWithFsEvents(watchPath, realPath, transform, globFilter) { 3392 if (this.fsw.closed || this.fsw._isIgnored(watchPath)) return; 3393 const opts = this.fsw.options; 3394 const watchCallback = async (fullPath, flags, info) => { 3395 if (this.fsw.closed) return; 3396 if ( 3397 opts.depth !== undefined && 3398 calcDepth(fullPath, realPath) > opts.depth 3399 ) return; 3400 const path = transform(sysPath$1.join( 3401 watchPath, sysPath$1.relative(watchPath, fullPath) 3402 )); 3403 if (globFilter && !globFilter(path)) return; 3404 // ensure directories are tracked 3405 const parent = sysPath$1.dirname(path); 3406 const item = sysPath$1.basename(path); 3407 const watchedDir = this.fsw._getWatchedDir( 3408 info.type === FSEVENT_TYPE_DIRECTORY ? path : parent 3409 ); 3410 3411 // correct for wrong events emitted 3412 if (wrongEventFlags.has(flags) || info.event === FSEVENT_UNKNOWN) { 3413 if (typeof opts.ignored === FUNCTION_TYPE$1) { 3414 let stats; 3415 try { 3416 stats = await stat$1(path); 3417 } catch (error) {} 3418 if (this.fsw.closed) return; 3419 if (this.checkIgnored(path, stats)) return; 3420 if (sameTypes(info, stats)) { 3421 this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts); 3422 } else { 3423 this.handleEvent(EV_UNLINK$1, path, fullPath, realPath, parent, watchedDir, item, info, opts); 3424 } 3425 } else { 3426 this.checkExists(path, fullPath, realPath, parent, watchedDir, item, info, opts); 3427 } 3428 } else { 3429 switch (info.event) { 3430 case FSEVENT_CREATED: 3431 case FSEVENT_MODIFIED: 3432 return this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts); 3433 case FSEVENT_DELETED: 3434 case FSEVENT_MOVED: 3435 return this.checkExists(path, fullPath, realPath, parent, watchedDir, item, info, opts); 3436 } 3437 } 3438 }; 3439 3440 const closer = setFSEventsListener( 3441 watchPath, 3442 realPath, 3443 watchCallback, 3444 this.fsw._emitRaw 3445 ); 3446 3447 this.fsw._emitReady(); 3448 return closer; 3449 } 3450 3451 /** 3452 * Handle symlinks encountered during directory scan 3453 * @param {String} linkPath path to symlink 3454 * @param {String} fullPath absolute path to the symlink 3455 * @param {Function} transform pre-existing path transformer 3456 * @param {Number} curDepth level of subdirectories traversed to where symlink is 3457 * @returns {Promise<void>} 3458 */ 3459 async _handleFsEventsSymlink(linkPath, fullPath, transform, curDepth) { 3460 // don't follow the same symlink more than once 3461 if (this.fsw.closed || this.fsw._symlinkPaths.has(fullPath)) return; 3462 3463 this.fsw._symlinkPaths.set(fullPath, true); 3464 this.fsw._incrReadyCount(); 3465 3466 try { 3467 const linkTarget = await realpath(linkPath); 3468 if (this.fsw.closed) return; 3469 if (this.fsw._isIgnored(linkTarget)) { 3470 return this.fsw._emitReady(); 3471 } 3472 3473 this.fsw._incrReadyCount(); 3474 3475 // add the linkTarget for watching with a wrapper for transform 3476 // that causes emitted paths to incorporate the link's path 3477 this._addToFsEvents(linkTarget || linkPath, (path) => { 3478 let aliasedPath = linkPath; 3479 if (linkTarget && linkTarget !== DOT_SLASH) { 3480 aliasedPath = path.replace(linkTarget, linkPath); 3481 } else if (path !== DOT_SLASH) { 3482 aliasedPath = sysPath$1.join(linkPath, path); 3483 } 3484 return transform(aliasedPath); 3485 }, false, curDepth); 3486 } catch(error) { 3487 if (this.fsw._handleError(error)) { 3488 return this.fsw._emitReady(); 3489 } 3490 } 3491 } 3492 3493 /** 3494 * 3495 * @param {Path} newPath 3496 * @param {fs.Stats} stats 3497 */ 3498 emitAdd(newPath, stats, processPath, opts, forceAdd) { 3499 const pp = processPath(newPath); 3500 const isDir = stats.isDirectory(); 3501 const dirObj = this.fsw._getWatchedDir(sysPath$1.dirname(pp)); 3502 const base = sysPath$1.basename(pp); 3503 3504 // ensure empty dirs get tracked 3505 if (isDir) this.fsw._getWatchedDir(pp); 3506 if (dirObj.has(base)) return; 3507 dirObj.add(base); 3508 3509 if (!opts.ignoreInitial || forceAdd === true) { 3510 this.fsw._emit(isDir ? EV_ADD_DIR$1 : EV_ADD$1, pp, stats); 3511 } 3512 } 3513 3514 initWatch(realPath, path, wh, processPath) { 3515 if (this.fsw.closed) return; 3516 const closer = this._watchWithFsEvents( 3517 wh.watchPath, 3518 sysPath$1.resolve(realPath || wh.watchPath), 3519 processPath, 3520 wh.globFilter 3521 ); 3522 this.fsw._addPathCloser(path, closer); 3523 } 3524 3525 /** 3526 * Handle added path with fsevents 3527 * @param {String} path file/dir path or glob pattern 3528 * @param {Function|Boolean=} transform converts working path to what the user expects 3529 * @param {Boolean=} forceAdd ensure add is emitted 3530 * @param {Number=} priorDepth Level of subdirectories already traversed. 3531 * @returns {Promise<void>} 3532 */ 3533 async _addToFsEvents(path, transform, forceAdd, priorDepth) { 3534 if (this.fsw.closed) { 3535 return; 3536 } 3537 const opts = this.fsw.options; 3538 const processPath = typeof transform === FUNCTION_TYPE$1 ? transform : IDENTITY_FN; 3539 3540 const wh = this.fsw._getWatchHelpers(path); 3541 3542 // evaluate what is at the path we're being asked to watch 3543 try { 3544 const stats = await statMethods[wh.statMethod](wh.watchPath); 3545 if (this.fsw.closed) return; 3546 if (this.fsw._isIgnored(wh.watchPath, stats)) { 3547 throw null; 3548 } 3549 if (stats.isDirectory()) { 3550 // emit addDir unless this is a glob parent 3551 if (!wh.globFilter) this.emitAdd(processPath(path), stats, processPath, opts, forceAdd); 3552 3553 // don't recurse further if it would exceed depth setting 3554 if (priorDepth && priorDepth > opts.depth) return; 3555 3556 // scan the contents of the dir 3557 this.fsw._readdirp(wh.watchPath, { 3558 fileFilter: entry => wh.filterPath(entry), 3559 directoryFilter: entry => wh.filterDir(entry), 3560 ...Depth(opts.depth - (priorDepth || 0)) 3561 }).on(STR_DATA, (entry) => { 3562 // need to check filterPath on dirs b/c filterDir is less restrictive 3563 if (this.fsw.closed) { 3564 return; 3565 } 3566 if (entry.stats.isDirectory() && !wh.filterPath(entry)) return; 3567 3568 const joinedPath = sysPath$1.join(wh.watchPath, entry.path); 3569 const {fullPath} = entry; 3570 3571 if (wh.followSymlinks && entry.stats.isSymbolicLink()) { 3572 // preserve the current depth here since it can't be derived from 3573 // real paths past the symlink 3574 const curDepth = opts.depth === undefined ? 3575 undefined : calcDepth(joinedPath, sysPath$1.resolve(wh.watchPath)) + 1; 3576 3577 this._handleFsEventsSymlink(joinedPath, fullPath, processPath, curDepth); 3578 } else { 3579 this.emitAdd(joinedPath, entry.stats, processPath, opts, forceAdd); 3580 } 3581 }).on(EV_ERROR$1, EMPTY_FN$1).on(STR_END$1, () => { 3582 this.fsw._emitReady(); 3583 }); 3584 } else { 3585 this.emitAdd(wh.watchPath, stats, processPath, opts, forceAdd); 3586 this.fsw._emitReady(); 3587 } 3588 } catch (error) { 3589 if (!error || this.fsw._handleError(error)) { 3590 // TODO: Strange thing: "should not choke on an ignored watch path" will be failed without 2 ready calls -__- 3591 this.fsw._emitReady(); 3592 this.fsw._emitReady(); 3593 } 3594 } 3595 3596 if (opts.persistent && forceAdd !== true) { 3597 if (typeof transform === FUNCTION_TYPE$1) { 3598 // realpath has already been resolved 3599 this.initWatch(undefined, path, wh, processPath); 3600 } else { 3601 let realPath; 3602 try { 3603 realPath = await realpath(wh.watchPath); 3604 } catch (e) {} 3605 this.initWatch(realPath, path, wh, processPath); 3606 } 3607 } 3608 } 3609 3610 }; 3611 3612 fseventsHandler.exports = FsEventsHandler$1; 3613 fseventsHandler.exports.canUse = canUse; 3614 3615 var fseventsHandlerExports = fseventsHandler.exports; 3616 3617 const { EventEmitter } = require$$0$3; 3618 const fs = require$$0$1; 3619 const sysPath = require$$0$2; 3620 const { promisify } = require$$2; 3621 const readdirp = readdirp_1; 3622 const anymatch = anymatchExports.default; 3623 const globParent = globParent$1; 3624 const isGlob = isGlob$2; 3625 const braces = braces_1; 3626 const normalizePath = normalizePath$2; 3627 3628 const NodeFsHandler = nodefsHandler; 3629 const FsEventsHandler = fseventsHandlerExports; 3630 const { 3631 EV_ALL, 3632 EV_READY, 3633 EV_ADD, 3634 EV_CHANGE, 3635 EV_UNLINK, 3636 EV_ADD_DIR, 3637 EV_UNLINK_DIR, 3638 EV_RAW, 3639 EV_ERROR, 3640 3641 STR_CLOSE, 3642 STR_END, 3643 3644 BACK_SLASH_RE, 3645 DOUBLE_SLASH_RE, 3646 SLASH_OR_BACK_SLASH_RE, 3647 DOT_RE, 3648 REPLACER_RE, 3649 3650 SLASH, 3651 SLASH_SLASH, 3652 BRACE_START, 3653 BANG, 3654 ONE_DOT, 3655 TWO_DOTS, 3656 GLOBSTAR, 3657 SLASH_GLOBSTAR, 3658 ANYMATCH_OPTS, 3659 STRING_TYPE, 3660 FUNCTION_TYPE, 3661 EMPTY_STR, 3662 EMPTY_FN, 3663 3664 isWindows, 3665 isMacos, 3666 isIBMi 3667 } = constants; 3668 3669 const stat = promisify(fs.stat); 3670 const readdir = promisify(fs.readdir); 3671 3672 /** 3673 * @typedef {String} Path 3674 * @typedef {'all'|'add'|'addDir'|'change'|'unlink'|'unlinkDir'|'raw'|'error'|'ready'} EventName 3675 * @typedef {'readdir'|'watch'|'add'|'remove'|'change'} ThrottleType 3676 */ 3677 3678 /** 3679 * 3680 * @typedef {Object} WatchHelpers 3681 * @property {Boolean} followSymlinks 3682 * @property {'stat'|'lstat'} statMethod 3683 * @property {Path} path 3684 * @property {Path} watchPath 3685 * @property {Function} entryPath 3686 * @property {Boolean} hasGlob 3687 * @property {Object} globFilter 3688 * @property {Function} filterPath 3689 * @property {Function} filterDir 3690 */ 3691 3692 const arrify = (value = []) => Array.isArray(value) ? value : [value]; 3693 const flatten = (list, result = []) => { 3694 list.forEach(item => { 3695 if (Array.isArray(item)) { 3696 flatten(item, result); 3697 } else { 3698 result.push(item); 3699 } 3700 }); 3701 return result; 3702 }; 3703 3704 const unifyPaths = (paths_) => { 3705 /** 3706 * @type {Array<String>} 3707 */ 3708 const paths = flatten(arrify(paths_)); 3709 if (!paths.every(p => typeof p === STRING_TYPE)) { 3710 throw new TypeError(`Non-string provided as watch path: ${paths}`); 3711 } 3712 return paths.map(normalizePathToUnix); 3713 }; 3714 3715 // If SLASH_SLASH occurs at the beginning of path, it is not replaced 3716 // because "//StoragePC/DrivePool/Movies" is a valid network path 3717 const toUnix = (string) => { 3718 let str = string.replace(BACK_SLASH_RE, SLASH); 3719 let prepend = false; 3720 if (str.startsWith(SLASH_SLASH)) { 3721 prepend = true; 3722 } 3723 while (str.match(DOUBLE_SLASH_RE)) { 3724 str = str.replace(DOUBLE_SLASH_RE, SLASH); 3725 } 3726 if (prepend) { 3727 str = SLASH + str; 3728 } 3729 return str; 3730 }; 3731 3732 // Our version of upath.normalize 3733 // TODO: this is not equal to path-normalize module - investigate why 3734 const normalizePathToUnix = (path) => toUnix(sysPath.normalize(toUnix(path))); 3735 3736 const normalizeIgnored = (cwd = EMPTY_STR) => (path) => { 3737 if (typeof path !== STRING_TYPE) return path; 3738 return normalizePathToUnix(sysPath.isAbsolute(path) ? path : sysPath.join(cwd, path)); 3739 }; 3740 3741 const getAbsolutePath = (path, cwd) => { 3742 if (sysPath.isAbsolute(path)) { 3743 return path; 3744 } 3745 if (path.startsWith(BANG)) { 3746 return BANG + sysPath.join(cwd, path.slice(1)); 3747 } 3748 return sysPath.join(cwd, path); 3749 }; 3750 3751 const undef = (opts, key) => opts[key] === undefined; 3752 3753 /** 3754 * Directory entry. 3755 * @property {Path} path 3756 * @property {Set<Path>} items 3757 */ 3758 class DirEntry { 3759 /** 3760 * @param {Path} dir 3761 * @param {Function} removeWatcher 3762 */ 3763 constructor(dir, removeWatcher) { 3764 this.path = dir; 3765 this._removeWatcher = removeWatcher; 3766 /** @type {Set<Path>} */ 3767 this.items = new Set(); 3768 } 3769 3770 add(item) { 3771 const {items} = this; 3772 if (!items) return; 3773 if (item !== ONE_DOT && item !== TWO_DOTS) items.add(item); 3774 } 3775 3776 async remove(item) { 3777 const {items} = this; 3778 if (!items) return; 3779 items.delete(item); 3780 if (items.size > 0) return; 3781 3782 const dir = this.path; 3783 try { 3784 await readdir(dir); 3785 } catch (err) { 3786 if (this._removeWatcher) { 3787 this._removeWatcher(sysPath.dirname(dir), sysPath.basename(dir)); 3788 } 3789 } 3790 } 3791 3792 has(item) { 3793 const {items} = this; 3794 if (!items) return; 3795 return items.has(item); 3796 } 3797 3798 /** 3799 * @returns {Array<String>} 3800 */ 3801 getChildren() { 3802 const {items} = this; 3803 if (!items) return; 3804 return [...items.values()]; 3805 } 3806 3807 dispose() { 3808 this.items.clear(); 3809 delete this.path; 3810 delete this._removeWatcher; 3811 delete this.items; 3812 Object.freeze(this); 3813 } 3814 } 3815 3816 const STAT_METHOD_F = 'stat'; 3817 const STAT_METHOD_L = 'lstat'; 3818 class WatchHelper { 3819 constructor(path, watchPath, follow, fsw) { 3820 this.fsw = fsw; 3821 this.path = path = path.replace(REPLACER_RE, EMPTY_STR); 3822 this.watchPath = watchPath; 3823 this.fullWatchPath = sysPath.resolve(watchPath); 3824 this.hasGlob = watchPath !== path; 3825 /** @type {object|boolean} */ 3826 if (path === EMPTY_STR) this.hasGlob = false; 3827 this.globSymlink = this.hasGlob && follow ? undefined : false; 3828 this.globFilter = this.hasGlob ? anymatch(path, undefined, ANYMATCH_OPTS) : false; 3829 this.dirParts = this.getDirParts(path); 3830 this.dirParts.forEach((parts) => { 3831 if (parts.length > 1) parts.pop(); 3832 }); 3833 this.followSymlinks = follow; 3834 this.statMethod = follow ? STAT_METHOD_F : STAT_METHOD_L; 3835 } 3836 3837 checkGlobSymlink(entry) { 3838 // only need to resolve once 3839 // first entry should always have entry.parentDir === EMPTY_STR 3840 if (this.globSymlink === undefined) { 3841 this.globSymlink = entry.fullParentDir === this.fullWatchPath ? 3842 false : {realPath: entry.fullParentDir, linkPath: this.fullWatchPath}; 3843 } 3844 3845 if (this.globSymlink) { 3846 return entry.fullPath.replace(this.globSymlink.realPath, this.globSymlink.linkPath); 3847 } 3848 3849 return entry.fullPath; 3850 } 3851 3852 entryPath(entry) { 3853 return sysPath.join(this.watchPath, 3854 sysPath.relative(this.watchPath, this.checkGlobSymlink(entry)) 3855 ); 3856 } 3857 3858 filterPath(entry) { 3859 const {stats} = entry; 3860 if (stats && stats.isSymbolicLink()) return this.filterDir(entry); 3861 const resolvedPath = this.entryPath(entry); 3862 const matchesGlob = this.hasGlob && typeof this.globFilter === FUNCTION_TYPE ? 3863 this.globFilter(resolvedPath) : true; 3864 return matchesGlob && 3865 this.fsw._isntIgnored(resolvedPath, stats) && 3866 this.fsw._hasReadPermissions(stats); 3867 } 3868 3869 getDirParts(path) { 3870 if (!this.hasGlob) return []; 3871 const parts = []; 3872 const expandedPath = path.includes(BRACE_START) ? braces.expand(path) : [path]; 3873 expandedPath.forEach((path) => { 3874 parts.push(sysPath.relative(this.watchPath, path).split(SLASH_OR_BACK_SLASH_RE)); 3875 }); 3876 return parts; 3877 } 3878 3879 filterDir(entry) { 3880 if (this.hasGlob) { 3881 const entryParts = this.getDirParts(this.checkGlobSymlink(entry)); 3882 let globstar = false; 3883 this.unmatchedGlob = !this.dirParts.some((parts) => { 3884 return parts.every((part, i) => { 3885 if (part === GLOBSTAR) globstar = true; 3886 return globstar || !entryParts[0][i] || anymatch(part, entryParts[0][i], ANYMATCH_OPTS); 3887 }); 3888 }); 3889 } 3890 return !this.unmatchedGlob && this.fsw._isntIgnored(this.entryPath(entry), entry.stats); 3891 } 3892 } 3893 3894 /** 3895 * Watches files & directories for changes. Emitted events: 3896 * `add`, `addDir`, `change`, `unlink`, `unlinkDir`, `all`, `error` 3897 * 3898 * new FSWatcher() 3899 * .add(directories) 3900 * .on('add', path => log('File', path, 'was added')) 3901 */ 3902 class FSWatcher extends EventEmitter { 3903 // Not indenting methods for history sake; for now. 3904 constructor(_opts) { 3905 super(); 3906 3907 const opts = {}; 3908 if (_opts) Object.assign(opts, _opts); // for frozen objects 3909 3910 /** @type {Map<String, DirEntry>} */ 3911 this._watched = new Map(); 3912 /** @type {Map<String, Array>} */ 3913 this._closers = new Map(); 3914 /** @type {Set<String>} */ 3915 this._ignoredPaths = new Set(); 3916 3917 /** @type {Map<ThrottleType, Map>} */ 3918 this._throttled = new Map(); 3919 3920 /** @type {Map<Path, String|Boolean>} */ 3921 this._symlinkPaths = new Map(); 3922 3923 this._streams = new Set(); 3924 this.closed = false; 3925 3926 // Set up default options. 3927 if (undef(opts, 'persistent')) opts.persistent = true; 3928 if (undef(opts, 'ignoreInitial')) opts.ignoreInitial = false; 3929 if (undef(opts, 'ignorePermissionErrors')) opts.ignorePermissionErrors = false; 3930 if (undef(opts, 'interval')) opts.interval = 100; 3931 if (undef(opts, 'binaryInterval')) opts.binaryInterval = 300; 3932 if (undef(opts, 'disableGlobbing')) opts.disableGlobbing = false; 3933 opts.enableBinaryInterval = opts.binaryInterval !== opts.interval; 3934 3935 // Enable fsevents on OS X when polling isn't explicitly enabled. 3936 if (undef(opts, 'useFsEvents')) opts.useFsEvents = !opts.usePolling; 3937 3938 // If we can't use fsevents, ensure the options reflect it's disabled. 3939 const canUseFsEvents = FsEventsHandler.canUse(); 3940 if (!canUseFsEvents) opts.useFsEvents = false; 3941 3942 // Use polling on Mac if not using fsevents. 3943 // Other platforms use non-polling fs_watch. 3944 if (undef(opts, 'usePolling') && !opts.useFsEvents) { 3945 opts.usePolling = isMacos; 3946 } 3947 3948 // Always default to polling on IBM i because fs.watch() is not available on IBM i. 3949 if(isIBMi) { 3950 opts.usePolling = true; 3951 } 3952 3953 // Global override (useful for end-developers that need to force polling for all 3954 // instances of chokidar, regardless of usage/dependency depth) 3955 const envPoll = process.env.CHOKIDAR_USEPOLLING; 3956 if (envPoll !== undefined) { 3957 const envLower = envPoll.toLowerCase(); 3958 3959 if (envLower === 'false' || envLower === '0') { 3960 opts.usePolling = false; 3961 } else if (envLower === 'true' || envLower === '1') { 3962 opts.usePolling = true; 3963 } else { 3964 opts.usePolling = !!envLower; 3965 } 3966 } 3967 const envInterval = process.env.CHOKIDAR_INTERVAL; 3968 if (envInterval) { 3969 opts.interval = Number.parseInt(envInterval, 10); 3970 } 3971 3972 // Editor atomic write normalization enabled by default with fs.watch 3973 if (undef(opts, 'atomic')) opts.atomic = !opts.usePolling && !opts.useFsEvents; 3974 if (opts.atomic) this._pendingUnlinks = new Map(); 3975 3976 if (undef(opts, 'followSymlinks')) opts.followSymlinks = true; 3977 3978 if (undef(opts, 'awaitWriteFinish')) opts.awaitWriteFinish = false; 3979 if (opts.awaitWriteFinish === true) opts.awaitWriteFinish = {}; 3980 const awf = opts.awaitWriteFinish; 3981 if (awf) { 3982 if (!awf.stabilityThreshold) awf.stabilityThreshold = 2000; 3983 if (!awf.pollInterval) awf.pollInterval = 100; 3984 this._pendingWrites = new Map(); 3985 } 3986 if (opts.ignored) opts.ignored = arrify(opts.ignored); 3987 3988 let readyCalls = 0; 3989 this._emitReady = () => { 3990 readyCalls++; 3991 if (readyCalls >= this._readyCount) { 3992 this._emitReady = EMPTY_FN; 3993 this._readyEmitted = true; 3994 // use process.nextTick to allow time for listener to be bound 3995 process.nextTick(() => this.emit(EV_READY)); 3996 } 3997 }; 3998 this._emitRaw = (...args) => this.emit(EV_RAW, ...args); 3999 this._readyEmitted = false; 4000 this.options = opts; 4001 4002 // Initialize with proper watcher. 4003 if (opts.useFsEvents) { 4004 this._fsEventsHandler = new FsEventsHandler(this); 4005 } else { 4006 this._nodeFsHandler = new NodeFsHandler(this); 4007 } 4008 4009 // You’re frozen when your heart’s not open. 4010 Object.freeze(opts); 4011 } 4012 4013 // Public methods 4014 4015 /** 4016 * Adds paths to be watched on an existing FSWatcher instance 4017 * @param {Path|Array<Path>} paths_ 4018 * @param {String=} _origAdd private; for handling non-existent paths to be watched 4019 * @param {Boolean=} _internal private; indicates a non-user add 4020 * @returns {FSWatcher} for chaining 4021 */ 4022 add(paths_, _origAdd, _internal) { 4023 const {cwd, disableGlobbing} = this.options; 4024 this.closed = false; 4025 let paths = unifyPaths(paths_); 4026 if (cwd) { 4027 paths = paths.map((path) => { 4028 const absPath = getAbsolutePath(path, cwd); 4029 4030 // Check `path` instead of `absPath` because the cwd portion can't be a glob 4031 if (disableGlobbing || !isGlob(path)) { 4032 return absPath; 4033 } 4034 return normalizePath(absPath); 4035 }); 4036 } 4037 4038 // set aside negated glob strings 4039 paths = paths.filter((path) => { 4040 if (path.startsWith(BANG)) { 4041 this._ignoredPaths.add(path.slice(1)); 4042 return false; 4043 } 4044 4045 // if a path is being added that was previously ignored, stop ignoring it 4046 this._ignoredPaths.delete(path); 4047 this._ignoredPaths.delete(path + SLASH_GLOBSTAR); 4048 4049 // reset the cached userIgnored anymatch fn 4050 // to make ignoredPaths changes effective 4051 this._userIgnored = undefined; 4052 4053 return true; 4054 }); 4055 4056 if (this.options.useFsEvents && this._fsEventsHandler) { 4057 if (!this._readyCount) this._readyCount = paths.length; 4058 if (this.options.persistent) this._readyCount += paths.length; 4059 paths.forEach((path) => this._fsEventsHandler._addToFsEvents(path)); 4060 } else { 4061 if (!this._readyCount) this._readyCount = 0; 4062 this._readyCount += paths.length; 4063 Promise.all( 4064 paths.map(async path => { 4065 const res = await this._nodeFsHandler._addToNodeFs(path, !_internal, 0, 0, _origAdd); 4066 if (res) this._emitReady(); 4067 return res; 4068 }) 4069 ).then(results => { 4070 if (this.closed) return; 4071 results.filter(item => item).forEach(item => { 4072 this.add(sysPath.dirname(item), sysPath.basename(_origAdd || item)); 4073 }); 4074 }); 4075 } 4076 4077 return this; 4078 } 4079 4080 /** 4081 * Close watchers or start ignoring events from specified paths. 4082 * @param {Path|Array<Path>} paths_ - string or array of strings, file/directory paths and/or globs 4083 * @returns {FSWatcher} for chaining 4084 */ 4085 unwatch(paths_) { 4086 if (this.closed) return this; 4087 const paths = unifyPaths(paths_); 4088 const {cwd} = this.options; 4089 4090 paths.forEach((path) => { 4091 // convert to absolute path unless relative path already matches 4092 if (!sysPath.isAbsolute(path) && !this._closers.has(path)) { 4093 if (cwd) path = sysPath.join(cwd, path); 4094 path = sysPath.resolve(path); 4095 } 4096 4097 this._closePath(path); 4098 4099 this._ignoredPaths.add(path); 4100 if (this._watched.has(path)) { 4101 this._ignoredPaths.add(path + SLASH_GLOBSTAR); 4102 } 4103 4104 // reset the cached userIgnored anymatch fn 4105 // to make ignoredPaths changes effective 4106 this._userIgnored = undefined; 4107 }); 4108 4109 return this; 4110 } 4111 4112 /** 4113 * Close watchers and remove all listeners from watched paths. 4114 * @returns {Promise<void>}. 4115 */ 4116 close() { 4117 if (this.closed) return this._closePromise; 4118 this.closed = true; 4119 4120 // Memory management. 4121 this.removeAllListeners(); 4122 const closers = []; 4123 this._closers.forEach(closerList => closerList.forEach(closer => { 4124 const promise = closer(); 4125 if (promise instanceof Promise) closers.push(promise); 4126 })); 4127 this._streams.forEach(stream => stream.destroy()); 4128 this._userIgnored = undefined; 4129 this._readyCount = 0; 4130 this._readyEmitted = false; 4131 this._watched.forEach(dirent => dirent.dispose()); 4132 ['closers', 'watched', 'streams', 'symlinkPaths', 'throttled'].forEach(key => { 4133 this[`_${key}`].clear(); 4134 }); 4135 4136 this._closePromise = closers.length ? Promise.all(closers).then(() => undefined) : Promise.resolve(); 4137 return this._closePromise; 4138 } 4139 4140 /** 4141 * Expose list of watched paths 4142 * @returns {Object} for chaining 4143 */ 4144 getWatched() { 4145 const watchList = {}; 4146 this._watched.forEach((entry, dir) => { 4147 const key = this.options.cwd ? sysPath.relative(this.options.cwd, dir) : dir; 4148 watchList[key || ONE_DOT] = entry.getChildren().sort(); 4149 }); 4150 return watchList; 4151 } 4152 4153 emitWithAll(event, args) { 4154 this.emit(...args); 4155 if (event !== EV_ERROR) this.emit(EV_ALL, ...args); 4156 } 4157 4158 // Common helpers 4159 // -------------- 4160 4161 /** 4162 * Normalize and emit events. 4163 * Calling _emit DOES NOT MEAN emit() would be called! 4164 * @param {EventName} event Type of event 4165 * @param {Path} path File or directory path 4166 * @param {*=} val1 arguments to be passed with event 4167 * @param {*=} val2 4168 * @param {*=} val3 4169 * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag 4170 */ 4171 async _emit(event, path, val1, val2, val3) { 4172 if (this.closed) return; 4173 4174 const opts = this.options; 4175 if (isWindows) path = sysPath.normalize(path); 4176 if (opts.cwd) path = sysPath.relative(opts.cwd, path); 4177 /** @type Array<any> */ 4178 const args = [event, path]; 4179 if (val3 !== undefined) args.push(val1, val2, val3); 4180 else if (val2 !== undefined) args.push(val1, val2); 4181 else if (val1 !== undefined) args.push(val1); 4182 4183 const awf = opts.awaitWriteFinish; 4184 let pw; 4185 if (awf && (pw = this._pendingWrites.get(path))) { 4186 pw.lastChange = new Date(); 4187 return this; 4188 } 4189 4190 if (opts.atomic) { 4191 if (event === EV_UNLINK) { 4192 this._pendingUnlinks.set(path, args); 4193 setTimeout(() => { 4194 this._pendingUnlinks.forEach((entry, path) => { 4195 this.emit(...entry); 4196 this.emit(EV_ALL, ...entry); 4197 this._pendingUnlinks.delete(path); 4198 }); 4199 }, typeof opts.atomic === 'number' ? opts.atomic : 100); 4200 return this; 4201 } 4202 if (event === EV_ADD && this._pendingUnlinks.has(path)) { 4203 event = args[0] = EV_CHANGE; 4204 this._pendingUnlinks.delete(path); 4205 } 4206 } 4207 4208 if (awf && (event === EV_ADD || event === EV_CHANGE) && this._readyEmitted) { 4209 const awfEmit = (err, stats) => { 4210 if (err) { 4211 event = args[0] = EV_ERROR; 4212 args[1] = err; 4213 this.emitWithAll(event, args); 4214 } else if (stats) { 4215 // if stats doesn't exist the file must have been deleted 4216 if (args.length > 2) { 4217 args[2] = stats; 4218 } else { 4219 args.push(stats); 4220 } 4221 this.emitWithAll(event, args); 4222 } 4223 }; 4224 4225 this._awaitWriteFinish(path, awf.stabilityThreshold, event, awfEmit); 4226 return this; 4227 } 4228 4229 if (event === EV_CHANGE) { 4230 const isThrottled = !this._throttle(EV_CHANGE, path, 50); 4231 if (isThrottled) return this; 4232 } 4233 4234 if (opts.alwaysStat && val1 === undefined && 4235 (event === EV_ADD || event === EV_ADD_DIR || event === EV_CHANGE) 4236 ) { 4237 const fullPath = opts.cwd ? sysPath.join(opts.cwd, path) : path; 4238 let stats; 4239 try { 4240 stats = await stat(fullPath); 4241 } catch (err) {} 4242 // Suppress event when fs_stat fails, to avoid sending undefined 'stat' 4243 if (!stats || this.closed) return; 4244 args.push(stats); 4245 } 4246 this.emitWithAll(event, args); 4247 4248 return this; 4249 } 4250 4251 /** 4252 * Common handler for errors 4253 * @param {Error} error 4254 * @returns {Error|Boolean} The error if defined, otherwise the value of the FSWatcher instance's `closed` flag 4255 */ 4256 _handleError(error) { 4257 const code = error && error.code; 4258 if (error && code !== 'ENOENT' && code !== 'ENOTDIR' && 4259 (!this.options.ignorePermissionErrors || (code !== 'EPERM' && code !== 'EACCES')) 4260 ) { 4261 this.emit(EV_ERROR, error); 4262 } 4263 return error || this.closed; 4264 } 4265 4266 /** 4267 * Helper utility for throttling 4268 * @param {ThrottleType} actionType type being throttled 4269 * @param {Path} path being acted upon 4270 * @param {Number} timeout duration of time to suppress duplicate actions 4271 * @returns {Object|false} tracking object or false if action should be suppressed 4272 */ 4273 _throttle(actionType, path, timeout) { 4274 if (!this._throttled.has(actionType)) { 4275 this._throttled.set(actionType, new Map()); 4276 } 4277 4278 /** @type {Map<Path, Object>} */ 4279 const action = this._throttled.get(actionType); 4280 /** @type {Object} */ 4281 const actionPath = action.get(path); 4282 4283 if (actionPath) { 4284 actionPath.count++; 4285 return false; 4286 } 4287 4288 let timeoutObject; 4289 const clear = () => { 4290 const item = action.get(path); 4291 const count = item ? item.count : 0; 4292 action.delete(path); 4293 clearTimeout(timeoutObject); 4294 if (item) clearTimeout(item.timeoutObject); 4295 return count; 4296 }; 4297 timeoutObject = setTimeout(clear, timeout); 4298 const thr = {timeoutObject, clear, count: 0}; 4299 action.set(path, thr); 4300 return thr; 4301 } 4302 4303 _incrReadyCount() { 4304 return this._readyCount++; 4305 } 4306 4307 /** 4308 * Awaits write operation to finish. 4309 * Polls a newly created file for size variations. When files size does not change for 'threshold' milliseconds calls callback. 4310 * @param {Path} path being acted upon 4311 * @param {Number} threshold Time in milliseconds a file size must be fixed before acknowledging write OP is finished 4312 * @param {EventName} event 4313 * @param {Function} awfEmit Callback to be called when ready for event to be emitted. 4314 */ 4315 _awaitWriteFinish(path, threshold, event, awfEmit) { 4316 let timeoutHandler; 4317 4318 let fullPath = path; 4319 if (this.options.cwd && !sysPath.isAbsolute(path)) { 4320 fullPath = sysPath.join(this.options.cwd, path); 4321 } 4322 4323 const now = new Date(); 4324 4325 const awaitWriteFinish = (prevStat) => { 4326 fs.stat(fullPath, (err, curStat) => { 4327 if (err || !this._pendingWrites.has(path)) { 4328 if (err && err.code !== 'ENOENT') awfEmit(err); 4329 return; 4330 } 4331 4332 const now = Number(new Date()); 4333 4334 if (prevStat && curStat.size !== prevStat.size) { 4335 this._pendingWrites.get(path).lastChange = now; 4336 } 4337 const pw = this._pendingWrites.get(path); 4338 const df = now - pw.lastChange; 4339 4340 if (df >= threshold) { 4341 this._pendingWrites.delete(path); 4342 awfEmit(undefined, curStat); 4343 } else { 4344 timeoutHandler = setTimeout( 4345 awaitWriteFinish, 4346 this.options.awaitWriteFinish.pollInterval, 4347 curStat 4348 ); 4349 } 4350 }); 4351 }; 4352 4353 if (!this._pendingWrites.has(path)) { 4354 this._pendingWrites.set(path, { 4355 lastChange: now, 4356 cancelWait: () => { 4357 this._pendingWrites.delete(path); 4358 clearTimeout(timeoutHandler); 4359 return event; 4360 } 4361 }); 4362 timeoutHandler = setTimeout( 4363 awaitWriteFinish, 4364 this.options.awaitWriteFinish.pollInterval 4365 ); 4366 } 4367 } 4368 4369 _getGlobIgnored() { 4370 return [...this._ignoredPaths.values()]; 4371 } 4372 4373 /** 4374 * Determines whether user has asked to ignore this path. 4375 * @param {Path} path filepath or dir 4376 * @param {fs.Stats=} stats result of fs.stat 4377 * @returns {Boolean} 4378 */ 4379 _isIgnored(path, stats) { 4380 if (this.options.atomic && DOT_RE.test(path)) return true; 4381 if (!this._userIgnored) { 4382 const {cwd} = this.options; 4383 const ign = this.options.ignored; 4384 4385 const ignored = ign && ign.map(normalizeIgnored(cwd)); 4386 const paths = arrify(ignored) 4387 .filter((path) => typeof path === STRING_TYPE && !isGlob(path)) 4388 .map((path) => path + SLASH_GLOBSTAR); 4389 const list = this._getGlobIgnored().map(normalizeIgnored(cwd)).concat(ignored, paths); 4390 this._userIgnored = anymatch(list, undefined, ANYMATCH_OPTS); 4391 } 4392 4393 return this._userIgnored([path, stats]); 4394 } 4395 4396 _isntIgnored(path, stat) { 4397 return !this._isIgnored(path, stat); 4398 } 4399 4400 /** 4401 * Provides a set of common helpers and properties relating to symlink and glob handling. 4402 * @param {Path} path file, directory, or glob pattern being watched 4403 * @param {Number=} depth at any depth > 0, this isn't a glob 4404 * @returns {WatchHelper} object containing helpers for this path 4405 */ 4406 _getWatchHelpers(path, depth) { 4407 const watchPath = depth || this.options.disableGlobbing || !isGlob(path) ? path : globParent(path); 4408 const follow = this.options.followSymlinks; 4409 4410 return new WatchHelper(path, watchPath, follow, this); 4411 } 4412 4413 // Directory helpers 4414 // ----------------- 4415 4416 /** 4417 * Provides directory tracking objects 4418 * @param {String} directory path of the directory 4419 * @returns {DirEntry} the directory's tracking object 4420 */ 4421 _getWatchedDir(directory) { 4422 if (!this._boundRemove) this._boundRemove = this._remove.bind(this); 4423 const dir = sysPath.resolve(directory); 4424 if (!this._watched.has(dir)) this._watched.set(dir, new DirEntry(dir, this._boundRemove)); 4425 return this._watched.get(dir); 4426 } 4427 4428 // File helpers 4429 // ------------ 4430 4431 /** 4432 * Check for read permissions. 4433 * Based on this answer on SO: https://stackoverflow.com/a/11781404/1358405 4434 * @param {fs.Stats} stats - object, result of fs_stat 4435 * @returns {Boolean} indicates whether the file can be read 4436 */ 4437 _hasReadPermissions(stats) { 4438 if (this.options.ignorePermissionErrors) return true; 4439 4440 // stats.mode may be bigint 4441 const md = stats && Number.parseInt(stats.mode, 10); 4442 const st = md & 0o777; 4443 const it = Number.parseInt(st.toString(8)[0], 10); 4444 return Boolean(4 & it); 4445 } 4446 4447 /** 4448 * Handles emitting unlink events for 4449 * files and directories, and via recursion, for 4450 * files and directories within directories that are unlinked 4451 * @param {String} directory within which the following item is located 4452 * @param {String} item base path of item/directory 4453 * @returns {void} 4454 */ 4455 _remove(directory, item, isDirectory) { 4456 // if what is being deleted is a directory, get that directory's paths 4457 // for recursive deleting and cleaning of watched object 4458 // if it is not a directory, nestedDirectoryChildren will be empty array 4459 const path = sysPath.join(directory, item); 4460 const fullPath = sysPath.resolve(path); 4461 isDirectory = isDirectory != null 4462 ? isDirectory 4463 : this._watched.has(path) || this._watched.has(fullPath); 4464 4465 // prevent duplicate handling in case of arriving here nearly simultaneously 4466 // via multiple paths (such as _handleFile and _handleDir) 4467 if (!this._throttle('remove', path, 100)) return; 4468 4469 // if the only watched file is removed, watch for its return 4470 if (!isDirectory && !this.options.useFsEvents && this._watched.size === 1) { 4471 this.add(directory, item, true); 4472 } 4473 4474 // This will create a new entry in the watched object in either case 4475 // so we got to do the directory check beforehand 4476 const wp = this._getWatchedDir(path); 4477 const nestedDirectoryChildren = wp.getChildren(); 4478 4479 // Recursively remove children directories / files. 4480 nestedDirectoryChildren.forEach(nested => this._remove(path, nested)); 4481 4482 // Check if item was on the watched list and remove it 4483 const parent = this._getWatchedDir(directory); 4484 const wasTracked = parent.has(item); 4485 parent.remove(item); 4486 4487 // Fixes issue #1042 -> Relative paths were detected and added as symlinks 4488 // (https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L612), 4489 // but never removed from the map in case the path was deleted. 4490 // This leads to an incorrect state if the path was recreated: 4491 // https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L553 4492 if (this._symlinkPaths.has(fullPath)) { 4493 this._symlinkPaths.delete(fullPath); 4494 } 4495 4496 // If we wait for this file to be fully written, cancel the wait. 4497 let relPath = path; 4498 if (this.options.cwd) relPath = sysPath.relative(this.options.cwd, path); 4499 if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) { 4500 const event = this._pendingWrites.get(relPath).cancelWait(); 4501 if (event === EV_ADD) return; 4502 } 4503 4504 // The Entry will either be a directory that just got removed 4505 // or a bogus entry to a file, in either case we have to remove it 4506 this._watched.delete(path); 4507 this._watched.delete(fullPath); 4508 const eventName = isDirectory ? EV_UNLINK_DIR : EV_UNLINK; 4509 if (wasTracked && !this._isIgnored(path)) this._emit(eventName, path); 4510 4511 // Avoid conflicts if we later create another file with the same name 4512 if (!this.options.useFsEvents) { 4513 this._closePath(path); 4514 } 4515 } 4516 4517 /** 4518 * Closes all watchers for a path 4519 * @param {Path} path 4520 */ 4521 _closePath(path) { 4522 this._closeFile(path); 4523 const dir = sysPath.dirname(path); 4524 this._getWatchedDir(dir).remove(sysPath.basename(path)); 4525 } 4526 4527 /** 4528 * Closes only file-specific watchers 4529 * @param {Path} path 4530 */ 4531 _closeFile(path) { 4532 const closers = this._closers.get(path); 4533 if (!closers) return; 4534 closers.forEach(closer => closer()); 4535 this._closers.delete(path); 4536 } 4537 4538 /** 4539 * 4540 * @param {Path} path 4541 * @param {Function} closer 4542 */ 4543 _addPathCloser(path, closer) { 4544 if (!closer) return; 4545 let list = this._closers.get(path); 4546 if (!list) { 4547 list = []; 4548 this._closers.set(path, list); 4549 } 4550 list.push(closer); 4551 } 4552 4553 _readdirp(root, opts) { 4554 if (this.closed) return; 4555 const options = {type: EV_ALL, alwaysStat: true, lstat: true, ...opts}; 4556 let stream = readdirp(root, options); 4557 this._streams.add(stream); 4558 stream.once(STR_CLOSE, () => { 4559 stream = undefined; 4560 }); 4561 stream.once(STR_END, () => { 4562 if (stream) { 4563 this._streams.delete(stream); 4564 stream = undefined; 4565 } 4566 }); 4567 return stream; 4568 } 4569 4570 } 4571 4572 // Export FSWatcher class 4573 chokidar.FSWatcher = FSWatcher; 4574 4575 /** 4576 * Instantiates watcher with paths to be tracked. 4577 * @param {String|Array<String>} paths file/directory paths and/or globs 4578 * @param {Object=} options chokidar opts 4579 * @returns an instance of FSWatcher for chaining. 4580 */ 4581 const watch = (paths, options) => { 4582 const watcher = new FSWatcher(options); 4583 watcher.add(paths); 4584 return watcher; 4585 }; 4586 4587 chokidar.watch = watch; 8999 var chokidarExports = /*@__PURE__*/ requireChokidar(); 9000 const chokidar = /*@__PURE__*/rollup.getDefaultExportFromCjs(chokidarExports); 4588 9001 4589 9002 exports.chokidar = chokidar;
Note:
See TracChangeset
for help on using the changeset viewer.